Fix umulh and smulh bugs. Fix bugs in last week's sumov.s testsuite.
[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
152e1e1b 2623do_vec_SMOV_into_scalar (sim_cpu *cpu)
2e8cf49e
NC
2624{
2625 /* instr[31] = 0
2626 instr[30] = word(0)/long(1)
2627 instr[29,21] = 00 1110 000
152e1e1b
JW
2628 instr[20,16] = element size and index
2629 instr[15,10] = 00 0010 11
2e8cf49e
NC
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);
152e1e1b
JW
2635 unsigned imm5 = INSTR (20, 16);
2636 unsigned full = INSTR (30, 30);
2637 int size, index;
2e8cf49e
NC
2638
2639 NYI_assert (29, 21, 0x070);
152e1e1b 2640 NYI_assert (15, 10, 0x0B);
2e8cf49e 2641
2cdad34c 2642 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
152e1e1b
JW
2643
2644 if (imm5 & 0x1)
2645 {
2646 size = 0;
2647 index = (imm5 >> 1) & 0xF;
2648 }
2649 else if (imm5 & 0x2)
2650 {
2651 size = 1;
2652 index = (imm5 >> 2) & 0x7;
2653 }
2654 else if (full && (imm5 & 0x4))
2655 {
2656 size = 2;
2657 index = (imm5 >> 3) & 0x3;
2658 }
2659 else
2660 HALT_UNALLOC;
2661
2662 switch (size)
2e8cf49e 2663 {
152e1e1b
JW
2664 case 0:
2665 if (full)
2666 aarch64_set_reg_s64 (cpu, rd, NO_SP,
2667 aarch64_get_vec_s8 (cpu, vs, index));
2668 else
2669 aarch64_set_reg_s32 (cpu, rd, NO_SP,
2670 aarch64_get_vec_s8 (cpu, vs, index));
2e8cf49e
NC
2671 break;
2672
152e1e1b
JW
2673 case 1:
2674 if (full)
2675 aarch64_set_reg_s64 (cpu, rd, NO_SP,
2676 aarch64_get_vec_s16 (cpu, vs, index));
2677 else
2678 aarch64_set_reg_s32 (cpu, rd, NO_SP,
2679 aarch64_get_vec_s16 (cpu, vs, index));
2e8cf49e
NC
2680 break;
2681
152e1e1b
JW
2682 case 2:
2683 aarch64_set_reg_s64 (cpu, rd, NO_SP,
2684 aarch64_get_vec_s32 (cpu, vs, index));
2e8cf49e
NC
2685 break;
2686
2687 default:
152e1e1b
JW
2688 HALT_UNALLOC;
2689 }
2690}
2691
2692static void
2693do_vec_UMOV_into_scalar (sim_cpu *cpu)
2694{
2695 /* instr[31] = 0
2696 instr[30] = word(0)/long(1)
2697 instr[29,21] = 00 1110 000
2698 instr[20,16] = element size and index
2699 instr[15,10] = 00 0011 11
2700 instr[9,5] = V source
2701 instr[4,0] = R dest */
2702
2703 unsigned vs = INSTR (9, 5);
2704 unsigned rd = INSTR (4, 0);
2705 unsigned imm5 = INSTR (20, 16);
2706 unsigned full = INSTR (30, 30);
2707 int size, index;
2708
2709 NYI_assert (29, 21, 0x070);
2710 NYI_assert (15, 10, 0x0F);
2711
2712 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2713
2714 if (!full)
2715 {
2716 if (imm5 & 0x1)
2717 {
2718 size = 0;
2719 index = (imm5 >> 1) & 0xF;
2720 }
2721 else if (imm5 & 0x2)
2722 {
2723 size = 1;
2724 index = (imm5 >> 2) & 0x7;
2725 }
2726 else if (imm5 & 0x4)
2727 {
2728 size = 2;
2729 index = (imm5 >> 3) & 0x3;
2730 }
2731 else
2732 HALT_UNALLOC;
2733 }
2734 else if (imm5 & 0x8)
2735 {
2736 size = 3;
2737 index = (imm5 >> 4) & 0x1;
2738 }
2739 else
2740 HALT_UNALLOC;
2741
2742 switch (size)
2743 {
2744 case 0:
2745 aarch64_set_reg_u32 (cpu, rd, NO_SP,
2746 aarch64_get_vec_u8 (cpu, vs, index));
2747 break;
2748
2749 case 1:
2750 aarch64_set_reg_u32 (cpu, rd, NO_SP,
2751 aarch64_get_vec_u16 (cpu, vs, index));
2752 break;
2753
2754 case 2:
2755 aarch64_set_reg_u32 (cpu, rd, NO_SP,
2756 aarch64_get_vec_u32 (cpu, vs, index));
2757 break;
2758
2759 case 3:
2760 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2761 aarch64_get_vec_u64 (cpu, vs, index));
2762 break;
2763
2764 default:
2765 HALT_UNALLOC;
2e8cf49e
NC
2766 }
2767}
2768
2769static void
2770do_vec_INS (sim_cpu *cpu)
2771{
2772 /* instr[31,21] = 01001110000
2773 instr[20,16] = element size and index
2774 instr[15,10] = 000111
2775 instr[9,5] = W source
2776 instr[4,0] = V dest */
2777
2778 int index;
ef0d8ffc
NC
2779 unsigned rs = INSTR (9, 5);
2780 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2781
2782 NYI_assert (31, 21, 0x270);
2783 NYI_assert (15, 10, 0x07);
2784
2cdad34c 2785 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2786 if (INSTR (16, 16))
2e8cf49e 2787 {
ef0d8ffc 2788 index = INSTR (20, 17);
2e8cf49e
NC
2789 aarch64_set_vec_u8 (cpu, vd, index,
2790 aarch64_get_reg_u8 (cpu, rs, NO_SP));
2791 }
ef0d8ffc 2792 else if (INSTR (17, 17))
2e8cf49e 2793 {
ef0d8ffc 2794 index = INSTR (20, 18);
2e8cf49e
NC
2795 aarch64_set_vec_u16 (cpu, vd, index,
2796 aarch64_get_reg_u16 (cpu, rs, NO_SP));
2797 }
ef0d8ffc 2798 else if (INSTR (18, 18))
2e8cf49e 2799 {
ef0d8ffc 2800 index = INSTR (20, 19);
2e8cf49e
NC
2801 aarch64_set_vec_u32 (cpu, vd, index,
2802 aarch64_get_reg_u32 (cpu, rs, NO_SP));
2803 }
ef0d8ffc 2804 else if (INSTR (19, 19))
2e8cf49e 2805 {
ef0d8ffc 2806 index = INSTR (20, 20);
2e8cf49e
NC
2807 aarch64_set_vec_u64 (cpu, vd, index,
2808 aarch64_get_reg_u64 (cpu, rs, NO_SP));
2809 }
2810 else
2811 HALT_NYI;
2812}
2813
2814static void
2815do_vec_DUP_vector_into_vector (sim_cpu *cpu)
2816{
2817 /* instr[31] = 0
2818 instr[30] = half(0)/full(1)
2819 instr[29,21] = 00 1110 000
2820 instr[20,16] = element size and index
2821 instr[15,10] = 0000 01
2822 instr[9,5] = V source
2823 instr[4,0] = V dest. */
2824
ef0d8ffc
NC
2825 unsigned full = INSTR (30, 30);
2826 unsigned vs = INSTR (9, 5);
2827 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2828 int i, index;
2829
2830 NYI_assert (29, 21, 0x070);
2831 NYI_assert (15, 10, 0x01);
2832
2cdad34c 2833 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2834 if (INSTR (16, 16))
2e8cf49e 2835 {
ef0d8ffc 2836 index = INSTR (20, 17);
2e8cf49e
NC
2837
2838 for (i = 0; i < (full ? 16 : 8); i++)
2839 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, index));
2840 }
ef0d8ffc 2841 else if (INSTR (17, 17))
2e8cf49e 2842 {
ef0d8ffc 2843 index = INSTR (20, 18);
2e8cf49e
NC
2844
2845 for (i = 0; i < (full ? 8 : 4); i++)
2846 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, index));
2847 }
ef0d8ffc 2848 else if (INSTR (18, 18))
2e8cf49e 2849 {
ef0d8ffc 2850 index = INSTR (20, 19);
2e8cf49e
NC
2851
2852 for (i = 0; i < (full ? 4 : 2); i++)
2853 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, index));
2854 }
2855 else
2856 {
ef0d8ffc 2857 if (INSTR (19, 19) == 0)
2e8cf49e
NC
2858 HALT_UNALLOC;
2859
2860 if (! full)
2861 HALT_UNALLOC;
2862
ef0d8ffc 2863 index = INSTR (20, 20);
2e8cf49e
NC
2864
2865 for (i = 0; i < 2; i++)
2866 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, index));
2867 }
2868}
2869
2870static void
2871do_vec_TBL (sim_cpu *cpu)
2872{
2873 /* instr[31] = 0
2874 instr[30] = half(0)/full(1)
2875 instr[29,21] = 00 1110 000
2876 instr[20,16] = Vm
2877 instr[15] = 0
2878 instr[14,13] = vec length
2879 instr[12,10] = 000
2880 instr[9,5] = V start
2881 instr[4,0] = V dest */
2882
ef0d8ffc
NC
2883 int full = INSTR (30, 30);
2884 int len = INSTR (14, 13) + 1;
2885 unsigned vm = INSTR (20, 16);
2886 unsigned vn = INSTR (9, 5);
2887 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2888 unsigned i;
2889
2890 NYI_assert (29, 21, 0x070);
2891 NYI_assert (12, 10, 0);
2892
2cdad34c 2893 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2894 for (i = 0; i < (full ? 16 : 8); i++)
2895 {
2896 unsigned int selector = aarch64_get_vec_u8 (cpu, vm, i);
2897 uint8_t val;
2898
2899 if (selector < 16)
2900 val = aarch64_get_vec_u8 (cpu, vn, selector);
2901 else if (selector < 32)
2902 val = len < 2 ? 0 : aarch64_get_vec_u8 (cpu, vn + 1, selector - 16);
2903 else if (selector < 48)
2904 val = len < 3 ? 0 : aarch64_get_vec_u8 (cpu, vn + 2, selector - 32);
2905 else if (selector < 64)
2906 val = len < 4 ? 0 : aarch64_get_vec_u8 (cpu, vn + 3, selector - 48);
2907 else
2908 val = 0;
2909
2910 aarch64_set_vec_u8 (cpu, vd, i, val);
2911 }
2912}
2913
2914static void
2915do_vec_TRN (sim_cpu *cpu)
2916{
2917 /* instr[31] = 0
2918 instr[30] = half(0)/full(1)
2919 instr[29,24] = 00 1110
2920 instr[23,22] = size
2921 instr[21] = 0
2922 instr[20,16] = Vm
2923 instr[15] = 0
2924 instr[14] = TRN1 (0) / TRN2 (1)
2925 instr[13,10] = 1010
2926 instr[9,5] = V source
2927 instr[4,0] = V dest. */
2928
ef0d8ffc
NC
2929 int full = INSTR (30, 30);
2930 int second = INSTR (14, 14);
2931 unsigned vm = INSTR (20, 16);
2932 unsigned vn = INSTR (9, 5);
2933 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2934 unsigned i;
2935
2936 NYI_assert (29, 24, 0x0E);
2937 NYI_assert (13, 10, 0xA);
2938
2cdad34c 2939 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2940 switch (INSTR (23, 22))
2e8cf49e
NC
2941 {
2942 case 0:
2943 for (i = 0; i < (full ? 8 : 4); i++)
2944 {
2945 aarch64_set_vec_u8
2946 (cpu, vd, i * 2,
2947 aarch64_get_vec_u8 (cpu, second ? vm : vn, i * 2));
2948 aarch64_set_vec_u8
2949 (cpu, vd, 1 * 2 + 1,
2950 aarch64_get_vec_u8 (cpu, second ? vn : vm, i * 2 + 1));
2951 }
2952 break;
2953
2954 case 1:
2955 for (i = 0; i < (full ? 4 : 2); i++)
2956 {
2957 aarch64_set_vec_u16
2958 (cpu, vd, i * 2,
2959 aarch64_get_vec_u16 (cpu, second ? vm : vn, i * 2));
2960 aarch64_set_vec_u16
2961 (cpu, vd, 1 * 2 + 1,
2962 aarch64_get_vec_u16 (cpu, second ? vn : vm, i * 2 + 1));
2963 }
2964 break;
2965
2966 case 2:
2967 aarch64_set_vec_u32
2968 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, second ? vm : vn, 0));
2969 aarch64_set_vec_u32
2970 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, second ? vn : vm, 1));
2971 aarch64_set_vec_u32
2972 (cpu, vd, 2, aarch64_get_vec_u32 (cpu, second ? vm : vn, 2));
2973 aarch64_set_vec_u32
2974 (cpu, vd, 3, aarch64_get_vec_u32 (cpu, second ? vn : vm, 3));
2975 break;
2976
2977 case 3:
2978 if (! full)
2979 HALT_UNALLOC;
2980
2981 aarch64_set_vec_u64 (cpu, vd, 0,
2982 aarch64_get_vec_u64 (cpu, second ? vm : vn, 0));
2983 aarch64_set_vec_u64 (cpu, vd, 1,
2984 aarch64_get_vec_u64 (cpu, second ? vn : vm, 1));
2985 break;
2e8cf49e
NC
2986 }
2987}
2988
2989static void
2990do_vec_DUP_scalar_into_vector (sim_cpu *cpu)
2991{
2992 /* instr[31] = 0
2993 instr[30] = 0=> zero top 64-bits, 1=> duplicate into top 64-bits
2994 [must be 1 for 64-bit xfer]
2995 instr[29,20] = 00 1110 0000
2996 instr[19,16] = element size: 0001=> 8-bits, 0010=> 16-bits,
2997 0100=> 32-bits. 1000=>64-bits
2998 instr[15,10] = 0000 11
2999 instr[9,5] = W source
3000 instr[4,0] = V dest. */
3001
3002 unsigned i;
ef0d8ffc
NC
3003 unsigned Vd = INSTR (4, 0);
3004 unsigned Rs = INSTR (9, 5);
3005 int both = INSTR (30, 30);
2e8cf49e
NC
3006
3007 NYI_assert (29, 20, 0x0E0);
3008 NYI_assert (15, 10, 0x03);
3009
2cdad34c 3010 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3011 switch (INSTR (19, 16))
2e8cf49e
NC
3012 {
3013 case 1:
3014 for (i = 0; i < (both ? 16 : 8); i++)
3015 aarch64_set_vec_u8 (cpu, Vd, i, aarch64_get_reg_u8 (cpu, Rs, NO_SP));
3016 break;
3017
3018 case 2:
3019 for (i = 0; i < (both ? 8 : 4); i++)
3020 aarch64_set_vec_u16 (cpu, Vd, i, aarch64_get_reg_u16 (cpu, Rs, NO_SP));
3021 break;
3022
3023 case 4:
3024 for (i = 0; i < (both ? 4 : 2); i++)
3025 aarch64_set_vec_u32 (cpu, Vd, i, aarch64_get_reg_u32 (cpu, Rs, NO_SP));
3026 break;
3027
3028 case 8:
3029 if (!both)
3030 HALT_NYI;
3031 aarch64_set_vec_u64 (cpu, Vd, 0, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
3032 aarch64_set_vec_u64 (cpu, Vd, 1, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
3033 break;
3034
3035 default:
3036 HALT_NYI;
3037 }
3038}
3039
3040static void
3041do_vec_UZP (sim_cpu *cpu)
3042{
3043 /* instr[31] = 0
3044 instr[30] = half(0)/full(1)
3045 instr[29,24] = 00 1110
3046 instr[23,22] = size: byte(00), half(01), word (10), long (11)
3047 instr[21] = 0
3048 instr[20,16] = Vm
3049 instr[15] = 0
3050 instr[14] = lower (0) / upper (1)
3051 instr[13,10] = 0110
3052 instr[9,5] = Vn
3053 instr[4,0] = Vd. */
3054
ef0d8ffc
NC
3055 int full = INSTR (30, 30);
3056 int upper = INSTR (14, 14);
2e8cf49e 3057
ef0d8ffc
NC
3058 unsigned vm = INSTR (20, 16);
3059 unsigned vn = INSTR (9, 5);
3060 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3061
3062 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
3063 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
3064 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
3065 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
3066
a4fb5981
JW
3067 uint64_t val1;
3068 uint64_t val2;
2e8cf49e 3069
a4fb5981 3070 uint64_t input2 = full ? val_n2 : val_m1;
2e8cf49e
NC
3071
3072 NYI_assert (29, 24, 0x0E);
3073 NYI_assert (21, 21, 0);
3074 NYI_assert (15, 15, 0);
3075 NYI_assert (13, 10, 6);
3076
2cdad34c 3077 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
a4fb5981 3078 switch (INSTR (23, 22))
2e8cf49e
NC
3079 {
3080 case 0:
a4fb5981
JW
3081 val1 = (val_n1 >> (upper * 8)) & 0xFFULL;
3082 val1 |= (val_n1 >> ((upper * 8) + 8)) & 0xFF00ULL;
3083 val1 |= (val_n1 >> ((upper * 8) + 16)) & 0xFF0000ULL;
3084 val1 |= (val_n1 >> ((upper * 8) + 24)) & 0xFF000000ULL;
3085
3086 val1 |= (input2 << (32 - (upper * 8))) & 0xFF00000000ULL;
3087 val1 |= (input2 << (24 - (upper * 8))) & 0xFF0000000000ULL;
3088 val1 |= (input2 << (16 - (upper * 8))) & 0xFF000000000000ULL;
3089 val1 |= (input2 << (8 - (upper * 8))) & 0xFF00000000000000ULL;
3090
3091 if (full)
2e8cf49e 3092 {
a4fb5981
JW
3093 val2 = (val_m1 >> (upper * 8)) & 0xFFULL;
3094 val2 |= (val_m1 >> ((upper * 8) + 8)) & 0xFF00ULL;
3095 val2 |= (val_m1 >> ((upper * 8) + 16)) & 0xFF0000ULL;
3096 val2 |= (val_m1 >> ((upper * 8) + 24)) & 0xFF000000ULL;
3097
3098 val2 |= (val_m2 << (32 - (upper * 8))) & 0xFF00000000ULL;
3099 val2 |= (val_m2 << (24 - (upper * 8))) & 0xFF0000000000ULL;
3100 val2 |= (val_m2 << (16 - (upper * 8))) & 0xFF000000000000ULL;
3101 val2 |= (val_m2 << (8 - (upper * 8))) & 0xFF00000000000000ULL;
2e8cf49e
NC
3102 }
3103 break;
3104
3105 case 1:
a4fb5981
JW
3106 val1 = (val_n1 >> (upper * 16)) & 0xFFFFULL;
3107 val1 |= (val_n1 >> ((upper * 16) + 16)) & 0xFFFF0000ULL;
3108
3109 val1 |= (input2 << (32 - (upper * 16))) & 0xFFFF00000000ULL;;
3110 val1 |= (input2 << (16 - (upper * 16))) & 0xFFFF000000000000ULL;
3111
3112 if (full)
2e8cf49e 3113 {
a4fb5981
JW
3114 val2 = (val_m1 >> (upper * 16)) & 0xFFFFULL;
3115 val2 |= (val_m1 >> ((upper * 16) + 16)) & 0xFFFF0000ULL;
3116
3117 val2 |= (val_m2 << (32 - (upper * 16))) & 0xFFFF00000000ULL;
3118 val2 |= (val_m2 << (16 - (upper * 16))) & 0xFFFF000000000000ULL;
2e8cf49e
NC
3119 }
3120 break;
3121
3122 case 2:
a4fb5981
JW
3123 val1 = (val_n1 >> (upper * 32)) & 0xFFFFFFFF;
3124 val1 |= (input2 << (32 - (upper * 32))) & 0xFFFFFFFF00000000ULL;
3125
3126 if (full)
3127 {
3128 val2 = (val_m1 >> (upper * 32)) & 0xFFFFFFFF;
3129 val2 |= (val_m2 << (32 - (upper * 32))) & 0xFFFFFFFF00000000ULL;
3130 }
3131 break;
2e8cf49e
NC
3132
3133 case 3:
a4fb5981
JW
3134 if (! full)
3135 HALT_UNALLOC;
3136
3137 val1 = upper ? val_n2 : val_n1;
3138 val2 = upper ? val_m2 : val_m1;
3139 break;
2e8cf49e
NC
3140 }
3141
3142 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3143 if (full)
3144 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3145}
3146
3147static void
3148do_vec_ZIP (sim_cpu *cpu)
3149{
3150 /* instr[31] = 0
3151 instr[30] = half(0)/full(1)
3152 instr[29,24] = 00 1110
3153 instr[23,22] = size: byte(00), hald(01), word (10), long (11)
3154 instr[21] = 0
3155 instr[20,16] = Vm
3156 instr[15] = 0
3157 instr[14] = lower (0) / upper (1)
3158 instr[13,10] = 1110
3159 instr[9,5] = Vn
3160 instr[4,0] = Vd. */
3161
ef0d8ffc
NC
3162 int full = INSTR (30, 30);
3163 int upper = INSTR (14, 14);
2e8cf49e 3164
ef0d8ffc
NC
3165 unsigned vm = INSTR (20, 16);
3166 unsigned vn = INSTR (9, 5);
3167 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3168
3169 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
3170 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
3171 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
3172 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
3173
3174 uint64_t val1 = 0;
3175 uint64_t val2 = 0;
3176
3177 uint64_t input1 = upper ? val_n1 : val_m1;
3178 uint64_t input2 = upper ? val_n2 : val_m2;
3179
3180 NYI_assert (29, 24, 0x0E);
3181 NYI_assert (21, 21, 0);
3182 NYI_assert (15, 15, 0);
3183 NYI_assert (13, 10, 0xE);
3184
2cdad34c 3185 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3186 switch (INSTR (23, 23))
2e8cf49e
NC
3187 {
3188 case 0:
3189 val1 =
3190 ((input1 << 0) & (0xFF << 0))
3191 | ((input2 << 8) & (0xFF << 8))
3192 | ((input1 << 8) & (0xFF << 16))
3193 | ((input2 << 16) & (0xFF << 24))
3194 | ((input1 << 16) & (0xFFULL << 32))
3195 | ((input2 << 24) & (0xFFULL << 40))
3196 | ((input1 << 24) & (0xFFULL << 48))
3197 | ((input2 << 32) & (0xFFULL << 56));
3198
3199 val2 =
3200 ((input1 >> 32) & (0xFF << 0))
3201 | ((input2 >> 24) & (0xFF << 8))
3202 | ((input1 >> 24) & (0xFF << 16))
3203 | ((input2 >> 16) & (0xFF << 24))
3204 | ((input1 >> 16) & (0xFFULL << 32))
3205 | ((input2 >> 8) & (0xFFULL << 40))
3206 | ((input1 >> 8) & (0xFFULL << 48))
3207 | ((input2 >> 0) & (0xFFULL << 56));
3208 break;
3209
3210 case 1:
3211 val1 =
3212 ((input1 << 0) & (0xFFFF << 0))
3213 | ((input2 << 16) & (0xFFFF << 16))
3214 | ((input1 << 16) & (0xFFFFULL << 32))
3215 | ((input2 << 32) & (0xFFFFULL << 48));
3216
3217 val2 =
3218 ((input1 >> 32) & (0xFFFF << 0))
3219 | ((input2 >> 16) & (0xFFFF << 16))
3220 | ((input1 >> 16) & (0xFFFFULL << 32))
3221 | ((input2 >> 0) & (0xFFFFULL << 48));
3222 break;
3223
3224 case 2:
3225 val1 = (input1 & 0xFFFFFFFFULL) | (input2 << 32);
3226 val2 = (input2 & 0xFFFFFFFFULL) | (input1 << 32);
3227 break;
3228
3229 case 3:
3230 val1 = input1;
3231 val2 = input2;
3232 break;
3233 }
3234
3235 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3236 if (full)
3237 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3238}
3239
3240/* Floating point immediates are encoded in 8 bits.
3241 fpimm[7] = sign bit.
3242 fpimm[6:4] = signed exponent.
3243 fpimm[3:0] = fraction (assuming leading 1).
3244 i.e. F = s * 1.f * 2^(e - b). */
3245
3246static float
3247fp_immediate_for_encoding_32 (uint32_t imm8)
3248{
3249 float u;
3250 uint32_t s, e, f, i;
3251
3252 s = (imm8 >> 7) & 0x1;
3253 e = (imm8 >> 4) & 0x7;
3254 f = imm8 & 0xf;
3255
3256 /* The fp value is s * n/16 * 2r where n is 16+e. */
3257 u = (16.0 + f) / 16.0;
3258
3259 /* N.B. exponent is signed. */
3260 if (e < 4)
3261 {
3262 int epos = e;
3263
3264 for (i = 0; i <= epos; i++)
3265 u *= 2.0;
3266 }
3267 else
3268 {
3269 int eneg = 7 - e;
3270
3271 for (i = 0; i < eneg; i++)
3272 u /= 2.0;
3273 }
3274
3275 if (s)
3276 u = - u;
3277
3278 return u;
3279}
3280
3281static double
3282fp_immediate_for_encoding_64 (uint32_t imm8)
3283{
3284 double u;
3285 uint32_t s, e, f, i;
3286
3287 s = (imm8 >> 7) & 0x1;
3288 e = (imm8 >> 4) & 0x7;
3289 f = imm8 & 0xf;
3290
3291 /* The fp value is s * n/16 * 2r where n is 16+e. */
3292 u = (16.0 + f) / 16.0;
3293
3294 /* N.B. exponent is signed. */
3295 if (e < 4)
3296 {
3297 int epos = e;
3298
3299 for (i = 0; i <= epos; i++)
3300 u *= 2.0;
3301 }
3302 else
3303 {
3304 int eneg = 7 - e;
3305
3306 for (i = 0; i < eneg; i++)
3307 u /= 2.0;
3308 }
3309
3310 if (s)
3311 u = - u;
3312
3313 return u;
3314}
3315
3316static void
3317do_vec_MOV_immediate (sim_cpu *cpu)
3318{
3319 /* instr[31] = 0
3320 instr[30] = full/half selector
3321 instr[29,19] = 00111100000
3322 instr[18,16] = high 3 bits of uimm8
3323 instr[15,12] = size & shift:
3324 0000 => 32-bit
3325 0010 => 32-bit + LSL#8
3326 0100 => 32-bit + LSL#16
3327 0110 => 32-bit + LSL#24
3328 1010 => 16-bit + LSL#8
3329 1000 => 16-bit
3330 1101 => 32-bit + MSL#16
3331 1100 => 32-bit + MSL#8
3332 1110 => 8-bit
3333 1111 => double
3334 instr[11,10] = 01
3335 instr[9,5] = low 5-bits of uimm8
3336 instr[4,0] = Vd. */
3337
ef0d8ffc
NC
3338 int full = INSTR (30, 30);
3339 unsigned vd = INSTR (4, 0);
7517e550 3340 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3341 unsigned i;
3342
3343 NYI_assert (29, 19, 0x1E0);
3344 NYI_assert (11, 10, 1);
3345
2cdad34c 3346 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3347 switch (INSTR (15, 12))
2e8cf49e
NC
3348 {
3349 case 0x0: /* 32-bit, no shift. */
3350 case 0x2: /* 32-bit, shift by 8. */
3351 case 0x4: /* 32-bit, shift by 16. */
3352 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3353 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3354 for (i = 0; i < (full ? 4 : 2); i++)
3355 aarch64_set_vec_u32 (cpu, vd, i, val);
3356 break;
3357
3358 case 0xa: /* 16-bit, shift by 8. */
3359 val <<= 8;
3360 /* Fall through. */
3361 case 0x8: /* 16-bit, no shift. */
3362 for (i = 0; i < (full ? 8 : 4); i++)
3363 aarch64_set_vec_u16 (cpu, vd, i, val);
c0386d4d
JW
3364 break;
3365
2e8cf49e
NC
3366 case 0xd: /* 32-bit, mask shift by 16. */
3367 val <<= 8;
3368 val |= 0xFF;
3369 /* Fall through. */
3370 case 0xc: /* 32-bit, mask shift by 8. */
3371 val <<= 8;
3372 val |= 0xFF;
3373 for (i = 0; i < (full ? 4 : 2); i++)
3374 aarch64_set_vec_u32 (cpu, vd, i, val);
3375 break;
3376
3377 case 0xe: /* 8-bit, no shift. */
3378 for (i = 0; i < (full ? 16 : 8); i++)
3379 aarch64_set_vec_u8 (cpu, vd, i, val);
3380 break;
3381
3382 case 0xf: /* FMOV Vs.{2|4}S, #fpimm. */
3383 {
3384 float u = fp_immediate_for_encoding_32 (val);
3385 for (i = 0; i < (full ? 4 : 2); i++)
3386 aarch64_set_vec_float (cpu, vd, i, u);
3387 break;
3388 }
3389
3390 default:
3391 HALT_NYI;
3392 }
3393}
3394
3395static void
3396do_vec_MVNI (sim_cpu *cpu)
3397{
3398 /* instr[31] = 0
3399 instr[30] = full/half selector
3400 instr[29,19] = 10111100000
3401 instr[18,16] = high 3 bits of uimm8
3402 instr[15,12] = selector
3403 instr[11,10] = 01
3404 instr[9,5] = low 5-bits of uimm8
3405 instr[4,0] = Vd. */
3406
ef0d8ffc
NC
3407 int full = INSTR (30, 30);
3408 unsigned vd = INSTR (4, 0);
7517e550 3409 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3410 unsigned i;
3411
3412 NYI_assert (29, 19, 0x5E0);
3413 NYI_assert (11, 10, 1);
3414
2cdad34c 3415 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3416 switch (INSTR (15, 12))
2e8cf49e
NC
3417 {
3418 case 0x0: /* 32-bit, no shift. */
3419 case 0x2: /* 32-bit, shift by 8. */
3420 case 0x4: /* 32-bit, shift by 16. */
3421 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3422 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3423 val = ~ val;
3424 for (i = 0; i < (full ? 4 : 2); i++)
3425 aarch64_set_vec_u32 (cpu, vd, i, val);
3426 return;
3427
3428 case 0xa: /* 16-bit, 8 bit shift. */
3429 val <<= 8;
3430 case 0x8: /* 16-bit, no shift. */
3431 val = ~ val;
3432 for (i = 0; i < (full ? 8 : 4); i++)
3433 aarch64_set_vec_u16 (cpu, vd, i, val);
3434 return;
3435
3436 case 0xd: /* 32-bit, mask shift by 16. */
3437 val <<= 8;
3438 val |= 0xFF;
3439 case 0xc: /* 32-bit, mask shift by 8. */
3440 val <<= 8;
3441 val |= 0xFF;
3442 val = ~ val;
3443 for (i = 0; i < (full ? 4 : 2); i++)
3444 aarch64_set_vec_u32 (cpu, vd, i, val);
3445 return;
3446
3447 case 0xE: /* MOVI Dn, #mask64 */
3448 {
3449 uint64_t mask = 0;
3450
3451 for (i = 0; i < 8; i++)
3452 if (val & (1 << i))
7517e550 3453 mask |= (0xFFUL << (i * 8));
2e8cf49e 3454 aarch64_set_vec_u64 (cpu, vd, 0, mask);
7517e550 3455 aarch64_set_vec_u64 (cpu, vd, 1, mask);
2e8cf49e
NC
3456 return;
3457 }
3458
3459 case 0xf: /* FMOV Vd.2D, #fpimm. */
3460 {
3461 double u = fp_immediate_for_encoding_64 (val);
3462
3463 if (! full)
3464 HALT_UNALLOC;
3465
3466 aarch64_set_vec_double (cpu, vd, 0, u);
3467 aarch64_set_vec_double (cpu, vd, 1, u);
3468 return;
3469 }
3470
3471 default:
3472 HALT_NYI;
3473 }
3474}
3475
3476#define ABS(A) ((A) < 0 ? - (A) : (A))
3477
3478static void
3479do_vec_ABS (sim_cpu *cpu)
3480{
3481 /* instr[31] = 0
3482 instr[30] = half(0)/full(1)
3483 instr[29,24] = 00 1110
3484 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3485 instr[21,10] = 10 0000 1011 10
3486 instr[9,5] = Vn
3487 instr[4.0] = Vd. */
3488
ef0d8ffc
NC
3489 unsigned vn = INSTR (9, 5);
3490 unsigned vd = INSTR (4, 0);
3491 unsigned full = INSTR (30, 30);
2e8cf49e
NC
3492 unsigned i;
3493
3494 NYI_assert (29, 24, 0x0E);
3495 NYI_assert (21, 10, 0x82E);
3496
2cdad34c 3497 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3498 switch (INSTR (23, 22))
2e8cf49e
NC
3499 {
3500 case 0:
3501 for (i = 0; i < (full ? 16 : 8); i++)
3502 aarch64_set_vec_s8 (cpu, vd, i,
3503 ABS (aarch64_get_vec_s8 (cpu, vn, i)));
3504 break;
3505
3506 case 1:
3507 for (i = 0; i < (full ? 8 : 4); i++)
3508 aarch64_set_vec_s16 (cpu, vd, i,
3509 ABS (aarch64_get_vec_s16 (cpu, vn, i)));
3510 break;
3511
3512 case 2:
3513 for (i = 0; i < (full ? 4 : 2); i++)
3514 aarch64_set_vec_s32 (cpu, vd, i,
3515 ABS (aarch64_get_vec_s32 (cpu, vn, i)));
3516 break;
3517
3518 case 3:
3519 if (! full)
3520 HALT_NYI;
3521 for (i = 0; i < 2; i++)
3522 aarch64_set_vec_s64 (cpu, vd, i,
3523 ABS (aarch64_get_vec_s64 (cpu, vn, i)));
3524 break;
3525 }
3526}
3527
3528static void
3529do_vec_ADDV (sim_cpu *cpu)
3530{
3531 /* instr[31] = 0
3532 instr[30] = full/half selector
3533 instr[29,24] = 00 1110
3534 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3535 instr[21,10] = 11 0001 1011 10
3536 instr[9,5] = Vm
3537 instr[4.0] = Rd. */
3538
ef0d8ffc
NC
3539 unsigned vm = INSTR (9, 5);
3540 unsigned rd = INSTR (4, 0);
2e8cf49e 3541 unsigned i;
ef0d8ffc 3542 int full = INSTR (30, 30);
2e8cf49e
NC
3543
3544 NYI_assert (29, 24, 0x0E);
3545 NYI_assert (21, 10, 0xC6E);
3546
2cdad34c 3547 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3548 switch (INSTR (23, 22))
2e8cf49e
NC
3549 {
3550 case 0:
2e7e5e28
JW
3551 {
3552 uint8_t val = 0;
3553 for (i = 0; i < (full ? 16 : 8); i++)
3554 val += aarch64_get_vec_u8 (cpu, vm, i);
3555 aarch64_set_vec_u64 (cpu, rd, 0, val);
3556 return;
3557 }
2e8cf49e
NC
3558
3559 case 1:
2e7e5e28
JW
3560 {
3561 uint16_t val = 0;
3562 for (i = 0; i < (full ? 8 : 4); i++)
3563 val += aarch64_get_vec_u16 (cpu, vm, i);
3564 aarch64_set_vec_u64 (cpu, rd, 0, val);
3565 return;
3566 }
2e8cf49e
NC
3567
3568 case 2:
2e7e5e28
JW
3569 {
3570 uint32_t val = 0;
3571 if (! full)
3572 HALT_UNALLOC;
3573 for (i = 0; i < 4; i++)
3574 val += aarch64_get_vec_u32 (cpu, vm, i);
3575 aarch64_set_vec_u64 (cpu, rd, 0, val);
3576 return;
3577 }
2e8cf49e
NC
3578
3579 case 3:
05b3d79d 3580 HALT_UNALLOC;
2e8cf49e
NC
3581 }
3582}
3583
3584static void
3585do_vec_ins_2 (sim_cpu *cpu)
3586{
3587 /* instr[31,21] = 01001110000
3588 instr[20,18] = size & element selector
3589 instr[17,14] = 0000
3590 instr[13] = direction: to vec(0), from vec (1)
3591 instr[12,10] = 111
3592 instr[9,5] = Vm
3593 instr[4,0] = Vd. */
3594
3595 unsigned elem;
ef0d8ffc
NC
3596 unsigned vm = INSTR (9, 5);
3597 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3598
3599 NYI_assert (31, 21, 0x270);
3600 NYI_assert (17, 14, 0);
3601 NYI_assert (12, 10, 7);
3602
2cdad34c 3603 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3604 if (INSTR (13, 13) == 1)
2e8cf49e 3605 {
ef0d8ffc 3606 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3607 {
3608 /* 32-bit moves. */
ef0d8ffc 3609 elem = INSTR (20, 19);
2e8cf49e
NC
3610 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3611 aarch64_get_vec_u32 (cpu, vm, elem));
3612 }
3613 else
3614 {
3615 /* 64-bit moves. */
ef0d8ffc 3616 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3617 HALT_NYI;
3618
ef0d8ffc 3619 elem = INSTR (20, 20);
2e8cf49e
NC
3620 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3621 aarch64_get_vec_u64 (cpu, vm, elem));
3622 }
3623 }
3624 else
3625 {
ef0d8ffc 3626 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3627 {
3628 /* 32-bit moves. */
ef0d8ffc 3629 elem = INSTR (20, 19);
2e8cf49e
NC
3630 aarch64_set_vec_u32 (cpu, vd, elem,
3631 aarch64_get_reg_u32 (cpu, vm, NO_SP));
3632 }
3633 else
3634 {
3635 /* 64-bit moves. */
ef0d8ffc 3636 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3637 HALT_NYI;
3638
ef0d8ffc 3639 elem = INSTR (20, 20);
2e8cf49e
NC
3640 aarch64_set_vec_u64 (cpu, vd, elem,
3641 aarch64_get_reg_u64 (cpu, vm, NO_SP));
3642 }
3643 }
3644}
3645
7517e550
NC
3646#define DO_VEC_WIDENING_MUL(N, DST_TYPE, READ_TYPE, WRITE_TYPE) \
3647 do \
3648 { \
3649 DST_TYPE a[N], b[N]; \
3650 \
3651 for (i = 0; i < (N); i++) \
3652 { \
3653 a[i] = aarch64_get_vec_##READ_TYPE (cpu, vn, i + bias); \
3654 b[i] = aarch64_get_vec_##READ_TYPE (cpu, vm, i + bias); \
3655 } \
3656 for (i = 0; i < (N); i++) \
3657 aarch64_set_vec_##WRITE_TYPE (cpu, vd, i, a[i] * b[i]); \
3658 } \
3659 while (0)
3660
2e8cf49e
NC
3661static void
3662do_vec_mull (sim_cpu *cpu)
3663{
3664 /* instr[31] = 0
3665 instr[30] = lower(0)/upper(1) selector
3666 instr[29] = signed(0)/unsigned(1)
3667 instr[28,24] = 0 1110
3668 instr[23,22] = size: 8-bit (00), 16-bit (01), 32-bit (10)
3669 instr[21] = 1
3670 instr[20,16] = Vm
3671 instr[15,10] = 11 0000
3672 instr[9,5] = Vn
3673 instr[4.0] = Vd. */
3674
ef0d8ffc
NC
3675 int unsign = INSTR (29, 29);
3676 int bias = INSTR (30, 30);
3677 unsigned vm = INSTR (20, 16);
3678 unsigned vn = INSTR ( 9, 5);
3679 unsigned vd = INSTR ( 4, 0);
2e8cf49e
NC
3680 unsigned i;
3681
3682 NYI_assert (28, 24, 0x0E);
3683 NYI_assert (15, 10, 0x30);
3684
2cdad34c 3685 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
3686 /* NB: Read source values before writing results, in case
3687 the source and destination vectors are the same. */
ef0d8ffc 3688 switch (INSTR (23, 22))
2e8cf49e
NC
3689 {
3690 case 0:
3691 if (bias)
3692 bias = 8;
3693 if (unsign)
7517e550 3694 DO_VEC_WIDENING_MUL (8, uint16_t, u8, u16);
2e8cf49e 3695 else
7517e550 3696 DO_VEC_WIDENING_MUL (8, int16_t, s8, s16);
2e8cf49e
NC
3697 return;
3698
3699 case 1:
3700 if (bias)
3701 bias = 4;
3702 if (unsign)
7517e550 3703 DO_VEC_WIDENING_MUL (4, uint32_t, u16, u32);
2e8cf49e 3704 else
7517e550 3705 DO_VEC_WIDENING_MUL (4, int32_t, s16, s32);
2e8cf49e
NC
3706 return;
3707
3708 case 2:
3709 if (bias)
3710 bias = 2;
3711 if (unsign)
7517e550 3712 DO_VEC_WIDENING_MUL (2, uint64_t, u32, u64);
2e8cf49e 3713 else
7517e550 3714 DO_VEC_WIDENING_MUL (2, int64_t, s32, s64);
2e8cf49e
NC
3715 return;
3716
3717 case 3:
2e8cf49e
NC
3718 HALT_NYI;
3719 }
3720}
3721
3722static void
3723do_vec_fadd (sim_cpu *cpu)
3724{
3725 /* instr[31] = 0
3726 instr[30] = half(0)/full(1)
3727 instr[29,24] = 001110
3728 instr[23] = FADD(0)/FSUB(1)
3729 instr[22] = float (0)/double(1)
3730 instr[21] = 1
3731 instr[20,16] = Vm
3732 instr[15,10] = 110101
3733 instr[9,5] = Vn
3734 instr[4.0] = Vd. */
3735
ef0d8ffc
NC
3736 unsigned vm = INSTR (20, 16);
3737 unsigned vn = INSTR (9, 5);
3738 unsigned vd = INSTR (4, 0);
2e8cf49e 3739 unsigned i;
ef0d8ffc 3740 int full = INSTR (30, 30);
2e8cf49e
NC
3741
3742 NYI_assert (29, 24, 0x0E);
3743 NYI_assert (21, 21, 1);
3744 NYI_assert (15, 10, 0x35);
3745
2cdad34c 3746 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3747 if (INSTR (23, 23))
2e8cf49e 3748 {
ef0d8ffc 3749 if (INSTR (22, 22))
2e8cf49e
NC
3750 {
3751 if (! full)
3752 HALT_NYI;
3753
3754 for (i = 0; i < 2; i++)
3755 aarch64_set_vec_double (cpu, vd, i,
3756 aarch64_get_vec_double (cpu, vn, i)
3757 - aarch64_get_vec_double (cpu, vm, i));
3758 }
3759 else
3760 {
3761 for (i = 0; i < (full ? 4 : 2); i++)
3762 aarch64_set_vec_float (cpu, vd, i,
3763 aarch64_get_vec_float (cpu, vn, i)
3764 - aarch64_get_vec_float (cpu, vm, i));
3765 }
3766 }
3767 else
3768 {
ef0d8ffc 3769 if (INSTR (22, 22))
2e8cf49e
NC
3770 {
3771 if (! full)
3772 HALT_NYI;
3773
3774 for (i = 0; i < 2; i++)
3775 aarch64_set_vec_double (cpu, vd, i,
3776 aarch64_get_vec_double (cpu, vm, i)
3777 + aarch64_get_vec_double (cpu, vn, i));
3778 }
3779 else
3780 {
3781 for (i = 0; i < (full ? 4 : 2); i++)
3782 aarch64_set_vec_float (cpu, vd, i,
3783 aarch64_get_vec_float (cpu, vm, i)
3784 + aarch64_get_vec_float (cpu, vn, i));
3785 }
3786 }
3787}
3788
3789static void
3790do_vec_add (sim_cpu *cpu)
3791{
3792 /* instr[31] = 0
3793 instr[30] = full/half selector
3794 instr[29,24] = 001110
3795 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3796 instr[21] = 1
3797 instr[20,16] = Vn
3798 instr[15,10] = 100001
3799 instr[9,5] = Vm
3800 instr[4.0] = Vd. */
3801
ef0d8ffc
NC
3802 unsigned vm = INSTR (20, 16);
3803 unsigned vn = INSTR (9, 5);
3804 unsigned vd = INSTR (4, 0);
2e8cf49e 3805 unsigned i;
ef0d8ffc 3806 int full = INSTR (30, 30);
2e8cf49e
NC
3807
3808 NYI_assert (29, 24, 0x0E);
3809 NYI_assert (21, 21, 1);
3810 NYI_assert (15, 10, 0x21);
3811
2cdad34c 3812 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3813 switch (INSTR (23, 22))
2e8cf49e
NC
3814 {
3815 case 0:
3816 for (i = 0; i < (full ? 16 : 8); i++)
3817 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
3818 + aarch64_get_vec_u8 (cpu, vm, i));
3819 return;
3820
3821 case 1:
3822 for (i = 0; i < (full ? 8 : 4); i++)
3823 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
3824 + aarch64_get_vec_u16 (cpu, vm, i));
3825 return;
3826
3827 case 2:
3828 for (i = 0; i < (full ? 4 : 2); i++)
3829 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
3830 + aarch64_get_vec_u32 (cpu, vm, i));
3831 return;
3832
3833 case 3:
3834 if (! full)
3835 HALT_UNALLOC;
3836 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vn, 0)
3837 + aarch64_get_vec_u64 (cpu, vm, 0));
3838 aarch64_set_vec_u64 (cpu, vd, 1,
3839 aarch64_get_vec_u64 (cpu, vn, 1)
3840 + aarch64_get_vec_u64 (cpu, vm, 1));
3841 return;
2e8cf49e
NC
3842 }
3843}
3844
3845static void
3846do_vec_mul (sim_cpu *cpu)
3847{
3848 /* instr[31] = 0
3849 instr[30] = full/half selector
3850 instr[29,24] = 00 1110
3851 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3852 instr[21] = 1
3853 instr[20,16] = Vn
3854 instr[15,10] = 10 0111
3855 instr[9,5] = Vm
3856 instr[4.0] = Vd. */
3857
ef0d8ffc
NC
3858 unsigned vm = INSTR (20, 16);
3859 unsigned vn = INSTR (9, 5);
3860 unsigned vd = INSTR (4, 0);
2e8cf49e 3861 unsigned i;
ef0d8ffc 3862 int full = INSTR (30, 30);
7517e550 3863 int bias = 0;
2e8cf49e
NC
3864
3865 NYI_assert (29, 24, 0x0E);
3866 NYI_assert (21, 21, 1);
3867 NYI_assert (15, 10, 0x27);
3868
2cdad34c 3869 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3870 switch (INSTR (23, 22))
2e8cf49e
NC
3871 {
3872 case 0:
c0386d4d 3873 DO_VEC_WIDENING_MUL (full ? 16 : 8, uint8_t, u8, u8);
2e8cf49e
NC
3874 return;
3875
3876 case 1:
c0386d4d 3877 DO_VEC_WIDENING_MUL (full ? 8 : 4, uint16_t, u16, u16);
2e8cf49e
NC
3878 return;
3879
3880 case 2:
c0386d4d 3881 DO_VEC_WIDENING_MUL (full ? 4 : 2, uint32_t, u32, u32);
2e8cf49e
NC
3882 return;
3883
2e8cf49e
NC
3884 case 3:
3885 HALT_UNALLOC;
3886 }
3887}
3888
3889static void
3890do_vec_MLA (sim_cpu *cpu)
3891{
3892 /* instr[31] = 0
3893 instr[30] = full/half selector
3894 instr[29,24] = 00 1110
3895 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3896 instr[21] = 1
3897 instr[20,16] = Vn
3898 instr[15,10] = 1001 01
3899 instr[9,5] = Vm
3900 instr[4.0] = Vd. */
3901
ef0d8ffc
NC
3902 unsigned vm = INSTR (20, 16);
3903 unsigned vn = INSTR (9, 5);
3904 unsigned vd = INSTR (4, 0);
2e8cf49e 3905 unsigned i;
ef0d8ffc 3906 int full = INSTR (30, 30);
2e8cf49e
NC
3907
3908 NYI_assert (29, 24, 0x0E);
3909 NYI_assert (21, 21, 1);
3910 NYI_assert (15, 10, 0x25);
3911
2cdad34c 3912 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3913 switch (INSTR (23, 22))
2e8cf49e
NC
3914 {
3915 case 0:
742e3a77
JW
3916 for (i = 0; i < (full ? 16 : 8); i++)
3917 aarch64_set_vec_u8 (cpu, vd, i,
3918 aarch64_get_vec_u8 (cpu, vd, i)
3919 + (aarch64_get_vec_u8 (cpu, vn, i)
3920 * aarch64_get_vec_u8 (cpu, vm, i)));
2e8cf49e
NC
3921 return;
3922
3923 case 1:
742e3a77
JW
3924 for (i = 0; i < (full ? 8 : 4); i++)
3925 aarch64_set_vec_u16 (cpu, vd, i,
3926 aarch64_get_vec_u16 (cpu, vd, i)
3927 + (aarch64_get_vec_u16 (cpu, vn, i)
3928 * aarch64_get_vec_u16 (cpu, vm, i)));
2e8cf49e
NC
3929 return;
3930
3931 case 2:
742e3a77
JW
3932 for (i = 0; i < (full ? 4 : 2); i++)
3933 aarch64_set_vec_u32 (cpu, vd, i,
3934 aarch64_get_vec_u32 (cpu, vd, i)
3935 + (aarch64_get_vec_u32 (cpu, vn, i)
3936 * aarch64_get_vec_u32 (cpu, vm, i)));
2e8cf49e
NC
3937 return;
3938
742e3a77 3939 default:
2e8cf49e
NC
3940 HALT_UNALLOC;
3941 }
3942}
3943
3944static float
3945fmaxnm (float a, float b)
3946{
c0386d4d 3947 if (! isnan (a))
2e8cf49e 3948 {
c0386d4d 3949 if (! isnan (b))
2e8cf49e
NC
3950 return a > b ? a : b;
3951 return a;
3952 }
c0386d4d 3953 else if (! isnan (b))
2e8cf49e
NC
3954 return b;
3955 return a;
3956}
3957
3958static float
3959fminnm (float a, float b)
3960{
c0386d4d 3961 if (! isnan (a))
2e8cf49e 3962 {
c0386d4d 3963 if (! isnan (b))
2e8cf49e
NC
3964 return a < b ? a : b;
3965 return a;
3966 }
c0386d4d 3967 else if (! isnan (b))
2e8cf49e
NC
3968 return b;
3969 return a;
3970}
3971
3972static double
3973dmaxnm (double a, double b)
3974{
c0386d4d 3975 if (! isnan (a))
2e8cf49e 3976 {
c0386d4d 3977 if (! isnan (b))
2e8cf49e
NC
3978 return a > b ? a : b;
3979 return a;
3980 }
c0386d4d 3981 else if (! isnan (b))
2e8cf49e
NC
3982 return b;
3983 return a;
3984}
3985
3986static double
3987dminnm (double a, double b)
3988{
c0386d4d 3989 if (! isnan (a))
2e8cf49e 3990 {
c0386d4d 3991 if (! isnan (b))
2e8cf49e
NC
3992 return a < b ? a : b;
3993 return a;
3994 }
c0386d4d 3995 else if (! isnan (b))
2e8cf49e
NC
3996 return b;
3997 return a;
3998}
3999
4000static void
4001do_vec_FminmaxNMP (sim_cpu *cpu)
4002{
ef0d8ffc
NC
4003 /* instr [31] = 0
4004 instr [30] = half (0)/full (1)
4005 instr [29,24] = 10 1110
4006 instr [23] = max(0)/min(1)
4007 instr [22] = float (0)/double (1)
4008 instr [21] = 1
4009 instr [20,16] = Vn
4010 instr [15,10] = 1100 01
4011 instr [9,5] = Vm
4012 instr [4.0] = Vd. */
4013
4014 unsigned vm = INSTR (20, 16);
4015 unsigned vn = INSTR (9, 5);
4016 unsigned vd = INSTR (4, 0);
4017 int full = INSTR (30, 30);
2e8cf49e
NC
4018
4019 NYI_assert (29, 24, 0x2E);
4020 NYI_assert (21, 21, 1);
4021 NYI_assert (15, 10, 0x31);
4022
2cdad34c 4023 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4024 if (INSTR (22, 22))
2e8cf49e 4025 {
ef0d8ffc 4026 double (* fn)(double, double) = INSTR (23, 23)
2e8cf49e
NC
4027 ? dminnm : dmaxnm;
4028
4029 if (! full)
4030 HALT_NYI;
4031 aarch64_set_vec_double (cpu, vd, 0,
4032 fn (aarch64_get_vec_double (cpu, vn, 0),
4033 aarch64_get_vec_double (cpu, vn, 1)));
4034 aarch64_set_vec_double (cpu, vd, 0,
4035 fn (aarch64_get_vec_double (cpu, vm, 0),
4036 aarch64_get_vec_double (cpu, vm, 1)));
4037 }
4038 else
4039 {
ef0d8ffc 4040 float (* fn)(float, float) = INSTR (23, 23)
2e8cf49e
NC
4041 ? fminnm : fmaxnm;
4042
4043 aarch64_set_vec_float (cpu, vd, 0,
4044 fn (aarch64_get_vec_float (cpu, vn, 0),
4045 aarch64_get_vec_float (cpu, vn, 1)));
4046 if (full)
4047 aarch64_set_vec_float (cpu, vd, 1,
4048 fn (aarch64_get_vec_float (cpu, vn, 2),
4049 aarch64_get_vec_float (cpu, vn, 3)));
4050
4051 aarch64_set_vec_float (cpu, vd, (full ? 2 : 1),
4052 fn (aarch64_get_vec_float (cpu, vm, 0),
4053 aarch64_get_vec_float (cpu, vm, 1)));
4054 if (full)
4055 aarch64_set_vec_float (cpu, vd, 3,
4056 fn (aarch64_get_vec_float (cpu, vm, 2),
4057 aarch64_get_vec_float (cpu, vm, 3)));
4058 }
4059}
4060
4061static void
4062do_vec_AND (sim_cpu *cpu)
4063{
4064 /* instr[31] = 0
4065 instr[30] = half (0)/full (1)
4066 instr[29,21] = 001110001
4067 instr[20,16] = Vm
4068 instr[15,10] = 000111
4069 instr[9,5] = Vn
4070 instr[4.0] = Vd. */
4071
ef0d8ffc
NC
4072 unsigned vm = INSTR (20, 16);
4073 unsigned vn = INSTR (9, 5);
4074 unsigned vd = INSTR (4, 0);
2e8cf49e 4075 unsigned i;
ef0d8ffc 4076 int full = INSTR (30, 30);
2e8cf49e
NC
4077
4078 NYI_assert (29, 21, 0x071);
4079 NYI_assert (15, 10, 0x07);
4080
2cdad34c 4081 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4082 for (i = 0; i < (full ? 4 : 2); i++)
4083 aarch64_set_vec_u32 (cpu, vd, i,
4084 aarch64_get_vec_u32 (cpu, vn, i)
4085 & aarch64_get_vec_u32 (cpu, vm, i));
4086}
4087
4088static void
4089do_vec_BSL (sim_cpu *cpu)
4090{
4091 /* instr[31] = 0
4092 instr[30] = half (0)/full (1)
4093 instr[29,21] = 101110011
4094 instr[20,16] = Vm
4095 instr[15,10] = 000111
4096 instr[9,5] = Vn
4097 instr[4.0] = Vd. */
4098
ef0d8ffc
NC
4099 unsigned vm = INSTR (20, 16);
4100 unsigned vn = INSTR (9, 5);
4101 unsigned vd = INSTR (4, 0);
2e8cf49e 4102 unsigned i;
ef0d8ffc 4103 int full = INSTR (30, 30);
2e8cf49e
NC
4104
4105 NYI_assert (29, 21, 0x173);
4106 NYI_assert (15, 10, 0x07);
4107
2cdad34c 4108 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4109 for (i = 0; i < (full ? 16 : 8); i++)
4110 aarch64_set_vec_u8 (cpu, vd, i,
4111 ( aarch64_get_vec_u8 (cpu, vd, i)
4112 & aarch64_get_vec_u8 (cpu, vn, i))
4113 | ((~ aarch64_get_vec_u8 (cpu, vd, i))
4114 & aarch64_get_vec_u8 (cpu, vm, i)));
4115}
4116
4117static void
4118do_vec_EOR (sim_cpu *cpu)
4119{
4120 /* instr[31] = 0
4121 instr[30] = half (0)/full (1)
4122 instr[29,21] = 10 1110 001
4123 instr[20,16] = Vm
4124 instr[15,10] = 000111
4125 instr[9,5] = Vn
4126 instr[4.0] = Vd. */
4127
ef0d8ffc
NC
4128 unsigned vm = INSTR (20, 16);
4129 unsigned vn = INSTR (9, 5);
4130 unsigned vd = INSTR (4, 0);
2e8cf49e 4131 unsigned i;
ef0d8ffc 4132 int full = INSTR (30, 30);
2e8cf49e
NC
4133
4134 NYI_assert (29, 21, 0x171);
4135 NYI_assert (15, 10, 0x07);
4136
2cdad34c 4137 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4138 for (i = 0; i < (full ? 4 : 2); i++)
4139 aarch64_set_vec_u32 (cpu, vd, i,
4140 aarch64_get_vec_u32 (cpu, vn, i)
4141 ^ aarch64_get_vec_u32 (cpu, vm, i));
4142}
4143
4144static void
4145do_vec_bit (sim_cpu *cpu)
4146{
4147 /* instr[31] = 0
4148 instr[30] = half (0)/full (1)
4149 instr[29,23] = 10 1110 1
4150 instr[22] = BIT (0) / BIF (1)
4151 instr[21] = 1
4152 instr[20,16] = Vm
4153 instr[15,10] = 0001 11
4154 instr[9,5] = Vn
4155 instr[4.0] = Vd. */
4156
ef0d8ffc
NC
4157 unsigned vm = INSTR (20, 16);
4158 unsigned vn = INSTR (9, 5);
4159 unsigned vd = INSTR (4, 0);
4160 unsigned full = INSTR (30, 30);
4161 unsigned test_false = INSTR (22, 22);
2e8cf49e
NC
4162 unsigned i;
4163
4164 NYI_assert (29, 23, 0x5D);
4165 NYI_assert (21, 21, 1);
4166 NYI_assert (15, 10, 0x07);
4167
2cdad34c 4168 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
bf25e9a0 4169 for (i = 0; i < (full ? 4 : 2); i++)
2e8cf49e 4170 {
bf25e9a0
JW
4171 uint32_t vd_val = aarch64_get_vec_u32 (cpu, vd, i);
4172 uint32_t vn_val = aarch64_get_vec_u32 (cpu, vn, i);
4173 uint32_t vm_val = aarch64_get_vec_u32 (cpu, vm, i);
4174 if (test_false)
4175 aarch64_set_vec_u32 (cpu, vd, i,
4176 (vd_val & vm_val) | (vn_val & ~vm_val));
4177 else
4178 aarch64_set_vec_u32 (cpu, vd, i,
4179 (vd_val & ~vm_val) | (vn_val & vm_val));
2e8cf49e
NC
4180 }
4181}
4182
4183static void
4184do_vec_ORN (sim_cpu *cpu)
4185{
4186 /* instr[31] = 0
4187 instr[30] = half (0)/full (1)
4188 instr[29,21] = 00 1110 111
4189 instr[20,16] = Vm
4190 instr[15,10] = 00 0111
4191 instr[9,5] = Vn
4192 instr[4.0] = Vd. */
4193
ef0d8ffc
NC
4194 unsigned vm = INSTR (20, 16);
4195 unsigned vn = INSTR (9, 5);
4196 unsigned vd = INSTR (4, 0);
2e8cf49e 4197 unsigned i;
ef0d8ffc 4198 int full = INSTR (30, 30);
2e8cf49e
NC
4199
4200 NYI_assert (29, 21, 0x077);
4201 NYI_assert (15, 10, 0x07);
4202
2cdad34c 4203 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4204 for (i = 0; i < (full ? 16 : 8); i++)
4205 aarch64_set_vec_u8 (cpu, vd, i,
4206 aarch64_get_vec_u8 (cpu, vn, i)
4207 | ~ aarch64_get_vec_u8 (cpu, vm, i));
4208}
4209
4210static void
4211do_vec_ORR (sim_cpu *cpu)
4212{
4213 /* instr[31] = 0
4214 instr[30] = half (0)/full (1)
4215 instr[29,21] = 00 1110 101
4216 instr[20,16] = Vm
4217 instr[15,10] = 0001 11
4218 instr[9,5] = Vn
4219 instr[4.0] = Vd. */
4220
ef0d8ffc
NC
4221 unsigned vm = INSTR (20, 16);
4222 unsigned vn = INSTR (9, 5);
4223 unsigned vd = INSTR (4, 0);
2e8cf49e 4224 unsigned i;
ef0d8ffc 4225 int full = INSTR (30, 30);
2e8cf49e
NC
4226
4227 NYI_assert (29, 21, 0x075);
4228 NYI_assert (15, 10, 0x07);
4229
2cdad34c 4230 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4231 for (i = 0; i < (full ? 16 : 8); i++)
4232 aarch64_set_vec_u8 (cpu, vd, i,
4233 aarch64_get_vec_u8 (cpu, vn, i)
4234 | aarch64_get_vec_u8 (cpu, vm, i));
4235}
4236
4237static void
4238do_vec_BIC (sim_cpu *cpu)
4239{
4240 /* instr[31] = 0
4241 instr[30] = half (0)/full (1)
4242 instr[29,21] = 00 1110 011
4243 instr[20,16] = Vm
4244 instr[15,10] = 00 0111
4245 instr[9,5] = Vn
4246 instr[4.0] = Vd. */
4247
ef0d8ffc
NC
4248 unsigned vm = INSTR (20, 16);
4249 unsigned vn = INSTR (9, 5);
4250 unsigned vd = INSTR (4, 0);
2e8cf49e 4251 unsigned i;
ef0d8ffc 4252 int full = INSTR (30, 30);
2e8cf49e
NC
4253
4254 NYI_assert (29, 21, 0x073);
4255 NYI_assert (15, 10, 0x07);
4256
2cdad34c 4257 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4258 for (i = 0; i < (full ? 16 : 8); i++)
4259 aarch64_set_vec_u8 (cpu, vd, i,
4260 aarch64_get_vec_u8 (cpu, vn, i)
4261 & ~ aarch64_get_vec_u8 (cpu, vm, i));
4262}
4263
4264static void
4265do_vec_XTN (sim_cpu *cpu)
4266{
4267 /* instr[31] = 0
4268 instr[30] = first part (0)/ second part (1)
4269 instr[29,24] = 00 1110
4270 instr[23,22] = size: byte(00), half(01), word (10)
4271 instr[21,10] = 1000 0100 1010
4272 instr[9,5] = Vs
4273 instr[4,0] = Vd. */
4274
ef0d8ffc
NC
4275 unsigned vs = INSTR (9, 5);
4276 unsigned vd = INSTR (4, 0);
4277 unsigned bias = INSTR (30, 30);
2e8cf49e
NC
4278 unsigned i;
4279
4280 NYI_assert (29, 24, 0x0E);
4281 NYI_assert (21, 10, 0x84A);
4282
2cdad34c 4283 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4284 switch (INSTR (23, 22))
2e8cf49e
NC
4285 {
4286 case 0:
05b3d79d
JW
4287 for (i = 0; i < 8; i++)
4288 aarch64_set_vec_u8 (cpu, vd, i + (bias * 8),
4289 aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4290 return;
4291
4292 case 1:
05b3d79d
JW
4293 for (i = 0; i < 4; i++)
4294 aarch64_set_vec_u16 (cpu, vd, i + (bias * 4),
4295 aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e
NC
4296 return;
4297
4298 case 2:
05b3d79d
JW
4299 for (i = 0; i < 2; i++)
4300 aarch64_set_vec_u32 (cpu, vd, i + (bias * 2),
4301 aarch64_get_vec_u64 (cpu, vs, i));
2e8cf49e 4302 return;
2e8cf49e
NC
4303 }
4304}
4305
ac189e7b
JW
4306/* Return the number of bits set in the input value. */
4307#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
4308# define popcount __builtin_popcount
4309#else
4310static int
4311popcount (unsigned char x)
4312{
4313 static const unsigned char popcnt[16] =
4314 {
4315 0, 1, 1, 2,
4316 1, 2, 2, 3,
4317 1, 2, 2, 3,
4318 2, 3, 3, 4
4319 };
4320
4321 /* Only counts the low 8 bits of the input as that is all we need. */
4322 return popcnt[x % 16] + popcnt[x / 16];
4323}
4324#endif
4325
4326static void
4327do_vec_CNT (sim_cpu *cpu)
4328{
4329 /* instr[31] = 0
4330 instr[30] = half (0)/ full (1)
4331 instr[29,24] = 00 1110
4332 instr[23,22] = size: byte(00)
4333 instr[21,10] = 1000 0001 0110
4334 instr[9,5] = Vs
4335 instr[4,0] = Vd. */
4336
4337 unsigned vs = INSTR (9, 5);
4338 unsigned vd = INSTR (4, 0);
4339 int full = INSTR (30, 30);
4340 int size = INSTR (23, 22);
4341 int i;
4342
4343 NYI_assert (29, 24, 0x0E);
4344 NYI_assert (21, 10, 0x816);
4345
4346 if (size != 0)
4347 HALT_UNALLOC;
4348
4349 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
4350
4351 for (i = 0; i < (full ? 16 : 8); i++)
4352 aarch64_set_vec_u8 (cpu, vd, i,
4353 popcount (aarch64_get_vec_u8 (cpu, vs, i)));
4354}
4355
2e8cf49e
NC
4356static void
4357do_vec_maxv (sim_cpu *cpu)
4358{
4359 /* instr[31] = 0
4360 instr[30] = half(0)/full(1)
4361 instr[29] = signed (0)/unsigned(1)
4362 instr[28,24] = 0 1110
4363 instr[23,22] = size: byte(00), half(01), word (10)
4364 instr[21] = 1
4365 instr[20,17] = 1 000
4366 instr[16] = max(0)/min(1)
4367 instr[15,10] = 1010 10
4368 instr[9,5] = V source
4369 instr[4.0] = R dest. */
4370
ef0d8ffc
NC
4371 unsigned vs = INSTR (9, 5);
4372 unsigned rd = INSTR (4, 0);
4373 unsigned full = INSTR (30, 30);
2e8cf49e
NC
4374 unsigned i;
4375
4376 NYI_assert (28, 24, 0x0E);
4377 NYI_assert (21, 21, 1);
4378 NYI_assert (20, 17, 8);
4379 NYI_assert (15, 10, 0x2A);
4380
2cdad34c 4381 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 4382 switch ((INSTR (29, 29) << 1) | INSTR (16, 16))
2e8cf49e
NC
4383 {
4384 case 0: /* SMAXV. */
4385 {
4386 int64_t smax;
ef0d8ffc 4387 switch (INSTR (23, 22))
2e8cf49e
NC
4388 {
4389 case 0:
4390 smax = aarch64_get_vec_s8 (cpu, vs, 0);
4391 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4392 smax = max (smax, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4393 break;
4394 case 1:
4395 smax = aarch64_get_vec_s16 (cpu, vs, 0);
4396 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4397 smax = max (smax, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4398 break;
4399 case 2:
4400 smax = aarch64_get_vec_s32 (cpu, vs, 0);
4401 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4402 smax = max (smax, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4403 break;
2e8cf49e
NC
4404 case 3:
4405 HALT_UNALLOC;
4406 }
4407 aarch64_set_reg_s64 (cpu, rd, NO_SP, smax);
4408 return;
4409 }
4410
4411 case 1: /* SMINV. */
4412 {
4413 int64_t smin;
ef0d8ffc 4414 switch (INSTR (23, 22))
2e8cf49e
NC
4415 {
4416 case 0:
4417 smin = aarch64_get_vec_s8 (cpu, vs, 0);
4418 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4419 smin = min (smin, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4420 break;
4421 case 1:
4422 smin = aarch64_get_vec_s16 (cpu, vs, 0);
4423 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4424 smin = min (smin, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4425 break;
4426 case 2:
4427 smin = aarch64_get_vec_s32 (cpu, vs, 0);
4428 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4429 smin = min (smin, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4430 break;
5ab6d79e 4431
2e8cf49e
NC
4432 case 3:
4433 HALT_UNALLOC;
4434 }
4435 aarch64_set_reg_s64 (cpu, rd, NO_SP, smin);
4436 return;
4437 }
4438
4439 case 2: /* UMAXV. */
4440 {
4441 uint64_t umax;
ef0d8ffc 4442 switch (INSTR (23, 22))
2e8cf49e
NC
4443 {
4444 case 0:
4445 umax = aarch64_get_vec_u8 (cpu, vs, 0);
4446 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4447 umax = max (umax, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4448 break;
4449 case 1:
4450 umax = aarch64_get_vec_u16 (cpu, vs, 0);
4451 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4452 umax = max (umax, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4453 break;
4454 case 2:
4455 umax = aarch64_get_vec_u32 (cpu, vs, 0);
4456 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4457 umax = max (umax, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4458 break;
5ab6d79e 4459
2e8cf49e
NC
4460 case 3:
4461 HALT_UNALLOC;
4462 }
4463 aarch64_set_reg_u64 (cpu, rd, NO_SP, umax);
4464 return;
4465 }
4466
4467 case 3: /* UMINV. */
4468 {
4469 uint64_t umin;
ef0d8ffc 4470 switch (INSTR (23, 22))
2e8cf49e
NC
4471 {
4472 case 0:
4473 umin = aarch64_get_vec_u8 (cpu, vs, 0);
4474 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4475 umin = min (umin, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4476 break;
4477 case 1:
4478 umin = aarch64_get_vec_u16 (cpu, vs, 0);
4479 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4480 umin = min (umin, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4481 break;
4482 case 2:
4483 umin = aarch64_get_vec_u32 (cpu, vs, 0);
4484 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4485 umin = min (umin, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4486 break;
5ab6d79e 4487
2e8cf49e
NC
4488 case 3:
4489 HALT_UNALLOC;
4490 }
4491 aarch64_set_reg_u64 (cpu, rd, NO_SP, umin);
4492 return;
4493 }
2e8cf49e
NC
4494 }
4495}
4496
4497static void
4498do_vec_fminmaxV (sim_cpu *cpu)
4499{
4500 /* instr[31,24] = 0110 1110
4501 instr[23] = max(0)/min(1)
4502 instr[22,14] = 011 0000 11
4503 instr[13,12] = nm(00)/normal(11)
4504 instr[11,10] = 10
4505 instr[9,5] = V source
4506 instr[4.0] = R dest. */
4507
ef0d8ffc
NC
4508 unsigned vs = INSTR (9, 5);
4509 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
4510 unsigned i;
4511 float res = aarch64_get_vec_float (cpu, vs, 0);
4512
4513 NYI_assert (31, 24, 0x6E);
4514 NYI_assert (22, 14, 0x0C3);
4515 NYI_assert (11, 10, 2);
4516
2cdad34c 4517 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4518 if (INSTR (23, 23))
2e8cf49e 4519 {
ef0d8ffc 4520 switch (INSTR (13, 12))
2e8cf49e
NC
4521 {
4522 case 0: /* FMNINNMV. */
4523 for (i = 1; i < 4; i++)
4524 res = fminnm (res, aarch64_get_vec_float (cpu, vs, i));
4525 break;
4526
4527 case 3: /* FMINV. */
4528 for (i = 1; i < 4; i++)
bc273e17 4529 res = min (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4530 break;
4531
4532 default:
4533 HALT_NYI;
4534 }
4535 }
4536 else
4537 {
ef0d8ffc 4538 switch (INSTR (13, 12))
2e8cf49e
NC
4539 {
4540 case 0: /* FMNAXNMV. */
4541 for (i = 1; i < 4; i++)
4542 res = fmaxnm (res, aarch64_get_vec_float (cpu, vs, i));
4543 break;
4544
4545 case 3: /* FMAXV. */
4546 for (i = 1; i < 4; i++)
bc273e17 4547 res = max (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4548 break;
4549
4550 default:
4551 HALT_NYI;
4552 }
4553 }
4554
4555 aarch64_set_FP_float (cpu, rd, res);
4556}
4557
4558static void
4559do_vec_Fminmax (sim_cpu *cpu)
4560{
4561 /* instr[31] = 0
4562 instr[30] = half(0)/full(1)
4563 instr[29,24] = 00 1110
4564 instr[23] = max(0)/min(1)
4565 instr[22] = float(0)/double(1)
4566 instr[21] = 1
4567 instr[20,16] = Vm
4568 instr[15,14] = 11
4569 instr[13,12] = nm(00)/normal(11)
4570 instr[11,10] = 01
4571 instr[9,5] = Vn
4572 instr[4,0] = Vd. */
4573
ef0d8ffc
NC
4574 unsigned vm = INSTR (20, 16);
4575 unsigned vn = INSTR (9, 5);
4576 unsigned vd = INSTR (4, 0);
4577 unsigned full = INSTR (30, 30);
4578 unsigned min = INSTR (23, 23);
2e8cf49e
NC
4579 unsigned i;
4580
4581 NYI_assert (29, 24, 0x0E);
4582 NYI_assert (21, 21, 1);
4583 NYI_assert (15, 14, 3);
4584 NYI_assert (11, 10, 1);
4585
2cdad34c 4586 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4587 if (INSTR (22, 22))
2e8cf49e
NC
4588 {
4589 double (* func)(double, double);
4590
4591 if (! full)
4592 HALT_NYI;
4593
ef0d8ffc 4594 if (INSTR (13, 12) == 0)
2e8cf49e 4595 func = min ? dminnm : dmaxnm;
ef0d8ffc 4596 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4597 func = min ? fmin : fmax;
4598 else
4599 HALT_NYI;
4600
4601 for (i = 0; i < 2; i++)
4602 aarch64_set_vec_double (cpu, vd, i,
4603 func (aarch64_get_vec_double (cpu, vn, i),
4604 aarch64_get_vec_double (cpu, vm, i)));
4605 }
4606 else
4607 {
4608 float (* func)(float, float);
4609
ef0d8ffc 4610 if (INSTR (13, 12) == 0)
2e8cf49e 4611 func = min ? fminnm : fmaxnm;
ef0d8ffc 4612 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4613 func = min ? fminf : fmaxf;
4614 else
4615 HALT_NYI;
4616
4617 for (i = 0; i < (full ? 4 : 2); i++)
4618 aarch64_set_vec_float (cpu, vd, i,
4619 func (aarch64_get_vec_float (cpu, vn, i),
4620 aarch64_get_vec_float (cpu, vm, i)));
4621 }
4622}
4623
4624static void
4625do_vec_SCVTF (sim_cpu *cpu)
4626{
4627 /* instr[31] = 0
4628 instr[30] = Q
4629 instr[29,23] = 00 1110 0
4630 instr[22] = float(0)/double(1)
4631 instr[21,10] = 10 0001 1101 10
4632 instr[9,5] = Vn
4633 instr[4,0] = Vd. */
4634
ef0d8ffc
NC
4635 unsigned vn = INSTR (9, 5);
4636 unsigned vd = INSTR (4, 0);
4637 unsigned full = INSTR (30, 30);
4638 unsigned size = INSTR (22, 22);
2e8cf49e
NC
4639 unsigned i;
4640
4641 NYI_assert (29, 23, 0x1C);
4642 NYI_assert (21, 10, 0x876);
4643
2cdad34c 4644 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4645 if (size)
4646 {
4647 if (! full)
4648 HALT_UNALLOC;
4649
4650 for (i = 0; i < 2; i++)
4651 {
4652 double val = (double) aarch64_get_vec_u64 (cpu, vn, i);
4653 aarch64_set_vec_double (cpu, vd, i, val);
4654 }
4655 }
4656 else
4657 {
4658 for (i = 0; i < (full ? 4 : 2); i++)
4659 {
4660 float val = (float) aarch64_get_vec_u32 (cpu, vn, i);
4661 aarch64_set_vec_float (cpu, vd, i, val);
4662 }
4663 }
4664}
4665
4666#define VEC_CMP(SOURCE, CMP) \
4667 do \
4668 { \
4669 switch (size) \
4670 { \
4671 case 0: \
4672 for (i = 0; i < (full ? 16 : 8); i++) \
4673 aarch64_set_vec_u8 (cpu, vd, i, \
4674 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4675 CMP \
4676 aarch64_get_vec_##SOURCE##8 (cpu, vm, i) \
4677 ? -1 : 0); \
4678 return; \
4679 case 1: \
4680 for (i = 0; i < (full ? 8 : 4); i++) \
4681 aarch64_set_vec_u16 (cpu, vd, i, \
4682 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4683 CMP \
4684 aarch64_get_vec_##SOURCE##16 (cpu, vm, i) \
4685 ? -1 : 0); \
4686 return; \
4687 case 2: \
4688 for (i = 0; i < (full ? 4 : 2); i++) \
4689 aarch64_set_vec_u32 (cpu, vd, i, \
4690 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4691 CMP \
4692 aarch64_get_vec_##SOURCE##32 (cpu, vm, i) \
4693 ? -1 : 0); \
4694 return; \
4695 case 3: \
4696 if (! full) \
4697 HALT_UNALLOC; \
4698 for (i = 0; i < 2; i++) \
4699 aarch64_set_vec_u64 (cpu, vd, i, \
4700 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4701 CMP \
4702 aarch64_get_vec_##SOURCE##64 (cpu, vm, i) \
4703 ? -1ULL : 0); \
4704 return; \
2e8cf49e
NC
4705 } \
4706 } \
4707 while (0)
4708
4709#define VEC_CMP0(SOURCE, CMP) \
4710 do \
4711 { \
4712 switch (size) \
4713 { \
4714 case 0: \
4715 for (i = 0; i < (full ? 16 : 8); i++) \
4716 aarch64_set_vec_u8 (cpu, vd, i, \
4717 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4718 CMP 0 ? -1 : 0); \
4719 return; \
4720 case 1: \
4721 for (i = 0; i < (full ? 8 : 4); i++) \
4722 aarch64_set_vec_u16 (cpu, vd, i, \
4723 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4724 CMP 0 ? -1 : 0); \
4725 return; \
4726 case 2: \
4727 for (i = 0; i < (full ? 4 : 2); i++) \
4728 aarch64_set_vec_u32 (cpu, vd, i, \
4729 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4730 CMP 0 ? -1 : 0); \
4731 return; \
4732 case 3: \
4733 if (! full) \
4734 HALT_UNALLOC; \
4735 for (i = 0; i < 2; i++) \
4736 aarch64_set_vec_u64 (cpu, vd, i, \
4737 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4738 CMP 0 ? -1ULL : 0); \
4739 return; \
2e8cf49e
NC
4740 } \
4741 } \
4742 while (0)
4743
4744#define VEC_FCMP0(CMP) \
4745 do \
4746 { \
4747 if (vm != 0) \
4748 HALT_NYI; \
2cdad34c 4749 if (INSTR (22, 22)) \
2e8cf49e
NC
4750 { \
4751 if (! full) \
4752 HALT_NYI; \
4753 for (i = 0; i < 2; i++) \
4754 aarch64_set_vec_u64 (cpu, vd, i, \
4755 aarch64_get_vec_double (cpu, vn, i) \
4756 CMP 0.0 ? -1 : 0); \
4757 } \
4758 else \
4759 { \
4760 for (i = 0; i < (full ? 4 : 2); i++) \
4761 aarch64_set_vec_u32 (cpu, vd, i, \
4762 aarch64_get_vec_float (cpu, vn, i) \
4763 CMP 0.0 ? -1 : 0); \
4764 } \
4765 return; \
4766 } \
4767 while (0)
4768
4769#define VEC_FCMP(CMP) \
4770 do \
4771 { \
2cdad34c 4772 if (INSTR (22, 22)) \
2e8cf49e
NC
4773 { \
4774 if (! full) \
4775 HALT_NYI; \
4776 for (i = 0; i < 2; i++) \
4777 aarch64_set_vec_u64 (cpu, vd, i, \
4778 aarch64_get_vec_double (cpu, vn, i) \
4779 CMP \
4780 aarch64_get_vec_double (cpu, vm, i) \
4781 ? -1 : 0); \
4782 } \
4783 else \
4784 { \
4785 for (i = 0; i < (full ? 4 : 2); i++) \
4786 aarch64_set_vec_u32 (cpu, vd, i, \
4787 aarch64_get_vec_float (cpu, vn, i) \
4788 CMP \
4789 aarch64_get_vec_float (cpu, vm, i) \
4790 ? -1 : 0); \
4791 } \
4792 return; \
4793 } \
4794 while (0)
4795
4796static void
4797do_vec_compare (sim_cpu *cpu)
4798{
4799 /* instr[31] = 0
4800 instr[30] = half(0)/full(1)
4801 instr[29] = part-of-comparison-type
4802 instr[28,24] = 0 1110
4803 instr[23,22] = size of integer compares: byte(00), half(01), word (10), long (11)
4804 type of float compares: single (-0) / double (-1)
4805 instr[21] = 1
4806 instr[20,16] = Vm or 00000 (compare vs 0)
4807 instr[15,10] = part-of-comparison-type
4808 instr[9,5] = Vn
4809 instr[4.0] = Vd. */
4810
ef0d8ffc
NC
4811 int full = INSTR (30, 30);
4812 int size = INSTR (23, 22);
4813 unsigned vm = INSTR (20, 16);
4814 unsigned vn = INSTR (9, 5);
4815 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
4816 unsigned i;
4817
4818 NYI_assert (28, 24, 0x0E);
4819 NYI_assert (21, 21, 1);
4820
2cdad34c 4821 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc
NC
4822 if ((INSTR (11, 11)
4823 && INSTR (14, 14))
4824 || ((INSTR (11, 11) == 0
4825 && INSTR (10, 10) == 0)))
2e8cf49e
NC
4826 {
4827 /* A compare vs 0. */
4828 if (vm != 0)
4829 {
ef0d8ffc 4830 if (INSTR (15, 10) == 0x2A)
2e8cf49e 4831 do_vec_maxv (cpu);
ef0d8ffc
NC
4832 else if (INSTR (15, 10) == 0x32
4833 || INSTR (15, 10) == 0x3E)
2e8cf49e 4834 do_vec_fminmaxV (cpu);
ef0d8ffc
NC
4835 else if (INSTR (29, 23) == 0x1C
4836 && INSTR (21, 10) == 0x876)
2e8cf49e
NC
4837 do_vec_SCVTF (cpu);
4838 else
4839 HALT_NYI;
4840 return;
4841 }
4842 }
4843
ef0d8ffc 4844 if (INSTR (14, 14))
2e8cf49e
NC
4845 {
4846 /* A floating point compare. */
7517e550 4847 unsigned decode = (INSTR (29, 29) << 5) | (INSTR (23, 23) << 4)
ef0d8ffc 4848 | INSTR (13, 10);
2e8cf49e
NC
4849
4850 NYI_assert (15, 15, 1);
4851
4852 switch (decode)
4853 {
4854 case /* 0b010010: GT#0 */ 0x12: VEC_FCMP0 (>);
4855 case /* 0b110010: GE#0 */ 0x32: VEC_FCMP0 (>=);
4856 case /* 0b010110: EQ#0 */ 0x16: VEC_FCMP0 (==);
4857 case /* 0b110110: LE#0 */ 0x36: VEC_FCMP0 (<=);
4858 case /* 0b011010: LT#0 */ 0x1A: VEC_FCMP0 (<);
4859 case /* 0b111001: GT */ 0x39: VEC_FCMP (>);
4860 case /* 0b101001: GE */ 0x29: VEC_FCMP (>=);
4861 case /* 0b001001: EQ */ 0x09: VEC_FCMP (==);
4862
4863 default:
4864 HALT_NYI;
4865 }
4866 }
4867 else
4868 {
7517e550 4869 unsigned decode = (INSTR (29, 29) << 6) | INSTR (15, 10);
2e8cf49e
NC
4870
4871 switch (decode)
4872 {
4873 case 0x0D: /* 0001101 GT */ VEC_CMP (s, > );
4874 case 0x0F: /* 0001111 GE */ VEC_CMP (s, >= );
4875 case 0x22: /* 0100010 GT #0 */ VEC_CMP0 (s, > );
fbf32f63 4876 case 0x23: /* 0100011 TST */ VEC_CMP (u, & );
2e8cf49e
NC
4877 case 0x26: /* 0100110 EQ #0 */ VEC_CMP0 (s, == );
4878 case 0x2A: /* 0101010 LT #0 */ VEC_CMP0 (s, < );
4879 case 0x4D: /* 1001101 HI */ VEC_CMP (u, > );
4880 case 0x4F: /* 1001111 HS */ VEC_CMP (u, >= );
4881 case 0x62: /* 1100010 GE #0 */ VEC_CMP0 (s, >= );
4882 case 0x63: /* 1100011 EQ */ VEC_CMP (u, == );
4883 case 0x66: /* 1100110 LE #0 */ VEC_CMP0 (s, <= );
4884 default:
4885 if (vm == 0)
4886 HALT_NYI;
4887 do_vec_maxv (cpu);
4888 }
4889 }
4890}
4891
4892static void
4893do_vec_SSHL (sim_cpu *cpu)
4894{
4895 /* instr[31] = 0
4896 instr[30] = first part (0)/ second part (1)
4897 instr[29,24] = 00 1110
4898 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4899 instr[21] = 1
4900 instr[20,16] = Vm
4901 instr[15,10] = 0100 01
4902 instr[9,5] = Vn
4903 instr[4,0] = Vd. */
4904
ef0d8ffc
NC
4905 unsigned full = INSTR (30, 30);
4906 unsigned vm = INSTR (20, 16);
4907 unsigned vn = INSTR (9, 5);
4908 unsigned vd = INSTR (4, 0);
2e8cf49e 4909 unsigned i;
5ab6d79e 4910 signed int shift;
2e8cf49e
NC
4911
4912 NYI_assert (29, 24, 0x0E);
4913 NYI_assert (21, 21, 1);
4914 NYI_assert (15, 10, 0x11);
4915
4916 /* FIXME: What is a signed shift left in this context ?. */
4917
2cdad34c 4918 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4919 switch (INSTR (23, 22))
2e8cf49e
NC
4920 {
4921 case 0:
4922 for (i = 0; i < (full ? 16 : 8); i++)
5ab6d79e
NC
4923 {
4924 shift = aarch64_get_vec_s8 (cpu, vm, i);
4925 if (shift >= 0)
4926 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4927 << shift);
4928 else
4929 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4930 >> - shift);
4931 }
2e8cf49e
NC
4932 return;
4933
4934 case 1:
4935 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 4936 {
7517e550 4937 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
4938 if (shift >= 0)
4939 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4940 << shift);
4941 else
4942 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4943 >> - shift);
4944 }
2e8cf49e
NC
4945 return;
4946
4947 case 2:
4948 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 4949 {
7517e550 4950 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
4951 if (shift >= 0)
4952 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4953 << shift);
4954 else
4955 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4956 >> - shift);
4957 }
2e8cf49e
NC
4958 return;
4959
4960 case 3:
4961 if (! full)
4962 HALT_UNALLOC;
4963 for (i = 0; i < 2; i++)
5ab6d79e 4964 {
7517e550 4965 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
4966 if (shift >= 0)
4967 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4968 << shift);
4969 else
4970 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4971 >> - shift);
4972 }
2e8cf49e 4973 return;
2e8cf49e
NC
4974 }
4975}
4976
4977static void
4978do_vec_USHL (sim_cpu *cpu)
4979{
4980 /* instr[31] = 0
4981 instr[30] = first part (0)/ second part (1)
4982 instr[29,24] = 10 1110
4983 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4984 instr[21] = 1
4985 instr[20,16] = Vm
4986 instr[15,10] = 0100 01
4987 instr[9,5] = Vn
4988 instr[4,0] = Vd */
4989
ef0d8ffc
NC
4990 unsigned full = INSTR (30, 30);
4991 unsigned vm = INSTR (20, 16);
4992 unsigned vn = INSTR (9, 5);
4993 unsigned vd = INSTR (4, 0);
2e8cf49e 4994 unsigned i;
5ab6d79e 4995 signed int shift;
2e8cf49e
NC
4996
4997 NYI_assert (29, 24, 0x2E);
4998 NYI_assert (15, 10, 0x11);
4999
2cdad34c 5000 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5001 switch (INSTR (23, 22))
2e8cf49e
NC
5002 {
5003 case 0:
5ab6d79e
NC
5004 for (i = 0; i < (full ? 16 : 8); i++)
5005 {
5006 shift = aarch64_get_vec_s8 (cpu, vm, i);
5007 if (shift >= 0)
5008 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
5009 << shift);
5010 else
5011 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
5012 >> - shift);
5013 }
2e8cf49e
NC
5014 return;
5015
5016 case 1:
5017 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 5018 {
7517e550 5019 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
5020 if (shift >= 0)
5021 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
5022 << shift);
5023 else
5024 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
5025 >> - shift);
5026 }
2e8cf49e
NC
5027 return;
5028
5029 case 2:
5030 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 5031 {
7517e550 5032 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
5033 if (shift >= 0)
5034 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
5035 << shift);
5036 else
5037 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
5038 >> - shift);
5039 }
2e8cf49e
NC
5040 return;
5041
5042 case 3:
5043 if (! full)
5044 HALT_UNALLOC;
5045 for (i = 0; i < 2; i++)
5ab6d79e 5046 {
7517e550 5047 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
5048 if (shift >= 0)
5049 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
5050 << shift);
5051 else
5052 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
5053 >> - shift);
5054 }
2e8cf49e 5055 return;
2e8cf49e
NC
5056 }
5057}
5058
5059static void
5060do_vec_FMLA (sim_cpu *cpu)
5061{
5062 /* instr[31] = 0
5063 instr[30] = full/half selector
5064 instr[29,23] = 0011100
5065 instr[22] = size: 0=>float, 1=>double
5066 instr[21] = 1
5067 instr[20,16] = Vn
5068 instr[15,10] = 1100 11
5069 instr[9,5] = Vm
5070 instr[4.0] = Vd. */
5071
ef0d8ffc
NC
5072 unsigned vm = INSTR (20, 16);
5073 unsigned vn = INSTR (9, 5);
5074 unsigned vd = INSTR (4, 0);
2e8cf49e 5075 unsigned i;
ef0d8ffc 5076 int full = INSTR (30, 30);
2e8cf49e
NC
5077
5078 NYI_assert (29, 23, 0x1C);
5079 NYI_assert (21, 21, 1);
5080 NYI_assert (15, 10, 0x33);
5081
2cdad34c 5082 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5083 if (INSTR (22, 22))
2e8cf49e
NC
5084 {
5085 if (! full)
5086 HALT_UNALLOC;
5087 for (i = 0; i < 2; i++)
5088 aarch64_set_vec_double (cpu, vd, i,
5089 aarch64_get_vec_double (cpu, vn, i) *
5090 aarch64_get_vec_double (cpu, vm, i) +
5091 aarch64_get_vec_double (cpu, vd, i));
5092 }
5093 else
5094 {
5095 for (i = 0; i < (full ? 4 : 2); i++)
5096 aarch64_set_vec_float (cpu, vd, i,
5097 aarch64_get_vec_float (cpu, vn, i) *
5098 aarch64_get_vec_float (cpu, vm, i) +
5099 aarch64_get_vec_float (cpu, vd, i));
5100 }
5101}
5102
5103static void
5104do_vec_max (sim_cpu *cpu)
5105{
5106 /* instr[31] = 0
5107 instr[30] = full/half selector
5108 instr[29] = SMAX (0) / UMAX (1)
5109 instr[28,24] = 0 1110
5110 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
5111 instr[21] = 1
5112 instr[20,16] = Vn
5113 instr[15,10] = 0110 01
5114 instr[9,5] = Vm
5115 instr[4.0] = Vd. */
5116
ef0d8ffc
NC
5117 unsigned vm = INSTR (20, 16);
5118 unsigned vn = INSTR (9, 5);
5119 unsigned vd = INSTR (4, 0);
2e8cf49e 5120 unsigned i;
ef0d8ffc 5121 int full = INSTR (30, 30);
2e8cf49e
NC
5122
5123 NYI_assert (28, 24, 0x0E);
5124 NYI_assert (21, 21, 1);
5125 NYI_assert (15, 10, 0x19);
5126
2cdad34c 5127 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5128 if (INSTR (29, 29))
2e8cf49e 5129 {
ef0d8ffc 5130 switch (INSTR (23, 22))
2e8cf49e
NC
5131 {
5132 case 0:
5133 for (i = 0; i < (full ? 16 : 8); i++)
5134 aarch64_set_vec_u8 (cpu, vd, i,
5135 aarch64_get_vec_u8 (cpu, vn, i)
5136 > aarch64_get_vec_u8 (cpu, vm, i)
5137 ? aarch64_get_vec_u8 (cpu, vn, i)
5138 : aarch64_get_vec_u8 (cpu, vm, i));
5139 return;
5140
5141 case 1:
5142 for (i = 0; i < (full ? 8 : 4); i++)
5143 aarch64_set_vec_u16 (cpu, vd, i,
5144 aarch64_get_vec_u16 (cpu, vn, i)
5145 > aarch64_get_vec_u16 (cpu, vm, i)
5146 ? aarch64_get_vec_u16 (cpu, vn, i)
5147 : aarch64_get_vec_u16 (cpu, vm, i));
5148 return;
5149
5150 case 2:
5151 for (i = 0; i < (full ? 4 : 2); i++)
5152 aarch64_set_vec_u32 (cpu, vd, i,
5153 aarch64_get_vec_u32 (cpu, vn, i)
5154 > aarch64_get_vec_u32 (cpu, vm, i)
5155 ? aarch64_get_vec_u32 (cpu, vn, i)
5156 : aarch64_get_vec_u32 (cpu, vm, i));
5157 return;
5158
2e8cf49e
NC
5159 case 3:
5160 HALT_UNALLOC;
5161 }
5162 }
5163 else
5164 {
ef0d8ffc 5165 switch (INSTR (23, 22))
2e8cf49e
NC
5166 {
5167 case 0:
5168 for (i = 0; i < (full ? 16 : 8); i++)
5169 aarch64_set_vec_s8 (cpu, vd, i,
5170 aarch64_get_vec_s8 (cpu, vn, i)
5171 > aarch64_get_vec_s8 (cpu, vm, i)
5172 ? aarch64_get_vec_s8 (cpu, vn, i)
5173 : aarch64_get_vec_s8 (cpu, vm, i));
5174 return;
5175
5176 case 1:
5177 for (i = 0; i < (full ? 8 : 4); i++)
5178 aarch64_set_vec_s16 (cpu, vd, i,
5179 aarch64_get_vec_s16 (cpu, vn, i)
5180 > aarch64_get_vec_s16 (cpu, vm, i)
5181 ? aarch64_get_vec_s16 (cpu, vn, i)
5182 : aarch64_get_vec_s16 (cpu, vm, i));
5183 return;
5184
5185 case 2:
5186 for (i = 0; i < (full ? 4 : 2); i++)
5187 aarch64_set_vec_s32 (cpu, vd, i,
5188 aarch64_get_vec_s32 (cpu, vn, i)
5189 > aarch64_get_vec_s32 (cpu, vm, i)
5190 ? aarch64_get_vec_s32 (cpu, vn, i)
5191 : aarch64_get_vec_s32 (cpu, vm, i));
5192 return;
5193
2e8cf49e
NC
5194 case 3:
5195 HALT_UNALLOC;
5196 }
5197 }
5198}
5199
5200static void
5201do_vec_min (sim_cpu *cpu)
5202{
5203 /* instr[31] = 0
5204 instr[30] = full/half selector
5205 instr[29] = SMIN (0) / UMIN (1)
5206 instr[28,24] = 0 1110
5207 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
5208 instr[21] = 1
5209 instr[20,16] = Vn
5210 instr[15,10] = 0110 11
5211 instr[9,5] = Vm
5212 instr[4.0] = Vd. */
5213
ef0d8ffc
NC
5214 unsigned vm = INSTR (20, 16);
5215 unsigned vn = INSTR (9, 5);
5216 unsigned vd = INSTR (4, 0);
2e8cf49e 5217 unsigned i;
ef0d8ffc 5218 int full = INSTR (30, 30);
2e8cf49e
NC
5219
5220 NYI_assert (28, 24, 0x0E);
5221 NYI_assert (21, 21, 1);
5222 NYI_assert (15, 10, 0x1B);
5223
2cdad34c 5224 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5225 if (INSTR (29, 29))
2e8cf49e 5226 {
ef0d8ffc 5227 switch (INSTR (23, 22))
2e8cf49e
NC
5228 {
5229 case 0:
5230 for (i = 0; i < (full ? 16 : 8); i++)
5231 aarch64_set_vec_u8 (cpu, vd, i,
5232 aarch64_get_vec_u8 (cpu, vn, i)
5233 < aarch64_get_vec_u8 (cpu, vm, i)
5234 ? aarch64_get_vec_u8 (cpu, vn, i)
5235 : aarch64_get_vec_u8 (cpu, vm, i));
5236 return;
5237
5238 case 1:
5239 for (i = 0; i < (full ? 8 : 4); i++)
5240 aarch64_set_vec_u16 (cpu, vd, i,
5241 aarch64_get_vec_u16 (cpu, vn, i)
5242 < aarch64_get_vec_u16 (cpu, vm, i)
5243 ? aarch64_get_vec_u16 (cpu, vn, i)
5244 : aarch64_get_vec_u16 (cpu, vm, i));
5245 return;
5246
5247 case 2:
5248 for (i = 0; i < (full ? 4 : 2); i++)
5249 aarch64_set_vec_u32 (cpu, vd, i,
5250 aarch64_get_vec_u32 (cpu, vn, i)
5251 < aarch64_get_vec_u32 (cpu, vm, i)
5252 ? aarch64_get_vec_u32 (cpu, vn, i)
5253 : aarch64_get_vec_u32 (cpu, vm, i));
5254 return;
5255
2e8cf49e
NC
5256 case 3:
5257 HALT_UNALLOC;
5258 }
5259 }
5260 else
5261 {
ef0d8ffc 5262 switch (INSTR (23, 22))
2e8cf49e
NC
5263 {
5264 case 0:
5265 for (i = 0; i < (full ? 16 : 8); i++)
5266 aarch64_set_vec_s8 (cpu, vd, i,
5267 aarch64_get_vec_s8 (cpu, vn, i)
5268 < aarch64_get_vec_s8 (cpu, vm, i)
5269 ? aarch64_get_vec_s8 (cpu, vn, i)
5270 : aarch64_get_vec_s8 (cpu, vm, i));
5271 return;
5272
5273 case 1:
5274 for (i = 0; i < (full ? 8 : 4); i++)
5275 aarch64_set_vec_s16 (cpu, vd, i,
5276 aarch64_get_vec_s16 (cpu, vn, i)
5277 < aarch64_get_vec_s16 (cpu, vm, i)
5278 ? aarch64_get_vec_s16 (cpu, vn, i)
5279 : aarch64_get_vec_s16 (cpu, vm, i));
5280 return;
5281
5282 case 2:
5283 for (i = 0; i < (full ? 4 : 2); i++)
5284 aarch64_set_vec_s32 (cpu, vd, i,
5285 aarch64_get_vec_s32 (cpu, vn, i)
5286 < aarch64_get_vec_s32 (cpu, vm, i)
5287 ? aarch64_get_vec_s32 (cpu, vn, i)
5288 : aarch64_get_vec_s32 (cpu, vm, i));
5289 return;
5290
2e8cf49e
NC
5291 case 3:
5292 HALT_UNALLOC;
5293 }
5294 }
5295}
5296
5297static void
5298do_vec_sub_long (sim_cpu *cpu)
5299{
5300 /* instr[31] = 0
5301 instr[30] = lower (0) / upper (1)
5302 instr[29] = signed (0) / unsigned (1)
5303 instr[28,24] = 0 1110
5304 instr[23,22] = size: bytes (00), half (01), word (10)
5305 instr[21] = 1
5306 insrt[20,16] = Vm
5307 instr[15,10] = 0010 00
5308 instr[9,5] = Vn
5309 instr[4,0] = V dest. */
5310
ef0d8ffc
NC
5311 unsigned size = INSTR (23, 22);
5312 unsigned vm = INSTR (20, 16);
5313 unsigned vn = INSTR (9, 5);
5314 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5315 unsigned bias = 0;
5316 unsigned i;
5317
5318 NYI_assert (28, 24, 0x0E);
5319 NYI_assert (21, 21, 1);
5320 NYI_assert (15, 10, 0x08);
5321
5322 if (size == 3)
5323 HALT_UNALLOC;
5324
2cdad34c 5325 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5326 switch (INSTR (30, 29))
2e8cf49e
NC
5327 {
5328 case 2: /* SSUBL2. */
5329 bias = 2;
5330 case 0: /* SSUBL. */
5331 switch (size)
5332 {
5333 case 0:
5334 bias *= 3;
5335 for (i = 0; i < 8; i++)
5336 aarch64_set_vec_s16 (cpu, vd, i,
5337 aarch64_get_vec_s8 (cpu, vn, i + bias)
5338 - aarch64_get_vec_s8 (cpu, vm, i + bias));
5339 break;
5340
5341 case 1:
5342 bias *= 2;
5343 for (i = 0; i < 4; i++)
5344 aarch64_set_vec_s32 (cpu, vd, i,
5345 aarch64_get_vec_s16 (cpu, vn, i + bias)
5346 - aarch64_get_vec_s16 (cpu, vm, i + bias));
5347 break;
5348
5349 case 2:
5350 for (i = 0; i < 2; i++)
5351 aarch64_set_vec_s64 (cpu, vd, i,
5352 aarch64_get_vec_s32 (cpu, vn, i + bias)
5353 - aarch64_get_vec_s32 (cpu, vm, i + bias));
5354 break;
5355
5356 default:
5357 HALT_UNALLOC;
5358 }
5359 break;
5360
5361 case 3: /* USUBL2. */
5362 bias = 2;
5363 case 1: /* USUBL. */
5364 switch (size)
5365 {
5366 case 0:
5367 bias *= 3;
5368 for (i = 0; i < 8; i++)
5369 aarch64_set_vec_u16 (cpu, vd, i,
5370 aarch64_get_vec_u8 (cpu, vn, i + bias)
5371 - aarch64_get_vec_u8 (cpu, vm, i + bias));
5372 break;
5373
5374 case 1:
5375 bias *= 2;
5376 for (i = 0; i < 4; i++)
5377 aarch64_set_vec_u32 (cpu, vd, i,
5378 aarch64_get_vec_u16 (cpu, vn, i + bias)
5379 - aarch64_get_vec_u16 (cpu, vm, i + bias));
5380 break;
5381
5382 case 2:
5383 for (i = 0; i < 2; i++)
5384 aarch64_set_vec_u64 (cpu, vd, i,
5385 aarch64_get_vec_u32 (cpu, vn, i + bias)
5386 - aarch64_get_vec_u32 (cpu, vm, i + bias));
5387 break;
5388
5389 default:
5390 HALT_UNALLOC;
5391 }
5392 break;
5393 }
5394}
5395
2e8cf49e
NC
5396static void
5397do_vec_ADDP (sim_cpu *cpu)
5398{
5399 /* instr[31] = 0
5400 instr[30] = half(0)/full(1)
5401 instr[29,24] = 00 1110
5402 instr[23,22] = size: bytes (00), half (01), word (10), long (11)
5403 instr[21] = 1
5404 insrt[20,16] = Vm
5405 instr[15,10] = 1011 11
5406 instr[9,5] = Vn
5407 instr[4,0] = V dest. */
5408
57aa1742
NC
5409 FRegister copy_vn;
5410 FRegister copy_vm;
ef0d8ffc
NC
5411 unsigned full = INSTR (30, 30);
5412 unsigned size = INSTR (23, 22);
5413 unsigned vm = INSTR (20, 16);
5414 unsigned vn = INSTR (9, 5);
5415 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5416 unsigned i, range;
5417
5418 NYI_assert (29, 24, 0x0E);
5419 NYI_assert (21, 21, 1);
5420 NYI_assert (15, 10, 0x2F);
5421
57aa1742
NC
5422 /* Make copies of the source registers in case vd == vn/vm. */
5423 copy_vn = cpu->fr[vn];
5424 copy_vm = cpu->fr[vm];
5425
2cdad34c 5426 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
5427 switch (size)
5428 {
5429 case 0:
5430 range = full ? 8 : 4;
57aa1742
NC
5431 for (i = 0; i < range; i++)
5432 {
5433 aarch64_set_vec_u8 (cpu, vd, i,
5434 copy_vn.b[i * 2] + copy_vn.b[i * 2 + 1]);
5435 aarch64_set_vec_u8 (cpu, vd, i + range,
5436 copy_vm.b[i * 2] + copy_vm.b[i * 2 + 1]);
5437 }
2e8cf49e
NC
5438 return;
5439
5440 case 1:
5441 range = full ? 4 : 2;
57aa1742
NC
5442 for (i = 0; i < range; i++)
5443 {
5444 aarch64_set_vec_u16 (cpu, vd, i,
5445 copy_vn.h[i * 2] + copy_vn.h[i * 2 + 1]);
5446 aarch64_set_vec_u16 (cpu, vd, i + range,
5447 copy_vm.h[i * 2] + copy_vm.h[i * 2 + 1]);
5448 }
2e8cf49e
NC
5449 return;
5450
5451 case 2:
5452 range = full ? 2 : 1;
57aa1742
NC
5453 for (i = 0; i < range; i++)
5454 {
5455 aarch64_set_vec_u32 (cpu, vd, i,
5456 copy_vn.w[i * 2] + copy_vn.w[i * 2 + 1]);
5457 aarch64_set_vec_u32 (cpu, vd, i + range,
5458 copy_vm.w[i * 2] + copy_vm.w[i * 2 + 1]);
5459 }
2e8cf49e
NC
5460 return;
5461
5462 case 3:
5463 if (! full)
5464 HALT_UNALLOC;
57aa1742
NC
5465 aarch64_set_vec_u64 (cpu, vd, 0, copy_vn.v[0] + copy_vn.v[1]);
5466 aarch64_set_vec_u64 (cpu, vd, 1, copy_vm.v[0] + copy_vm.v[1]);
2e8cf49e 5467 return;
2e8cf49e
NC
5468 }
5469}
5470
2e8cf49e
NC
5471static void
5472do_vec_FABS (sim_cpu *cpu)
5473{
5474 /* instr[31] = 0
5475 instr[30] = half(0)/full(1)
5476 instr[29,23] = 00 1110 1
5477 instr[22] = float(0)/double(1)
5478 instr[21,16] = 10 0000
5479 instr[15,10] = 1111 10
5480 instr[9,5] = Vn
5481 instr[4,0] = Vd. */
5482
ef0d8ffc
NC
5483 unsigned vn = INSTR (9, 5);
5484 unsigned vd = INSTR (4, 0);
5485 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5486 unsigned i;
5487
5488 NYI_assert (29, 23, 0x1D);
5489 NYI_assert (21, 10, 0x83E);
5490
2cdad34c 5491 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5492 if (INSTR (22, 22))
2e8cf49e
NC
5493 {
5494 if (! full)
5495 HALT_NYI;
5496
5497 for (i = 0; i < 2; i++)
5498 aarch64_set_vec_double (cpu, vd, i,
5499 fabs (aarch64_get_vec_double (cpu, vn, i)));
5500 }
5501 else
5502 {
5503 for (i = 0; i < (full ? 4 : 2); i++)
5504 aarch64_set_vec_float (cpu, vd, i,
5505 fabsf (aarch64_get_vec_float (cpu, vn, i)));
5506 }
5507}
5508
5509static void
5510do_vec_FCVTZS (sim_cpu *cpu)
5511{
5512 /* instr[31] = 0
5513 instr[30] = half (0) / all (1)
5514 instr[29,23] = 00 1110 1
5515 instr[22] = single (0) / double (1)
5516 instr[21,10] = 10 0001 1011 10
5517 instr[9,5] = Rn
5518 instr[4,0] = Rd. */
5519
ef0d8ffc
NC
5520 unsigned rn = INSTR (9, 5);
5521 unsigned rd = INSTR (4, 0);
5522 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5523 unsigned i;
5524
5525 NYI_assert (31, 31, 0);
5526 NYI_assert (29, 23, 0x1D);
5527 NYI_assert (21, 10, 0x86E);
5528
2cdad34c 5529 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5530 if (INSTR (22, 22))
2e8cf49e
NC
5531 {
5532 if (! full)
5533 HALT_UNALLOC;
5534
5535 for (i = 0; i < 2; i++)
5536 aarch64_set_vec_s64 (cpu, rd, i,
5537 (int64_t) aarch64_get_vec_double (cpu, rn, i));
5538 }
5539 else
5540 for (i = 0; i < (full ? 4 : 2); i++)
5541 aarch64_set_vec_s32 (cpu, rd, i,
5542 (int32_t) aarch64_get_vec_float (cpu, rn, i));
5543}
5544
67f101ee
NC
5545static void
5546do_vec_REV64 (sim_cpu *cpu)
5547{
5548 /* instr[31] = 0
5549 instr[30] = full/half
5550 instr[29,24] = 00 1110
5551 instr[23,22] = size
5552 instr[21,10] = 10 0000 0000 10
5553 instr[9,5] = Rn
5554 instr[4,0] = Rd. */
5555
5556 unsigned rn = INSTR (9, 5);
5557 unsigned rd = INSTR (4, 0);
5558 unsigned size = INSTR (23, 22);
5559 unsigned full = INSTR (30, 30);
5560 unsigned i;
5561 FRegister val;
5562
5563 NYI_assert (29, 24, 0x0E);
5564 NYI_assert (21, 10, 0x802);
5565
2cdad34c 5566 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
5567 switch (size)
5568 {
5569 case 0:
5570 for (i = 0; i < (full ? 16 : 8); i++)
5571 val.b[i ^ 0x7] = aarch64_get_vec_u8 (cpu, rn, i);
5572 break;
5573
5574 case 1:
5575 for (i = 0; i < (full ? 8 : 4); i++)
5576 val.h[i ^ 0x3] = aarch64_get_vec_u16 (cpu, rn, i);
5577 break;
5578
5579 case 2:
5580 for (i = 0; i < (full ? 4 : 2); i++)
5581 val.w[i ^ 0x1] = aarch64_get_vec_u32 (cpu, rn, i);
5582 break;
5583
5584 case 3:
5585 HALT_UNALLOC;
5586 }
5587
5588 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5589 if (full)
5590 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5591}
5592
5593static void
5594do_vec_REV16 (sim_cpu *cpu)
5595{
5596 /* instr[31] = 0
5597 instr[30] = full/half
5598 instr[29,24] = 00 1110
5599 instr[23,22] = size
5600 instr[21,10] = 10 0000 0001 10
5601 instr[9,5] = Rn
5602 instr[4,0] = Rd. */
5603
5604 unsigned rn = INSTR (9, 5);
5605 unsigned rd = INSTR (4, 0);
5606 unsigned size = INSTR (23, 22);
5607 unsigned full = INSTR (30, 30);
5608 unsigned i;
5609 FRegister val;
5610
5611 NYI_assert (29, 24, 0x0E);
5612 NYI_assert (21, 10, 0x806);
5613
2cdad34c 5614 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
5615 switch (size)
5616 {
5617 case 0:
5618 for (i = 0; i < (full ? 16 : 8); i++)
5619 val.b[i ^ 0x1] = aarch64_get_vec_u8 (cpu, rn, i);
5620 break;
5621
5622 default:
5623 HALT_UNALLOC;
5624 }
5625
5626 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5627 if (full)
5628 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5629}
5630
2e8cf49e
NC
5631static void
5632do_vec_op1 (sim_cpu *cpu)
5633{
5634 /* instr[31] = 0
5635 instr[30] = half/full
5636 instr[29,24] = 00 1110
5637 instr[23,21] = ???
5638 instr[20,16] = Vm
5639 instr[15,10] = sub-opcode
5640 instr[9,5] = Vn
5641 instr[4,0] = Vd */
5642 NYI_assert (29, 24, 0x0E);
5643
ef0d8ffc 5644 if (INSTR (21, 21) == 0)
2e8cf49e 5645 {
ef0d8ffc 5646 if (INSTR (23, 22) == 0)
2e8cf49e 5647 {
ef0d8ffc
NC
5648 if (INSTR (30, 30) == 1
5649 && INSTR (17, 14) == 0
5650 && INSTR (12, 10) == 7)
2e8cf49e
NC
5651 return do_vec_ins_2 (cpu);
5652
ef0d8ffc 5653 switch (INSTR (15, 10))
2e8cf49e
NC
5654 {
5655 case 0x01: do_vec_DUP_vector_into_vector (cpu); return;
5656 case 0x03: do_vec_DUP_scalar_into_vector (cpu); return;
5657 case 0x07: do_vec_INS (cpu); return;
152e1e1b
JW
5658 case 0x0B: do_vec_SMOV_into_scalar (cpu); return;
5659 case 0x0F: do_vec_UMOV_into_scalar (cpu); return;
2e8cf49e
NC
5660
5661 case 0x00:
5662 case 0x08:
5663 case 0x10:
5664 case 0x18:
5665 do_vec_TBL (cpu); return;
5666
5667 case 0x06:
5668 case 0x16:
5669 do_vec_UZP (cpu); return;
5670
152e1e1b
JW
5671 case 0x0A: do_vec_TRN (cpu); return;
5672
2e8cf49e
NC
5673 case 0x0E:
5674 case 0x1E:
5675 do_vec_ZIP (cpu); return;
5676
5677 default:
5678 HALT_NYI;
5679 }
5680 }
5681
ef0d8ffc 5682 switch (INSTR (13, 10))
2e8cf49e
NC
5683 {
5684 case 0x6: do_vec_UZP (cpu); return;
5685 case 0xE: do_vec_ZIP (cpu); return;
5686 case 0xA: do_vec_TRN (cpu); return;
2e8cf49e
NC
5687 default: HALT_NYI;
5688 }
5689 }
5690
ef0d8ffc 5691 switch (INSTR (15, 10))
2e8cf49e 5692 {
67f101ee
NC
5693 case 0x02: do_vec_REV64 (cpu); return;
5694 case 0x06: do_vec_REV16 (cpu); return;
5695
2e8cf49e 5696 case 0x07:
ef0d8ffc 5697 switch (INSTR (23, 21))
2e8cf49e
NC
5698 {
5699 case 1: do_vec_AND (cpu); return;
5700 case 3: do_vec_BIC (cpu); return;
5701 case 5: do_vec_ORR (cpu); return;
5702 case 7: do_vec_ORN (cpu); return;
5703 default: HALT_NYI;
5704 }
5705
5706 case 0x08: do_vec_sub_long (cpu); return;
5707 case 0x0a: do_vec_XTN (cpu); return;
5708 case 0x11: do_vec_SSHL (cpu); return;
ac189e7b 5709 case 0x16: do_vec_CNT (cpu); return;
2e8cf49e
NC
5710 case 0x19: do_vec_max (cpu); return;
5711 case 0x1B: do_vec_min (cpu); return;
5712 case 0x21: do_vec_add (cpu); return;
5713 case 0x25: do_vec_MLA (cpu); return;
5714 case 0x27: do_vec_mul (cpu); return;
5715 case 0x2F: do_vec_ADDP (cpu); return;
5716 case 0x30: do_vec_mull (cpu); return;
5717 case 0x33: do_vec_FMLA (cpu); return;
5718 case 0x35: do_vec_fadd (cpu); return;
5719
5720 case 0x2E:
ef0d8ffc 5721 switch (INSTR (20, 16))
2e8cf49e
NC
5722 {
5723 case 0x00: do_vec_ABS (cpu); return;
5724 case 0x01: do_vec_FCVTZS (cpu); return;
5725 case 0x11: do_vec_ADDV (cpu); return;
5726 default: HALT_NYI;
5727 }
5728
5729 case 0x31:
5730 case 0x3B:
5731 do_vec_Fminmax (cpu); return;
5732
5733 case 0x0D:
5734 case 0x0F:
5735 case 0x22:
5736 case 0x23:
5737 case 0x26:
5738 case 0x2A:
5739 case 0x32:
5740 case 0x36:
5741 case 0x39:
5742 case 0x3A:
5743 do_vec_compare (cpu); return;
5744
5745 case 0x3E:
5746 do_vec_FABS (cpu); return;
5747
5748 default:
5749 HALT_NYI;
5750 }
5751}
5752
5753static void
5754do_vec_xtl (sim_cpu *cpu)
5755{
5756 /* instr[31] = 0
5757 instr[30,29] = SXTL (00), UXTL (01), SXTL2 (10), UXTL2 (11)
5758 instr[28,22] = 0 1111 00
5759 instr[21,16] = size & shift (USHLL, SSHLL, USHLL2, SSHLL2)
5760 instr[15,10] = 1010 01
5761 instr[9,5] = V source
5762 instr[4,0] = V dest. */
5763
ef0d8ffc
NC
5764 unsigned vs = INSTR (9, 5);
5765 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5766 unsigned i, shift, bias = 0;
5767
5768 NYI_assert (28, 22, 0x3C);
5769 NYI_assert (15, 10, 0x29);
5770
2cdad34c 5771 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5772 switch (INSTR (30, 29))
2e8cf49e
NC
5773 {
5774 case 2: /* SXTL2, SSHLL2. */
5775 bias = 2;
5776 case 0: /* SXTL, SSHLL. */
ef0d8ffc 5777 if (INSTR (21, 21))
2e8cf49e 5778 {
7517e550
NC
5779 int64_t val1, val2;
5780
ef0d8ffc 5781 shift = INSTR (20, 16);
7517e550
NC
5782 /* Get the source values before setting the destination values
5783 in case the source and destination are the same. */
5784 val1 = aarch64_get_vec_s32 (cpu, vs, bias) << shift;
5785 val2 = aarch64_get_vec_s32 (cpu, vs, bias + 1) << shift;
5786 aarch64_set_vec_s64 (cpu, vd, 0, val1);
5787 aarch64_set_vec_s64 (cpu, vd, 1, val2);
2e8cf49e 5788 }
ef0d8ffc 5789 else if (INSTR (20, 20))
2e8cf49e 5790 {
7517e550
NC
5791 int32_t v[4];
5792 int32_t v1,v2,v3,v4;
5793
ef0d8ffc 5794 shift = INSTR (19, 16);
2e8cf49e
NC
5795 bias *= 2;
5796 for (i = 0; i < 4; i++)
7517e550
NC
5797 v[i] = aarch64_get_vec_s16 (cpu, vs, bias + i) << shift;
5798 for (i = 0; i < 4; i++)
5799 aarch64_set_vec_s32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5800 }
5801 else
5802 {
7517e550 5803 int16_t v[8];
2e8cf49e
NC
5804 NYI_assert (19, 19, 1);
5805
ef0d8ffc 5806 shift = INSTR (18, 16);
2e7e5e28 5807 bias *= 4;
2e8cf49e 5808 for (i = 0; i < 8; i++)
7517e550
NC
5809 v[i] = aarch64_get_vec_s8 (cpu, vs, i + bias) << shift;
5810 for (i = 0; i < 8; i++)
5811 aarch64_set_vec_s16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5812 }
5813 return;
5814
5815 case 3: /* UXTL2, USHLL2. */
5816 bias = 2;
5817 case 1: /* UXTL, USHLL. */
ef0d8ffc 5818 if (INSTR (21, 21))
2e8cf49e 5819 {
7517e550 5820 uint64_t v1, v2;
ef0d8ffc 5821 shift = INSTR (20, 16);
7517e550
NC
5822 v1 = aarch64_get_vec_u32 (cpu, vs, bias) << shift;
5823 v2 = aarch64_get_vec_u32 (cpu, vs, bias + 1) << shift;
5824 aarch64_set_vec_u64 (cpu, vd, 0, v1);
5825 aarch64_set_vec_u64 (cpu, vd, 1, v2);
2e8cf49e 5826 }
ef0d8ffc 5827 else if (INSTR (20, 20))
2e8cf49e 5828 {
7517e550 5829 uint32_t v[4];
ef0d8ffc 5830 shift = INSTR (19, 16);
2e8cf49e
NC
5831 bias *= 2;
5832 for (i = 0; i < 4; i++)
7517e550
NC
5833 v[i] = aarch64_get_vec_u16 (cpu, vs, i + bias) << shift;
5834 for (i = 0; i < 4; i++)
5835 aarch64_set_vec_u32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5836 }
5837 else
5838 {
7517e550 5839 uint16_t v[8];
2e8cf49e
NC
5840 NYI_assert (19, 19, 1);
5841
ef0d8ffc 5842 shift = INSTR (18, 16);
2e7e5e28 5843 bias *= 4;
2e8cf49e 5844 for (i = 0; i < 8; i++)
7517e550
NC
5845 v[i] = aarch64_get_vec_u8 (cpu, vs, i + bias) << shift;
5846 for (i = 0; i < 8; i++)
5847 aarch64_set_vec_u16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5848 }
5849 return;
2e8cf49e
NC
5850 }
5851}
5852
5853static void
5854do_vec_SHL (sim_cpu *cpu)
5855{
5856 /* instr [31] = 0
5857 instr [30] = half(0)/full(1)
5858 instr [29,23] = 001 1110
5859 instr [22,16] = size and shift amount
5860 instr [15,10] = 01 0101
5861 instr [9, 5] = Vs
5862 instr [4, 0] = Vd. */
5863
5864 int shift;
ef0d8ffc
NC
5865 int full = INSTR (30, 30);
5866 unsigned vs = INSTR (9, 5);
5867 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5868 unsigned i;
5869
5870 NYI_assert (29, 23, 0x1E);
5871 NYI_assert (15, 10, 0x15);
5872
2cdad34c 5873 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5874 if (INSTR (22, 22))
2e8cf49e 5875 {
ef0d8ffc 5876 shift = INSTR (21, 16);
2e8cf49e
NC
5877
5878 if (full == 0)
5879 HALT_UNALLOC;
5880
5881 for (i = 0; i < 2; i++)
5882 {
5883 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5884 aarch64_set_vec_u64 (cpu, vd, i, val << shift);
5885 }
5886
5887 return;
5888 }
5889
ef0d8ffc 5890 if (INSTR (21, 21))
2e8cf49e 5891 {
ef0d8ffc 5892 shift = INSTR (20, 16);
2e8cf49e
NC
5893
5894 for (i = 0; i < (full ? 4 : 2); i++)
5895 {
5896 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5897 aarch64_set_vec_u32 (cpu, vd, i, val << shift);
5898 }
5899
5900 return;
5901 }
5902
ef0d8ffc 5903 if (INSTR (20, 20))
2e8cf49e 5904 {
ef0d8ffc 5905 shift = INSTR (19, 16);
2e8cf49e
NC
5906
5907 for (i = 0; i < (full ? 8 : 4); i++)
5908 {
5909 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5910 aarch64_set_vec_u16 (cpu, vd, i, val << shift);
5911 }
5912
5913 return;
5914 }
5915
ef0d8ffc 5916 if (INSTR (19, 19) == 0)
2e8cf49e
NC
5917 HALT_UNALLOC;
5918
ef0d8ffc 5919 shift = INSTR (18, 16);
2e8cf49e
NC
5920
5921 for (i = 0; i < (full ? 16 : 8); i++)
5922 {
5923 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5924 aarch64_set_vec_u8 (cpu, vd, i, val << shift);
5925 }
5926}
5927
5928static void
5929do_vec_SSHR_USHR (sim_cpu *cpu)
5930{
5931 /* instr [31] = 0
5932 instr [30] = half(0)/full(1)
5933 instr [29] = signed(0)/unsigned(1)
5ab6d79e 5934 instr [28,23] = 0 1111 0
2e8cf49e
NC
5935 instr [22,16] = size and shift amount
5936 instr [15,10] = 0000 01
5937 instr [9, 5] = Vs
5938 instr [4, 0] = Vd. */
5939
5ab6d79e
NC
5940 int full = INSTR (30, 30);
5941 int sign = ! INSTR (29, 29);
5942 unsigned shift = INSTR (22, 16);
5943 unsigned vs = INSTR (9, 5);
5944 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5945 unsigned i;
5946
5947 NYI_assert (28, 23, 0x1E);
5948 NYI_assert (15, 10, 0x01);
5949
2cdad34c 5950 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5951 if (INSTR (22, 22))
2e8cf49e 5952 {
5ab6d79e 5953 shift = 128 - shift;
2e8cf49e
NC
5954
5955 if (full == 0)
5956 HALT_UNALLOC;
5957
5958 if (sign)
5959 for (i = 0; i < 2; i++)
5960 {
5961 int64_t val = aarch64_get_vec_s64 (cpu, vs, i);
5962 aarch64_set_vec_s64 (cpu, vd, i, val >> shift);
5963 }
5964 else
5965 for (i = 0; i < 2; i++)
5966 {
5967 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5968 aarch64_set_vec_u64 (cpu, vd, i, val >> shift);
5969 }
5970
5971 return;
5972 }
5973
ef0d8ffc 5974 if (INSTR (21, 21))
2e8cf49e 5975 {
5ab6d79e 5976 shift = 64 - shift;
2e8cf49e
NC
5977
5978 if (sign)
5979 for (i = 0; i < (full ? 4 : 2); i++)
5980 {
5981 int32_t val = aarch64_get_vec_s32 (cpu, vs, i);
5982 aarch64_set_vec_s32 (cpu, vd, i, val >> shift);
5983 }
5984 else
5985 for (i = 0; i < (full ? 4 : 2); i++)
5986 {
5987 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5988 aarch64_set_vec_u32 (cpu, vd, i, val >> shift);
5989 }
5990
5991 return;
5992 }
5993
ef0d8ffc 5994 if (INSTR (20, 20))
2e8cf49e 5995 {
5ab6d79e 5996 shift = 32 - shift;
2e8cf49e
NC
5997
5998 if (sign)
5999 for (i = 0; i < (full ? 8 : 4); i++)
6000 {
6001 int16_t val = aarch64_get_vec_s16 (cpu, vs, i);
6002 aarch64_set_vec_s16 (cpu, vd, i, val >> shift);
6003 }
6004 else
6005 for (i = 0; i < (full ? 8 : 4); i++)
6006 {
6007 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
6008 aarch64_set_vec_u16 (cpu, vd, i, val >> shift);
6009 }
6010
6011 return;
6012 }
6013
ef0d8ffc 6014 if (INSTR (19, 19) == 0)
2e8cf49e
NC
6015 HALT_UNALLOC;
6016
5ab6d79e 6017 shift = 16 - shift;
2e8cf49e
NC
6018
6019 if (sign)
6020 for (i = 0; i < (full ? 16 : 8); i++)
6021 {
6022 int8_t val = aarch64_get_vec_s8 (cpu, vs, i);
6023 aarch64_set_vec_s8 (cpu, vd, i, val >> shift);
6024 }
6025 else
6026 for (i = 0; i < (full ? 16 : 8); i++)
6027 {
6028 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
6029 aarch64_set_vec_u8 (cpu, vd, i, val >> shift);
6030 }
6031}
6032
e101a78b
NC
6033static void
6034do_vec_MUL_by_element (sim_cpu *cpu)
6035{
6036 /* instr[31] = 0
6037 instr[30] = half/full
6038 instr[29,24] = 00 1111
6039 instr[23,22] = size
6040 instr[21] = L
6041 instr[20] = M
6042 instr[19,16] = m
6043 instr[15,12] = 1000
6044 instr[11] = H
6045 instr[10] = 0
6046 instr[9,5] = Vn
6047 instr[4,0] = Vd */
6048
ef0d8ffc
NC
6049 unsigned full = INSTR (30, 30);
6050 unsigned L = INSTR (21, 21);
6051 unsigned H = INSTR (11, 11);
6052 unsigned vn = INSTR (9, 5);
6053 unsigned vd = INSTR (4, 0);
6054 unsigned size = INSTR (23, 22);
e101a78b
NC
6055 unsigned index;
6056 unsigned vm;
6057 unsigned e;
6058
6059 NYI_assert (29, 24, 0x0F);
6060 NYI_assert (15, 12, 0x8);
6061 NYI_assert (10, 10, 0);
6062
2cdad34c 6063 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
6064 switch (size)
6065 {
6066 case 1:
6067 {
6068 /* 16 bit products. */
6069 uint16_t product;
6070 uint16_t element1;
6071 uint16_t element2;
6072
ef0d8ffc
NC
6073 index = (H << 2) | (L << 1) | INSTR (20, 20);
6074 vm = INSTR (19, 16);
e101a78b
NC
6075 element2 = aarch64_get_vec_u16 (cpu, vm, index);
6076
6077 for (e = 0; e < (full ? 8 : 4); e ++)
6078 {
6079 element1 = aarch64_get_vec_u16 (cpu, vn, e);
6080 product = element1 * element2;
6081 aarch64_set_vec_u16 (cpu, vd, e, product);
6082 }
6083 }
6084 break;
6085
6086 case 2:
6087 {
6088 /* 32 bit products. */
6089 uint32_t product;
6090 uint32_t element1;
6091 uint32_t element2;
6092
6093 index = (H << 1) | L;
ef0d8ffc 6094 vm = INSTR (20, 16);
e101a78b
NC
6095 element2 = aarch64_get_vec_u32 (cpu, vm, index);
6096
6097 for (e = 0; e < (full ? 4 : 2); e ++)
6098 {
6099 element1 = aarch64_get_vec_u32 (cpu, vn, e);
6100 product = element1 * element2;
6101 aarch64_set_vec_u32 (cpu, vd, e, product);
6102 }
6103 }
6104 break;
6105
6106 default:
6107 HALT_UNALLOC;
6108 }
6109}
6110
fd7ed446
NC
6111static void
6112do_FMLA_by_element (sim_cpu *cpu)
6113{
6114 /* instr[31] = 0
6115 instr[30] = half/full
6116 instr[29,23] = 00 1111 1
6117 instr[22] = size
6118 instr[21] = L
6119 instr[20,16] = m
6120 instr[15,12] = 0001
6121 instr[11] = H
6122 instr[10] = 0
6123 instr[9,5] = Vn
6124 instr[4,0] = Vd */
6125
6126 unsigned full = INSTR (30, 30);
6127 unsigned size = INSTR (22, 22);
6128 unsigned L = INSTR (21, 21);
6129 unsigned vm = INSTR (20, 16);
6130 unsigned H = INSTR (11, 11);
6131 unsigned vn = INSTR (9, 5);
6132 unsigned vd = INSTR (4, 0);
6133 unsigned e;
6134
6135 NYI_assert (29, 23, 0x1F);
6136 NYI_assert (15, 12, 0x1);
6137 NYI_assert (10, 10, 0);
6138
6139 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
6140 if (size)
6141 {
6142 double element1, element2;
6143
6144 if (! full || L)
6145 HALT_UNALLOC;
6146
6147 element2 = aarch64_get_vec_double (cpu, vm, H);
6148
6149 for (e = 0; e < 2; e++)
6150 {
6151 element1 = aarch64_get_vec_double (cpu, vn, e);
6152 element1 *= element2;
6153 element1 += aarch64_get_vec_double (cpu, vd, e);
6154 aarch64_set_vec_double (cpu, vd, e, element1);
6155 }
6156 }
6157 else
6158 {
6159 float element1;
6160 float element2 = aarch64_get_vec_float (cpu, vm, (H << 1) | L);
6161
6162 for (e = 0; e < (full ? 4 : 2); e++)
6163 {
6164 element1 = aarch64_get_vec_float (cpu, vn, e);
6165 element1 *= element2;
6166 element1 += aarch64_get_vec_float (cpu, vd, e);
6167 aarch64_set_vec_float (cpu, vd, e, element1);
6168 }
6169 }
6170}
6171
2e8cf49e
NC
6172static void
6173do_vec_op2 (sim_cpu *cpu)
6174{
6175 /* instr[31] = 0
6176 instr[30] = half/full
6177 instr[29,24] = 00 1111
6178 instr[23] = ?
6179 instr[22,16] = element size & index
6180 instr[15,10] = sub-opcode
6181 instr[9,5] = Vm
e101a78b 6182 instr[4,0] = Vd */
2e8cf49e
NC
6183
6184 NYI_assert (29, 24, 0x0F);
6185
ef0d8ffc 6186 if (INSTR (23, 23) != 0)
2e8cf49e 6187 {
ef0d8ffc 6188 switch (INSTR (15, 10))
e101a78b 6189 {
fd7ed446
NC
6190 case 0x04:
6191 case 0x06:
6192 do_FMLA_by_element (cpu);
6193 return;
6194
e101a78b 6195 case 0x20:
fd7ed446
NC
6196 case 0x22:
6197 do_vec_MUL_by_element (cpu);
6198 return;
6199
6200 default:
6201 HALT_NYI;
e101a78b
NC
6202 }
6203 }
6204 else
6205 {
ef0d8ffc 6206 switch (INSTR (15, 10))
e101a78b
NC
6207 {
6208 case 0x01: do_vec_SSHR_USHR (cpu); return;
6209 case 0x15: do_vec_SHL (cpu); return;
6210 case 0x20:
6211 case 0x22: do_vec_MUL_by_element (cpu); return;
6212 case 0x29: do_vec_xtl (cpu); return;
6213 default: HALT_NYI;
6214 }
2e8cf49e
NC
6215 }
6216}
6217
6218static void
6219do_vec_neg (sim_cpu *cpu)
6220{
6221 /* instr[31] = 0
6222 instr[30] = full(1)/half(0)
6223 instr[29,24] = 10 1110
6224 instr[23,22] = size: byte(00), half (01), word (10), long (11)
6225 instr[21,10] = 1000 0010 1110
6226 instr[9,5] = Vs
6227 instr[4,0] = Vd */
6228
ef0d8ffc
NC
6229 int full = INSTR (30, 30);
6230 unsigned vs = INSTR (9, 5);
6231 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6232 unsigned i;
6233
6234 NYI_assert (29, 24, 0x2E);
6235 NYI_assert (21, 10, 0x82E);
6236
2cdad34c 6237 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6238 switch (INSTR (23, 22))
2e8cf49e
NC
6239 {
6240 case 0:
6241 for (i = 0; i < (full ? 16 : 8); i++)
6242 aarch64_set_vec_s8 (cpu, vd, i, - aarch64_get_vec_s8 (cpu, vs, i));
6243 return;
6244
6245 case 1:
6246 for (i = 0; i < (full ? 8 : 4); i++)
6247 aarch64_set_vec_s16 (cpu, vd, i, - aarch64_get_vec_s16 (cpu, vs, i));
6248 return;
6249
6250 case 2:
6251 for (i = 0; i < (full ? 4 : 2); i++)
6252 aarch64_set_vec_s32 (cpu, vd, i, - aarch64_get_vec_s32 (cpu, vs, i));
6253 return;
6254
6255 case 3:
6256 if (! full)
6257 HALT_NYI;
6258 for (i = 0; i < 2; i++)
6259 aarch64_set_vec_s64 (cpu, vd, i, - aarch64_get_vec_s64 (cpu, vs, i));
6260 return;
2e8cf49e
NC
6261 }
6262}
6263
6264static void
6265do_vec_sqrt (sim_cpu *cpu)
6266{
6267 /* instr[31] = 0
6268 instr[30] = full(1)/half(0)
6269 instr[29,23] = 101 1101
6270 instr[22] = single(0)/double(1)
6271 instr[21,10] = 1000 0111 1110
6272 instr[9,5] = Vs
6273 instr[4,0] = Vd. */
6274
ef0d8ffc
NC
6275 int full = INSTR (30, 30);
6276 unsigned vs = INSTR (9, 5);
6277 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6278 unsigned i;
6279
6280 NYI_assert (29, 23, 0x5B);
6281 NYI_assert (21, 10, 0x87E);
6282
2cdad34c 6283 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6284 if (INSTR (22, 22) == 0)
2e8cf49e
NC
6285 for (i = 0; i < (full ? 4 : 2); i++)
6286 aarch64_set_vec_float (cpu, vd, i,
6287 sqrtf (aarch64_get_vec_float (cpu, vs, i)));
6288 else
6289 for (i = 0; i < 2; i++)
6290 aarch64_set_vec_double (cpu, vd, i,
6291 sqrt (aarch64_get_vec_double (cpu, vs, i)));
6292}
6293
6294static void
6295do_vec_mls_indexed (sim_cpu *cpu)
6296{
6297 /* instr[31] = 0
6298 instr[30] = half(0)/full(1)
6299 instr[29,24] = 10 1111
6300 instr[23,22] = 16-bit(01)/32-bit(10)
6301 instr[21,20+11] = index (if 16-bit)
6302 instr[21+11] = index (if 32-bit)
6303 instr[20,16] = Vm
6304 instr[15,12] = 0100
6305 instr[11] = part of index
6306 instr[10] = 0
6307 instr[9,5] = Vs
6308 instr[4,0] = Vd. */
6309
ef0d8ffc
NC
6310 int full = INSTR (30, 30);
6311 unsigned vs = INSTR (9, 5);
6312 unsigned vd = INSTR (4, 0);
6313 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
6314 unsigned i;
6315
6316 NYI_assert (15, 12, 4);
6317 NYI_assert (10, 10, 0);
6318
2cdad34c 6319 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6320 switch (INSTR (23, 22))
2e8cf49e
NC
6321 {
6322 case 1:
6323 {
6324 unsigned elem;
6325 uint32_t val;
6326
6327 if (vm > 15)
6328 HALT_NYI;
6329
7517e550 6330 elem = (INSTR (21, 20) << 1) | INSTR (11, 11);
2e8cf49e
NC
6331 val = aarch64_get_vec_u16 (cpu, vm, elem);
6332
6333 for (i = 0; i < (full ? 8 : 4); i++)
6334 aarch64_set_vec_u32 (cpu, vd, i,
6335 aarch64_get_vec_u32 (cpu, vd, i) -
6336 (aarch64_get_vec_u32 (cpu, vs, i) * val));
6337 return;
6338 }
6339
6340 case 2:
6341 {
7517e550 6342 unsigned elem = (INSTR (21, 21) << 1) | INSTR (11, 11);
2e8cf49e
NC
6343 uint64_t val = aarch64_get_vec_u32 (cpu, vm, elem);
6344
6345 for (i = 0; i < (full ? 4 : 2); i++)
6346 aarch64_set_vec_u64 (cpu, vd, i,
6347 aarch64_get_vec_u64 (cpu, vd, i) -
6348 (aarch64_get_vec_u64 (cpu, vs, i) * val));
6349 return;
6350 }
6351
6352 case 0:
6353 case 3:
6354 default:
6355 HALT_NYI;
6356 }
6357}
6358
6359static void
6360do_vec_SUB (sim_cpu *cpu)
6361{
6362 /* instr [31] = 0
6363 instr [30] = half(0)/full(1)
6364 instr [29,24] = 10 1110
6365 instr [23,22] = size: byte(00, half(01), word (10), long (11)
6366 instr [21] = 1
6367 instr [20,16] = Vm
6368 instr [15,10] = 10 0001
6369 instr [9, 5] = Vn
6370 instr [4, 0] = Vd. */
6371
ef0d8ffc
NC
6372 unsigned full = INSTR (30, 30);
6373 unsigned vm = INSTR (20, 16);
6374 unsigned vn = INSTR (9, 5);
6375 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6376 unsigned i;
6377
6378 NYI_assert (29, 24, 0x2E);
6379 NYI_assert (21, 21, 1);
6380 NYI_assert (15, 10, 0x21);
6381
2cdad34c 6382 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6383 switch (INSTR (23, 22))
2e8cf49e
NC
6384 {
6385 case 0:
6386 for (i = 0; i < (full ? 16 : 8); i++)
6387 aarch64_set_vec_s8 (cpu, vd, i,
6388 aarch64_get_vec_s8 (cpu, vn, i)
6389 - aarch64_get_vec_s8 (cpu, vm, i));
6390 return;
6391
6392 case 1:
6393 for (i = 0; i < (full ? 8 : 4); i++)
6394 aarch64_set_vec_s16 (cpu, vd, i,
6395 aarch64_get_vec_s16 (cpu, vn, i)
6396 - aarch64_get_vec_s16 (cpu, vm, i));
6397 return;
6398
6399 case 2:
6400 for (i = 0; i < (full ? 4 : 2); i++)
6401 aarch64_set_vec_s32 (cpu, vd, i,
6402 aarch64_get_vec_s32 (cpu, vn, i)
6403 - aarch64_get_vec_s32 (cpu, vm, i));
6404 return;
6405
6406 case 3:
6407 if (full == 0)
6408 HALT_UNALLOC;
6409
6410 for (i = 0; i < 2; i++)
6411 aarch64_set_vec_s64 (cpu, vd, i,
6412 aarch64_get_vec_s64 (cpu, vn, i)
6413 - aarch64_get_vec_s64 (cpu, vm, i));
6414 return;
2e8cf49e
NC
6415 }
6416}
6417
6418static void
6419do_vec_MLS (sim_cpu *cpu)
6420{
6421 /* instr [31] = 0
6422 instr [30] = half(0)/full(1)
6423 instr [29,24] = 10 1110
6424 instr [23,22] = size: byte(00, half(01), word (10)
6425 instr [21] = 1
6426 instr [20,16] = Vm
6427 instr [15,10] = 10 0101
6428 instr [9, 5] = Vn
6429 instr [4, 0] = Vd. */
6430
ef0d8ffc
NC
6431 unsigned full = INSTR (30, 30);
6432 unsigned vm = INSTR (20, 16);
6433 unsigned vn = INSTR (9, 5);
6434 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6435 unsigned i;
6436
6437 NYI_assert (29, 24, 0x2E);
6438 NYI_assert (21, 21, 1);
6439 NYI_assert (15, 10, 0x25);
6440
2cdad34c 6441 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6442 switch (INSTR (23, 22))
2e8cf49e
NC
6443 {
6444 case 0:
6445 for (i = 0; i < (full ? 16 : 8); i++)
6446 aarch64_set_vec_u8 (cpu, vd, i,
c0386d4d
JW
6447 aarch64_get_vec_u8 (cpu, vd, i)
6448 - (aarch64_get_vec_u8 (cpu, vn, i)
6449 * aarch64_get_vec_u8 (cpu, vm, i)));
2e8cf49e
NC
6450 return;
6451
6452 case 1:
6453 for (i = 0; i < (full ? 8 : 4); i++)
6454 aarch64_set_vec_u16 (cpu, vd, i,
c0386d4d
JW
6455 aarch64_get_vec_u16 (cpu, vd, i)
6456 - (aarch64_get_vec_u16 (cpu, vn, i)
6457 * aarch64_get_vec_u16 (cpu, vm, i)));
2e8cf49e
NC
6458 return;
6459
6460 case 2:
6461 for (i = 0; i < (full ? 4 : 2); i++)
6462 aarch64_set_vec_u32 (cpu, vd, i,
c0386d4d
JW
6463 aarch64_get_vec_u32 (cpu, vd, i)
6464 - (aarch64_get_vec_u32 (cpu, vn, i)
6465 * aarch64_get_vec_u32 (cpu, vm, i)));
2e8cf49e
NC
6466 return;
6467
6468 default:
6469 HALT_UNALLOC;
6470 }
6471}
6472
6473static void
6474do_vec_FDIV (sim_cpu *cpu)
6475{
6476 /* instr [31] = 0
6477 instr [30] = half(0)/full(1)
6478 instr [29,23] = 10 1110 0
6479 instr [22] = float()/double(1)
6480 instr [21] = 1
6481 instr [20,16] = Vm
6482 instr [15,10] = 1111 11
6483 instr [9, 5] = Vn
6484 instr [4, 0] = Vd. */
6485
ef0d8ffc
NC
6486 unsigned full = INSTR (30, 30);
6487 unsigned vm = INSTR (20, 16);
6488 unsigned vn = INSTR (9, 5);
6489 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6490 unsigned i;
6491
6492 NYI_assert (29, 23, 0x5C);
6493 NYI_assert (21, 21, 1);
6494 NYI_assert (15, 10, 0x3F);
6495
2cdad34c 6496 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6497 if (INSTR (22, 22))
2e8cf49e
NC
6498 {
6499 if (! full)
6500 HALT_UNALLOC;
6501
6502 for (i = 0; i < 2; i++)
6503 aarch64_set_vec_double (cpu, vd, i,
6504 aarch64_get_vec_double (cpu, vn, i)
6505 / aarch64_get_vec_double (cpu, vm, i));
6506 }
6507 else
6508 for (i = 0; i < (full ? 4 : 2); i++)
6509 aarch64_set_vec_float (cpu, vd, i,
6510 aarch64_get_vec_float (cpu, vn, i)
6511 / aarch64_get_vec_float (cpu, vm, i));
6512}
6513
6514static void
6515do_vec_FMUL (sim_cpu *cpu)
6516{
6517 /* instr [31] = 0
6518 instr [30] = half(0)/full(1)
6519 instr [29,23] = 10 1110 0
6520 instr [22] = float(0)/double(1)
6521 instr [21] = 1
6522 instr [20,16] = Vm
6523 instr [15,10] = 1101 11
6524 instr [9, 5] = Vn
6525 instr [4, 0] = Vd. */
6526
ef0d8ffc
NC
6527 unsigned full = INSTR (30, 30);
6528 unsigned vm = INSTR (20, 16);
6529 unsigned vn = INSTR (9, 5);
6530 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6531 unsigned i;
6532
6533 NYI_assert (29, 23, 0x5C);
6534 NYI_assert (21, 21, 1);
6535 NYI_assert (15, 10, 0x37);
6536
2cdad34c 6537 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6538 if (INSTR (22, 22))
2e8cf49e
NC
6539 {
6540 if (! full)
6541 HALT_UNALLOC;
6542
6543 for (i = 0; i < 2; i++)
6544 aarch64_set_vec_double (cpu, vd, i,
6545 aarch64_get_vec_double (cpu, vn, i)
6546 * aarch64_get_vec_double (cpu, vm, i));
6547 }
6548 else
6549 for (i = 0; i < (full ? 4 : 2); i++)
6550 aarch64_set_vec_float (cpu, vd, i,
6551 aarch64_get_vec_float (cpu, vn, i)
6552 * aarch64_get_vec_float (cpu, vm, i));
6553}
6554
6555static void
6556do_vec_FADDP (sim_cpu *cpu)
6557{
6558 /* instr [31] = 0
6559 instr [30] = half(0)/full(1)
6560 instr [29,23] = 10 1110 0
6561 instr [22] = float(0)/double(1)
6562 instr [21] = 1
6563 instr [20,16] = Vm
6564 instr [15,10] = 1101 01
6565 instr [9, 5] = Vn
6566 instr [4, 0] = Vd. */
6567
ef0d8ffc
NC
6568 unsigned full = INSTR (30, 30);
6569 unsigned vm = INSTR (20, 16);
6570 unsigned vn = INSTR (9, 5);
6571 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6572
6573 NYI_assert (29, 23, 0x5C);
6574 NYI_assert (21, 21, 1);
6575 NYI_assert (15, 10, 0x35);
6576
2cdad34c 6577 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6578 if (INSTR (22, 22))
2e8cf49e 6579 {
57aa1742
NC
6580 /* Extract values before adding them incase vd == vn/vm. */
6581 double tmp1 = aarch64_get_vec_double (cpu, vn, 0);
6582 double tmp2 = aarch64_get_vec_double (cpu, vn, 1);
6583 double tmp3 = aarch64_get_vec_double (cpu, vm, 0);
6584 double tmp4 = aarch64_get_vec_double (cpu, vm, 1);
6585
2e8cf49e
NC
6586 if (! full)
6587 HALT_UNALLOC;
6588
57aa1742
NC
6589 aarch64_set_vec_double (cpu, vd, 0, tmp1 + tmp2);
6590 aarch64_set_vec_double (cpu, vd, 1, tmp3 + tmp4);
2e8cf49e
NC
6591 }
6592 else
6593 {
57aa1742
NC
6594 /* Extract values before adding them incase vd == vn/vm. */
6595 float tmp1 = aarch64_get_vec_float (cpu, vn, 0);
6596 float tmp2 = aarch64_get_vec_float (cpu, vn, 1);
6597 float tmp5 = aarch64_get_vec_float (cpu, vm, 0);
6598 float tmp6 = aarch64_get_vec_float (cpu, vm, 1);
6599
2e8cf49e 6600 if (full)
57aa1742
NC
6601 {
6602 float tmp3 = aarch64_get_vec_float (cpu, vn, 2);
6603 float tmp4 = aarch64_get_vec_float (cpu, vn, 3);
6604 float tmp7 = aarch64_get_vec_float (cpu, vm, 2);
6605 float tmp8 = aarch64_get_vec_float (cpu, vm, 3);
6606
6607 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6608 aarch64_set_vec_float (cpu, vd, 1, tmp3 + tmp4);
6609 aarch64_set_vec_float (cpu, vd, 2, tmp5 + tmp6);
6610 aarch64_set_vec_float (cpu, vd, 3, tmp7 + tmp8);
6611 }
6612 else
6613 {
6614 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6615 aarch64_set_vec_float (cpu, vd, 1, tmp5 + tmp6);
6616 }
2e8cf49e
NC
6617 }
6618}
6619
6620static void
6621do_vec_FSQRT (sim_cpu *cpu)
6622{
6623 /* instr[31] = 0
6624 instr[30] = half(0)/full(1)
6625 instr[29,23] = 10 1110 1
6626 instr[22] = single(0)/double(1)
6627 instr[21,10] = 10 0001 1111 10
6628 instr[9,5] = Vsrc
6629 instr[4,0] = Vdest. */
6630
ef0d8ffc
NC
6631 unsigned vn = INSTR (9, 5);
6632 unsigned vd = INSTR (4, 0);
6633 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6634 int i;
6635
6636 NYI_assert (29, 23, 0x5D);
6637 NYI_assert (21, 10, 0x87E);
6638
2cdad34c 6639 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6640 if (INSTR (22, 22))
2e8cf49e
NC
6641 {
6642 if (! full)
6643 HALT_UNALLOC;
6644
6645 for (i = 0; i < 2; i++)
6646 aarch64_set_vec_double (cpu, vd, i,
6647 sqrt (aarch64_get_vec_double (cpu, vn, i)));
6648 }
6649 else
6650 {
6651 for (i = 0; i < (full ? 4 : 2); i++)
6652 aarch64_set_vec_float (cpu, vd, i,
6653 sqrtf (aarch64_get_vec_float (cpu, vn, i)));
6654 }
6655}
6656
6657static void
6658do_vec_FNEG (sim_cpu *cpu)
6659{
6660 /* instr[31] = 0
6661 instr[30] = half (0)/full (1)
6662 instr[29,23] = 10 1110 1
6663 instr[22] = single (0)/double (1)
6664 instr[21,10] = 10 0000 1111 10
6665 instr[9,5] = Vsrc
6666 instr[4,0] = Vdest. */
6667
ef0d8ffc
NC
6668 unsigned vn = INSTR (9, 5);
6669 unsigned vd = INSTR (4, 0);
6670 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6671 int i;
6672
6673 NYI_assert (29, 23, 0x5D);
6674 NYI_assert (21, 10, 0x83E);
6675
2cdad34c 6676 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6677 if (INSTR (22, 22))
2e8cf49e
NC
6678 {
6679 if (! full)
6680 HALT_UNALLOC;
6681
6682 for (i = 0; i < 2; i++)
6683 aarch64_set_vec_double (cpu, vd, i,
6684 - aarch64_get_vec_double (cpu, vn, i));
6685 }
6686 else
6687 {
6688 for (i = 0; i < (full ? 4 : 2); i++)
6689 aarch64_set_vec_float (cpu, vd, i,
6690 - aarch64_get_vec_float (cpu, vn, i));
6691 }
6692}
6693
6694static void
6695do_vec_NOT (sim_cpu *cpu)
6696{
6697 /* instr[31] = 0
6698 instr[30] = half (0)/full (1)
5ab6d79e 6699 instr[29,10] = 10 1110 0010 0000 0101 10
2e8cf49e
NC
6700 instr[9,5] = Vn
6701 instr[4.0] = Vd. */
6702
ef0d8ffc
NC
6703 unsigned vn = INSTR (9, 5);
6704 unsigned vd = INSTR (4, 0);
2e8cf49e 6705 unsigned i;
ef0d8ffc 6706 int full = INSTR (30, 30);
2e8cf49e
NC
6707
6708 NYI_assert (29, 10, 0xB8816);
6709
2cdad34c 6710 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
6711 for (i = 0; i < (full ? 16 : 8); i++)
6712 aarch64_set_vec_u8 (cpu, vd, i, ~ aarch64_get_vec_u8 (cpu, vn, i));
6713}
6714
5ab6d79e
NC
6715static unsigned int
6716clz (uint64_t val, unsigned size)
6717{
6718 uint64_t mask = 1;
6719 int count;
6720
6721 mask <<= (size - 1);
6722 count = 0;
6723 do
6724 {
6725 if (val & mask)
6726 break;
6727 mask >>= 1;
6728 count ++;
6729 }
6730 while (mask);
6731
6732 return count;
6733}
6734
6735static void
6736do_vec_CLZ (sim_cpu *cpu)
6737{
6738 /* instr[31] = 0
6739 instr[30] = half (0)/full (1)
6740 instr[29,24] = 10 1110
6741 instr[23,22] = size
6742 instr[21,10] = 10 0000 0100 10
6743 instr[9,5] = Vn
6744 instr[4.0] = Vd. */
6745
6746 unsigned vn = INSTR (9, 5);
6747 unsigned vd = INSTR (4, 0);
6748 unsigned i;
6749 int full = INSTR (30,30);
6750
6751 NYI_assert (29, 24, 0x2E);
6752 NYI_assert (21, 10, 0x812);
6753
2cdad34c 6754 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
6755 switch (INSTR (23, 22))
6756 {
6757 case 0:
6758 for (i = 0; i < (full ? 16 : 8); i++)
6759 aarch64_set_vec_u8 (cpu, vd, i, clz (aarch64_get_vec_u8 (cpu, vn, i), 8));
6760 break;
6761 case 1:
6762 for (i = 0; i < (full ? 8 : 4); i++)
6763 aarch64_set_vec_u16 (cpu, vd, i, clz (aarch64_get_vec_u16 (cpu, vn, i), 16));
6764 break;
6765 case 2:
6766 for (i = 0; i < (full ? 4 : 2); i++)
6767 aarch64_set_vec_u32 (cpu, vd, i, clz (aarch64_get_vec_u32 (cpu, vn, i), 32));
6768 break;
6769 case 3:
6770 if (! full)
6771 HALT_UNALLOC;
6772 aarch64_set_vec_u64 (cpu, vd, 0, clz (aarch64_get_vec_u64 (cpu, vn, 0), 64));
6773 aarch64_set_vec_u64 (cpu, vd, 1, clz (aarch64_get_vec_u64 (cpu, vn, 1), 64));
6774 break;
6775 }
6776}
6777
2e8cf49e
NC
6778static void
6779do_vec_MOV_element (sim_cpu *cpu)
6780{
6781 /* instr[31,21] = 0110 1110 000
6782 instr[20,16] = size & dest index
6783 instr[15] = 0
6784 instr[14,11] = source index
6785 instr[10] = 1
6786 instr[9,5] = Vs
6787 instr[4.0] = Vd. */
6788
ef0d8ffc
NC
6789 unsigned vs = INSTR (9, 5);
6790 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6791 unsigned src_index;
6792 unsigned dst_index;
6793
6794 NYI_assert (31, 21, 0x370);
6795 NYI_assert (15, 15, 0);
6796 NYI_assert (10, 10, 1);
6797
2cdad34c 6798 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6799 if (INSTR (16, 16))
2e8cf49e
NC
6800 {
6801 /* Move a byte. */
ef0d8ffc
NC
6802 src_index = INSTR (14, 11);
6803 dst_index = INSTR (20, 17);
2e8cf49e
NC
6804 aarch64_set_vec_u8 (cpu, vd, dst_index,
6805 aarch64_get_vec_u8 (cpu, vs, src_index));
6806 }
ef0d8ffc 6807 else if (INSTR (17, 17))
2e8cf49e
NC
6808 {
6809 /* Move 16-bits. */
6810 NYI_assert (11, 11, 0);
ef0d8ffc
NC
6811 src_index = INSTR (14, 12);
6812 dst_index = INSTR (20, 18);
2e8cf49e
NC
6813 aarch64_set_vec_u16 (cpu, vd, dst_index,
6814 aarch64_get_vec_u16 (cpu, vs, src_index));
6815 }
ef0d8ffc 6816 else if (INSTR (18, 18))
2e8cf49e
NC
6817 {
6818 /* Move 32-bits. */
6819 NYI_assert (12, 11, 0);
ef0d8ffc
NC
6820 src_index = INSTR (14, 13);
6821 dst_index = INSTR (20, 19);
2e8cf49e
NC
6822 aarch64_set_vec_u32 (cpu, vd, dst_index,
6823 aarch64_get_vec_u32 (cpu, vs, src_index));
6824 }
6825 else
6826 {
6827 NYI_assert (19, 19, 1);
6828 NYI_assert (13, 11, 0);
ef0d8ffc
NC
6829 src_index = INSTR (14, 14);
6830 dst_index = INSTR (20, 20);
2e8cf49e
NC
6831 aarch64_set_vec_u64 (cpu, vd, dst_index,
6832 aarch64_get_vec_u64 (cpu, vs, src_index));
6833 }
6834}
6835
67f101ee
NC
6836static void
6837do_vec_REV32 (sim_cpu *cpu)
6838{
6839 /* instr[31] = 0
6840 instr[30] = full/half
6841 instr[29,24] = 10 1110
6842 instr[23,22] = size
6843 instr[21,10] = 10 0000 0000 10
6844 instr[9,5] = Rn
6845 instr[4,0] = Rd. */
6846
6847 unsigned rn = INSTR (9, 5);
6848 unsigned rd = INSTR (4, 0);
6849 unsigned size = INSTR (23, 22);
6850 unsigned full = INSTR (30, 30);
6851 unsigned i;
6852 FRegister val;
6853
6854 NYI_assert (29, 24, 0x2E);
6855 NYI_assert (21, 10, 0x802);
6856
2cdad34c 6857 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
6858 switch (size)
6859 {
6860 case 0:
6861 for (i = 0; i < (full ? 16 : 8); i++)
6862 val.b[i ^ 0x3] = aarch64_get_vec_u8 (cpu, rn, i);
6863 break;
6864
6865 case 1:
6866 for (i = 0; i < (full ? 8 : 4); i++)
6867 val.h[i ^ 0x1] = aarch64_get_vec_u16 (cpu, rn, i);
6868 break;
6869
6870 default:
6871 HALT_UNALLOC;
6872 }
6873
6874 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
6875 if (full)
6876 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
6877}
6878
6879static void
6880do_vec_EXT (sim_cpu *cpu)
6881{
6882 /* instr[31] = 0
6883 instr[30] = full/half
6884 instr[29,21] = 10 1110 000
6885 instr[20,16] = Vm
6886 instr[15] = 0
6887 instr[14,11] = source index
6888 instr[10] = 0
6889 instr[9,5] = Vn
6890 instr[4.0] = Vd. */
6891
6892 unsigned vm = INSTR (20, 16);
6893 unsigned vn = INSTR (9, 5);
6894 unsigned vd = INSTR (4, 0);
6895 unsigned src_index = INSTR (14, 11);
6896 unsigned full = INSTR (30, 30);
6897 unsigned i;
6898 unsigned j;
6899 FRegister val;
6900
6901 NYI_assert (31, 21, 0x370);
6902 NYI_assert (15, 15, 0);
6903 NYI_assert (10, 10, 0);
6904
6905 if (!full && (src_index & 0x8))
6906 HALT_UNALLOC;
6907
6908 j = 0;
6909
2cdad34c 6910 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
6911 for (i = src_index; i < (full ? 16 : 8); i++)
6912 val.b[j ++] = aarch64_get_vec_u8 (cpu, vn, i);
6913 for (i = 0; i < src_index; i++)
6914 val.b[j ++] = aarch64_get_vec_u8 (cpu, vm, i);
6915
6916 aarch64_set_vec_u64 (cpu, vd, 0, val.v[0]);
6917 if (full)
6918 aarch64_set_vec_u64 (cpu, vd, 1, val.v[1]);
6919}
6920
2e8cf49e
NC
6921static void
6922dexAdvSIMD0 (sim_cpu *cpu)
6923{
6924 /* instr [28,25] = 0 111. */
ef0d8ffc
NC
6925 if ( INSTR (15, 10) == 0x07
6926 && (INSTR (9, 5) ==
6927 INSTR (20, 16)))
2e8cf49e 6928 {
ef0d8ffc
NC
6929 if (INSTR (31, 21) == 0x075
6930 || INSTR (31, 21) == 0x275)
2e8cf49e
NC
6931 {
6932 do_vec_MOV_whole_vector (cpu);
6933 return;
6934 }
6935 }
6936
ef0d8ffc 6937 if (INSTR (29, 19) == 0x1E0)
2e8cf49e
NC
6938 {
6939 do_vec_MOV_immediate (cpu);
6940 return;
6941 }
6942
ef0d8ffc 6943 if (INSTR (29, 19) == 0x5E0)
2e8cf49e
NC
6944 {
6945 do_vec_MVNI (cpu);
6946 return;
6947 }
6948
ef0d8ffc
NC
6949 if (INSTR (29, 19) == 0x1C0
6950 || INSTR (29, 19) == 0x1C1)
2e8cf49e 6951 {
ef0d8ffc 6952 if (INSTR (15, 10) == 0x03)
2e8cf49e
NC
6953 {
6954 do_vec_DUP_scalar_into_vector (cpu);
6955 return;
6956 }
6957 }
6958
ef0d8ffc 6959 switch (INSTR (29, 24))
2e8cf49e
NC
6960 {
6961 case 0x0E: do_vec_op1 (cpu); return;
6962 case 0x0F: do_vec_op2 (cpu); return;
6963
2e8cf49e 6964 case 0x2E:
ef0d8ffc 6965 if (INSTR (21, 21) == 1)
2e8cf49e 6966 {
ef0d8ffc 6967 switch (INSTR (15, 10))
2e8cf49e 6968 {
67f101ee
NC
6969 case 0x02:
6970 do_vec_REV32 (cpu);
6971 return;
6972
2e8cf49e 6973 case 0x07:
ef0d8ffc 6974 switch (INSTR (23, 22))
2e8cf49e
NC
6975 {
6976 case 0: do_vec_EOR (cpu); return;
6977 case 1: do_vec_BSL (cpu); return;
6978 case 2:
6979 case 3: do_vec_bit (cpu); return;
6980 }
6981 break;
6982
6983 case 0x08: do_vec_sub_long (cpu); return;
6984 case 0x11: do_vec_USHL (cpu); return;
5ab6d79e 6985 case 0x12: do_vec_CLZ (cpu); return;
2e8cf49e
NC
6986 case 0x16: do_vec_NOT (cpu); return;
6987 case 0x19: do_vec_max (cpu); return;
6988 case 0x1B: do_vec_min (cpu); return;
6989 case 0x21: do_vec_SUB (cpu); return;
6990 case 0x25: do_vec_MLS (cpu); return;
6991 case 0x31: do_vec_FminmaxNMP (cpu); return;
6992 case 0x35: do_vec_FADDP (cpu); return;
6993 case 0x37: do_vec_FMUL (cpu); return;
6994 case 0x3F: do_vec_FDIV (cpu); return;
6995
6996 case 0x3E:
ef0d8ffc 6997 switch (INSTR (20, 16))
2e8cf49e
NC
6998 {
6999 case 0x00: do_vec_FNEG (cpu); return;
7000 case 0x01: do_vec_FSQRT (cpu); return;
7001 default: HALT_NYI;
7002 }
7003
7004 case 0x0D:
7005 case 0x0F:
7006 case 0x22:
7007 case 0x23:
7008 case 0x26:
7009 case 0x2A:
7010 case 0x32:
7011 case 0x36:
7012 case 0x39:
7013 case 0x3A:
7014 do_vec_compare (cpu); return;
7015
5ab6d79e
NC
7016 default:
7017 break;
2e8cf49e
NC
7018 }
7019 }
7020
ef0d8ffc 7021 if (INSTR (31, 21) == 0x370)
2e8cf49e 7022 {
67f101ee
NC
7023 if (INSTR (10, 10))
7024 do_vec_MOV_element (cpu);
7025 else
7026 do_vec_EXT (cpu);
2e8cf49e
NC
7027 return;
7028 }
7029
ef0d8ffc 7030 switch (INSTR (21, 10))
2e8cf49e
NC
7031 {
7032 case 0x82E: do_vec_neg (cpu); return;
7033 case 0x87E: do_vec_sqrt (cpu); return;
7034 default:
ef0d8ffc 7035 if (INSTR (15, 10) == 0x30)
2e8cf49e
NC
7036 {
7037 do_vec_mull (cpu);
7038 return;
7039 }
7040 break;
7041 }
7042 break;
7043
67f101ee
NC
7044 case 0x2f:
7045 switch (INSTR (15, 10))
7046 {
7047 case 0x01: do_vec_SSHR_USHR (cpu); return;
7048 case 0x10:
7049 case 0x12: do_vec_mls_indexed (cpu); return;
7050 case 0x29: do_vec_xtl (cpu); return;
7051 default:
7052 HALT_NYI;
7053 }
7054
2e8cf49e
NC
7055 default:
7056 break;
7057 }
7058
7059 HALT_NYI;
7060}
7061
7062/* 3 sources. */
7063
7064/* Float multiply add. */
7065static void
7066fmadds (sim_cpu *cpu)
7067{
ef0d8ffc
NC
7068 unsigned sa = INSTR (14, 10);
7069 unsigned sm = INSTR (20, 16);
7070 unsigned sn = INSTR ( 9, 5);
7071 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7072
2cdad34c 7073 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7074 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
7075 + aarch64_get_FP_float (cpu, sn)
7076 * aarch64_get_FP_float (cpu, sm));
7077}
7078
7079/* Double multiply add. */
7080static void
7081fmaddd (sim_cpu *cpu)
7082{
ef0d8ffc
NC
7083 unsigned sa = INSTR (14, 10);
7084 unsigned sm = INSTR (20, 16);
7085 unsigned sn = INSTR ( 9, 5);
7086 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7087
2cdad34c 7088 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7089 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
7090 + aarch64_get_FP_double (cpu, sn)
7091 * aarch64_get_FP_double (cpu, sm));
7092}
7093
7094/* Float multiply subtract. */
7095static void
7096fmsubs (sim_cpu *cpu)
7097{
ef0d8ffc
NC
7098 unsigned sa = INSTR (14, 10);
7099 unsigned sm = INSTR (20, 16);
7100 unsigned sn = INSTR ( 9, 5);
7101 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7102
2cdad34c 7103 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7104 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
7105 - aarch64_get_FP_float (cpu, sn)
7106 * aarch64_get_FP_float (cpu, sm));
7107}
7108
7109/* Double multiply subtract. */
7110static void
7111fmsubd (sim_cpu *cpu)
7112{
ef0d8ffc
NC
7113 unsigned sa = INSTR (14, 10);
7114 unsigned sm = INSTR (20, 16);
7115 unsigned sn = INSTR ( 9, 5);
7116 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7117
2cdad34c 7118 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7119 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
7120 - aarch64_get_FP_double (cpu, sn)
7121 * aarch64_get_FP_double (cpu, sm));
7122}
7123
7124/* Float negative multiply add. */
7125static void
7126fnmadds (sim_cpu *cpu)
7127{
ef0d8ffc
NC
7128 unsigned sa = INSTR (14, 10);
7129 unsigned sm = INSTR (20, 16);
7130 unsigned sn = INSTR ( 9, 5);
7131 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7132
2cdad34c 7133 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7134 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
7135 + (- aarch64_get_FP_float (cpu, sn))
7136 * aarch64_get_FP_float (cpu, sm));
7137}
7138
7139/* Double negative multiply add. */
7140static void
7141fnmaddd (sim_cpu *cpu)
7142{
ef0d8ffc
NC
7143 unsigned sa = INSTR (14, 10);
7144 unsigned sm = INSTR (20, 16);
7145 unsigned sn = INSTR ( 9, 5);
7146 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7147
2cdad34c 7148 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7149 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
7150 + (- aarch64_get_FP_double (cpu, sn))
7151 * aarch64_get_FP_double (cpu, sm));
7152}
7153
7154/* Float negative multiply subtract. */
7155static void
7156fnmsubs (sim_cpu *cpu)
7157{
ef0d8ffc
NC
7158 unsigned sa = INSTR (14, 10);
7159 unsigned sm = INSTR (20, 16);
7160 unsigned sn = INSTR ( 9, 5);
7161 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7162
2cdad34c 7163 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7164 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
7165 + aarch64_get_FP_float (cpu, sn)
7166 * aarch64_get_FP_float (cpu, sm));
7167}
7168
7169/* Double negative multiply subtract. */
7170static void
7171fnmsubd (sim_cpu *cpu)
7172{
ef0d8ffc
NC
7173 unsigned sa = INSTR (14, 10);
7174 unsigned sm = INSTR (20, 16);
7175 unsigned sn = INSTR ( 9, 5);
7176 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7177
2cdad34c 7178 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7179 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
7180 + aarch64_get_FP_double (cpu, sn)
7181 * aarch64_get_FP_double (cpu, sm));
7182}
7183
7184static void
7185dexSimpleFPDataProc3Source (sim_cpu *cpu)
7186{
7187 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7188 instr[30] = 0
7189 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7190 instr[28,25] = 1111
7191 instr[24] = 1
7192 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7193 instr[21] ==> o1 : 0 ==> unnegated, 1 ==> negated
7194 instr[15] ==> o2 : 0 ==> ADD, 1 ==> SUB */
7195
7517e550 7196 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
2e8cf49e 7197 /* dispatch on combined type:o1:o2. */
7517e550 7198 uint32_t dispatch = (INSTR (23, 21) << 1) | INSTR (15, 15);
2e8cf49e
NC
7199
7200 if (M_S != 0)
7201 HALT_UNALLOC;
7202
7203 switch (dispatch)
7204 {
7205 case 0: fmadds (cpu); return;
7206 case 1: fmsubs (cpu); return;
7207 case 2: fnmadds (cpu); return;
7208 case 3: fnmsubs (cpu); return;
7209 case 4: fmaddd (cpu); return;
7210 case 5: fmsubd (cpu); return;
7211 case 6: fnmaddd (cpu); return;
7212 case 7: fnmsubd (cpu); return;
7213 default:
7214 /* type > 1 is currently unallocated. */
7215 HALT_UNALLOC;
7216 }
7217}
7218
7219static void
7220dexSimpleFPFixedConvert (sim_cpu *cpu)
7221{
7222 HALT_NYI;
7223}
7224
7225static void
7226dexSimpleFPCondCompare (sim_cpu *cpu)
7227{
5ab6d79e
NC
7228 /* instr [31,23] = 0001 1110 0
7229 instr [22] = type
7230 instr [21] = 1
7231 instr [20,16] = Rm
7232 instr [15,12] = condition
7233 instr [11,10] = 01
7234 instr [9,5] = Rn
7235 instr [4] = 0
7236 instr [3,0] = nzcv */
7237
7238 unsigned rm = INSTR (20, 16);
7239 unsigned rn = INSTR (9, 5);
7240
7241 NYI_assert (31, 23, 0x3C);
7242 NYI_assert (11, 10, 0x1);
7243 NYI_assert (4, 4, 0);
7244
2cdad34c 7245 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7246 if (! testConditionCode (cpu, INSTR (15, 12)))
7247 {
7248 aarch64_set_CPSR (cpu, INSTR (3, 0));
7249 return;
7250 }
7251
7252 if (INSTR (22, 22))
7253 {
7254 /* Double precision. */
7255 double val1 = aarch64_get_vec_double (cpu, rn, 0);
7256 double val2 = aarch64_get_vec_double (cpu, rm, 0);
7257
7258 /* FIXME: Check for NaNs. */
7259 if (val1 == val2)
7260 aarch64_set_CPSR (cpu, (Z | C));
7261 else if (val1 < val2)
7262 aarch64_set_CPSR (cpu, N);
7263 else /* val1 > val2 */
7264 aarch64_set_CPSR (cpu, C);
7265 }
7266 else
7267 {
7268 /* Single precision. */
7269 float val1 = aarch64_get_vec_float (cpu, rn, 0);
7270 float val2 = aarch64_get_vec_float (cpu, rm, 0);
ef0d8ffc 7271
5ab6d79e
NC
7272 /* FIXME: Check for NaNs. */
7273 if (val1 == val2)
7274 aarch64_set_CPSR (cpu, (Z | C));
7275 else if (val1 < val2)
7276 aarch64_set_CPSR (cpu, N);
7277 else /* val1 > val2 */
7278 aarch64_set_CPSR (cpu, C);
7279 }
2e8cf49e
NC
7280}
7281
7282/* 2 sources. */
7283
7284/* Float add. */
7285static void
7286fadds (sim_cpu *cpu)
7287{
ef0d8ffc
NC
7288 unsigned sm = INSTR (20, 16);
7289 unsigned sn = INSTR ( 9, 5);
7290 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7291
2cdad34c 7292 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7293 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7294 + aarch64_get_FP_float (cpu, sm));
7295}
7296
7297/* Double add. */
7298static void
7299faddd (sim_cpu *cpu)
7300{
ef0d8ffc
NC
7301 unsigned sm = INSTR (20, 16);
7302 unsigned sn = INSTR ( 9, 5);
7303 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7304
2cdad34c 7305 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7306 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7307 + aarch64_get_FP_double (cpu, sm));
7308}
7309
7310/* Float divide. */
7311static void
7312fdivs (sim_cpu *cpu)
7313{
ef0d8ffc
NC
7314 unsigned sm = INSTR (20, 16);
7315 unsigned sn = INSTR ( 9, 5);
7316 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7317
2cdad34c 7318 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7319 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7320 / aarch64_get_FP_float (cpu, sm));
7321}
7322
7323/* Double divide. */
7324static void
7325fdivd (sim_cpu *cpu)
7326{
ef0d8ffc
NC
7327 unsigned sm = INSTR (20, 16);
7328 unsigned sn = INSTR ( 9, 5);
7329 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7330
2cdad34c 7331 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7332 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7333 / aarch64_get_FP_double (cpu, sm));
7334}
7335
7336/* Float multiply. */
7337static void
7338fmuls (sim_cpu *cpu)
7339{
ef0d8ffc
NC
7340 unsigned sm = INSTR (20, 16);
7341 unsigned sn = INSTR ( 9, 5);
7342 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7343
2cdad34c 7344 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7345 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7346 * aarch64_get_FP_float (cpu, sm));
7347}
7348
7349/* Double multiply. */
7350static void
7351fmuld (sim_cpu *cpu)
7352{
ef0d8ffc
NC
7353 unsigned sm = INSTR (20, 16);
7354 unsigned sn = INSTR ( 9, 5);
7355 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7356
2cdad34c 7357 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7358 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7359 * aarch64_get_FP_double (cpu, sm));
7360}
7361
7362/* Float negate and multiply. */
7363static void
7364fnmuls (sim_cpu *cpu)
7365{
ef0d8ffc
NC
7366 unsigned sm = INSTR (20, 16);
7367 unsigned sn = INSTR ( 9, 5);
7368 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7369
2cdad34c 7370 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7371 aarch64_set_FP_float (cpu, sd, - (aarch64_get_FP_float (cpu, sn)
7372 * aarch64_get_FP_float (cpu, sm)));
7373}
7374
7375/* Double negate and multiply. */
7376static void
7377fnmuld (sim_cpu *cpu)
7378{
ef0d8ffc
NC
7379 unsigned sm = INSTR (20, 16);
7380 unsigned sn = INSTR ( 9, 5);
7381 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7382
2cdad34c 7383 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7384 aarch64_set_FP_double (cpu, sd, - (aarch64_get_FP_double (cpu, sn)
7385 * aarch64_get_FP_double (cpu, sm)));
7386}
7387
7388/* Float subtract. */
7389static void
7390fsubs (sim_cpu *cpu)
7391{
ef0d8ffc
NC
7392 unsigned sm = INSTR (20, 16);
7393 unsigned sn = INSTR ( 9, 5);
7394 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7395
2cdad34c 7396 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7397 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7398 - aarch64_get_FP_float (cpu, sm));
7399}
7400
7401/* Double subtract. */
7402static void
7403fsubd (sim_cpu *cpu)
7404{
ef0d8ffc
NC
7405 unsigned sm = INSTR (20, 16);
7406 unsigned sn = INSTR ( 9, 5);
7407 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7408
2cdad34c 7409 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7410 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7411 - aarch64_get_FP_double (cpu, sm));
7412}
7413
7414static void
7415do_FMINNM (sim_cpu *cpu)
7416{
7417 /* instr[31,23] = 0 0011 1100
7418 instr[22] = float(0)/double(1)
7419 instr[21] = 1
7420 instr[20,16] = Sm
7421 instr[15,10] = 01 1110
7422 instr[9,5] = Sn
7423 instr[4,0] = Cpu */
7424
ef0d8ffc
NC
7425 unsigned sm = INSTR (20, 16);
7426 unsigned sn = INSTR ( 9, 5);
7427 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7428
7429 NYI_assert (31, 23, 0x03C);
7430 NYI_assert (15, 10, 0x1E);
7431
2cdad34c 7432 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7433 if (INSTR (22, 22))
2e8cf49e
NC
7434 aarch64_set_FP_double (cpu, sd,
7435 dminnm (aarch64_get_FP_double (cpu, sn),
7436 aarch64_get_FP_double (cpu, sm)));
7437 else
7438 aarch64_set_FP_float (cpu, sd,
7439 fminnm (aarch64_get_FP_float (cpu, sn),
7440 aarch64_get_FP_float (cpu, sm)));
7441}
7442
7443static void
7444do_FMAXNM (sim_cpu *cpu)
7445{
7446 /* instr[31,23] = 0 0011 1100
7447 instr[22] = float(0)/double(1)
7448 instr[21] = 1
7449 instr[20,16] = Sm
7450 instr[15,10] = 01 1010
7451 instr[9,5] = Sn
7452 instr[4,0] = Cpu */
7453
ef0d8ffc
NC
7454 unsigned sm = INSTR (20, 16);
7455 unsigned sn = INSTR ( 9, 5);
7456 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7457
7458 NYI_assert (31, 23, 0x03C);
7459 NYI_assert (15, 10, 0x1A);
7460
2cdad34c 7461 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7462 if (INSTR (22, 22))
2e8cf49e
NC
7463 aarch64_set_FP_double (cpu, sd,
7464 dmaxnm (aarch64_get_FP_double (cpu, sn),
7465 aarch64_get_FP_double (cpu, sm)));
7466 else
7467 aarch64_set_FP_float (cpu, sd,
7468 fmaxnm (aarch64_get_FP_float (cpu, sn),
7469 aarch64_get_FP_float (cpu, sm)));
7470}
7471
7472static void
7473dexSimpleFPDataProc2Source (sim_cpu *cpu)
7474{
7475 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7476 instr[30] = 0
7477 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7478 instr[28,25] = 1111
7479 instr[24] = 0
7480 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7481 instr[21] = 1
7482 instr[20,16] = Vm
7483 instr[15,12] ==> opcode : 0000 ==> FMUL, 0001 ==> FDIV
7484 0010 ==> FADD, 0011 ==> FSUB,
7485 0100 ==> FMAX, 0101 ==> FMIN
7486 0110 ==> FMAXNM, 0111 ==> FMINNM
7487 1000 ==> FNMUL, ow ==> UNALLOC
7488 instr[11,10] = 10
7489 instr[9,5] = Vn
7490 instr[4,0] = Vd */
7491
7517e550 7492 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc 7493 uint32_t type = INSTR (23, 22);
2e8cf49e 7494 /* Dispatch on opcode. */
ef0d8ffc 7495 uint32_t dispatch = INSTR (15, 12);
2e8cf49e
NC
7496
7497 if (type > 1)
7498 HALT_UNALLOC;
7499
7500 if (M_S != 0)
7501 HALT_UNALLOC;
7502
7503 if (type)
7504 switch (dispatch)
7505 {
7506 case 0: fmuld (cpu); return;
7507 case 1: fdivd (cpu); return;
7508 case 2: faddd (cpu); return;
7509 case 3: fsubd (cpu); return;
7510 case 6: do_FMAXNM (cpu); return;
7511 case 7: do_FMINNM (cpu); return;
7512 case 8: fnmuld (cpu); return;
7513
7514 /* Have not yet implemented fmax and fmin. */
7515 case 4:
7516 case 5:
7517 HALT_NYI;
7518
7519 default:
7520 HALT_UNALLOC;
7521 }
7522 else /* type == 0 => floats. */
7523 switch (dispatch)
7524 {
7525 case 0: fmuls (cpu); return;
7526 case 1: fdivs (cpu); return;
7527 case 2: fadds (cpu); return;
7528 case 3: fsubs (cpu); return;
7529 case 6: do_FMAXNM (cpu); return;
7530 case 7: do_FMINNM (cpu); return;
7531 case 8: fnmuls (cpu); return;
7532
7533 case 4:
7534 case 5:
7535 HALT_NYI;
7536
7537 default:
7538 HALT_UNALLOC;
7539 }
7540}
7541
7542static void
7543dexSimpleFPCondSelect (sim_cpu *cpu)
7544{
7545 /* FCSEL
7546 instr[31,23] = 0 0011 1100
7547 instr[22] = 0=>single 1=>double
7548 instr[21] = 1
7549 instr[20,16] = Sm
7550 instr[15,12] = cond
7551 instr[11,10] = 11
7552 instr[9,5] = Sn
7553 instr[4,0] = Cpu */
ef0d8ffc
NC
7554 unsigned sm = INSTR (20, 16);
7555 unsigned sn = INSTR ( 9, 5);
7556 unsigned sd = INSTR ( 4, 0);
7557 uint32_t set = testConditionCode (cpu, INSTR (15, 12));
2e8cf49e
NC
7558
7559 NYI_assert (31, 23, 0x03C);
7560 NYI_assert (11, 10, 0x3);
7561
2cdad34c 7562 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7563 if (INSTR (22, 22))
c0386d4d
JW
7564 aarch64_set_FP_double (cpu, sd, (set ? aarch64_get_FP_double (cpu, sn)
7565 : aarch64_get_FP_double (cpu, sm)));
2e8cf49e 7566 else
c0386d4d
JW
7567 aarch64_set_FP_float (cpu, sd, (set ? aarch64_get_FP_float (cpu, sn)
7568 : aarch64_get_FP_float (cpu, sm)));
2e8cf49e
NC
7569}
7570
7571/* Store 32 bit unscaled signed 9 bit. */
7572static void
7573fsturs (sim_cpu *cpu, int32_t offset)
7574{
ef0d8ffc
NC
7575 unsigned int rn = INSTR (9, 5);
7576 unsigned int st = INSTR (4, 0);
2e8cf49e 7577
2cdad34c 7578 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1
JW
7579 aarch64_set_mem_u32 (cpu, aarch64_get_reg_u64 (cpu, rn, 1) + offset,
7580 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
7581}
7582
7583/* Store 64 bit unscaled signed 9 bit. */
7584static void
7585fsturd (sim_cpu *cpu, int32_t offset)
7586{
ef0d8ffc
NC
7587 unsigned int rn = INSTR (9, 5);
7588 unsigned int st = INSTR (4, 0);
2e8cf49e 7589
2cdad34c 7590 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1
JW
7591 aarch64_set_mem_u64 (cpu, aarch64_get_reg_u64 (cpu, rn, 1) + offset,
7592 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
7593}
7594
7595/* Store 128 bit unscaled signed 9 bit. */
7596static void
7597fsturq (sim_cpu *cpu, int32_t offset)
7598{
ef0d8ffc
NC
7599 unsigned int rn = INSTR (9, 5);
7600 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7601 FRegister a;
7602
2cdad34c 7603 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1 7604 aarch64_get_FP_long_double (cpu, st, & a);
2e8cf49e 7605 aarch64_set_mem_long_double (cpu,
88ddd4a1 7606 aarch64_get_reg_u64 (cpu, rn, 1)
2e8cf49e
NC
7607 + offset, a);
7608}
7609
7610/* TODO FP move register. */
7611
7612/* 32 bit fp to fp move register. */
7613static void
7614ffmovs (sim_cpu *cpu)
7615{
ef0d8ffc
NC
7616 unsigned int rn = INSTR (9, 5);
7617 unsigned int st = INSTR (4, 0);
2e8cf49e 7618
2cdad34c 7619 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7620 aarch64_set_FP_float (cpu, st, aarch64_get_FP_float (cpu, rn));
7621}
7622
7623/* 64 bit fp to fp move register. */
7624static void
7625ffmovd (sim_cpu *cpu)
7626{
ef0d8ffc
NC
7627 unsigned int rn = INSTR (9, 5);
7628 unsigned int st = INSTR (4, 0);
2e8cf49e 7629
2cdad34c 7630 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7631 aarch64_set_FP_double (cpu, st, aarch64_get_FP_double (cpu, rn));
7632}
7633
7634/* 32 bit GReg to Vec move register. */
7635static void
7636fgmovs (sim_cpu *cpu)
7637{
ef0d8ffc
NC
7638 unsigned int rn = INSTR (9, 5);
7639 unsigned int st = INSTR (4, 0);
2e8cf49e 7640
2cdad34c 7641 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7642 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_reg_u32 (cpu, rn, NO_SP));
7643}
7644
7645/* 64 bit g to fp move register. */
7646static void
7647fgmovd (sim_cpu *cpu)
7648{
ef0d8ffc
NC
7649 unsigned int rn = INSTR (9, 5);
7650 unsigned int st = INSTR (4, 0);
2e8cf49e 7651
2cdad34c 7652 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7653 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_reg_u64 (cpu, rn, NO_SP));
7654}
7655
7656/* 32 bit fp to g move register. */
7657static void
7658gfmovs (sim_cpu *cpu)
7659{
ef0d8ffc
NC
7660 unsigned int rn = INSTR (9, 5);
7661 unsigned int st = INSTR (4, 0);
2e8cf49e 7662
2cdad34c 7663 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7664 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u32 (cpu, rn, 0));
7665}
7666
7667/* 64 bit fp to g move register. */
7668static void
7669gfmovd (sim_cpu *cpu)
7670{
ef0d8ffc
NC
7671 unsigned int rn = INSTR (9, 5);
7672 unsigned int st = INSTR (4, 0);
2e8cf49e 7673
2cdad34c 7674 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7675 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u64 (cpu, rn, 0));
7676}
7677
7678/* FP move immediate
7679
7680 These install an immediate 8 bit value in the target register
7681 where the 8 bits comprise 1 sign bit, 4 bits of fraction and a 3
7682 bit exponent. */
7683
7684static void
7685fmovs (sim_cpu *cpu)
7686{
ef0d8ffc
NC
7687 unsigned int sd = INSTR (4, 0);
7688 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7689 float f = fp_immediate_for_encoding_32 (imm);
7690
2cdad34c 7691 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7692 aarch64_set_FP_float (cpu, sd, f);
7693}
7694
7695static void
7696fmovd (sim_cpu *cpu)
7697{
ef0d8ffc
NC
7698 unsigned int sd = INSTR (4, 0);
7699 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7700 double d = fp_immediate_for_encoding_64 (imm);
7701
2cdad34c 7702 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7703 aarch64_set_FP_double (cpu, sd, d);
7704}
7705
7706static void
7707dexSimpleFPImmediate (sim_cpu *cpu)
7708{
7709 /* instr[31,23] == 00111100
7710 instr[22] == type : single(0)/double(1)
7711 instr[21] == 1
7712 instr[20,13] == imm8
7713 instr[12,10] == 100
7714 instr[9,5] == imm5 : 00000 ==> PK, ow ==> UNALLOC
7715 instr[4,0] == Rd */
ef0d8ffc 7716 uint32_t imm5 = INSTR (9, 5);
2e8cf49e
NC
7717
7718 NYI_assert (31, 23, 0x3C);
7719
7720 if (imm5 != 0)
7721 HALT_UNALLOC;
7722
ef0d8ffc 7723 if (INSTR (22, 22))
2e8cf49e
NC
7724 fmovd (cpu);
7725 else
7726 fmovs (cpu);
7727}
7728
7729/* TODO specific decode and execute for group Load Store. */
7730
7731/* TODO FP load/store single register (unscaled offset). */
7732
7733/* TODO load 8 bit unscaled signed 9 bit. */
7734/* TODO load 16 bit unscaled signed 9 bit. */
7735
7736/* Load 32 bit unscaled signed 9 bit. */
7737static void
7738fldurs (sim_cpu *cpu, int32_t offset)
7739{
ef0d8ffc
NC
7740 unsigned int rn = INSTR (9, 5);
7741 unsigned int st = INSTR (4, 0);
2e8cf49e 7742
2cdad34c 7743 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
7744 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
7745 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7746}
7747
7748/* Load 64 bit unscaled signed 9 bit. */
7749static void
7750fldurd (sim_cpu *cpu, int32_t offset)
7751{
ef0d8ffc
NC
7752 unsigned int rn = INSTR (9, 5);
7753 unsigned int st = INSTR (4, 0);
2e8cf49e 7754
2cdad34c 7755 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
7756 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64
7757 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7758}
7759
7760/* Load 128 bit unscaled signed 9 bit. */
7761static void
7762fldurq (sim_cpu *cpu, int32_t offset)
7763{
ef0d8ffc
NC
7764 unsigned int rn = INSTR (9, 5);
7765 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7766 FRegister a;
7767 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
7768
2cdad34c 7769 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7770 aarch64_get_mem_long_double (cpu, addr, & a);
7771 aarch64_set_FP_long_double (cpu, st, a);
7772}
7773
7774/* TODO store 8 bit unscaled signed 9 bit. */
7775/* TODO store 16 bit unscaled signed 9 bit. */
7776
7777
7778/* 1 source. */
7779
7780/* Float absolute value. */
7781static void
7782fabss (sim_cpu *cpu)
7783{
ef0d8ffc
NC
7784 unsigned sn = INSTR (9, 5);
7785 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7786 float value = aarch64_get_FP_float (cpu, sn);
7787
2cdad34c 7788 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7789 aarch64_set_FP_float (cpu, sd, fabsf (value));
7790}
7791
7792/* Double absolute value. */
7793static void
7794fabcpu (sim_cpu *cpu)
7795{
ef0d8ffc
NC
7796 unsigned sn = INSTR (9, 5);
7797 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7798 double value = aarch64_get_FP_double (cpu, sn);
7799
2cdad34c 7800 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7801 aarch64_set_FP_double (cpu, sd, fabs (value));
7802}
7803
7804/* Float negative value. */
7805static void
7806fnegs (sim_cpu *cpu)
7807{
ef0d8ffc
NC
7808 unsigned sn = INSTR (9, 5);
7809 unsigned sd = INSTR (4, 0);
2e8cf49e 7810
2cdad34c 7811 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7812 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sn));
7813}
7814
7815/* Double negative value. */
7816static void
7817fnegd (sim_cpu *cpu)
7818{
ef0d8ffc
NC
7819 unsigned sn = INSTR (9, 5);
7820 unsigned sd = INSTR (4, 0);
2e8cf49e 7821
2cdad34c 7822 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7823 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sn));
7824}
7825
7826/* Float square root. */
7827static void
7828fsqrts (sim_cpu *cpu)
7829{
ef0d8ffc
NC
7830 unsigned sn = INSTR (9, 5);
7831 unsigned sd = INSTR (4, 0);
2e8cf49e 7832
2cdad34c 7833 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
0f118bc7 7834 aarch64_set_FP_float (cpu, sd, sqrtf (aarch64_get_FP_float (cpu, sn)));
2e8cf49e
NC
7835}
7836
7837/* Double square root. */
7838static void
7839fsqrtd (sim_cpu *cpu)
7840{
ef0d8ffc
NC
7841 unsigned sn = INSTR (9, 5);
7842 unsigned sd = INSTR (4, 0);
2e8cf49e 7843
2cdad34c 7844 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7845 aarch64_set_FP_double (cpu, sd,
7846 sqrt (aarch64_get_FP_double (cpu, sn)));
7847}
7848
7849/* Convert double to float. */
7850static void
7851fcvtds (sim_cpu *cpu)
7852{
ef0d8ffc
NC
7853 unsigned sn = INSTR (9, 5);
7854 unsigned sd = INSTR (4, 0);
2e8cf49e 7855
2cdad34c 7856 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7857 aarch64_set_FP_float (cpu, sd, (float) aarch64_get_FP_double (cpu, sn));
7858}
7859
7860/* Convert float to double. */
7861static void
7862fcvtcpu (sim_cpu *cpu)
7863{
ef0d8ffc
NC
7864 unsigned sn = INSTR (9, 5);
7865 unsigned sd = INSTR (4, 0);
2e8cf49e 7866
2cdad34c 7867 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7868 aarch64_set_FP_double (cpu, sd, (double) aarch64_get_FP_float (cpu, sn));
7869}
7870
7871static void
7872do_FRINT (sim_cpu *cpu)
7873{
7874 /* instr[31,23] = 0001 1110 0
7875 instr[22] = single(0)/double(1)
7876 instr[21,18] = 1001
7877 instr[17,15] = rounding mode
7878 instr[14,10] = 10000
7879 instr[9,5] = source
7880 instr[4,0] = dest */
7881
7882 float val;
ef0d8ffc
NC
7883 unsigned rs = INSTR (9, 5);
7884 unsigned rd = INSTR (4, 0);
7885 unsigned int rmode = INSTR (17, 15);
2e8cf49e
NC
7886
7887 NYI_assert (31, 23, 0x03C);
7888 NYI_assert (21, 18, 0x9);
7889 NYI_assert (14, 10, 0x10);
7890
7891 if (rmode == 6 || rmode == 7)
7892 /* FIXME: Add support for rmode == 6 exactness check. */
7893 rmode = uimm (aarch64_get_FPSR (cpu), 23, 22);
7894
2cdad34c 7895 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7896 if (INSTR (22, 22))
2e8cf49e
NC
7897 {
7898 double val = aarch64_get_FP_double (cpu, rs);
7899
7900 switch (rmode)
7901 {
7902 case 0: /* mode N: nearest or even. */
7903 {
7904 double rval = round (val);
7905
7906 if (val - rval == 0.5)
7907 {
7908 if (((rval / 2.0) * 2.0) != rval)
7909 rval += 1.0;
7910 }
7911
7912 aarch64_set_FP_double (cpu, rd, round (val));
7913 return;
7914 }
7915
7916 case 1: /* mode P: towards +inf. */
7917 if (val < 0.0)
7918 aarch64_set_FP_double (cpu, rd, trunc (val));
7919 else
7920 aarch64_set_FP_double (cpu, rd, round (val));
7921 return;
7922
7923 case 2: /* mode M: towards -inf. */
7924 if (val < 0.0)
7925 aarch64_set_FP_double (cpu, rd, round (val));
7926 else
7927 aarch64_set_FP_double (cpu, rd, trunc (val));
7928 return;
7929
7930 case 3: /* mode Z: towards 0. */
7931 aarch64_set_FP_double (cpu, rd, trunc (val));
7932 return;
7933
7934 case 4: /* mode A: away from 0. */
7935 aarch64_set_FP_double (cpu, rd, round (val));
7936 return;
7937
7938 case 6: /* mode X: use FPCR with exactness check. */
7939 case 7: /* mode I: use FPCR mode. */
7940 HALT_NYI;
7941
7942 default:
7943 HALT_UNALLOC;
7944 }
7945 }
7946
7947 val = aarch64_get_FP_float (cpu, rs);
7948
7949 switch (rmode)
7950 {
7951 case 0: /* mode N: nearest or even. */
7952 {
7953 float rval = roundf (val);
7954
7955 if (val - rval == 0.5)
7956 {
7957 if (((rval / 2.0) * 2.0) != rval)
7958 rval += 1.0;
7959 }
7960
7961 aarch64_set_FP_float (cpu, rd, rval);
7962 return;
7963 }
7964
7965 case 1: /* mode P: towards +inf. */
7966 if (val < 0.0)
7967 aarch64_set_FP_float (cpu, rd, truncf (val));
7968 else
7969 aarch64_set_FP_float (cpu, rd, roundf (val));
7970 return;
7971
7972 case 2: /* mode M: towards -inf. */
7973 if (val < 0.0)
7974 aarch64_set_FP_float (cpu, rd, truncf (val));
7975 else
7976 aarch64_set_FP_float (cpu, rd, roundf (val));
7977 return;
7978
7979 case 3: /* mode Z: towards 0. */
7980 aarch64_set_FP_float (cpu, rd, truncf (val));
7981 return;
7982
7983 case 4: /* mode A: away from 0. */
7984 aarch64_set_FP_float (cpu, rd, roundf (val));
7985 return;
7986
7987 case 6: /* mode X: use FPCR with exactness check. */
7988 case 7: /* mode I: use FPCR mode. */
7989 HALT_NYI;
7990
7991 default:
7992 HALT_UNALLOC;
7993 }
7994}
7995
5ab6d79e
NC
7996/* Convert half to float. */
7997static void
ef0d8ffc 7998do_FCVT_half_to_single (sim_cpu *cpu)
5ab6d79e
NC
7999{
8000 unsigned rn = INSTR (9, 5);
8001 unsigned rd = INSTR (4, 0);
8002
8003 NYI_assert (31, 10, 0x7B890);
8004
2cdad34c 8005 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8006 aarch64_set_FP_float (cpu, rd, (float) aarch64_get_FP_half (cpu, rn));
8007}
8008
7517e550 8009/* Convert half to double. */
5ab6d79e 8010static void
ef0d8ffc 8011do_FCVT_half_to_double (sim_cpu *cpu)
5ab6d79e
NC
8012{
8013 unsigned rn = INSTR (9, 5);
8014 unsigned rd = INSTR (4, 0);
8015
8016 NYI_assert (31, 10, 0x7B8B0);
ef0d8ffc 8017
2cdad34c 8018 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8019 aarch64_set_FP_double (cpu, rd, (double) aarch64_get_FP_half (cpu, rn));
8020}
8021
8022static void
ef0d8ffc 8023do_FCVT_single_to_half (sim_cpu *cpu)
5ab6d79e
NC
8024{
8025 unsigned rn = INSTR (9, 5);
8026 unsigned rd = INSTR (4, 0);
8027
8028 NYI_assert (31, 10, 0x788F0);
8029
2cdad34c 8030 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8031 aarch64_set_FP_half (cpu, rd, aarch64_get_FP_float (cpu, rn));
8032}
8033
7517e550 8034/* Convert double to half. */
5ab6d79e 8035static void
ef0d8ffc 8036do_FCVT_double_to_half (sim_cpu *cpu)
5ab6d79e
NC
8037{
8038 unsigned rn = INSTR (9, 5);
8039 unsigned rd = INSTR (4, 0);
8040
8041 NYI_assert (31, 10, 0x798F0);
ef0d8ffc 8042
2cdad34c 8043 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8044 aarch64_set_FP_half (cpu, rd, (float) aarch64_get_FP_double (cpu, rn));
8045}
8046
2e8cf49e
NC
8047static void
8048dexSimpleFPDataProc1Source (sim_cpu *cpu)
8049{
8050 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
8051 instr[30] = 0
8052 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
8053 instr[28,25] = 1111
8054 instr[24] = 0
8055 instr[23,22] ==> type : 00 ==> source is single,
8056 01 ==> source is double
8057 10 ==> UNALLOC
8058 11 ==> UNALLOC or source is half
8059 instr[21] = 1
8060 instr[20,15] ==> opcode : with type 00 or 01
8061 000000 ==> FMOV, 000001 ==> FABS,
8062 000010 ==> FNEG, 000011 ==> FSQRT,
8063 000100 ==> UNALLOC, 000101 ==> FCVT,(to single/double)
8064 000110 ==> UNALLOC, 000111 ==> FCVT (to half)
8065 001000 ==> FRINTN, 001001 ==> FRINTP,
8066 001010 ==> FRINTM, 001011 ==> FRINTZ,
8067 001100 ==> FRINTA, 001101 ==> UNALLOC
8068 001110 ==> FRINTX, 001111 ==> FRINTI
8069 with type 11
8070 000100 ==> FCVT (half-to-single)
8071 000101 ==> FCVT (half-to-double)
8072 instr[14,10] = 10000. */
8073
7517e550 8074 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
8075 uint32_t type = INSTR (23, 22);
8076 uint32_t opcode = INSTR (20, 15);
2e8cf49e
NC
8077
8078 if (M_S != 0)
8079 HALT_UNALLOC;
8080
8081 if (type == 3)
8082 {
5ab6d79e
NC
8083 if (opcode == 4)
8084 do_FCVT_half_to_single (cpu);
8085 else if (opcode == 5)
8086 do_FCVT_half_to_double (cpu);
2e8cf49e
NC
8087 else
8088 HALT_UNALLOC;
5ab6d79e 8089 return;
2e8cf49e
NC
8090 }
8091
8092 if (type == 2)
8093 HALT_UNALLOC;
8094
8095 switch (opcode)
8096 {
8097 case 0:
8098 if (type)
8099 ffmovd (cpu);
8100 else
8101 ffmovs (cpu);
8102 return;
8103
8104 case 1:
8105 if (type)
8106 fabcpu (cpu);
8107 else
8108 fabss (cpu);
8109 return;
8110
8111 case 2:
8112 if (type)
8113 fnegd (cpu);
8114 else
8115 fnegs (cpu);
8116 return;
8117
8118 case 3:
8119 if (type)
8120 fsqrtd (cpu);
8121 else
8122 fsqrts (cpu);
8123 return;
8124
8125 case 4:
8126 if (type)
8127 fcvtds (cpu);
8128 else
8129 HALT_UNALLOC;
8130 return;
8131
8132 case 5:
8133 if (type)
8134 HALT_UNALLOC;
8135 fcvtcpu (cpu);
8136 return;
8137
8138 case 8: /* FRINTN etc. */
8139 case 9:
8140 case 10:
8141 case 11:
8142 case 12:
8143 case 14:
8144 case 15:
8145 do_FRINT (cpu);
8146 return;
8147
5ab6d79e
NC
8148 case 7:
8149 if (INSTR (22, 22))
8150 do_FCVT_double_to_half (cpu);
8151 else
8152 do_FCVT_single_to_half (cpu);
8153 return;
8154
2e8cf49e
NC
8155 case 13:
8156 HALT_NYI;
8157
8158 default:
8159 HALT_UNALLOC;
8160 }
8161}
8162
8163/* 32 bit signed int to float. */
8164static void
8165scvtf32 (sim_cpu *cpu)
8166{
ef0d8ffc
NC
8167 unsigned rn = INSTR (9, 5);
8168 unsigned sd = INSTR (4, 0);
2e8cf49e 8169
2cdad34c 8170 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8171 aarch64_set_FP_float
8172 (cpu, sd, (float) aarch64_get_reg_s32 (cpu, rn, NO_SP));
8173}
8174
8175/* signed int to float. */
8176static void
8177scvtf (sim_cpu *cpu)
8178{
ef0d8ffc
NC
8179 unsigned rn = INSTR (9, 5);
8180 unsigned sd = INSTR (4, 0);
2e8cf49e 8181
2cdad34c 8182 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8183 aarch64_set_FP_float
8184 (cpu, sd, (float) aarch64_get_reg_s64 (cpu, rn, NO_SP));
8185}
8186
8187/* 32 bit signed int to double. */
8188static void
8189scvtd32 (sim_cpu *cpu)
8190{
ef0d8ffc
NC
8191 unsigned rn = INSTR (9, 5);
8192 unsigned sd = INSTR (4, 0);
2e8cf49e 8193
2cdad34c 8194 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8195 aarch64_set_FP_double
8196 (cpu, sd, (double) aarch64_get_reg_s32 (cpu, rn, NO_SP));
8197}
8198
8199/* signed int to double. */
8200static void
8201scvtd (sim_cpu *cpu)
8202{
ef0d8ffc
NC
8203 unsigned rn = INSTR (9, 5);
8204 unsigned sd = INSTR (4, 0);
2e8cf49e 8205
2cdad34c 8206 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8207 aarch64_set_FP_double
8208 (cpu, sd, (double) aarch64_get_reg_s64 (cpu, rn, NO_SP));
8209}
8210
8211static const float FLOAT_INT_MAX = (float) INT_MAX;
8212static const float FLOAT_INT_MIN = (float) INT_MIN;
8213static const double DOUBLE_INT_MAX = (double) INT_MAX;
8214static const double DOUBLE_INT_MIN = (double) INT_MIN;
8215static const float FLOAT_LONG_MAX = (float) LONG_MAX;
8216static const float FLOAT_LONG_MIN = (float) LONG_MIN;
8217static const double DOUBLE_LONG_MAX = (double) LONG_MAX;
8218static const double DOUBLE_LONG_MIN = (double) LONG_MIN;
8219
c0386d4d
JW
8220#define UINT_MIN 0
8221#define ULONG_MIN 0
8222static const float FLOAT_UINT_MAX = (float) UINT_MAX;
8223static const float FLOAT_UINT_MIN = (float) UINT_MIN;
8224static const double DOUBLE_UINT_MAX = (double) UINT_MAX;
8225static const double DOUBLE_UINT_MIN = (double) UINT_MIN;
8226static const float FLOAT_ULONG_MAX = (float) ULONG_MAX;
8227static const float FLOAT_ULONG_MIN = (float) ULONG_MIN;
8228static const double DOUBLE_ULONG_MAX = (double) ULONG_MAX;
8229static const double DOUBLE_ULONG_MIN = (double) ULONG_MIN;
8230
2e8cf49e
NC
8231/* Check for FP exception conditions:
8232 NaN raises IO
8233 Infinity raises IO
8234 Out of Range raises IO and IX and saturates value
8235 Denormal raises ID and IX and sets to zero. */
8236#define RAISE_EXCEPTIONS(F, VALUE, FTYPE, ITYPE) \
8237 do \
8238 { \
8239 switch (fpclassify (F)) \
8240 { \
8241 case FP_INFINITE: \
8242 case FP_NAN: \
8243 aarch64_set_FPSR (cpu, IO); \
8244 if (signbit (F)) \
8245 VALUE = ITYPE##_MAX; \
8246 else \
8247 VALUE = ITYPE##_MIN; \
8248 break; \
8249 \
8250 case FP_NORMAL: \
8251 if (F >= FTYPE##_##ITYPE##_MAX) \
8252 { \
8253 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
8254 VALUE = ITYPE##_MAX; \
8255 } \
8256 else if (F <= FTYPE##_##ITYPE##_MIN) \
8257 { \
8258 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
8259 VALUE = ITYPE##_MIN; \
8260 } \
8261 break; \
8262 \
8263 case FP_SUBNORMAL: \
8264 aarch64_set_FPSR_bits (cpu, IO | IX | ID, IX | ID); \
8265 VALUE = 0; \
8266 break; \
8267 \
8268 default: \
8269 case FP_ZERO: \
8270 VALUE = 0; \
8271 break; \
8272 } \
8273 } \
8274 while (0)
8275
8276/* 32 bit convert float to signed int truncate towards zero. */
8277static void
8278fcvtszs32 (sim_cpu *cpu)
8279{
ef0d8ffc
NC
8280 unsigned sn = INSTR (9, 5);
8281 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8282 /* TODO : check that this rounds toward zero. */
8283 float f = aarch64_get_FP_float (cpu, sn);
8284 int32_t value = (int32_t) f;
8285
8286 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
8287
2cdad34c 8288 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8289 /* Avoid sign extension to 64 bit. */
8290 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8291}
8292
8293/* 64 bit convert float to signed int truncate towards zero. */
8294static void
8295fcvtszs (sim_cpu *cpu)
8296{
ef0d8ffc
NC
8297 unsigned sn = INSTR (9, 5);
8298 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8299 float f = aarch64_get_FP_float (cpu, sn);
8300 int64_t value = (int64_t) f;
8301
8302 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
8303
2cdad34c 8304 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8305 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8306}
8307
8308/* 32 bit convert double to signed int truncate towards zero. */
8309static void
8310fcvtszd32 (sim_cpu *cpu)
8311{
ef0d8ffc
NC
8312 unsigned sn = INSTR (9, 5);
8313 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8314 /* TODO : check that this rounds toward zero. */
8315 double d = aarch64_get_FP_double (cpu, sn);
8316 int32_t value = (int32_t) d;
8317
8318 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
8319
2cdad34c 8320 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8321 /* Avoid sign extension to 64 bit. */
8322 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8323}
8324
8325/* 64 bit convert double to signed int truncate towards zero. */
8326static void
8327fcvtszd (sim_cpu *cpu)
8328{
ef0d8ffc
NC
8329 unsigned sn = INSTR (9, 5);
8330 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8331 /* TODO : check that this rounds toward zero. */
8332 double d = aarch64_get_FP_double (cpu, sn);
8333 int64_t value;
8334
8335 value = (int64_t) d;
8336
8337 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
8338
2cdad34c 8339 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8340 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8341}
8342
8343static void
8344do_fcvtzu (sim_cpu *cpu)
8345{
8346 /* instr[31] = size: 32-bit (0), 64-bit (1)
8347 instr[30,23] = 00111100
8348 instr[22] = type: single (0)/ double (1)
8349 instr[21] = enable (0)/disable(1) precision
8350 instr[20,16] = 11001
8351 instr[15,10] = precision
8352 instr[9,5] = Rs
8353 instr[4,0] = Rd. */
8354
ef0d8ffc
NC
8355 unsigned rs = INSTR (9, 5);
8356 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8357
8358 NYI_assert (30, 23, 0x3C);
8359 NYI_assert (20, 16, 0x19);
8360
ef0d8ffc 8361 if (INSTR (21, 21) != 1)
2e8cf49e
NC
8362 /* Convert to fixed point. */
8363 HALT_NYI;
8364
2cdad34c 8365 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8366 if (INSTR (31, 31))
2e8cf49e
NC
8367 {
8368 /* Convert to unsigned 64-bit integer. */
ef0d8ffc 8369 if (INSTR (22, 22))
2e8cf49e
NC
8370 {
8371 double d = aarch64_get_FP_double (cpu, rs);
8372 uint64_t value = (uint64_t) d;
8373
8374 /* Do not raise an exception if we have reached ULONG_MAX. */
8375 if (value != (1UL << 63))
c0386d4d 8376 RAISE_EXCEPTIONS (d, value, DOUBLE, ULONG);
2e8cf49e
NC
8377
8378 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8379 }
8380 else
8381 {
8382 float f = aarch64_get_FP_float (cpu, rs);
8383 uint64_t value = (uint64_t) f;
8384
8385 /* Do not raise an exception if we have reached ULONG_MAX. */
8386 if (value != (1UL << 63))
c0386d4d 8387 RAISE_EXCEPTIONS (f, value, FLOAT, ULONG);
2e8cf49e
NC
8388
8389 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8390 }
8391 }
8392 else
8393 {
8394 uint32_t value;
8395
8396 /* Convert to unsigned 32-bit integer. */
ef0d8ffc 8397 if (INSTR (22, 22))
2e8cf49e
NC
8398 {
8399 double d = aarch64_get_FP_double (cpu, rs);
8400
8401 value = (uint32_t) d;
8402 /* Do not raise an exception if we have reached UINT_MAX. */
8403 if (value != (1UL << 31))
c0386d4d 8404 RAISE_EXCEPTIONS (d, value, DOUBLE, UINT);
2e8cf49e
NC
8405 }
8406 else
8407 {
8408 float f = aarch64_get_FP_float (cpu, rs);
8409
8410 value = (uint32_t) f;
8411 /* Do not raise an exception if we have reached UINT_MAX. */
8412 if (value != (1UL << 31))
c0386d4d 8413 RAISE_EXCEPTIONS (f, value, FLOAT, UINT);
2e8cf49e
NC
8414 }
8415
8416 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8417 }
8418}
8419
8420static void
8421do_UCVTF (sim_cpu *cpu)
8422{
8423 /* instr[31] = size: 32-bit (0), 64-bit (1)
8424 instr[30,23] = 001 1110 0
8425 instr[22] = type: single (0)/ double (1)
8426 instr[21] = enable (0)/disable(1) precision
8427 instr[20,16] = 0 0011
8428 instr[15,10] = precision
8429 instr[9,5] = Rs
8430 instr[4,0] = Rd. */
8431
ef0d8ffc
NC
8432 unsigned rs = INSTR (9, 5);
8433 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8434
8435 NYI_assert (30, 23, 0x3C);
8436 NYI_assert (20, 16, 0x03);
8437
ef0d8ffc 8438 if (INSTR (21, 21) != 1)
2e8cf49e
NC
8439 HALT_NYI;
8440
8441 /* FIXME: Add exception raising. */
2cdad34c 8442 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8443 if (INSTR (31, 31))
2e8cf49e
NC
8444 {
8445 uint64_t value = aarch64_get_reg_u64 (cpu, rs, NO_SP);
8446
ef0d8ffc 8447 if (INSTR (22, 22))
2e8cf49e
NC
8448 aarch64_set_FP_double (cpu, rd, (double) value);
8449 else
8450 aarch64_set_FP_float (cpu, rd, (float) value);
8451 }
8452 else
8453 {
8454 uint32_t value = aarch64_get_reg_u32 (cpu, rs, NO_SP);
8455
ef0d8ffc 8456 if (INSTR (22, 22))
2e8cf49e
NC
8457 aarch64_set_FP_double (cpu, rd, (double) value);
8458 else
8459 aarch64_set_FP_float (cpu, rd, (float) value);
8460 }
8461}
8462
8463static void
8464float_vector_move (sim_cpu *cpu)
8465{
8466 /* instr[31,17] == 100 1111 0101 0111
8467 instr[16] ==> direction 0=> to GR, 1=> from GR
8468 instr[15,10] => ???
8469 instr[9,5] ==> source
8470 instr[4,0] ==> dest. */
8471
ef0d8ffc
NC
8472 unsigned rn = INSTR (9, 5);
8473 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8474
8475 NYI_assert (31, 17, 0x4F57);
8476
ef0d8ffc 8477 if (INSTR (15, 10) != 0)
2e8cf49e
NC
8478 HALT_UNALLOC;
8479
2cdad34c 8480 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8481 if (INSTR (16, 16))
2e8cf49e
NC
8482 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_reg_u64 (cpu, rn, NO_SP));
8483 else
8484 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, rn, 1));
8485}
8486
8487static void
8488dexSimpleFPIntegerConvert (sim_cpu *cpu)
8489{
8490 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8491 instr[30 = 0
8492 instr[29] = S : 0 ==> OK, 1 ==> UNALLOC
8493 instr[28,25] = 1111
8494 instr[24] = 0
8495 instr[23,22] = type : 00 ==> single, 01 ==> double, 1x ==> UNALLOC
8496 instr[21] = 1
8497 instr[20,19] = rmode
8498 instr[18,16] = opcode
8499 instr[15,10] = 10 0000 */
8500
8501 uint32_t rmode_opcode;
8502 uint32_t size_type;
8503 uint32_t type;
8504 uint32_t size;
8505 uint32_t S;
8506
ef0d8ffc 8507 if (INSTR (31, 17) == 0x4F57)
2e8cf49e
NC
8508 {
8509 float_vector_move (cpu);
8510 return;
8511 }
8512
ef0d8ffc
NC
8513 size = INSTR (31, 31);
8514 S = INSTR (29, 29);
2e8cf49e
NC
8515 if (S != 0)
8516 HALT_UNALLOC;
8517
ef0d8ffc 8518 type = INSTR (23, 22);
2e8cf49e
NC
8519 if (type > 1)
8520 HALT_UNALLOC;
8521
ef0d8ffc 8522 rmode_opcode = INSTR (20, 16);
2e8cf49e
NC
8523 size_type = (size << 1) | type; /* 0==32f, 1==32d, 2==64f, 3==64d. */
8524
8525 switch (rmode_opcode)
8526 {
8527 case 2: /* SCVTF. */
8528 switch (size_type)
8529 {
8530 case 0: scvtf32 (cpu); return;
8531 case 1: scvtd32 (cpu); return;
8532 case 2: scvtf (cpu); return;
8533 case 3: scvtd (cpu); return;
2e8cf49e
NC
8534 }
8535
8536 case 6: /* FMOV GR, Vec. */
8537 switch (size_type)
8538 {
8539 case 0: gfmovs (cpu); return;
8540 case 3: gfmovd (cpu); return;
8541 default: HALT_UNALLOC;
8542 }
8543
8544 case 7: /* FMOV vec, GR. */
8545 switch (size_type)
8546 {
8547 case 0: fgmovs (cpu); return;
8548 case 3: fgmovd (cpu); return;
8549 default: HALT_UNALLOC;
8550 }
8551
8552 case 24: /* FCVTZS. */
8553 switch (size_type)
8554 {
8555 case 0: fcvtszs32 (cpu); return;
8556 case 1: fcvtszd32 (cpu); return;
8557 case 2: fcvtszs (cpu); return;
8558 case 3: fcvtszd (cpu); return;
2e8cf49e
NC
8559 }
8560
8561 case 25: do_fcvtzu (cpu); return;
8562 case 3: do_UCVTF (cpu); return;
8563
8564 case 0: /* FCVTNS. */
8565 case 1: /* FCVTNU. */
8566 case 4: /* FCVTAS. */
8567 case 5: /* FCVTAU. */
8568 case 8: /* FCVPTS. */
8569 case 9: /* FCVTPU. */
8570 case 16: /* FCVTMS. */
8571 case 17: /* FCVTMU. */
8572 default:
8573 HALT_NYI;
8574 }
8575}
8576
8577static void
8578set_flags_for_float_compare (sim_cpu *cpu, float fvalue1, float fvalue2)
8579{
8580 uint32_t flags;
8581
87903eaf 8582 /* FIXME: Add exception raising. */
2e8cf49e
NC
8583 if (isnan (fvalue1) || isnan (fvalue2))
8584 flags = C|V;
87903eaf
JW
8585 else if (isinf (fvalue1) && isinf (fvalue2))
8586 {
8587 /* Subtracting two infinities may give a NaN. We only need to compare
8588 the signs, which we can get from isinf. */
8589 int result = isinf (fvalue1) - isinf (fvalue2);
8590
8591 if (result == 0)
8592 flags = Z|C;
8593 else if (result < 0)
8594 flags = N;
8595 else /* (result > 0). */
8596 flags = C;
8597 }
2e8cf49e
NC
8598 else
8599 {
8600 float result = fvalue1 - fvalue2;
8601
8602 if (result == 0.0)
8603 flags = Z|C;
8604 else if (result < 0)
8605 flags = N;
8606 else /* (result > 0). */
8607 flags = C;
8608 }
8609
8610 aarch64_set_CPSR (cpu, flags);
8611}
8612
8613static void
8614fcmps (sim_cpu *cpu)
8615{
ef0d8ffc
NC
8616 unsigned sm = INSTR (20, 16);
8617 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8618
8619 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8620 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8621
2cdad34c 8622 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8623 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8624}
8625
8626/* Float compare to zero -- Invalid Operation exception
8627 only on signaling NaNs. */
8628static void
8629fcmpzs (sim_cpu *cpu)
8630{
ef0d8ffc 8631 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8632 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8633
2cdad34c 8634 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8635 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8636}
8637
8638/* Float compare -- Invalid Operation exception on all NaNs. */
8639static void
8640fcmpes (sim_cpu *cpu)
8641{
ef0d8ffc
NC
8642 unsigned sm = INSTR (20, 16);
8643 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8644
8645 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8646 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8647
2cdad34c 8648 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8649 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8650}
8651
8652/* Float compare to zero -- Invalid Operation exception on all NaNs. */
8653static void
8654fcmpzes (sim_cpu *cpu)
8655{
ef0d8ffc 8656 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8657 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8658
2cdad34c 8659 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8660 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8661}
8662
8663static void
8664set_flags_for_double_compare (sim_cpu *cpu, double dval1, double dval2)
8665{
8666 uint32_t flags;
8667
87903eaf 8668 /* FIXME: Add exception raising. */
2e8cf49e
NC
8669 if (isnan (dval1) || isnan (dval2))
8670 flags = C|V;
87903eaf
JW
8671 else if (isinf (dval1) && isinf (dval2))
8672 {
8673 /* Subtracting two infinities may give a NaN. We only need to compare
8674 the signs, which we can get from isinf. */
8675 int result = isinf (dval1) - isinf (dval2);
8676
8677 if (result == 0)
8678 flags = Z|C;
8679 else if (result < 0)
8680 flags = N;
8681 else /* (result > 0). */
8682 flags = C;
8683 }
2e8cf49e
NC
8684 else
8685 {
8686 double result = dval1 - dval2;
8687
8688 if (result == 0.0)
8689 flags = Z|C;
8690 else if (result < 0)
8691 flags = N;
8692 else /* (result > 0). */
8693 flags = C;
8694 }
8695
8696 aarch64_set_CPSR (cpu, flags);
8697}
8698
8699/* Double compare -- Invalid Operation exception only on signaling NaNs. */
8700static void
8701fcmpd (sim_cpu *cpu)
8702{
ef0d8ffc
NC
8703 unsigned sm = INSTR (20, 16);
8704 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8705
8706 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8707 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8708
2cdad34c 8709 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8710 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8711}
8712
8713/* Double compare to zero -- Invalid Operation exception
8714 only on signaling NaNs. */
8715static void
8716fcmpzd (sim_cpu *cpu)
8717{
ef0d8ffc 8718 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8719 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8720
2cdad34c 8721 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8722 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8723}
8724
8725/* Double compare -- Invalid Operation exception on all NaNs. */
8726static void
8727fcmped (sim_cpu *cpu)
8728{
ef0d8ffc
NC
8729 unsigned sm = INSTR (20, 16);
8730 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8731
8732 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8733 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8734
2cdad34c 8735 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8736 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8737}
8738
8739/* Double compare to zero -- Invalid Operation exception on all NaNs. */
8740static void
8741fcmpzed (sim_cpu *cpu)
8742{
ef0d8ffc 8743 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8744 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8745
2cdad34c 8746 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8747 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8748}
8749
8750static void
8751dexSimpleFPCompare (sim_cpu *cpu)
8752{
8753 /* assert instr[28,25] == 1111
8754 instr[30:24:21:13,10] = 0011000
8755 instr[31] = M : 0 ==> OK, 1 ==> UNALLOC
8756 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
8757 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
8758 instr[15,14] ==> op : 00 ==> OK, ow ==> UNALLOC
8759 instr[4,0] ==> opcode2 : 00000 ==> FCMP, 10000 ==> FCMPE,
8760 01000 ==> FCMPZ, 11000 ==> FCMPEZ,
8761 ow ==> UNALLOC */
8762 uint32_t dispatch;
7517e550 8763 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
8764 uint32_t type = INSTR (23, 22);
8765 uint32_t op = INSTR (15, 14);
8766 uint32_t op2_2_0 = INSTR (2, 0);
2e8cf49e
NC
8767
8768 if (op2_2_0 != 0)
8769 HALT_UNALLOC;
8770
8771 if (M_S != 0)
8772 HALT_UNALLOC;
8773
8774 if (type > 1)
8775 HALT_UNALLOC;
8776
8777 if (op != 0)
8778 HALT_UNALLOC;
8779
8780 /* dispatch on type and top 2 bits of opcode. */
ef0d8ffc 8781 dispatch = (type << 2) | INSTR (4, 3);
2e8cf49e
NC
8782
8783 switch (dispatch)
8784 {
8785 case 0: fcmps (cpu); return;
8786 case 1: fcmpzs (cpu); return;
8787 case 2: fcmpes (cpu); return;
8788 case 3: fcmpzes (cpu); return;
8789 case 4: fcmpd (cpu); return;
8790 case 5: fcmpzd (cpu); return;
8791 case 6: fcmped (cpu); return;
8792 case 7: fcmpzed (cpu); return;
2e8cf49e
NC
8793 }
8794}
8795
8796static void
8797do_scalar_FADDP (sim_cpu *cpu)
8798{
7517e550 8799 /* instr [31,23] = 0111 1110 0
2e8cf49e 8800 instr [22] = single(0)/double(1)
7517e550 8801 instr [21,10] = 11 0000 1101 10
2e8cf49e
NC
8802 instr [9,5] = Fn
8803 instr [4,0] = Fd. */
8804
ef0d8ffc
NC
8805 unsigned Fn = INSTR (9, 5);
8806 unsigned Fd = INSTR (4, 0);
2e8cf49e
NC
8807
8808 NYI_assert (31, 23, 0x0FC);
8809 NYI_assert (21, 10, 0xC36);
8810
2cdad34c 8811 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8812 if (INSTR (22, 22))
2e8cf49e
NC
8813 {
8814 double val1 = aarch64_get_vec_double (cpu, Fn, 0);
8815 double val2 = aarch64_get_vec_double (cpu, Fn, 1);
8816
8817 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8818 }
8819 else
8820 {
8821 float val1 = aarch64_get_vec_float (cpu, Fn, 0);
8822 float val2 = aarch64_get_vec_float (cpu, Fn, 1);
8823
8824 aarch64_set_FP_float (cpu, Fd, val1 + val2);
8825 }
8826}
8827
8828/* Floating point absolute difference. */
8829
8830static void
8831do_scalar_FABD (sim_cpu *cpu)
8832{
8833 /* instr [31,23] = 0111 1110 1
8834 instr [22] = float(0)/double(1)
8835 instr [21] = 1
8836 instr [20,16] = Rm
8837 instr [15,10] = 1101 01
8838 instr [9, 5] = Rn
8839 instr [4, 0] = Rd. */
8840
ef0d8ffc
NC
8841 unsigned rm = INSTR (20, 16);
8842 unsigned rn = INSTR (9, 5);
8843 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8844
8845 NYI_assert (31, 23, 0x0FD);
8846 NYI_assert (21, 21, 1);
8847 NYI_assert (15, 10, 0x35);
8848
2cdad34c 8849 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8850 if (INSTR (22, 22))
2e8cf49e
NC
8851 aarch64_set_FP_double (cpu, rd,
8852 fabs (aarch64_get_FP_double (cpu, rn)
8853 - aarch64_get_FP_double (cpu, rm)));
8854 else
8855 aarch64_set_FP_float (cpu, rd,
8856 fabsf (aarch64_get_FP_float (cpu, rn)
8857 - aarch64_get_FP_float (cpu, rm)));
8858}
8859
8860static void
8861do_scalar_CMGT (sim_cpu *cpu)
8862{
8863 /* instr [31,21] = 0101 1110 111
8864 instr [20,16] = Rm
8865 instr [15,10] = 00 1101
8866 instr [9, 5] = Rn
8867 instr [4, 0] = Rd. */
8868
ef0d8ffc
NC
8869 unsigned rm = INSTR (20, 16);
8870 unsigned rn = INSTR (9, 5);
8871 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8872
8873 NYI_assert (31, 21, 0x2F7);
8874 NYI_assert (15, 10, 0x0D);
8875
2cdad34c 8876 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8877 aarch64_set_vec_u64 (cpu, rd, 0,
8878 aarch64_get_vec_u64 (cpu, rn, 0) >
8879 aarch64_get_vec_u64 (cpu, rm, 0) ? -1L : 0L);
8880}
8881
8882static void
8883do_scalar_USHR (sim_cpu *cpu)
8884{
8885 /* instr [31,23] = 0111 1111 0
8886 instr [22,16] = shift amount
8887 instr [15,10] = 0000 01
8888 instr [9, 5] = Rn
8889 instr [4, 0] = Rd. */
8890
5ab6d79e
NC
8891 unsigned amount = 128 - INSTR (22, 16);
8892 unsigned rn = INSTR (9, 5);
8893 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8894
8895 NYI_assert (31, 23, 0x0FE);
8896 NYI_assert (15, 10, 0x01);
8897
2cdad34c 8898 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8899 aarch64_set_vec_u64 (cpu, rd, 0,
8900 aarch64_get_vec_u64 (cpu, rn, 0) >> amount);
8901}
8902
8903static void
5ab6d79e
NC
8904do_scalar_SSHL (sim_cpu *cpu)
8905{
8906 /* instr [31,21] = 0101 1110 111
8907 instr [20,16] = Rm
8908 instr [15,10] = 0100 01
8909 instr [9, 5] = Rn
8910 instr [4, 0] = Rd. */
8911
8912 unsigned rm = INSTR (20, 16);
8913 unsigned rn = INSTR (9, 5);
8914 unsigned rd = INSTR (4, 0);
8915 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
8916
8917 NYI_assert (31, 21, 0x2F7);
8918 NYI_assert (15, 10, 0x11);
8919
2cdad34c 8920 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8921 if (shift >= 0)
8922 aarch64_set_vec_s64 (cpu, rd, 0,
8923 aarch64_get_vec_s64 (cpu, rn, 0) << shift);
8924 else
8925 aarch64_set_vec_s64 (cpu, rd, 0,
ef0d8ffc 8926 aarch64_get_vec_s64 (cpu, rn, 0) >> - shift);
5ab6d79e
NC
8927}
8928
8929static void
8930do_scalar_shift (sim_cpu *cpu)
2e8cf49e 8931{
5ab6d79e 8932 /* instr [31,23] = 0101 1111 0
2e8cf49e 8933 instr [22,16] = shift amount
5ab6d79e
NC
8934 instr [15,10] = 0101 01 [SHL]
8935 instr [15,10] = 0000 01 [SSHR]
2e8cf49e
NC
8936 instr [9, 5] = Rn
8937 instr [4, 0] = Rd. */
8938
5ab6d79e
NC
8939 unsigned rn = INSTR (9, 5);
8940 unsigned rd = INSTR (4, 0);
8941 unsigned amount;
2e8cf49e
NC
8942
8943 NYI_assert (31, 23, 0x0BE);
2e8cf49e 8944
5ab6d79e 8945 if (INSTR (22, 22) == 0)
2e8cf49e
NC
8946 HALT_UNALLOC;
8947
2cdad34c 8948 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8949 switch (INSTR (15, 10))
8950 {
8951 case 0x01: /* SSHR */
8952 amount = 128 - INSTR (22, 16);
8953 aarch64_set_vec_s64 (cpu, rd, 0,
8954 aarch64_get_vec_s64 (cpu, rn, 0) >> amount);
8955 return;
8956 case 0x15: /* SHL */
8957 amount = INSTR (22, 16) - 64;
8958 aarch64_set_vec_u64 (cpu, rd, 0,
8959 aarch64_get_vec_u64 (cpu, rn, 0) << amount);
8960 return;
8961 default:
8962 HALT_NYI;
8963 }
2e8cf49e
NC
8964}
8965
8966/* FCMEQ FCMGT FCMGE. */
8967static void
8968do_scalar_FCM (sim_cpu *cpu)
8969{
8970 /* instr [31,30] = 01
8971 instr [29] = U
8972 instr [28,24] = 1 1110
8973 instr [23] = E
8974 instr [22] = size
8975 instr [21] = 1
8976 instr [20,16] = Rm
8977 instr [15,12] = 1110
8978 instr [11] = AC
8979 instr [10] = 1
8980 instr [9, 5] = Rn
8981 instr [4, 0] = Rd. */
8982
ef0d8ffc
NC
8983 unsigned rm = INSTR (20, 16);
8984 unsigned rn = INSTR (9, 5);
8985 unsigned rd = INSTR (4, 0);
7517e550 8986 unsigned EUac = (INSTR (23, 23) << 2) | (INSTR (29, 29) << 1) | INSTR (11, 11);
2e8cf49e
NC
8987 unsigned result;
8988 float val1;
8989 float val2;
8990
8991 NYI_assert (31, 30, 1);
8992 NYI_assert (28, 24, 0x1E);
8993 NYI_assert (21, 21, 1);
8994 NYI_assert (15, 12, 0xE);
8995 NYI_assert (10, 10, 1);
8996
2cdad34c 8997 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8998 if (INSTR (22, 22))
2e8cf49e
NC
8999 {
9000 double val1 = aarch64_get_FP_double (cpu, rn);
9001 double val2 = aarch64_get_FP_double (cpu, rm);
9002
9003 switch (EUac)
9004 {
9005 case 0: /* 000 */
9006 result = val1 == val2;
9007 break;
9008
9009 case 3: /* 011 */
9010 val1 = fabs (val1);
9011 val2 = fabs (val2);
9012 /* Fall through. */
9013 case 2: /* 010 */
9014 result = val1 >= val2;
9015 break;
9016
9017 case 7: /* 111 */
9018 val1 = fabs (val1);
9019 val2 = fabs (val2);
9020 /* Fall through. */
9021 case 6: /* 110 */
9022 result = val1 > val2;
9023 break;
9024
9025 default:
9026 HALT_UNALLOC;
9027 }
9028
9029 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
9030 return;
9031 }
9032
9033 val1 = aarch64_get_FP_float (cpu, rn);
9034 val2 = aarch64_get_FP_float (cpu, rm);
9035
9036 switch (EUac)
9037 {
9038 case 0: /* 000 */
9039 result = val1 == val2;
9040 break;
9041
9042 case 3: /* 011 */
9043 val1 = fabsf (val1);
9044 val2 = fabsf (val2);
9045 /* Fall through. */
9046 case 2: /* 010 */
9047 result = val1 >= val2;
9048 break;
9049
9050 case 7: /* 111 */
9051 val1 = fabsf (val1);
9052 val2 = fabsf (val2);
9053 /* Fall through. */
9054 case 6: /* 110 */
9055 result = val1 > val2;
9056 break;
9057
9058 default:
9059 HALT_UNALLOC;
9060 }
9061
9062 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
9063}
9064
9065/* An alias of DUP. */
9066static void
9067do_scalar_MOV (sim_cpu *cpu)
9068{
9069 /* instr [31,21] = 0101 1110 000
9070 instr [20,16] = imm5
9071 instr [15,10] = 0000 01
9072 instr [9, 5] = Rn
9073 instr [4, 0] = Rd. */
9074
ef0d8ffc
NC
9075 unsigned rn = INSTR (9, 5);
9076 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9077 unsigned index;
9078
9079 NYI_assert (31, 21, 0x2F0);
9080 NYI_assert (15, 10, 0x01);
9081
2cdad34c 9082 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9083 if (INSTR (16, 16))
2e8cf49e
NC
9084 {
9085 /* 8-bit. */
ef0d8ffc 9086 index = INSTR (20, 17);
2e8cf49e
NC
9087 aarch64_set_vec_u8
9088 (cpu, rd, 0, aarch64_get_vec_u8 (cpu, rn, index));
9089 }
ef0d8ffc 9090 else if (INSTR (17, 17))
2e8cf49e
NC
9091 {
9092 /* 16-bit. */
ef0d8ffc 9093 index = INSTR (20, 18);
2e8cf49e
NC
9094 aarch64_set_vec_u16
9095 (cpu, rd, 0, aarch64_get_vec_u16 (cpu, rn, index));
9096 }
ef0d8ffc 9097 else if (INSTR (18, 18))
2e8cf49e
NC
9098 {
9099 /* 32-bit. */
ef0d8ffc 9100 index = INSTR (20, 19);
2e8cf49e
NC
9101 aarch64_set_vec_u32
9102 (cpu, rd, 0, aarch64_get_vec_u32 (cpu, rn, index));
9103 }
ef0d8ffc 9104 else if (INSTR (19, 19))
2e8cf49e
NC
9105 {
9106 /* 64-bit. */
ef0d8ffc 9107 index = INSTR (20, 20);
2e8cf49e
NC
9108 aarch64_set_vec_u64
9109 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, index));
9110 }
9111 else
9112 HALT_UNALLOC;
9113}
9114
e101a78b
NC
9115static void
9116do_scalar_NEG (sim_cpu *cpu)
9117{
5ab6d79e 9118 /* instr [31,10] = 0111 1110 1110 0000 1011 10
e101a78b
NC
9119 instr [9, 5] = Rn
9120 instr [4, 0] = Rd. */
9121
ef0d8ffc
NC
9122 unsigned rn = INSTR (9, 5);
9123 unsigned rd = INSTR (4, 0);
e101a78b 9124
5ab6d79e 9125 NYI_assert (31, 10, 0x1FB82E);
e101a78b 9126
2cdad34c 9127 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
9128 aarch64_set_vec_u64 (cpu, rd, 0, - aarch64_get_vec_u64 (cpu, rn, 0));
9129}
9130
5ab6d79e
NC
9131static void
9132do_scalar_USHL (sim_cpu *cpu)
9133{
9134 /* instr [31,21] = 0111 1110 111
9135 instr [20,16] = Rm
9136 instr [15,10] = 0100 01
9137 instr [9, 5] = Rn
9138 instr [4, 0] = Rd. */
9139
9140 unsigned rm = INSTR (20, 16);
9141 unsigned rn = INSTR (9, 5);
9142 unsigned rd = INSTR (4, 0);
9143 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
9144
9145 NYI_assert (31, 21, 0x3F7);
9146 NYI_assert (15, 10, 0x11);
9147
2cdad34c 9148 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
9149 if (shift >= 0)
9150 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) << shift);
9151 else
9152 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) >> - shift);
9153}
9154
2e8cf49e
NC
9155static void
9156do_double_add (sim_cpu *cpu)
9157{
5ab6d79e
NC
9158 /* instr [31,21] = 0101 1110 111
9159 instr [20,16] = Fn
9160 instr [15,10] = 1000 01
9161 instr [9,5] = Fm
9162 instr [4,0] = Fd. */
2e8cf49e
NC
9163 unsigned Fd;
9164 unsigned Fm;
9165 unsigned Fn;
9166 double val1;
9167 double val2;
9168
5ab6d79e
NC
9169 NYI_assert (31, 21, 0x2F7);
9170 NYI_assert (15, 10, 0x21);
9171
9172 Fd = INSTR (4, 0);
9173 Fm = INSTR (9, 5);
9174 Fn = INSTR (20, 16);
9175
2cdad34c 9176 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
9177 val1 = aarch64_get_FP_double (cpu, Fm);
9178 val2 = aarch64_get_FP_double (cpu, Fn);
9179
9180 aarch64_set_FP_double (cpu, Fd, val1 + val2);
9181}
9182
7517e550
NC
9183static void
9184do_scalar_UCVTF (sim_cpu *cpu)
9185{
9186 /* instr [31,23] = 0111 1110 0
9187 instr [22] = single(0)/double(1)
9188 instr [21,10] = 10 0001 1101 10
9189 instr [9,5] = rn
9190 instr [4,0] = rd. */
9191
9192 unsigned rn = INSTR (9, 5);
9193 unsigned rd = INSTR (4, 0);
9194
9195 NYI_assert (31, 23, 0x0FC);
9196 NYI_assert (21, 10, 0x876);
9197
2cdad34c 9198 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
9199 if (INSTR (22, 22))
9200 {
9201 uint64_t val = aarch64_get_vec_u64 (cpu, rn, 0);
9202
9203 aarch64_set_vec_double (cpu, rd, 0, (double) val);
9204 }
9205 else
9206 {
9207 uint32_t val = aarch64_get_vec_u32 (cpu, rn, 0);
9208
9209 aarch64_set_vec_float (cpu, rd, 0, (float) val);
9210 }
9211}
9212
5ab6d79e
NC
9213static void
9214do_scalar_vec (sim_cpu *cpu)
9215{
9216 /* instr [30] = 1. */
9217 /* instr [28,25] = 1111. */
ef0d8ffc 9218 switch (INSTR (31, 23))
2e8cf49e
NC
9219 {
9220 case 0xBC:
ef0d8ffc 9221 switch (INSTR (15, 10))
2e8cf49e
NC
9222 {
9223 case 0x01: do_scalar_MOV (cpu); return;
9224 case 0x39: do_scalar_FCM (cpu); return;
9225 case 0x3B: do_scalar_FCM (cpu); return;
9226 }
9227 break;
9228
5ab6d79e 9229 case 0xBE: do_scalar_shift (cpu); return;
2e8cf49e
NC
9230
9231 case 0xFC:
ef0d8ffc 9232 switch (INSTR (15, 10))
2e8cf49e 9233 {
7517e550
NC
9234 case 0x36:
9235 switch (INSTR (21, 16))
9236 {
9237 case 0x30: do_scalar_FADDP (cpu); return;
9238 case 0x21: do_scalar_UCVTF (cpu); return;
9239 }
9240 HALT_NYI;
2e8cf49e
NC
9241 case 0x39: do_scalar_FCM (cpu); return;
9242 case 0x3B: do_scalar_FCM (cpu); return;
9243 }
9244 break;
9245
9246 case 0xFD:
ef0d8ffc 9247 switch (INSTR (15, 10))
2e8cf49e
NC
9248 {
9249 case 0x0D: do_scalar_CMGT (cpu); return;
5ab6d79e
NC
9250 case 0x11: do_scalar_USHL (cpu); return;
9251 case 0x2E: do_scalar_NEG (cpu); return;
2e8cf49e
NC
9252 case 0x35: do_scalar_FABD (cpu); return;
9253 case 0x39: do_scalar_FCM (cpu); return;
9254 case 0x3B: do_scalar_FCM (cpu); return;
9255 default:
9256 HALT_NYI;
9257 }
9258
9259 case 0xFE: do_scalar_USHR (cpu); return;
5ab6d79e
NC
9260
9261 case 0xBD:
9262 switch (INSTR (15, 10))
9263 {
9264 case 0x21: do_double_add (cpu); return;
9265 case 0x11: do_scalar_SSHL (cpu); return;
9266 default:
9267 HALT_NYI;
9268 }
ef0d8ffc 9269
2e8cf49e 9270 default:
5ab6d79e 9271 HALT_NYI;
2e8cf49e 9272 }
2e8cf49e
NC
9273}
9274
9275static void
9276dexAdvSIMD1 (sim_cpu *cpu)
9277{
9278 /* instr [28,25] = 1 111. */
9279
5ab6d79e 9280 /* We are currently only interested in the basic
2e8cf49e 9281 scalar fp routines which all have bit 30 = 0. */
ef0d8ffc 9282 if (INSTR (30, 30))
5ab6d79e 9283 do_scalar_vec (cpu);
2e8cf49e
NC
9284
9285 /* instr[24] is set for FP data processing 3-source and clear for
9286 all other basic scalar fp instruction groups. */
ef0d8ffc 9287 else if (INSTR (24, 24))
2e8cf49e
NC
9288 dexSimpleFPDataProc3Source (cpu);
9289
9290 /* instr[21] is clear for floating <-> fixed conversions and set for
9291 all other basic scalar fp instruction groups. */
ef0d8ffc 9292 else if (!INSTR (21, 21))
2e8cf49e
NC
9293 dexSimpleFPFixedConvert (cpu);
9294
9295 /* instr[11,10] : 01 ==> cond compare, 10 ==> Data Proc 2 Source
9296 11 ==> cond select, 00 ==> other. */
9297 else
ef0d8ffc 9298 switch (INSTR (11, 10))
2e8cf49e
NC
9299 {
9300 case 1: dexSimpleFPCondCompare (cpu); return;
9301 case 2: dexSimpleFPDataProc2Source (cpu); return;
9302 case 3: dexSimpleFPCondSelect (cpu); return;
9303
9304 default:
9305 /* Now an ordered cascade of tests.
ef0d8ffc
NC
9306 FP immediate has instr [12] == 1.
9307 FP compare has instr [13] == 1.
9308 FP Data Proc 1 Source has instr [14] == 1.
9309 FP floating <--> integer conversions has instr [15] == 0. */
9310 if (INSTR (12, 12))
2e8cf49e
NC
9311 dexSimpleFPImmediate (cpu);
9312
ef0d8ffc 9313 else if (INSTR (13, 13))
2e8cf49e
NC
9314 dexSimpleFPCompare (cpu);
9315
ef0d8ffc 9316 else if (INSTR (14, 14))
2e8cf49e
NC
9317 dexSimpleFPDataProc1Source (cpu);
9318
ef0d8ffc 9319 else if (!INSTR (15, 15))
2e8cf49e
NC
9320 dexSimpleFPIntegerConvert (cpu);
9321
9322 else
9323 /* If we get here then instr[15] == 1 which means UNALLOC. */
9324 HALT_UNALLOC;
9325 }
9326}
9327
9328/* PC relative addressing. */
9329
9330static void
9331pcadr (sim_cpu *cpu)
9332{
9333 /* instr[31] = op : 0 ==> ADR, 1 ==> ADRP
9334 instr[30,29] = immlo
9335 instr[23,5] = immhi. */
9336 uint64_t address;
ef0d8ffc
NC
9337 unsigned rd = INSTR (4, 0);
9338 uint32_t isPage = INSTR (31, 31);
2e8cf49e
NC
9339 union { int64_t u64; uint64_t s64; } imm;
9340 uint64_t offset;
9341
9342 imm.s64 = simm64 (aarch64_get_instr (cpu), 23, 5);
9343 offset = imm.u64;
ef0d8ffc 9344 offset = (offset << 2) | INSTR (30, 29);
2e8cf49e
NC
9345
9346 address = aarch64_get_PC (cpu);
9347
9348 if (isPage)
9349 {
9350 offset <<= 12;
9351 address &= ~0xfff;
9352 }
9353
2cdad34c 9354 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9355 aarch64_set_reg_u64 (cpu, rd, NO_SP, address + offset);
9356}
9357
9358/* Specific decode and execute for group Data Processing Immediate. */
9359
9360static void
9361dexPCRelAddressing (sim_cpu *cpu)
9362{
9363 /* assert instr[28,24] = 10000. */
9364 pcadr (cpu);
9365}
9366
9367/* Immediate logical.
9368 The bimm32/64 argument is constructed by replicating a 2, 4, 8,
9369 16, 32 or 64 bit sequence pulled out at decode and possibly
9370 inverting it..
9371
9372 N.B. the output register (dest) can normally be Xn or SP
9373 the exception occurs for flag setting instructions which may
9374 only use Xn for the output (dest). The input register can
9375 never be SP. */
9376
9377/* 32 bit and immediate. */
9378static void
9379and32 (sim_cpu *cpu, uint32_t bimm)
9380{
ef0d8ffc
NC
9381 unsigned rn = INSTR (9, 5);
9382 unsigned rd = INSTR (4, 0);
2e8cf49e 9383
2cdad34c 9384 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9385 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9386 aarch64_get_reg_u32 (cpu, rn, NO_SP) & bimm);
9387}
9388
9389/* 64 bit and immediate. */
9390static void
9391and64 (sim_cpu *cpu, uint64_t bimm)
9392{
ef0d8ffc
NC
9393 unsigned rn = INSTR (9, 5);
9394 unsigned rd = INSTR (4, 0);
2e8cf49e 9395
2cdad34c 9396 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9397 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9398 aarch64_get_reg_u64 (cpu, rn, NO_SP) & bimm);
9399}
9400
9401/* 32 bit and immediate set flags. */
9402static void
9403ands32 (sim_cpu *cpu, uint32_t bimm)
9404{
ef0d8ffc
NC
9405 unsigned rn = INSTR (9, 5);
9406 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9407
9408 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9409 uint32_t value2 = bimm;
9410
2cdad34c 9411 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9412 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9413 set_flags_for_binop32 (cpu, value1 & value2);
9414}
9415
9416/* 64 bit and immediate set flags. */
9417static void
9418ands64 (sim_cpu *cpu, uint64_t bimm)
9419{
ef0d8ffc
NC
9420 unsigned rn = INSTR (9, 5);
9421 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9422
9423 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9424 uint64_t value2 = bimm;
9425
2cdad34c 9426 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9427 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9428 set_flags_for_binop64 (cpu, value1 & value2);
9429}
9430
9431/* 32 bit exclusive or immediate. */
9432static void
9433eor32 (sim_cpu *cpu, uint32_t bimm)
9434{
ef0d8ffc
NC
9435 unsigned rn = INSTR (9, 5);
9436 unsigned rd = INSTR (4, 0);
2e8cf49e 9437
2cdad34c 9438 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9439 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9440 aarch64_get_reg_u32 (cpu, rn, NO_SP) ^ bimm);
9441}
9442
9443/* 64 bit exclusive or immediate. */
9444static void
9445eor64 (sim_cpu *cpu, uint64_t bimm)
9446{
ef0d8ffc
NC
9447 unsigned rn = INSTR (9, 5);
9448 unsigned rd = INSTR (4, 0);
2e8cf49e 9449
2cdad34c 9450 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9451 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9452 aarch64_get_reg_u64 (cpu, rn, NO_SP) ^ bimm);
9453}
9454
9455/* 32 bit or immediate. */
9456static void
9457orr32 (sim_cpu *cpu, uint32_t bimm)
9458{
ef0d8ffc
NC
9459 unsigned rn = INSTR (9, 5);
9460 unsigned rd = INSTR (4, 0);
2e8cf49e 9461
2cdad34c 9462 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9463 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9464 aarch64_get_reg_u32 (cpu, rn, NO_SP) | bimm);
9465}
9466
9467/* 64 bit or immediate. */
9468static void
9469orr64 (sim_cpu *cpu, uint64_t bimm)
9470{
ef0d8ffc
NC
9471 unsigned rn = INSTR (9, 5);
9472 unsigned rd = INSTR (4, 0);
2e8cf49e 9473
2cdad34c 9474 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9475 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9476 aarch64_get_reg_u64 (cpu, rn, NO_SP) | bimm);
9477}
9478
9479/* Logical shifted register.
9480 These allow an optional LSL, ASR, LSR or ROR to the second source
9481 register with a count up to the register bit count.
9482 N.B register args may not be SP. */
9483
9484/* 32 bit AND shifted register. */
9485static void
9486and32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9487{
ef0d8ffc
NC
9488 unsigned rm = INSTR (20, 16);
9489 unsigned rn = INSTR (9, 5);
9490 unsigned rd = INSTR (4, 0);
2e8cf49e 9491
2cdad34c 9492 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9493 aarch64_set_reg_u64
9494 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9495 & shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9496}
9497
9498/* 64 bit AND shifted register. */
9499static void
9500and64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9501{
ef0d8ffc
NC
9502 unsigned rm = INSTR (20, 16);
9503 unsigned rn = INSTR (9, 5);
9504 unsigned rd = INSTR (4, 0);
2e8cf49e 9505
2cdad34c 9506 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9507 aarch64_set_reg_u64
9508 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9509 & shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9510}
9511
9512/* 32 bit AND shifted register setting flags. */
9513static void
9514ands32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9515{
ef0d8ffc
NC
9516 unsigned rm = INSTR (20, 16);
9517 unsigned rn = INSTR (9, 5);
9518 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9519
9520 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9521 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9522 shift, count);
9523
2cdad34c 9524 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9525 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9526 set_flags_for_binop32 (cpu, value1 & value2);
9527}
9528
9529/* 64 bit AND shifted register setting flags. */
9530static void
9531ands64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9532{
ef0d8ffc
NC
9533 unsigned rm = INSTR (20, 16);
9534 unsigned rn = INSTR (9, 5);
9535 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9536
9537 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9538 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9539 shift, count);
9540
2cdad34c 9541 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9542 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9543 set_flags_for_binop64 (cpu, value1 & value2);
9544}
9545
9546/* 32 bit BIC shifted register. */
9547static void
9548bic32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9549{
ef0d8ffc
NC
9550 unsigned rm = INSTR (20, 16);
9551 unsigned rn = INSTR (9, 5);
9552 unsigned rd = INSTR (4, 0);
2e8cf49e 9553
2cdad34c 9554 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9555 aarch64_set_reg_u64
9556 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9557 & ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9558}
9559
9560/* 64 bit BIC shifted register. */
9561static void
9562bic64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9563{
ef0d8ffc
NC
9564 unsigned rm = INSTR (20, 16);
9565 unsigned rn = INSTR (9, 5);
9566 unsigned rd = INSTR (4, 0);
2e8cf49e 9567
2cdad34c 9568 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9569 aarch64_set_reg_u64
9570 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9571 & ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9572}
9573
9574/* 32 bit BIC shifted register setting flags. */
9575static void
9576bics32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9577{
ef0d8ffc
NC
9578 unsigned rm = INSTR (20, 16);
9579 unsigned rn = INSTR (9, 5);
9580 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9581
9582 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9583 uint32_t value2 = ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9584 shift, count);
9585
2cdad34c 9586 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9587 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9588 set_flags_for_binop32 (cpu, value1 & value2);
9589}
9590
9591/* 64 bit BIC shifted register setting flags. */
9592static void
9593bics64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9594{
ef0d8ffc
NC
9595 unsigned rm = INSTR (20, 16);
9596 unsigned rn = INSTR (9, 5);
9597 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9598
9599 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9600 uint64_t value2 = ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9601 shift, count);
9602
2cdad34c 9603 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9604 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9605 set_flags_for_binop64 (cpu, value1 & value2);
9606}
9607
9608/* 32 bit EON shifted register. */
9609static void
9610eon32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9611{
ef0d8ffc
NC
9612 unsigned rm = INSTR (20, 16);
9613 unsigned rn = INSTR (9, 5);
9614 unsigned rd = INSTR (4, 0);
2e8cf49e 9615
2cdad34c 9616 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9617 aarch64_set_reg_u64
9618 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9619 ^ ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9620}
9621
9622/* 64 bit EON shifted register. */
9623static void
9624eon64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9625{
ef0d8ffc
NC
9626 unsigned rm = INSTR (20, 16);
9627 unsigned rn = INSTR (9, 5);
9628 unsigned rd = INSTR (4, 0);
2e8cf49e 9629
2cdad34c 9630 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9631 aarch64_set_reg_u64
9632 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9633 ^ ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9634}
9635
9636/* 32 bit EOR shifted register. */
9637static void
9638eor32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9639{
ef0d8ffc
NC
9640 unsigned rm = INSTR (20, 16);
9641 unsigned rn = INSTR (9, 5);
9642 unsigned rd = INSTR (4, 0);
2e8cf49e 9643
2cdad34c 9644 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9645 aarch64_set_reg_u64
9646 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9647 ^ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9648}
9649
9650/* 64 bit EOR shifted register. */
9651static void
9652eor64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9653{
ef0d8ffc
NC
9654 unsigned rm = INSTR (20, 16);
9655 unsigned rn = INSTR (9, 5);
9656 unsigned rd = INSTR (4, 0);
2e8cf49e 9657
2cdad34c 9658 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9659 aarch64_set_reg_u64
9660 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9661 ^ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9662}
9663
9664/* 32 bit ORR shifted register. */
9665static void
9666orr32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9667{
ef0d8ffc
NC
9668 unsigned rm = INSTR (20, 16);
9669 unsigned rn = INSTR (9, 5);
9670 unsigned rd = INSTR (4, 0);
2e8cf49e 9671
2cdad34c 9672 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9673 aarch64_set_reg_u64
9674 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9675 | shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9676}
9677
9678/* 64 bit ORR shifted register. */
9679static void
9680orr64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9681{
ef0d8ffc
NC
9682 unsigned rm = INSTR (20, 16);
9683 unsigned rn = INSTR (9, 5);
9684 unsigned rd = INSTR (4, 0);
2e8cf49e 9685
2cdad34c 9686 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9687 aarch64_set_reg_u64
9688 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9689 | shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9690}
9691
9692/* 32 bit ORN shifted register. */
9693static void
9694orn32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9695{
ef0d8ffc
NC
9696 unsigned rm = INSTR (20, 16);
9697 unsigned rn = INSTR (9, 5);
9698 unsigned rd = INSTR (4, 0);
2e8cf49e 9699
2cdad34c 9700 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9701 aarch64_set_reg_u64
9702 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9703 | ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9704}
9705
9706/* 64 bit ORN shifted register. */
9707static void
9708orn64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9709{
ef0d8ffc
NC
9710 unsigned rm = INSTR (20, 16);
9711 unsigned rn = INSTR (9, 5);
9712 unsigned rd = INSTR (4, 0);
2e8cf49e 9713
2cdad34c 9714 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9715 aarch64_set_reg_u64
9716 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9717 | ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9718}
9719
9720static void
9721dexLogicalImmediate (sim_cpu *cpu)
9722{
9723 /* assert instr[28,23] = 1001000
9724 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9725 instr[30,29] = op : 0 ==> AND, 1 ==> ORR, 2 ==> EOR, 3 ==> ANDS
9726 instr[22] = N : used to construct immediate mask
9727 instr[21,16] = immr
9728 instr[15,10] = imms
9729 instr[9,5] = Rn
9730 instr[4,0] = Rd */
9731
9732 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
ef0d8ffc
NC
9733 uint32_t size = INSTR (31, 31);
9734 uint32_t N = INSTR (22, 22);
9735 /* uint32_t immr = INSTR (21, 16);. */
9736 /* uint32_t imms = INSTR (15, 10);. */
9737 uint32_t index = INSTR (22, 10);
2e8cf49e 9738 uint64_t bimm64 = LITable [index];
ef0d8ffc 9739 uint32_t dispatch = INSTR (30, 29);
2e8cf49e
NC
9740
9741 if (~size & N)
9742 HALT_UNALLOC;
9743
9744 if (!bimm64)
9745 HALT_UNALLOC;
9746
9747 if (size == 0)
9748 {
9749 uint32_t bimm = (uint32_t) bimm64;
9750
9751 switch (dispatch)
9752 {
9753 case 0: and32 (cpu, bimm); return;
9754 case 1: orr32 (cpu, bimm); return;
9755 case 2: eor32 (cpu, bimm); return;
9756 case 3: ands32 (cpu, bimm); return;
9757 }
9758 }
9759 else
9760 {
9761 switch (dispatch)
9762 {
9763 case 0: and64 (cpu, bimm64); return;
9764 case 1: orr64 (cpu, bimm64); return;
9765 case 2: eor64 (cpu, bimm64); return;
9766 case 3: ands64 (cpu, bimm64); return;
9767 }
9768 }
9769 HALT_UNALLOC;
9770}
9771
9772/* Immediate move.
9773 The uimm argument is a 16 bit value to be inserted into the
9774 target register the pos argument locates the 16 bit word in the
9775 dest register i.e. it is in {0, 1} for 32 bit and {0, 1, 2,
9776 3} for 64 bit.
9777 N.B register arg may not be SP so it should be.
9778 accessed using the setGZRegisterXXX accessors. */
9779
9780/* 32 bit move 16 bit immediate zero remaining shorts. */
9781static void
9782movz32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9783{
ef0d8ffc 9784 unsigned rd = INSTR (4, 0);
2e8cf49e 9785
2cdad34c 9786 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9787 aarch64_set_reg_u64 (cpu, rd, NO_SP, val << (pos * 16));
9788}
9789
9790/* 64 bit move 16 bit immediate zero remaining shorts. */
9791static void
9792movz64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9793{
ef0d8ffc 9794 unsigned rd = INSTR (4, 0);
2e8cf49e 9795
2cdad34c 9796 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9797 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((uint64_t) val) << (pos * 16));
9798}
9799
9800/* 32 bit move 16 bit immediate negated. */
9801static void
9802movn32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9803{
ef0d8ffc 9804 unsigned rd = INSTR (4, 0);
2e8cf49e 9805
2cdad34c 9806 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9807 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((val << (pos * 16)) ^ 0xffffffffU));
9808}
9809
9810/* 64 bit move 16 bit immediate negated. */
9811static void
9812movn64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9813{
ef0d8ffc 9814 unsigned rd = INSTR (4, 0);
2e8cf49e 9815
2cdad34c 9816 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9817 aarch64_set_reg_u64
9818 (cpu, rd, NO_SP, ((((uint64_t) val) << (pos * 16))
9819 ^ 0xffffffffffffffffULL));
9820}
9821
9822/* 32 bit move 16 bit immediate keep remaining shorts. */
9823static void
9824movk32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9825{
ef0d8ffc 9826 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9827 uint32_t current = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9828 uint32_t value = val << (pos * 16);
9829 uint32_t mask = ~(0xffffU << (pos * 16));
9830
2cdad34c 9831 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9832 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
9833}
9834
9835/* 64 bit move 16 it immediate keep remaining shorts. */
9836static void
9837movk64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9838{
ef0d8ffc 9839 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9840 uint64_t current = aarch64_get_reg_u64 (cpu, rd, NO_SP);
9841 uint64_t value = (uint64_t) val << (pos * 16);
9842 uint64_t mask = ~(0xffffULL << (pos * 16));
9843
2cdad34c 9844 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9845 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
9846}
9847
9848static void
9849dexMoveWideImmediate (sim_cpu *cpu)
9850{
9851 /* assert instr[28:23] = 100101
9852 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9853 instr[30,29] = op : 0 ==> MOVN, 1 ==> UNALLOC, 2 ==> MOVZ, 3 ==> MOVK
9854 instr[22,21] = shift : 00 == LSL#0, 01 = LSL#16, 10 = LSL#32, 11 = LSL#48
9855 instr[20,5] = uimm16
9856 instr[4,0] = Rd */
9857
9858 /* N.B. the (multiple of 16) shift is applied by the called routine,
9859 we just pass the multiplier. */
9860
9861 uint32_t imm;
ef0d8ffc
NC
9862 uint32_t size = INSTR (31, 31);
9863 uint32_t op = INSTR (30, 29);
9864 uint32_t shift = INSTR (22, 21);
2e8cf49e
NC
9865
9866 /* 32 bit can only shift 0 or 1 lot of 16.
9867 anything else is an unallocated instruction. */
9868 if (size == 0 && (shift > 1))
9869 HALT_UNALLOC;
9870
9871 if (op == 1)
9872 HALT_UNALLOC;
9873
ef0d8ffc 9874 imm = INSTR (20, 5);
2e8cf49e
NC
9875
9876 if (size == 0)
9877 {
9878 if (op == 0)
9879 movn32 (cpu, imm, shift);
9880 else if (op == 2)
9881 movz32 (cpu, imm, shift);
9882 else
9883 movk32 (cpu, imm, shift);
9884 }
9885 else
9886 {
9887 if (op == 0)
9888 movn64 (cpu, imm, shift);
9889 else if (op == 2)
9890 movz64 (cpu, imm, shift);
9891 else
9892 movk64 (cpu, imm, shift);
9893 }
9894}
9895
9896/* Bitfield operations.
9897 These take a pair of bit positions r and s which are in {0..31}
9898 or {0..63} depending on the instruction word size.
9899 N.B register args may not be SP. */
9900
9901/* OK, we start with ubfm which just needs to pick
9902 some bits out of source zero the rest and write
9903 the result to dest. Just need two logical shifts. */
9904
9905/* 32 bit bitfield move, left and right of affected zeroed
9906 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9907static void
9908ubfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9909{
9910 unsigned rd;
ef0d8ffc 9911 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9912 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9913
9914 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
9915 if (r <= s)
9916 {
9917 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
9918 We want only bits s:xxx:r at the bottom of the word
9919 so we LSL bit s up to bit 31 i.e. by 31 - s
9920 and then we LSR to bring bit 31 down to bit s - r
9921 i.e. by 31 + r - s. */
9922 value <<= 31 - s;
9923 value >>= 31 + r - s;
9924 }
9925 else
9926 {
9927 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0
9928 We want only bits s:xxx:0 starting at it 31-(r-1)
9929 so we LSL bit s up to bit 31 i.e. by 31 - s
9930 and then we LSL to bring bit 31 down to 31-(r-1)+s
9931 i.e. by r - (s + 1). */
9932 value <<= 31 - s;
9933 value >>= r - (s + 1);
9934 }
9935
2cdad34c 9936 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9937 rd = INSTR (4, 0);
2e8cf49e
NC
9938 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
9939}
9940
9941/* 64 bit bitfield move, left and right of affected zeroed
9942 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9943static void
9944ubfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9945{
9946 unsigned rd;
ef0d8ffc 9947 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9948 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9949
9950 if (r <= s)
9951 {
9952 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9953 We want only bits s:xxx:r at the bottom of the word.
9954 So we LSL bit s up to bit 63 i.e. by 63 - s
9955 and then we LSR to bring bit 63 down to bit s - r
9956 i.e. by 63 + r - s. */
9957 value <<= 63 - s;
9958 value >>= 63 + r - s;
9959 }
9960 else
9961 {
9962 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0.
9963 We want only bits s:xxx:0 starting at it 63-(r-1).
9964 So we LSL bit s up to bit 63 i.e. by 63 - s
9965 and then we LSL to bring bit 63 down to 63-(r-1)+s
9966 i.e. by r - (s + 1). */
9967 value <<= 63 - s;
9968 value >>= r - (s + 1);
9969 }
9970
2cdad34c 9971 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9972 rd = INSTR (4, 0);
2e8cf49e
NC
9973 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
9974}
9975
9976/* The signed versions need to insert sign bits
9977 on the left of the inserted bit field. so we do
9978 much the same as the unsigned version except we
9979 use an arithmetic shift right -- this just means
9980 we need to operate on signed values. */
9981
9982/* 32 bit bitfield move, left of affected sign-extended, right zeroed. */
9983/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9984static void
9985sbfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9986{
9987 unsigned rd;
ef0d8ffc 9988 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9989 /* as per ubfm32 but use an ASR instead of an LSR. */
9990 int32_t value = aarch64_get_reg_s32 (cpu, rn, NO_SP);
9991
9992 if (r <= s)
9993 {
9994 value <<= 31 - s;
9995 value >>= 31 + r - s;
9996 }
9997 else
9998 {
9999 value <<= 31 - s;
10000 value >>= r - (s + 1);
10001 }
10002
2cdad34c 10003 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 10004 rd = INSTR (4, 0);
2e8cf49e
NC
10005 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
10006}
10007
10008/* 64 bit bitfield move, left of affected sign-extended, right zeroed. */
10009/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
10010static void
10011sbfm (sim_cpu *cpu, uint32_t r, uint32_t s)
10012{
10013 unsigned rd;
ef0d8ffc 10014 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10015 /* acpu per ubfm but use an ASR instead of an LSR. */
10016 int64_t value = aarch64_get_reg_s64 (cpu, rn, NO_SP);
10017
10018 if (r <= s)
10019 {
10020 value <<= 63 - s;
10021 value >>= 63 + r - s;
10022 }
10023 else
10024 {
10025 value <<= 63 - s;
10026 value >>= 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_s64 (cpu, rd, NO_SP, value);
10032}
10033
10034/* Finally, these versions leave non-affected bits
10035 as is. so we need to generate the bits as per
10036 ubfm and also generate a mask to pick the
10037 bits from the original and computed values. */
10038
10039/* 32 bit bitfield move, non-affected bits left as is.
10040 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
10041static void
10042bfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
10043{
ef0d8ffc 10044 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10045 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
10046 uint32_t mask = -1;
10047 unsigned rd;
10048 uint32_t value2;
10049
10050 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
10051 if (r <= s)
10052 {
10053 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
10054 We want only bits s:xxx:r at the bottom of the word
10055 so we LSL bit s up to bit 31 i.e. by 31 - s
10056 and then we LSR to bring bit 31 down to bit s - r
10057 i.e. by 31 + r - s. */
10058 value <<= 31 - s;
10059 value >>= 31 + r - s;
10060 /* the mask must include the same bits. */
10061 mask <<= 31 - s;
10062 mask >>= 31 + r - s;
10063 }
10064 else
10065 {
10066 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0.
10067 We want only bits s:xxx:0 starting at it 31-(r-1)
10068 so we LSL bit s up to bit 31 i.e. by 31 - s
10069 and then we LSL to bring bit 31 down to 31-(r-1)+s
10070 i.e. by r - (s + 1). */
10071 value <<= 31 - s;
10072 value >>= r - (s + 1);
10073 /* The mask must include the same bits. */
10074 mask <<= 31 - s;
10075 mask >>= r - (s + 1);
10076 }
10077
ef0d8ffc 10078 rd = INSTR (4, 0);
2e8cf49e
NC
10079 value2 = aarch64_get_reg_u32 (cpu, rd, NO_SP);
10080
10081 value2 &= ~mask;
10082 value2 |= value;
10083
2cdad34c 10084 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10085 aarch64_set_reg_u64
10086 (cpu, rd, NO_SP, (aarch64_get_reg_u32 (cpu, rd, NO_SP) & ~mask) | value);
10087}
10088
10089/* 64 bit bitfield move, non-affected bits left as is.
10090 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
10091static void
10092bfm (sim_cpu *cpu, uint32_t r, uint32_t s)
10093{
10094 unsigned rd;
ef0d8ffc 10095 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10096 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
10097 uint64_t mask = 0xffffffffffffffffULL;
10098
10099 if (r <= s)
10100 {
10101 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
10102 We want only bits s:xxx:r at the bottom of the word
10103 so we LSL bit s up to bit 63 i.e. by 63 - s
10104 and then we LSR to bring bit 63 down to bit s - r
10105 i.e. by 63 + r - s. */
10106 value <<= 63 - s;
10107 value >>= 63 + r - s;
10108 /* The mask must include the same bits. */
10109 mask <<= 63 - s;
10110 mask >>= 63 + r - s;
10111 }
10112 else
10113 {
10114 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0
10115 We want only bits s:xxx:0 starting at it 63-(r-1)
10116 so we LSL bit s up to bit 63 i.e. by 63 - s
10117 and then we LSL to bring bit 63 down to 63-(r-1)+s
10118 i.e. by r - (s + 1). */
10119 value <<= 63 - s;
10120 value >>= r - (s + 1);
10121 /* The mask must include the same bits. */
10122 mask <<= 63 - s;
10123 mask >>= r - (s + 1);
10124 }
10125
2cdad34c 10126 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 10127 rd = INSTR (4, 0);
2e8cf49e
NC
10128 aarch64_set_reg_u64
10129 (cpu, rd, NO_SP, (aarch64_get_reg_u64 (cpu, rd, NO_SP) & ~mask) | value);
10130}
10131
10132static void
10133dexBitfieldImmediate (sim_cpu *cpu)
10134{
10135 /* assert instr[28:23] = 100110
10136 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
10137 instr[30,29] = op : 0 ==> SBFM, 1 ==> BFM, 2 ==> UBFM, 3 ==> UNALLOC
10138 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit ow UNALLOC
10139 instr[21,16] = immr : 0xxxxx for 32 bit, xxxxxx for 64 bit
10140 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
10141 instr[9,5] = Rn
10142 instr[4,0] = Rd */
10143
10144 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
10145 uint32_t dispatch;
10146 uint32_t imms;
ef0d8ffc
NC
10147 uint32_t size = INSTR (31, 31);
10148 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
10149 /* 32 bit operations must have immr[5] = 0 and imms[5] = 0. */
10150 /* or else we have an UNALLOC. */
ef0d8ffc 10151 uint32_t immr = INSTR (21, 16);
2e8cf49e
NC
10152
10153 if (~size & N)
10154 HALT_UNALLOC;
10155
10156 if (!size && uimm (immr, 5, 5))
10157 HALT_UNALLOC;
10158
ef0d8ffc 10159 imms = INSTR (15, 10);
2e8cf49e
NC
10160 if (!size && uimm (imms, 5, 5))
10161 HALT_UNALLOC;
10162
10163 /* Switch on combined size and op. */
ef0d8ffc 10164 dispatch = INSTR (31, 29);
2e8cf49e
NC
10165 switch (dispatch)
10166 {
10167 case 0: sbfm32 (cpu, immr, imms); return;
10168 case 1: bfm32 (cpu, immr, imms); return;
10169 case 2: ubfm32 (cpu, immr, imms); return;
10170 case 4: sbfm (cpu, immr, imms); return;
10171 case 5: bfm (cpu, immr, imms); return;
10172 case 6: ubfm (cpu, immr, imms); return;
10173 default: HALT_UNALLOC;
10174 }
10175}
10176
10177static void
10178do_EXTR_32 (sim_cpu *cpu)
10179{
10180 /* instr[31:21] = 00010011100
10181 instr[20,16] = Rm
10182 instr[15,10] = imms : 0xxxxx for 32 bit
10183 instr[9,5] = Rn
10184 instr[4,0] = Rd */
ef0d8ffc
NC
10185 unsigned rm = INSTR (20, 16);
10186 unsigned imms = INSTR (15, 10) & 31;
10187 unsigned rn = INSTR ( 9, 5);
10188 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
10189 uint64_t val1;
10190 uint64_t val2;
10191
10192 val1 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
10193 val1 >>= imms;
10194 val2 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
10195 val2 <<= (32 - imms);
10196
2cdad34c 10197 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10198 aarch64_set_reg_u64 (cpu, rd, NO_SP, val1 | val2);
10199}
10200
10201static void
10202do_EXTR_64 (sim_cpu *cpu)
10203{
10204 /* instr[31:21] = 10010011100
10205 instr[20,16] = Rm
10206 instr[15,10] = imms
10207 instr[9,5] = Rn
10208 instr[4,0] = Rd */
ef0d8ffc
NC
10209 unsigned rm = INSTR (20, 16);
10210 unsigned imms = INSTR (15, 10) & 63;
10211 unsigned rn = INSTR ( 9, 5);
10212 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
10213 uint64_t val;
10214
10215 val = aarch64_get_reg_u64 (cpu, rm, NO_SP);
10216 val >>= imms;
10217 val |= (aarch64_get_reg_u64 (cpu, rn, NO_SP) << (64 - imms));
10218
10219 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
10220}
10221
10222static void
10223dexExtractImmediate (sim_cpu *cpu)
10224{
10225 /* assert instr[28:23] = 100111
10226 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
10227 instr[30,29] = op21 : 0 ==> EXTR, 1,2,3 ==> UNALLOC
10228 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit or UNALLOC
10229 instr[21] = op0 : must be 0 or UNALLOC
10230 instr[20,16] = Rm
10231 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
10232 instr[9,5] = Rn
10233 instr[4,0] = Rd */
10234
10235 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
10236 /* 64 bit operations must have N = 1 or else we have an UNALLOC. */
10237 uint32_t dispatch;
ef0d8ffc
NC
10238 uint32_t size = INSTR (31, 31);
10239 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
10240 /* 32 bit operations must have imms[5] = 0
10241 or else we have an UNALLOC. */
ef0d8ffc 10242 uint32_t imms = INSTR (15, 10);
2e8cf49e
NC
10243
10244 if (size ^ N)
10245 HALT_UNALLOC;
10246
10247 if (!size && uimm (imms, 5, 5))
10248 HALT_UNALLOC;
10249
10250 /* Switch on combined size and op. */
ef0d8ffc 10251 dispatch = INSTR (31, 29);
2e8cf49e
NC
10252
10253 if (dispatch == 0)
10254 do_EXTR_32 (cpu);
10255
10256 else if (dispatch == 4)
10257 do_EXTR_64 (cpu);
10258
10259 else if (dispatch == 1)
10260 HALT_NYI;
10261 else
10262 HALT_UNALLOC;
10263}
10264
10265static void
10266dexDPImm (sim_cpu *cpu)
10267{
10268 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
10269 assert group == GROUP_DPIMM_1000 || grpoup == GROUP_DPIMM_1001
10270 bits [25,23] of a DPImm are the secondary dispatch vector. */
10271 uint32_t group2 = dispatchDPImm (aarch64_get_instr (cpu));
10272
10273 switch (group2)
10274 {
10275 case DPIMM_PCADR_000:
10276 case DPIMM_PCADR_001:
10277 dexPCRelAddressing (cpu);
10278 return;
10279
10280 case DPIMM_ADDSUB_010:
10281 case DPIMM_ADDSUB_011:
10282 dexAddSubtractImmediate (cpu);
10283 return;
10284
10285 case DPIMM_LOG_100:
10286 dexLogicalImmediate (cpu);
10287 return;
10288
10289 case DPIMM_MOV_101:
10290 dexMoveWideImmediate (cpu);
10291 return;
10292
10293 case DPIMM_BITF_110:
10294 dexBitfieldImmediate (cpu);
10295 return;
10296
10297 case DPIMM_EXTR_111:
10298 dexExtractImmediate (cpu);
10299 return;
10300
10301 default:
10302 /* Should never reach here. */
10303 HALT_NYI;
10304 }
10305}
10306
10307static void
10308dexLoadUnscaledImmediate (sim_cpu *cpu)
10309{
10310 /* instr[29,24] == 111_00
10311 instr[21] == 0
10312 instr[11,10] == 00
10313 instr[31,30] = size
10314 instr[26] = V
10315 instr[23,22] = opc
10316 instr[20,12] = simm9
10317 instr[9,5] = rn may be SP. */
ef0d8ffc
NC
10318 /* unsigned rt = INSTR (4, 0); */
10319 uint32_t V = INSTR (26, 26);
7517e550 10320 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
2e8cf49e
NC
10321 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
10322
10323 if (!V)
10324 {
10325 /* GReg operations. */
10326 switch (dispatch)
10327 {
10328 case 0: sturb (cpu, imm); return;
10329 case 1: ldurb32 (cpu, imm); return;
10330 case 2: ldursb64 (cpu, imm); return;
10331 case 3: ldursb32 (cpu, imm); return;
10332 case 4: sturh (cpu, imm); return;
10333 case 5: ldurh32 (cpu, imm); return;
10334 case 6: ldursh64 (cpu, imm); return;
10335 case 7: ldursh32 (cpu, imm); return;
10336 case 8: stur32 (cpu, imm); return;
10337 case 9: ldur32 (cpu, imm); return;
10338 case 10: ldursw (cpu, imm); return;
10339 case 12: stur64 (cpu, imm); return;
10340 case 13: ldur64 (cpu, imm); return;
10341
10342 case 14:
10343 /* PRFUM NYI. */
10344 HALT_NYI;
10345
10346 default:
10347 case 11:
10348 case 15:
10349 HALT_UNALLOC;
10350 }
10351 }
10352
10353 /* FReg operations. */
10354 switch (dispatch)
10355 {
10356 case 2: fsturq (cpu, imm); return;
10357 case 3: fldurq (cpu, imm); return;
10358 case 8: fsturs (cpu, imm); return;
10359 case 9: fldurs (cpu, imm); return;
10360 case 12: fsturd (cpu, imm); return;
10361 case 13: fldurd (cpu, imm); return;
10362
10363 case 0: /* STUR 8 bit FP. */
10364 case 1: /* LDUR 8 bit FP. */
10365 case 4: /* STUR 16 bit FP. */
10366 case 5: /* LDUR 8 bit FP. */
10367 HALT_NYI;
10368
10369 default:
10370 case 6:
10371 case 7:
10372 case 10:
10373 case 11:
10374 case 14:
10375 case 15:
10376 HALT_UNALLOC;
10377 }
10378}
10379
10380/* N.B. A preliminary note regarding all the ldrs<x>32
10381 instructions
10382
10383 The signed value loaded by these instructions is cast to unsigned
10384 before being assigned to aarch64_get_reg_u64 (cpu, N) i.e. to the
10385 64 bit element of the GReg union. this performs a 32 bit sign extension
10386 (as required) but avoids 64 bit sign extension, thus ensuring that the
10387 top half of the register word is zero. this is what the spec demands
10388 when a 32 bit load occurs. */
10389
10390/* 32 bit load sign-extended byte scaled unsigned 12 bit. */
10391static void
10392ldrsb32_abs (sim_cpu *cpu, uint32_t offset)
10393{
ef0d8ffc
NC
10394 unsigned int rn = INSTR (9, 5);
10395 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10396
10397 /* The target register may not be SP but the source may be
10398 there is no scaling required for a byte load. */
10399 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
10400 aarch64_set_reg_u64 (cpu, rt, NO_SP,
10401 (int64_t) aarch64_get_mem_s8 (cpu, address));
10402}
10403
10404/* 32 bit load sign-extended byte scaled or unscaled zero-
10405 or sign-extended 32-bit register offset. */
10406static void
10407ldrsb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10408{
ef0d8ffc
NC
10409 unsigned int rm = INSTR (20, 16);
10410 unsigned int rn = INSTR (9, 5);
10411 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10412
10413 /* rn may reference SP, rm and rt must reference ZR. */
10414
10415 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10416 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10417 extension);
10418
10419 /* There is no scaling required for a byte load. */
10420 aarch64_set_reg_u64
10421 (cpu, rt, NO_SP, (int64_t) aarch64_get_mem_s8 (cpu, address
10422 + displacement));
10423}
10424
10425/* 32 bit load sign-extended byte unscaled signed 9 bit with
10426 pre- or post-writeback. */
10427static void
10428ldrsb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10429{
10430 uint64_t address;
ef0d8ffc
NC
10431 unsigned int rn = INSTR (9, 5);
10432 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10433
10434 if (rn == rt && wb != NoWriteBack)
10435 HALT_UNALLOC;
10436
10437 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10438
10439 if (wb == Pre)
10440 address += offset;
10441
10442 aarch64_set_reg_u64 (cpu, rt, NO_SP,
10443 (int64_t) aarch64_get_mem_s8 (cpu, address));
10444
10445 if (wb == Post)
10446 address += offset;
10447
10448 if (wb != NoWriteBack)
10449 aarch64_set_reg_u64 (cpu, rn, NO_SP, address);
10450}
10451
10452/* 8 bit store scaled. */
10453static void
10454fstrb_abs (sim_cpu *cpu, uint32_t offset)
10455{
ef0d8ffc
NC
10456 unsigned st = INSTR (4, 0);
10457 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10458
10459 aarch64_set_mem_u8 (cpu,
10460 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
10461 aarch64_get_vec_u8 (cpu, st, 0));
10462}
10463
10464/* 8 bit store scaled or unscaled zero- or
10465 sign-extended 8-bit register offset. */
10466static void
10467fstrb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10468{
ef0d8ffc
NC
10469 unsigned rm = INSTR (20, 16);
10470 unsigned rn = INSTR (9, 5);
10471 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10472
10473 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10474 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10475 extension);
7517e550 10476 uint64_t displacement = scaling == Scaled ? extended : 0;
2e8cf49e
NC
10477
10478 aarch64_set_mem_u8
10479 (cpu, address + displacement, aarch64_get_vec_u8 (cpu, st, 0));
10480}
10481
10482/* 16 bit store scaled. */
10483static void
10484fstrh_abs (sim_cpu *cpu, uint32_t offset)
10485{
ef0d8ffc
NC
10486 unsigned st = INSTR (4, 0);
10487 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10488
10489 aarch64_set_mem_u16
10490 (cpu,
10491 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16),
10492 aarch64_get_vec_u16 (cpu, st, 0));
10493}
10494
10495/* 16 bit store scaled or unscaled zero-
10496 or sign-extended 16-bit register offset. */
10497static void
10498fstrh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10499{
ef0d8ffc
NC
10500 unsigned rm = INSTR (20, 16);
10501 unsigned rn = INSTR (9, 5);
10502 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10503
10504 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10505 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10506 extension);
7517e550 10507 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
2e8cf49e
NC
10508
10509 aarch64_set_mem_u16
10510 (cpu, address + displacement, aarch64_get_vec_u16 (cpu, st, 0));
10511}
10512
10513/* 32 bit store scaled unsigned 12 bit. */
10514static void
10515fstrs_abs (sim_cpu *cpu, uint32_t offset)
10516{
ef0d8ffc
NC
10517 unsigned st = INSTR (4, 0);
10518 unsigned rn = INSTR (9, 5);
2e8cf49e 10519
e101a78b 10520 aarch64_set_mem_u32
2e8cf49e
NC
10521 (cpu,
10522 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
e101a78b 10523 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10524}
10525
10526/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
10527static void
10528fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10529{
ef0d8ffc
NC
10530 unsigned rn = INSTR (9, 5);
10531 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10532
10533 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10534
10535 if (wb != Post)
10536 address += offset;
10537
e101a78b 10538 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10539
10540 if (wb == Post)
10541 address += offset;
10542
10543 if (wb != NoWriteBack)
10544 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10545}
10546
10547/* 32 bit store scaled or unscaled zero-
10548 or sign-extended 32-bit register offset. */
10549static void
10550fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10551{
ef0d8ffc
NC
10552 unsigned rm = INSTR (20, 16);
10553 unsigned rn = INSTR (9, 5);
10554 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10555
10556 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10557 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10558 extension);
10559 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
10560
e101a78b
NC
10561 aarch64_set_mem_u32
10562 (cpu, address + displacement, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10563}
10564
10565/* 64 bit store scaled unsigned 12 bit. */
10566static void
10567fstrd_abs (sim_cpu *cpu, uint32_t offset)
10568{
ef0d8ffc
NC
10569 unsigned st = INSTR (4, 0);
10570 unsigned rn = INSTR (9, 5);
2e8cf49e 10571
e101a78b 10572 aarch64_set_mem_u64
2e8cf49e
NC
10573 (cpu,
10574 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
e101a78b 10575 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10576}
10577
10578/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
10579static void
10580fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10581{
ef0d8ffc
NC
10582 unsigned rn = INSTR (9, 5);
10583 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10584
10585 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10586
10587 if (wb != Post)
10588 address += offset;
10589
e101a78b 10590 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10591
10592 if (wb == Post)
10593 address += offset;
10594
10595 if (wb != NoWriteBack)
10596 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10597}
10598
10599/* 64 bit store scaled or unscaled zero-
10600 or sign-extended 32-bit register offset. */
10601static void
10602fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10603{
ef0d8ffc
NC
10604 unsigned rm = INSTR (20, 16);
10605 unsigned rn = INSTR (9, 5);
10606 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10607
10608 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10609 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10610 extension);
10611 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
10612
e101a78b
NC
10613 aarch64_set_mem_u64
10614 (cpu, address + displacement, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10615}
10616
10617/* 128 bit store scaled unsigned 12 bit. */
10618static void
10619fstrq_abs (sim_cpu *cpu, uint32_t offset)
10620{
10621 FRegister a;
ef0d8ffc
NC
10622 unsigned st = INSTR (4, 0);
10623 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10624 uint64_t addr;
10625
10626 aarch64_get_FP_long_double (cpu, st, & a);
10627
10628 addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
10629 aarch64_set_mem_long_double (cpu, addr, a);
10630}
10631
10632/* 128 bit store unscaled signed 9 bit with pre- or post-writeback. */
10633static void
10634fstrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10635{
10636 FRegister a;
ef0d8ffc
NC
10637 unsigned rn = INSTR (9, 5);
10638 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10639 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10640
10641 if (wb != Post)
10642 address += offset;
10643
10644 aarch64_get_FP_long_double (cpu, st, & a);
10645 aarch64_set_mem_long_double (cpu, address, a);
10646
10647 if (wb == Post)
10648 address += offset;
10649
10650 if (wb != NoWriteBack)
10651 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10652}
10653
10654/* 128 bit store scaled or unscaled zero-
10655 or sign-extended 32-bit register offset. */
10656static void
10657fstrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10658{
ef0d8ffc
NC
10659 unsigned rm = INSTR (20, 16);
10660 unsigned rn = INSTR (9, 5);
10661 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10662
10663 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10664 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10665 extension);
10666 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
10667
10668 FRegister a;
10669
10670 aarch64_get_FP_long_double (cpu, st, & a);
10671 aarch64_set_mem_long_double (cpu, address + displacement, a);
10672}
10673
10674static void
10675dexLoadImmediatePrePost (sim_cpu *cpu)
10676{
ef0d8ffc
NC
10677 /* instr[31,30] = size
10678 instr[29,27] = 111
10679 instr[26] = V
10680 instr[25,24] = 00
2e8cf49e 10681 instr[23,22] = opc
ef0d8ffc 10682 instr[21] = 0
2e8cf49e 10683 instr[20,12] = simm9
ef0d8ffc
NC
10684 instr[11] = wb : 0 ==> Post, 1 ==> Pre
10685 instr[10] = 0
10686 instr[9,5] = Rn may be SP.
10687 instr[4,0] = Rt */
10688
10689 uint32_t V = INSTR (26, 26);
10690 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10691 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
10692 WriteBack wb = INSTR (11, 11);
2e8cf49e
NC
10693
10694 if (!V)
10695 {
10696 /* GReg operations. */
10697 switch (dispatch)
10698 {
10699 case 0: strb_wb (cpu, imm, wb); return;
10700 case 1: ldrb32_wb (cpu, imm, wb); return;
10701 case 2: ldrsb_wb (cpu, imm, wb); return;
10702 case 3: ldrsb32_wb (cpu, imm, wb); return;
10703 case 4: strh_wb (cpu, imm, wb); return;
10704 case 5: ldrh32_wb (cpu, imm, wb); return;
10705 case 6: ldrsh64_wb (cpu, imm, wb); return;
10706 case 7: ldrsh32_wb (cpu, imm, wb); return;
10707 case 8: str32_wb (cpu, imm, wb); return;
10708 case 9: ldr32_wb (cpu, imm, wb); return;
10709 case 10: ldrsw_wb (cpu, imm, wb); return;
10710 case 12: str_wb (cpu, imm, wb); return;
10711 case 13: ldr_wb (cpu, imm, wb); return;
10712
10713 default:
10714 case 11:
10715 case 14:
10716 case 15:
10717 HALT_UNALLOC;
10718 }
10719 }
10720
10721 /* FReg operations. */
10722 switch (dispatch)
10723 {
10724 case 2: fstrq_wb (cpu, imm, wb); return;
10725 case 3: fldrq_wb (cpu, imm, wb); return;
10726 case 8: fstrs_wb (cpu, imm, wb); return;
10727 case 9: fldrs_wb (cpu, imm, wb); return;
10728 case 12: fstrd_wb (cpu, imm, wb); return;
10729 case 13: fldrd_wb (cpu, imm, wb); return;
10730
10731 case 0: /* STUR 8 bit FP. */
10732 case 1: /* LDUR 8 bit FP. */
10733 case 4: /* STUR 16 bit FP. */
10734 case 5: /* LDUR 8 bit FP. */
10735 HALT_NYI;
10736
10737 default:
10738 case 6:
10739 case 7:
10740 case 10:
10741 case 11:
10742 case 14:
10743 case 15:
10744 HALT_UNALLOC;
10745 }
10746}
10747
10748static void
10749dexLoadRegisterOffset (sim_cpu *cpu)
10750{
10751 /* instr[31,30] = size
10752 instr[29,27] = 111
10753 instr[26] = V
10754 instr[25,24] = 00
10755 instr[23,22] = opc
10756 instr[21] = 1
10757 instr[20,16] = rm
10758 instr[15,13] = option : 010 ==> UXTW, 011 ==> UXTX/LSL,
10759 110 ==> SXTW, 111 ==> SXTX,
10760 ow ==> RESERVED
10761 instr[12] = scaled
10762 instr[11,10] = 10
10763 instr[9,5] = rn
10764 instr[4,0] = rt. */
10765
ef0d8ffc
NC
10766 uint32_t V = INSTR (26, 26);
10767 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10768 Scaling scale = INSTR (12, 12);
10769 Extension extensionType = INSTR (15, 13);
2e8cf49e
NC
10770
10771 /* Check for illegal extension types. */
10772 if (uimm (extensionType, 1, 1) == 0)
10773 HALT_UNALLOC;
10774
10775 if (extensionType == UXTX || extensionType == SXTX)
10776 extensionType = NoExtension;
10777
10778 if (!V)
10779 {
10780 /* GReg operations. */
10781 switch (dispatch)
10782 {
10783 case 0: strb_scale_ext (cpu, scale, extensionType); return;
10784 case 1: ldrb32_scale_ext (cpu, scale, extensionType); return;
10785 case 2: ldrsb_scale_ext (cpu, scale, extensionType); return;
10786 case 3: ldrsb32_scale_ext (cpu, scale, extensionType); return;
10787 case 4: strh_scale_ext (cpu, scale, extensionType); return;
10788 case 5: ldrh32_scale_ext (cpu, scale, extensionType); return;
10789 case 6: ldrsh_scale_ext (cpu, scale, extensionType); return;
10790 case 7: ldrsh32_scale_ext (cpu, scale, extensionType); return;
10791 case 8: str32_scale_ext (cpu, scale, extensionType); return;
10792 case 9: ldr32_scale_ext (cpu, scale, extensionType); return;
10793 case 10: ldrsw_scale_ext (cpu, scale, extensionType); return;
10794 case 12: str_scale_ext (cpu, scale, extensionType); return;
10795 case 13: ldr_scale_ext (cpu, scale, extensionType); return;
10796 case 14: prfm_scale_ext (cpu, scale, extensionType); return;
10797
10798 default:
10799 case 11:
10800 case 15:
10801 HALT_UNALLOC;
10802 }
10803 }
10804
10805 /* FReg operations. */
10806 switch (dispatch)
10807 {
10808 case 1: /* LDUR 8 bit FP. */
10809 HALT_NYI;
10810 case 3: fldrq_scale_ext (cpu, scale, extensionType); return;
10811 case 5: /* LDUR 8 bit FP. */
10812 HALT_NYI;
10813 case 9: fldrs_scale_ext (cpu, scale, extensionType); return;
10814 case 13: fldrd_scale_ext (cpu, scale, extensionType); return;
10815
10816 case 0: fstrb_scale_ext (cpu, scale, extensionType); return;
10817 case 2: fstrq_scale_ext (cpu, scale, extensionType); return;
10818 case 4: fstrh_scale_ext (cpu, scale, extensionType); return;
10819 case 8: fstrs_scale_ext (cpu, scale, extensionType); return;
10820 case 12: fstrd_scale_ext (cpu, scale, extensionType); return;
10821
10822 default:
10823 case 6:
10824 case 7:
10825 case 10:
10826 case 11:
10827 case 14:
10828 case 15:
10829 HALT_UNALLOC;
10830 }
10831}
10832
10833static void
10834dexLoadUnsignedImmediate (sim_cpu *cpu)
10835{
5ab6d79e 10836 /* instr[29,24] == 111_01
2e8cf49e 10837 instr[31,30] = size
5ab6d79e 10838 instr[26] = V
2e8cf49e
NC
10839 instr[23,22] = opc
10840 instr[21,10] = uimm12 : unsigned immediate offset
5ab6d79e
NC
10841 instr[9,5] = rn may be SP.
10842 instr[4,0] = rt. */
ef0d8ffc
NC
10843
10844 uint32_t V = INSTR (26,26);
7517e550 10845 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
ef0d8ffc 10846 uint32_t imm = INSTR (21, 10);
2e8cf49e
NC
10847
10848 if (!V)
10849 {
10850 /* GReg operations. */
10851 switch (dispatch)
10852 {
10853 case 0: strb_abs (cpu, imm); return;
10854 case 1: ldrb32_abs (cpu, imm); return;
10855 case 2: ldrsb_abs (cpu, imm); return;
10856 case 3: ldrsb32_abs (cpu, imm); return;
10857 case 4: strh_abs (cpu, imm); return;
10858 case 5: ldrh32_abs (cpu, imm); return;
10859 case 6: ldrsh_abs (cpu, imm); return;
10860 case 7: ldrsh32_abs (cpu, imm); return;
10861 case 8: str32_abs (cpu, imm); return;
10862 case 9: ldr32_abs (cpu, imm); return;
10863 case 10: ldrsw_abs (cpu, imm); return;
10864 case 12: str_abs (cpu, imm); return;
10865 case 13: ldr_abs (cpu, imm); return;
10866 case 14: prfm_abs (cpu, imm); return;
10867
10868 default:
10869 case 11:
10870 case 15:
10871 HALT_UNALLOC;
10872 }
10873 }
10874
10875 /* FReg operations. */
10876 switch (dispatch)
10877 {
2e8cf49e 10878 case 0: fstrb_abs (cpu, imm); return;
2e8cf49e
NC
10879 case 4: fstrh_abs (cpu, imm); return;
10880 case 8: fstrs_abs (cpu, imm); return;
10881 case 12: fstrd_abs (cpu, imm); return;
5ab6d79e 10882 case 2: fstrq_abs (cpu, imm); return;
2e8cf49e 10883
5ab6d79e
NC
10884 case 1: fldrb_abs (cpu, imm); return;
10885 case 5: fldrh_abs (cpu, imm); return;
10886 case 9: fldrs_abs (cpu, imm); return;
10887 case 13: fldrd_abs (cpu, imm); return;
10888 case 3: fldrq_abs (cpu, imm); return;
2e8cf49e
NC
10889
10890 default:
10891 case 6:
10892 case 7:
10893 case 10:
10894 case 11:
10895 case 14:
10896 case 15:
10897 HALT_UNALLOC;
10898 }
10899}
10900
10901static void
10902dexLoadExclusive (sim_cpu *cpu)
10903{
10904 /* assert instr[29:24] = 001000;
10905 instr[31,30] = size
10906 instr[23] = 0 if exclusive
10907 instr[22] = L : 1 if load, 0 if store
10908 instr[21] = 1 if pair
10909 instr[20,16] = Rs
10910 instr[15] = o0 : 1 if ordered
10911 instr[14,10] = Rt2
10912 instr[9,5] = Rn
10913 instr[4.0] = Rt. */
10914
ef0d8ffc 10915 switch (INSTR (22, 21))
2e8cf49e
NC
10916 {
10917 case 2: ldxr (cpu); return;
10918 case 0: stxr (cpu); return;
10919 default: HALT_NYI;
10920 }
10921}
10922
10923static void
10924dexLoadOther (sim_cpu *cpu)
10925{
10926 uint32_t dispatch;
10927
10928 /* instr[29,25] = 111_0
10929 instr[24] == 0 ==> dispatch, 1 ==> ldst reg unsigned immediate
10930 instr[21:11,10] is the secondary dispatch. */
ef0d8ffc 10931 if (INSTR (24, 24))
2e8cf49e
NC
10932 {
10933 dexLoadUnsignedImmediate (cpu);
10934 return;
10935 }
10936
7517e550 10937 dispatch = ((INSTR (21, 21) << 2) | INSTR (11, 10));
2e8cf49e
NC
10938 switch (dispatch)
10939 {
10940 case 0: dexLoadUnscaledImmediate (cpu); return;
10941 case 1: dexLoadImmediatePrePost (cpu); return;
10942 case 3: dexLoadImmediatePrePost (cpu); return;
10943 case 6: dexLoadRegisterOffset (cpu); return;
10944
10945 default:
10946 case 2:
10947 case 4:
10948 case 5:
10949 case 7:
10950 HALT_NYI;
10951 }
10952}
10953
10954static void
10955store_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10956{
ef0d8ffc
NC
10957 unsigned rn = INSTR (14, 10);
10958 unsigned rd = INSTR (9, 5);
10959 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10960 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10961
10962 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10963 HALT_UNALLOC; /* ??? */
10964
10965 offset <<= 2;
10966
10967 if (wb != Post)
10968 address += offset;
10969
10970 aarch64_set_mem_u32 (cpu, address,
10971 aarch64_get_reg_u32 (cpu, rm, NO_SP));
10972 aarch64_set_mem_u32 (cpu, address + 4,
10973 aarch64_get_reg_u32 (cpu, rn, NO_SP));
10974
10975 if (wb == Post)
10976 address += offset;
10977
10978 if (wb != NoWriteBack)
10979 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10980}
10981
10982static void
10983store_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10984{
ef0d8ffc
NC
10985 unsigned rn = INSTR (14, 10);
10986 unsigned rd = INSTR (9, 5);
10987 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10988 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10989
10990 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10991 HALT_UNALLOC; /* ??? */
10992
10993 offset <<= 3;
10994
10995 if (wb != Post)
10996 address += offset;
10997
10998 aarch64_set_mem_u64 (cpu, address,
7517e550 10999 aarch64_get_reg_u64 (cpu, rm, NO_SP));
2e8cf49e 11000 aarch64_set_mem_u64 (cpu, address + 8,
7517e550 11001 aarch64_get_reg_u64 (cpu, rn, NO_SP));
2e8cf49e
NC
11002
11003 if (wb == Post)
11004 address += offset;
11005
11006 if (wb != NoWriteBack)
11007 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11008}
11009
11010static void
11011load_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
11012{
ef0d8ffc
NC
11013 unsigned rn = INSTR (14, 10);
11014 unsigned rd = INSTR (9, 5);
11015 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11016 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11017
7517e550 11018 /* Treat this as unalloc to make sure we don't do it. */
2e8cf49e
NC
11019 if (rn == rm)
11020 HALT_UNALLOC;
11021
11022 offset <<= 2;
11023
11024 if (wb != Post)
11025 address += offset;
11026
11027 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u32 (cpu, address));
11028 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u32 (cpu, address + 4));
11029
11030 if (wb == Post)
11031 address += offset;
11032
11033 if (wb != NoWriteBack)
11034 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11035}
11036
11037static void
11038load_pair_s32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
11039{
ef0d8ffc
NC
11040 unsigned rn = INSTR (14, 10);
11041 unsigned rd = INSTR (9, 5);
11042 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11043 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11044
11045 /* Treat this as unalloc to make sure we don't do it. */
11046 if (rn == rm)
11047 HALT_UNALLOC;
11048
11049 offset <<= 2;
11050
11051 if (wb != Post)
11052 address += offset;
11053
11054 aarch64_set_reg_s64 (cpu, rm, SP_OK, aarch64_get_mem_s32 (cpu, address));
11055 aarch64_set_reg_s64 (cpu, rn, SP_OK, aarch64_get_mem_s32 (cpu, address + 4));
11056
11057 if (wb == Post)
11058 address += offset;
11059
11060 if (wb != NoWriteBack)
11061 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11062}
11063
11064static void
11065load_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
11066{
ef0d8ffc
NC
11067 unsigned rn = INSTR (14, 10);
11068 unsigned rd = INSTR (9, 5);
11069 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11070 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11071
11072 /* Treat this as unalloc to make sure we don't do it. */
11073 if (rn == rm)
11074 HALT_UNALLOC;
11075
11076 offset <<= 3;
11077
11078 if (wb != Post)
11079 address += offset;
11080
11081 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u64 (cpu, address));
11082 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u64 (cpu, address + 8));
11083
11084 if (wb == Post)
11085 address += offset;
11086
11087 if (wb != NoWriteBack)
11088 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11089}
11090
11091static void
11092dex_load_store_pair_gr (sim_cpu *cpu)
11093{
11094 /* instr[31,30] = size (10=> 64-bit, 01=> signed 32-bit, 00=> 32-bit)
11095 instr[29,25] = instruction encoding: 101_0
11096 instr[26] = V : 1 if fp 0 if gp
11097 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
11098 instr[22] = load/store (1=> load)
11099 instr[21,15] = signed, scaled, offset
11100 instr[14,10] = Rn
11101 instr[ 9, 5] = Rd
11102 instr[ 4, 0] = Rm. */
11103
7517e550 11104 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
11105 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
11106
11107 switch (dispatch)
11108 {
11109 case 2: store_pair_u32 (cpu, offset, Post); return;
11110 case 3: load_pair_u32 (cpu, offset, Post); return;
11111 case 4: store_pair_u32 (cpu, offset, NoWriteBack); return;
11112 case 5: load_pair_u32 (cpu, offset, NoWriteBack); return;
11113 case 6: store_pair_u32 (cpu, offset, Pre); return;
11114 case 7: load_pair_u32 (cpu, offset, Pre); return;
11115
11116 case 11: load_pair_s32 (cpu, offset, Post); return;
11117 case 13: load_pair_s32 (cpu, offset, NoWriteBack); return;
11118 case 15: load_pair_s32 (cpu, offset, Pre); return;
11119
11120 case 18: store_pair_u64 (cpu, offset, Post); return;
11121 case 19: load_pair_u64 (cpu, offset, Post); return;
11122 case 20: store_pair_u64 (cpu, offset, NoWriteBack); return;
11123 case 21: load_pair_u64 (cpu, offset, NoWriteBack); return;
11124 case 22: store_pair_u64 (cpu, offset, Pre); return;
11125 case 23: load_pair_u64 (cpu, offset, Pre); return;
11126
11127 default:
11128 HALT_UNALLOC;
11129 }
11130}
11131
11132static void
11133store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
11134{
ef0d8ffc
NC
11135 unsigned rn = INSTR (14, 10);
11136 unsigned rd = INSTR (9, 5);
11137 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11138 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11139
11140 offset <<= 2;
11141
11142 if (wb != Post)
11143 address += offset;
11144
e101a78b
NC
11145 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, rm, 0));
11146 aarch64_set_mem_u32 (cpu, address + 4, aarch64_get_vec_u32 (cpu, rn, 0));
2e8cf49e
NC
11147
11148 if (wb == Post)
11149 address += offset;
11150
11151 if (wb != NoWriteBack)
11152 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11153}
11154
11155static void
11156store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11157{
ef0d8ffc
NC
11158 unsigned rn = INSTR (14, 10);
11159 unsigned rd = INSTR (9, 5);
11160 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11161 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11162
11163 offset <<= 3;
11164
11165 if (wb != Post)
11166 address += offset;
11167
e101a78b
NC
11168 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, rm, 0));
11169 aarch64_set_mem_u64 (cpu, address + 8, aarch64_get_vec_u64 (cpu, rn, 0));
2e8cf49e
NC
11170
11171 if (wb == Post)
11172 address += offset;
11173
11174 if (wb != NoWriteBack)
11175 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11176}
11177
11178static void
11179store_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11180{
11181 FRegister a;
ef0d8ffc
NC
11182 unsigned rn = INSTR (14, 10);
11183 unsigned rd = INSTR (9, 5);
11184 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11185 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11186
11187 offset <<= 4;
11188
11189 if (wb != Post)
11190 address += offset;
11191
11192 aarch64_get_FP_long_double (cpu, rm, & a);
11193 aarch64_set_mem_long_double (cpu, address, a);
11194 aarch64_get_FP_long_double (cpu, rn, & a);
11195 aarch64_set_mem_long_double (cpu, address + 16, a);
11196
11197 if (wb == Post)
11198 address += offset;
11199
11200 if (wb != NoWriteBack)
11201 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11202}
11203
11204static void
11205load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
11206{
ef0d8ffc
NC
11207 unsigned rn = INSTR (14, 10);
11208 unsigned rd = INSTR (9, 5);
11209 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11210 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11211
11212 if (rm == rn)
11213 HALT_UNALLOC;
11214
11215 offset <<= 2;
11216
11217 if (wb != Post)
11218 address += offset;
11219
e101a78b
NC
11220 aarch64_set_vec_u32 (cpu, rm, 0, aarch64_get_mem_u32 (cpu, address));
11221 aarch64_set_vec_u32 (cpu, rn, 0, aarch64_get_mem_u32 (cpu, address + 4));
2e8cf49e
NC
11222
11223 if (wb == Post)
11224 address += offset;
11225
11226 if (wb != NoWriteBack)
11227 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11228}
11229
11230static void
11231load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11232{
ef0d8ffc
NC
11233 unsigned rn = INSTR (14, 10);
11234 unsigned rd = INSTR (9, 5);
11235 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11236 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11237
11238 if (rm == rn)
11239 HALT_UNALLOC;
11240
11241 offset <<= 3;
11242
11243 if (wb != Post)
11244 address += offset;
11245
e101a78b
NC
11246 aarch64_set_vec_u64 (cpu, rm, 0, aarch64_get_mem_u64 (cpu, address));
11247 aarch64_set_vec_u64 (cpu, rn, 0, aarch64_get_mem_u64 (cpu, address + 8));
2e8cf49e
NC
11248
11249 if (wb == Post)
11250 address += offset;
11251
11252 if (wb != NoWriteBack)
11253 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11254}
11255
11256static void
11257load_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11258{
11259 FRegister a;
ef0d8ffc
NC
11260 unsigned rn = INSTR (14, 10);
11261 unsigned rd = INSTR (9, 5);
11262 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11263 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11264
11265 if (rm == rn)
11266 HALT_UNALLOC;
11267
11268 offset <<= 4;
11269
11270 if (wb != Post)
11271 address += offset;
11272
11273 aarch64_get_mem_long_double (cpu, address, & a);
11274 aarch64_set_FP_long_double (cpu, rm, a);
11275 aarch64_get_mem_long_double (cpu, address + 16, & a);
11276 aarch64_set_FP_long_double (cpu, rn, a);
11277
11278 if (wb == Post)
11279 address += offset;
11280
11281 if (wb != NoWriteBack)
11282 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11283}
11284
11285static void
11286dex_load_store_pair_fp (sim_cpu *cpu)
11287{
11288 /* instr[31,30] = size (10=> 128-bit, 01=> 64-bit, 00=> 32-bit)
11289 instr[29,25] = instruction encoding
11290 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
11291 instr[22] = load/store (1=> load)
11292 instr[21,15] = signed, scaled, offset
11293 instr[14,10] = Rn
11294 instr[ 9, 5] = Rd
11295 instr[ 4, 0] = Rm */
11296
7517e550 11297 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
11298 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
11299
11300 switch (dispatch)
11301 {
11302 case 2: store_pair_float (cpu, offset, Post); return;
11303 case 3: load_pair_float (cpu, offset, Post); return;
11304 case 4: store_pair_float (cpu, offset, NoWriteBack); return;
11305 case 5: load_pair_float (cpu, offset, NoWriteBack); return;
11306 case 6: store_pair_float (cpu, offset, Pre); return;
11307 case 7: load_pair_float (cpu, offset, Pre); return;
11308
11309 case 10: store_pair_double (cpu, offset, Post); return;
11310 case 11: load_pair_double (cpu, offset, Post); return;
11311 case 12: store_pair_double (cpu, offset, NoWriteBack); return;
11312 case 13: load_pair_double (cpu, offset, NoWriteBack); return;
11313 case 14: store_pair_double (cpu, offset, Pre); return;
11314 case 15: load_pair_double (cpu, offset, Pre); return;
11315
11316 case 18: store_pair_long_double (cpu, offset, Post); return;
11317 case 19: load_pair_long_double (cpu, offset, Post); return;
11318 case 20: store_pair_long_double (cpu, offset, NoWriteBack); return;
11319 case 21: load_pair_long_double (cpu, offset, NoWriteBack); return;
11320 case 22: store_pair_long_double (cpu, offset, Pre); return;
11321 case 23: load_pair_long_double (cpu, offset, Pre); return;
11322
11323 default:
11324 HALT_UNALLOC;
11325 }
11326}
11327
11328static inline unsigned
11329vec_reg (unsigned v, unsigned o)
11330{
11331 return (v + o) & 0x3F;
11332}
11333
11334/* Load multiple N-element structures to N consecutive registers. */
11335static void
11336vec_load (sim_cpu *cpu, uint64_t address, unsigned N)
11337{
ef0d8ffc
NC
11338 int all = INSTR (30, 30);
11339 unsigned size = INSTR (11, 10);
11340 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11341 unsigned i;
11342
11343 switch (size)
11344 {
11345 case 0: /* 8-bit operations. */
11346 if (all)
11347 for (i = 0; i < (16 * N); i++)
11348 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15,
11349 aarch64_get_mem_u8 (cpu, address + i));
11350 else
11351 for (i = 0; i < (8 * N); i++)
11352 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7,
11353 aarch64_get_mem_u8 (cpu, address + i));
11354 return;
11355
11356 case 1: /* 16-bit operations. */
11357 if (all)
11358 for (i = 0; i < (8 * N); i++)
11359 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7,
11360 aarch64_get_mem_u16 (cpu, address + i * 2));
11361 else
11362 for (i = 0; i < (4 * N); i++)
11363 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3,
11364 aarch64_get_mem_u16 (cpu, address + i * 2));
11365 return;
11366
11367 case 2: /* 32-bit operations. */
11368 if (all)
11369 for (i = 0; i < (4 * N); i++)
11370 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3,
11371 aarch64_get_mem_u32 (cpu, address + i * 4));
11372 else
11373 for (i = 0; i < (2 * N); i++)
11374 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1,
11375 aarch64_get_mem_u32 (cpu, address + i * 4));
11376 return;
11377
11378 case 3: /* 64-bit operations. */
11379 if (all)
11380 for (i = 0; i < (2 * N); i++)
11381 aarch64_set_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1,
11382 aarch64_get_mem_u64 (cpu, address + i * 8));
11383 else
11384 for (i = 0; i < N; i++)
11385 aarch64_set_vec_u64 (cpu, vec_reg (vd, i), 0,
11386 aarch64_get_mem_u64 (cpu, address + i * 8));
11387 return;
2e8cf49e
NC
11388 }
11389}
11390
11391/* LD4: load multiple 4-element to four consecutive registers. */
11392static void
11393LD4 (sim_cpu *cpu, uint64_t address)
11394{
11395 vec_load (cpu, address, 4);
11396}
11397
11398/* LD3: load multiple 3-element structures to three consecutive registers. */
11399static void
11400LD3 (sim_cpu *cpu, uint64_t address)
11401{
11402 vec_load (cpu, address, 3);
11403}
11404
11405/* LD2: load multiple 2-element structures to two consecutive registers. */
11406static void
11407LD2 (sim_cpu *cpu, uint64_t address)
11408{
11409 vec_load (cpu, address, 2);
11410}
11411
11412/* Load multiple 1-element structures into one register. */
11413static void
11414LD1_1 (sim_cpu *cpu, uint64_t address)
11415{
ef0d8ffc
NC
11416 int all = INSTR (30, 30);
11417 unsigned size = INSTR (11, 10);
11418 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11419 unsigned i;
11420
11421 switch (size)
11422 {
11423 case 0:
11424 /* LD1 {Vd.16b}, addr, #16 */
11425 /* LD1 {Vd.8b}, addr, #8 */
11426 for (i = 0; i < (all ? 16 : 8); i++)
11427 aarch64_set_vec_u8 (cpu, vd, i,
11428 aarch64_get_mem_u8 (cpu, address + i));
11429 return;
11430
11431 case 1:
11432 /* LD1 {Vd.8h}, addr, #16 */
11433 /* LD1 {Vd.4h}, addr, #8 */
11434 for (i = 0; i < (all ? 8 : 4); i++)
11435 aarch64_set_vec_u16 (cpu, vd, i,
11436 aarch64_get_mem_u16 (cpu, address + i * 2));
11437 return;
11438
11439 case 2:
11440 /* LD1 {Vd.4s}, addr, #16 */
11441 /* LD1 {Vd.2s}, addr, #8 */
11442 for (i = 0; i < (all ? 4 : 2); i++)
11443 aarch64_set_vec_u32 (cpu, vd, i,
11444 aarch64_get_mem_u32 (cpu, address + i * 4));
11445 return;
11446
11447 case 3:
11448 /* LD1 {Vd.2d}, addr, #16 */
11449 /* LD1 {Vd.1d}, addr, #8 */
11450 for (i = 0; i < (all ? 2 : 1); i++)
11451 aarch64_set_vec_u64 (cpu, vd, i,
11452 aarch64_get_mem_u64 (cpu, address + i * 8));
11453 return;
2e8cf49e
NC
11454 }
11455}
11456
11457/* Load multiple 1-element structures into two registers. */
11458static void
11459LD1_2 (sim_cpu *cpu, uint64_t address)
11460{
11461 /* FIXME: This algorithm is *exactly* the same as the LD2 version.
11462 So why have two different instructions ? There must be something
11463 wrong somewhere. */
11464 vec_load (cpu, address, 2);
11465}
11466
11467/* Load multiple 1-element structures into three registers. */
11468static void
11469LD1_3 (sim_cpu *cpu, uint64_t address)
11470{
11471 /* FIXME: This algorithm is *exactly* the same as the LD3 version.
11472 So why have two different instructions ? There must be something
11473 wrong somewhere. */
11474 vec_load (cpu, address, 3);
11475}
11476
11477/* Load multiple 1-element structures into four registers. */
11478static void
11479LD1_4 (sim_cpu *cpu, uint64_t address)
11480{
11481 /* FIXME: This algorithm is *exactly* the same as the LD4 version.
11482 So why have two different instructions ? There must be something
11483 wrong somewhere. */
11484 vec_load (cpu, address, 4);
11485}
11486
11487/* Store multiple N-element structures to N consecutive registers. */
11488static void
11489vec_store (sim_cpu *cpu, uint64_t address, unsigned N)
11490{
ef0d8ffc
NC
11491 int all = INSTR (30, 30);
11492 unsigned size = INSTR (11, 10);
11493 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11494 unsigned i;
11495
11496 switch (size)
11497 {
11498 case 0: /* 8-bit operations. */
11499 if (all)
11500 for (i = 0; i < (16 * N); i++)
11501 aarch64_set_mem_u8
11502 (cpu, address + i,
11503 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15));
11504 else
11505 for (i = 0; i < (8 * N); i++)
11506 aarch64_set_mem_u8
11507 (cpu, address + i,
11508 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7));
11509 return;
11510
11511 case 1: /* 16-bit operations. */
11512 if (all)
11513 for (i = 0; i < (8 * N); i++)
11514 aarch64_set_mem_u16
11515 (cpu, address + i * 2,
11516 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7));
11517 else
11518 for (i = 0; i < (4 * N); i++)
11519 aarch64_set_mem_u16
11520 (cpu, address + i * 2,
11521 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3));
11522 return;
11523
11524 case 2: /* 32-bit operations. */
11525 if (all)
11526 for (i = 0; i < (4 * N); i++)
11527 aarch64_set_mem_u32
11528 (cpu, address + i * 4,
11529 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3));
11530 else
11531 for (i = 0; i < (2 * N); i++)
11532 aarch64_set_mem_u32
11533 (cpu, address + i * 4,
11534 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1));
11535 return;
11536
11537 case 3: /* 64-bit operations. */
11538 if (all)
11539 for (i = 0; i < (2 * N); i++)
11540 aarch64_set_mem_u64
11541 (cpu, address + i * 8,
11542 aarch64_get_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1));
11543 else
11544 for (i = 0; i < N; i++)
11545 aarch64_set_mem_u64
11546 (cpu, address + i * 8,
11547 aarch64_get_vec_u64 (cpu, vec_reg (vd, i), 0));
11548 return;
2e8cf49e
NC
11549 }
11550}
11551
11552/* Store multiple 4-element structure to four consecutive registers. */
11553static void
11554ST4 (sim_cpu *cpu, uint64_t address)
11555{
11556 vec_store (cpu, address, 4);
11557}
11558
11559/* Store multiple 3-element structures to three consecutive registers. */
11560static void
11561ST3 (sim_cpu *cpu, uint64_t address)
11562{
11563 vec_store (cpu, address, 3);
11564}
11565
11566/* Store multiple 2-element structures to two consecutive registers. */
11567static void
11568ST2 (sim_cpu *cpu, uint64_t address)
11569{
11570 vec_store (cpu, address, 2);
11571}
11572
11573/* Store multiple 1-element structures into one register. */
11574static void
11575ST1_1 (sim_cpu *cpu, uint64_t address)
11576{
ef0d8ffc
NC
11577 int all = INSTR (30, 30);
11578 unsigned size = INSTR (11, 10);
11579 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11580 unsigned i;
11581
11582 switch (size)
11583 {
11584 case 0:
11585 for (i = 0; i < (all ? 16 : 8); i++)
11586 aarch64_set_mem_u8 (cpu, address + i,
11587 aarch64_get_vec_u8 (cpu, vd, i));
11588 return;
11589
11590 case 1:
11591 for (i = 0; i < (all ? 8 : 4); i++)
11592 aarch64_set_mem_u16 (cpu, address + i * 2,
11593 aarch64_get_vec_u16 (cpu, vd, i));
11594 return;
11595
11596 case 2:
11597 for (i = 0; i < (all ? 4 : 2); i++)
11598 aarch64_set_mem_u32 (cpu, address + i * 4,
11599 aarch64_get_vec_u32 (cpu, vd, i));
11600 return;
11601
11602 case 3:
11603 for (i = 0; i < (all ? 2 : 1); i++)
11604 aarch64_set_mem_u64 (cpu, address + i * 8,
11605 aarch64_get_vec_u64 (cpu, vd, i));
11606 return;
2e8cf49e
NC
11607 }
11608}
11609
11610/* Store multiple 1-element structures into two registers. */
11611static void
11612ST1_2 (sim_cpu *cpu, uint64_t address)
11613{
11614 /* FIXME: This algorithm is *exactly* the same as the ST2 version.
11615 So why have two different instructions ? There must be
11616 something wrong somewhere. */
11617 vec_store (cpu, address, 2);
11618}
11619
11620/* Store multiple 1-element structures into three registers. */
11621static void
11622ST1_3 (sim_cpu *cpu, uint64_t address)
11623{
11624 /* FIXME: This algorithm is *exactly* the same as the ST3 version.
11625 So why have two different instructions ? There must be
11626 something wrong somewhere. */
11627 vec_store (cpu, address, 3);
11628}
11629
11630/* Store multiple 1-element structures into four registers. */
11631static void
11632ST1_4 (sim_cpu *cpu, uint64_t address)
11633{
11634 /* FIXME: This algorithm is *exactly* the same as the ST4 version.
11635 So why have two different instructions ? There must be
11636 something wrong somewhere. */
11637 vec_store (cpu, address, 4);
11638}
11639
e8f42b5e
JW
11640#define LDn_STn_SINGLE_LANE_AND_SIZE() \
11641 do \
11642 { \
11643 switch (INSTR (15, 14)) \
11644 { \
11645 case 0: \
11646 lane = (full << 3) | (s << 2) | size; \
11647 size = 0; \
11648 break; \
11649 \
11650 case 1: \
11651 if ((size & 1) == 1) \
11652 HALT_UNALLOC; \
11653 lane = (full << 2) | (s << 1) | (size >> 1); \
11654 size = 1; \
11655 break; \
11656 \
11657 case 2: \
11658 if ((size & 2) == 2) \
11659 HALT_UNALLOC; \
11660 \
11661 if ((size & 1) == 0) \
11662 { \
11663 lane = (full << 1) | s; \
11664 size = 2; \
11665 } \
11666 else \
11667 { \
11668 if (s) \
11669 HALT_UNALLOC; \
11670 lane = full; \
11671 size = 3; \
11672 } \
11673 break; \
11674 \
11675 default: \
11676 HALT_UNALLOC; \
11677 } \
11678 } \
11679 while (0)
11680
11681/* Load single structure into one lane of N registers. */
2e8cf49e 11682static void
e8f42b5e 11683do_vec_LDn_single (sim_cpu *cpu, uint64_t address)
2e8cf49e
NC
11684{
11685 /* instr[31] = 0
11686 instr[30] = element selector 0=>half, 1=>all elements
11687 instr[29,24] = 00 1101
11688 instr[23] = 0=>simple, 1=>post
11689 instr[22] = 1
e8f42b5e 11690 instr[21] = width: LD1-or-LD3 (0) / LD2-or-LD4 (1)
2e8cf49e
NC
11691 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
11692 11111 (immediate post inc)
e8f42b5e
JW
11693 instr[15,13] = opcode
11694 instr[12] = S, used for lane number
11695 instr[11,10] = size, also used for lane number
2e8cf49e
NC
11696 instr[9,5] = address
11697 instr[4,0] = Vd */
11698
ef0d8ffc
NC
11699 unsigned full = INSTR (30, 30);
11700 unsigned vd = INSTR (4, 0);
11701 unsigned size = INSTR (11, 10);
e8f42b5e
JW
11702 unsigned s = INSTR (12, 12);
11703 int nregs = ((INSTR (13, 13) << 1) | INSTR (21, 21)) + 1;
11704 int lane = 0;
2e8cf49e
NC
11705 int i;
11706
11707 NYI_assert (29, 24, 0x0D);
11708 NYI_assert (22, 22, 1);
2e8cf49e 11709
e8f42b5e
JW
11710 /* Compute the lane number first (using size), and then compute size. */
11711 LDn_STn_SINGLE_LANE_AND_SIZE ();
2e8cf49e 11712
e8f42b5e
JW
11713 for (i = 0; i < nregs; i++)
11714 switch (size)
11715 {
11716 case 0:
11717 {
11718 uint8_t val = aarch64_get_mem_u8 (cpu, address + i);
11719 aarch64_set_vec_u8 (cpu, vd + i, lane, val);
11720 break;
2e8cf49e 11721 }
2e8cf49e 11722
e8f42b5e 11723 case 1:
2e8cf49e 11724 {
e8f42b5e
JW
11725 uint16_t val = aarch64_get_mem_u16 (cpu, address + (i * 2));
11726 aarch64_set_vec_u16 (cpu, vd + i, lane, val);
11727 break;
11728 }
2e8cf49e 11729
e8f42b5e
JW
11730 case 2:
11731 {
11732 uint32_t val = aarch64_get_mem_u32 (cpu, address + (i * 4));
11733 aarch64_set_vec_u32 (cpu, vd + i, lane, val);
11734 break;
11735 }
2e8cf49e 11736
e8f42b5e
JW
11737 case 3:
11738 {
11739 uint64_t val = aarch64_get_mem_u64 (cpu, address + (i * 8));
11740 aarch64_set_vec_u64 (cpu, vd + i, lane, val);
11741 break;
11742 }
11743 }
11744}
2e8cf49e 11745
e8f42b5e
JW
11746/* Store single structure from one lane from N registers. */
11747static void
11748do_vec_STn_single (sim_cpu *cpu, uint64_t address)
11749{
11750 /* instr[31] = 0
11751 instr[30] = element selector 0=>half, 1=>all elements
11752 instr[29,24] = 00 1101
11753 instr[23] = 0=>simple, 1=>post
11754 instr[22] = 0
11755 instr[21] = width: LD1-or-LD3 (0) / LD2-or-LD4 (1)
11756 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
11757 11111 (immediate post inc)
11758 instr[15,13] = opcode
11759 instr[12] = S, used for lane number
11760 instr[11,10] = size, also used for lane number
11761 instr[9,5] = address
11762 instr[4,0] = Vd */
2e8cf49e 11763
e8f42b5e
JW
11764 unsigned full = INSTR (30, 30);
11765 unsigned vd = INSTR (4, 0);
11766 unsigned size = INSTR (11, 10);
11767 unsigned s = INSTR (12, 12);
11768 int nregs = ((INSTR (13, 13) << 1) | INSTR (21, 21)) + 1;
11769 int lane = 0;
11770 int i;
2e8cf49e 11771
e8f42b5e
JW
11772 NYI_assert (29, 24, 0x0D);
11773 NYI_assert (22, 22, 0);
2e8cf49e 11774
e8f42b5e
JW
11775 /* Compute the lane number first (using size), and then compute size. */
11776 LDn_STn_SINGLE_LANE_AND_SIZE ();
2e8cf49e 11777
e8f42b5e
JW
11778 for (i = 0; i < nregs; i++)
11779 switch (size)
11780 {
11781 case 0:
11782 {
11783 uint8_t val = aarch64_get_vec_u8 (cpu, vd + i, lane);
11784 aarch64_set_mem_u8 (cpu, address + i, val);
11785 break;
2e8cf49e 11786 }
2e8cf49e 11787
e8f42b5e 11788 case 1:
2e8cf49e 11789 {
e8f42b5e
JW
11790 uint16_t val = aarch64_get_vec_u16 (cpu, vd + i, lane);
11791 aarch64_set_mem_u16 (cpu, address + (i * 2), val);
2e8cf49e 11792 break;
e8f42b5e 11793 }
2e8cf49e 11794
e8f42b5e
JW
11795 case 2:
11796 {
11797 uint32_t val = aarch64_get_vec_u32 (cpu, vd + i, lane);
11798 aarch64_set_mem_u32 (cpu, address + (i * 4), val);
2e8cf49e 11799 break;
e8f42b5e 11800 }
2e8cf49e 11801
e8f42b5e
JW
11802 case 3:
11803 {
11804 uint64_t val = aarch64_get_vec_u64 (cpu, vd + i, lane);
11805 aarch64_set_mem_u64 (cpu, address + (i * 8), val);
2e8cf49e 11806 break;
e8f42b5e
JW
11807 }
11808 }
11809}
2e8cf49e 11810
e8f42b5e
JW
11811/* Load single structure into all lanes of N registers. */
11812static void
11813do_vec_LDnR (sim_cpu *cpu, uint64_t address)
11814{
11815 /* instr[31] = 0
11816 instr[30] = element selector 0=>half, 1=>all elements
11817 instr[29,24] = 00 1101
11818 instr[23] = 0=>simple, 1=>post
11819 instr[22] = 1
11820 instr[21] = width: LD1R-or-LD3R (0) / LD2R-or-LD4R (1)
11821 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
11822 11111 (immediate post inc)
11823 instr[15,14] = 11
11824 instr[13] = width: LD1R-or-LD2R (0) / LD3R-or-LD4R (1)
11825 instr[12] = 0
11826 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11827 10=> word(s), 11=> double(d)
11828 instr[9,5] = address
11829 instr[4,0] = Vd */
2e8cf49e 11830
e8f42b5e
JW
11831 unsigned full = INSTR (30, 30);
11832 unsigned vd = INSTR (4, 0);
11833 unsigned size = INSTR (11, 10);
11834 int nregs = ((INSTR (13, 13) << 1) | INSTR (21, 21)) + 1;
11835 int i, n;
2e8cf49e 11836
e8f42b5e
JW
11837 NYI_assert (29, 24, 0x0D);
11838 NYI_assert (22, 22, 1);
11839 NYI_assert (15, 14, 3);
11840 NYI_assert (12, 12, 0);
2e8cf49e 11841
e8f42b5e
JW
11842 for (n = 0; n < nregs; n++)
11843 switch (size)
11844 {
11845 case 0:
2e8cf49e 11846 {
e8f42b5e
JW
11847 uint8_t val = aarch64_get_mem_u8 (cpu, address + n);
11848 for (i = 0; i < (full ? 16 : 8); i++)
11849 aarch64_set_vec_u8 (cpu, vd + n, i, val);
2e8cf49e 11850 break;
e8f42b5e 11851 }
2e8cf49e 11852
e8f42b5e
JW
11853 case 1:
11854 {
11855 uint16_t val = aarch64_get_mem_u16 (cpu, address + (n * 2));
11856 for (i = 0; i < (full ? 8 : 4); i++)
11857 aarch64_set_vec_u16 (cpu, vd + n, i, val);
2e8cf49e 11858 break;
e8f42b5e 11859 }
2e8cf49e 11860
e8f42b5e
JW
11861 case 2:
11862 {
11863 uint32_t val = aarch64_get_mem_u32 (cpu, address + (n * 4));
11864 for (i = 0; i < (full ? 4 : 2); i++)
11865 aarch64_set_vec_u32 (cpu, vd + n, i, val);
2e8cf49e 11866 break;
e8f42b5e 11867 }
2e8cf49e 11868
e8f42b5e
JW
11869 case 3:
11870 {
11871 uint64_t val = aarch64_get_mem_u64 (cpu, address + (n * 8));
11872 for (i = 0; i < (full ? 2 : 1); i++)
11873 aarch64_set_vec_u64 (cpu, vd + n, i, val);
2e8cf49e 11874 break;
2e8cf49e 11875 }
2e8cf49e 11876
e8f42b5e
JW
11877 default:
11878 HALT_UNALLOC;
11879 }
2e8cf49e
NC
11880}
11881
11882static void
11883do_vec_load_store (sim_cpu *cpu)
11884{
11885 /* {LD|ST}<N> {Vd..Vd+N}, vaddr
11886
11887 instr[31] = 0
11888 instr[30] = element selector 0=>half, 1=>all elements
11889 instr[29,25] = 00110
e8f42b5e 11890 instr[24] = 0=>multiple struct, 1=>single struct
2e8cf49e
NC
11891 instr[23] = 0=>simple, 1=>post
11892 instr[22] = 0=>store, 1=>load
11893 instr[21] = 0 (LDn) / small(0)-large(1) selector (LDnR)
11894 instr[20,16] = 00000 (simple), Vinc (reg-post-inc, no SP),
11895 11111 (immediate post inc)
11896 instr[15,12] = elements and destinations. eg for load:
11897 0000=>LD4 => load multiple 4-element to
11898 four consecutive registers
11899 0100=>LD3 => load multiple 3-element to
11900 three consecutive registers
11901 1000=>LD2 => load multiple 2-element to
11902 two consecutive registers
11903 0010=>LD1 => load multiple 1-element to
11904 four consecutive registers
11905 0110=>LD1 => load multiple 1-element to
11906 three consecutive registers
11907 1010=>LD1 => load multiple 1-element to
11908 two consecutive registers
11909 0111=>LD1 => load multiple 1-element to
11910 one register
11911 1100=>LDR1,LDR2
11912 1110=>LDR3,LDR4
11913 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11914 10=> word(s), 11=> double(d)
11915 instr[9,5] = Vn, can be SP
11916 instr[4,0] = Vd */
11917
e8f42b5e 11918 int single;
2e8cf49e
NC
11919 int post;
11920 int load;
11921 unsigned vn;
11922 uint64_t address;
11923 int type;
11924
7517e550 11925 if (INSTR (31, 31) != 0 || INSTR (29, 25) != 0x06)
2e8cf49e
NC
11926 HALT_NYI;
11927
e8f42b5e 11928 single = INSTR (24, 24);
ef0d8ffc
NC
11929 post = INSTR (23, 23);
11930 load = INSTR (22, 22);
e8f42b5e 11931 type = INSTR (15, 12);
ef0d8ffc 11932 vn = INSTR (9, 5);
2e8cf49e
NC
11933 address = aarch64_get_reg_u64 (cpu, vn, SP_OK);
11934
e8f42b5e
JW
11935 if (! single && INSTR (21, 21) != 0)
11936 HALT_UNALLOC;
11937
2e8cf49e
NC
11938 if (post)
11939 {
ef0d8ffc 11940 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
11941
11942 if (vm == R31)
11943 {
11944 unsigned sizeof_operation;
11945
e8f42b5e 11946 if (single)
2e8cf49e 11947 {
e8f42b5e
JW
11948 if ((type >= 0) && (type <= 11))
11949 {
11950 int nregs = ((INSTR (13, 13) << 1) | INSTR (21, 21)) + 1;
11951 switch (INSTR (15, 14))
11952 {
11953 case 0:
11954 sizeof_operation = nregs * 1;
11955 break;
11956 case 1:
11957 sizeof_operation = nregs * 2;
11958 break;
11959 case 2:
11960 if (INSTR (10, 10) == 0)
11961 sizeof_operation = nregs * 4;
11962 else
11963 sizeof_operation = nregs * 8;
11964 break;
11965 default:
11966 HALT_UNALLOC;
11967 }
11968 }
11969 else if (type == 0xC)
11970 {
11971 sizeof_operation = INSTR (21, 21) ? 2 : 1;
11972 sizeof_operation <<= INSTR (11, 10);
11973 }
11974 else if (type == 0xE)
11975 {
11976 sizeof_operation = INSTR (21, 21) ? 4 : 3;
11977 sizeof_operation <<= INSTR (11, 10);
11978 }
11979 else
11980 HALT_UNALLOC;
11981 }
11982 else
11983 {
11984 switch (type)
11985 {
11986 case 0: sizeof_operation = 32; break;
11987 case 4: sizeof_operation = 24; break;
11988 case 8: sizeof_operation = 16; break;
2e8cf49e 11989
e8f42b5e
JW
11990 case 7:
11991 /* One register, immediate offset variant. */
11992 sizeof_operation = 8;
11993 break;
2e8cf49e 11994
e8f42b5e
JW
11995 case 10:
11996 /* Two registers, immediate offset variant. */
11997 sizeof_operation = 16;
11998 break;
ef0d8ffc 11999
e8f42b5e
JW
12000 case 6:
12001 /* Three registers, immediate offset variant. */
12002 sizeof_operation = 24;
12003 break;
57aa1742 12004
e8f42b5e
JW
12005 case 2:
12006 /* Four registers, immediate offset variant. */
12007 sizeof_operation = 32;
12008 break;
57aa1742 12009
e8f42b5e
JW
12010 default:
12011 HALT_UNALLOC;
12012 }
2e8cf49e 12013
e8f42b5e
JW
12014 if (INSTR (30, 30))
12015 sizeof_operation *= 2;
2e8cf49e
NC
12016 }
12017
2e8cf49e
NC
12018 aarch64_set_reg_u64 (cpu, vn, SP_OK, address + sizeof_operation);
12019 }
12020 else
12021 aarch64_set_reg_u64 (cpu, vn, SP_OK,
12022 address + aarch64_get_reg_u64 (cpu, vm, NO_SP));
12023 }
12024 else
12025 {
12026 NYI_assert (20, 16, 0);
12027 }
12028
e8f42b5e
JW
12029 if (single)
12030 {
12031 if (load)
12032 {
12033 if ((type >= 0) && (type <= 11))
12034 do_vec_LDn_single (cpu, address);
12035 else if ((type == 0xC) || (type == 0xE))
12036 do_vec_LDnR (cpu, address);
12037 else
12038 HALT_UNALLOC;
12039 return;
12040 }
12041
12042 /* Stores. */
12043 if ((type >= 0) && (type <= 11))
12044 {
12045 do_vec_STn_single (cpu, address);
12046 return;
12047 }
12048
12049 HALT_UNALLOC;
12050 }
12051
2e8cf49e
NC
12052 if (load)
12053 {
12054 switch (type)
12055 {
12056 case 0: LD4 (cpu, address); return;
12057 case 4: LD3 (cpu, address); return;
12058 case 8: LD2 (cpu, address); return;
12059 case 2: LD1_4 (cpu, address); return;
12060 case 6: LD1_3 (cpu, address); return;
12061 case 10: LD1_2 (cpu, address); return;
12062 case 7: LD1_1 (cpu, address); return;
12063
2e8cf49e 12064 default:
e8f42b5e 12065 HALT_UNALLOC;
2e8cf49e
NC
12066 }
12067 }
12068
12069 /* Stores. */
12070 switch (type)
12071 {
12072 case 0: ST4 (cpu, address); return;
12073 case 4: ST3 (cpu, address); return;
12074 case 8: ST2 (cpu, address); return;
12075 case 2: ST1_4 (cpu, address); return;
12076 case 6: ST1_3 (cpu, address); return;
12077 case 10: ST1_2 (cpu, address); return;
12078 case 7: ST1_1 (cpu, address); return;
12079 default:
e8f42b5e 12080 HALT_UNALLOC;
2e8cf49e
NC
12081 }
12082}
12083
12084static void
12085dexLdSt (sim_cpu *cpu)
12086{
12087 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12088 assert group == GROUP_LDST_0100 || group == GROUP_LDST_0110 ||
12089 group == GROUP_LDST_1100 || group == GROUP_LDST_1110
12090 bits [29,28:26] of a LS are the secondary dispatch vector. */
12091 uint32_t group2 = dispatchLS (aarch64_get_instr (cpu));
12092
12093 switch (group2)
12094 {
12095 case LS_EXCL_000:
12096 dexLoadExclusive (cpu); return;
12097
12098 case LS_LIT_010:
12099 case LS_LIT_011:
12100 dexLoadLiteral (cpu); return;
12101
12102 case LS_OTHER_110:
12103 case LS_OTHER_111:
12104 dexLoadOther (cpu); return;
12105
12106 case LS_ADVSIMD_001:
12107 do_vec_load_store (cpu); return;
12108
12109 case LS_PAIR_100:
12110 dex_load_store_pair_gr (cpu); return;
12111
12112 case LS_PAIR_101:
12113 dex_load_store_pair_fp (cpu); return;
12114
12115 default:
12116 /* Should never reach here. */
12117 HALT_NYI;
12118 }
12119}
12120
12121/* Specific decode and execute for group Data Processing Register. */
12122
12123static void
12124dexLogicalShiftedRegister (sim_cpu *cpu)
12125{
ef0d8ffc
NC
12126 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12127 instr[30,29] = op
12128 instr[28:24] = 01010
2e8cf49e 12129 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> ROR
ef0d8ffc
NC
12130 instr[21] = N
12131 instr[20,16] = Rm
2e8cf49e 12132 instr[15,10] = count : must be 0xxxxx for 32 bit
ef0d8ffc
NC
12133 instr[9,5] = Rn
12134 instr[4,0] = Rd */
2e8cf49e 12135
ef0d8ffc
NC
12136 uint32_t size = INSTR (31, 31);
12137 Shift shiftType = INSTR (23, 22);
12138 uint32_t count = INSTR (15, 10);
2e8cf49e 12139
ef0d8ffc
NC
12140 /* 32 bit operations must have count[5] = 0.
12141 or else we have an UNALLOC. */
12142 if (size == 0 && uimm (count, 5, 5))
2e8cf49e
NC
12143 HALT_UNALLOC;
12144
ef0d8ffc
NC
12145 /* Dispatch on size:op:N. */
12146 switch ((INSTR (31, 29) << 1) | INSTR (21, 21))
2e8cf49e
NC
12147 {
12148 case 0: and32_shift (cpu, shiftType, count); return;
12149 case 1: bic32_shift (cpu, shiftType, count); return;
12150 case 2: orr32_shift (cpu, shiftType, count); return;
12151 case 3: orn32_shift (cpu, shiftType, count); return;
12152 case 4: eor32_shift (cpu, shiftType, count); return;
12153 case 5: eon32_shift (cpu, shiftType, count); return;
12154 case 6: ands32_shift (cpu, shiftType, count); return;
12155 case 7: bics32_shift (cpu, shiftType, count); return;
12156 case 8: and64_shift (cpu, shiftType, count); return;
12157 case 9: bic64_shift (cpu, shiftType, count); return;
12158 case 10:orr64_shift (cpu, shiftType, count); return;
12159 case 11:orn64_shift (cpu, shiftType, count); return;
12160 case 12:eor64_shift (cpu, shiftType, count); return;
12161 case 13:eon64_shift (cpu, shiftType, count); return;
12162 case 14:ands64_shift (cpu, shiftType, count); return;
12163 case 15:bics64_shift (cpu, shiftType, count); return;
2e8cf49e
NC
12164 }
12165}
12166
12167/* 32 bit conditional select. */
12168static void
12169csel32 (sim_cpu *cpu, CondCode cc)
12170{
ef0d8ffc
NC
12171 unsigned rm = INSTR (20, 16);
12172 unsigned rn = INSTR (9, 5);
12173 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12174
12175 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12176 testConditionCode (cpu, cc)
12177 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12178 : aarch64_get_reg_u32 (cpu, rm, NO_SP));
12179}
12180
12181/* 64 bit conditional select. */
12182static void
12183csel64 (sim_cpu *cpu, CondCode cc)
12184{
ef0d8ffc
NC
12185 unsigned rm = INSTR (20, 16);
12186 unsigned rn = INSTR (9, 5);
12187 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12188
12189 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12190 testConditionCode (cpu, cc)
12191 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12192 : aarch64_get_reg_u64 (cpu, rm, NO_SP));
12193}
12194
12195/* 32 bit conditional increment. */
12196static void
12197csinc32 (sim_cpu *cpu, CondCode cc)
12198{
ef0d8ffc
NC
12199 unsigned rm = INSTR (20, 16);
12200 unsigned rn = INSTR (9, 5);
12201 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12202
12203 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12204 testConditionCode (cpu, cc)
12205 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12206 : aarch64_get_reg_u32 (cpu, rm, NO_SP) + 1);
12207}
12208
12209/* 64 bit conditional increment. */
12210static void
12211csinc64 (sim_cpu *cpu, CondCode cc)
12212{
ef0d8ffc
NC
12213 unsigned rm = INSTR (20, 16);
12214 unsigned rn = INSTR (9, 5);
12215 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12216
12217 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12218 testConditionCode (cpu, cc)
12219 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12220 : aarch64_get_reg_u64 (cpu, rm, NO_SP) + 1);
12221}
12222
12223/* 32 bit conditional invert. */
12224static void
12225csinv32 (sim_cpu *cpu, CondCode cc)
12226{
ef0d8ffc
NC
12227 unsigned rm = INSTR (20, 16);
12228 unsigned rn = INSTR (9, 5);
12229 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12230
12231 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12232 testConditionCode (cpu, cc)
12233 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12234 : ~ aarch64_get_reg_u32 (cpu, rm, NO_SP));
12235}
12236
12237/* 64 bit conditional invert. */
12238static void
12239csinv64 (sim_cpu *cpu, CondCode cc)
12240{
ef0d8ffc
NC
12241 unsigned rm = INSTR (20, 16);
12242 unsigned rn = INSTR (9, 5);
12243 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12244
12245 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12246 testConditionCode (cpu, cc)
12247 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12248 : ~ aarch64_get_reg_u64 (cpu, rm, NO_SP));
12249}
12250
12251/* 32 bit conditional negate. */
12252static void
12253csneg32 (sim_cpu *cpu, CondCode cc)
12254{
ef0d8ffc
NC
12255 unsigned rm = INSTR (20, 16);
12256 unsigned rn = INSTR (9, 5);
12257 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12258
12259 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12260 testConditionCode (cpu, cc)
12261 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12262 : - aarch64_get_reg_u32 (cpu, rm, NO_SP));
12263}
12264
12265/* 64 bit conditional negate. */
12266static void
12267csneg64 (sim_cpu *cpu, CondCode cc)
12268{
ef0d8ffc
NC
12269 unsigned rm = INSTR (20, 16);
12270 unsigned rn = INSTR (9, 5);
12271 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12272
12273 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12274 testConditionCode (cpu, cc)
12275 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12276 : - aarch64_get_reg_u64 (cpu, rm, NO_SP));
12277}
12278
12279static void
12280dexCondSelect (sim_cpu *cpu)
12281{
ef0d8ffc
NC
12282 /* instr[28,21] = 11011011
12283 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2e8cf49e
NC
12284 instr[30:11,10] = op : 000 ==> CSEL, 001 ==> CSINC,
12285 100 ==> CSINV, 101 ==> CSNEG,
12286 _1_ ==> UNALLOC
12287 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
12288 instr[15,12] = cond
12289 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC */
12290
ef0d8ffc
NC
12291 CondCode cc = INSTR (15, 12);
12292 uint32_t S = INSTR (29, 29);
12293 uint32_t op2 = INSTR (11, 10);
2e8cf49e
NC
12294
12295 if (S == 1)
12296 HALT_UNALLOC;
12297
12298 if (op2 & 0x2)
12299 HALT_UNALLOC;
12300
ef0d8ffc 12301 switch ((INSTR (31, 30) << 1) | op2)
2e8cf49e
NC
12302 {
12303 case 0: csel32 (cpu, cc); return;
12304 case 1: csinc32 (cpu, cc); return;
12305 case 2: csinv32 (cpu, cc); return;
12306 case 3: csneg32 (cpu, cc); return;
12307 case 4: csel64 (cpu, cc); return;
12308 case 5: csinc64 (cpu, cc); return;
12309 case 6: csinv64 (cpu, cc); return;
12310 case 7: csneg64 (cpu, cc); return;
2e8cf49e
NC
12311 }
12312}
12313
12314/* Some helpers for counting leading 1 or 0 bits. */
12315
12316/* Counts the number of leading bits which are the same
12317 in a 32 bit value in the range 1 to 32. */
12318static uint32_t
12319leading32 (uint32_t value)
12320{
12321 int32_t mask= 0xffff0000;
12322 uint32_t count= 16; /* Counts number of bits set in mask. */
12323 uint32_t lo = 1; /* Lower bound for number of sign bits. */
12324 uint32_t hi = 32; /* Upper bound for number of sign bits. */
12325
12326 while (lo + 1 < hi)
12327 {
12328 int32_t test = (value & mask);
12329
12330 if (test == 0 || test == mask)
12331 {
12332 lo = count;
12333 count = (lo + hi) / 2;
12334 mask >>= (count - lo);
12335 }
12336 else
12337 {
12338 hi = count;
12339 count = (lo + hi) / 2;
12340 mask <<= hi - count;
12341 }
12342 }
12343
12344 if (lo != hi)
12345 {
12346 int32_t test;
12347
12348 mask >>= 1;
12349 test = (value & mask);
12350
12351 if (test == 0 || test == mask)
12352 count = hi;
12353 else
12354 count = lo;
12355 }
12356
12357 return count;
12358}
12359
12360/* Counts the number of leading bits which are the same
12361 in a 64 bit value in the range 1 to 64. */
12362static uint64_t
12363leading64 (uint64_t value)
12364{
12365 int64_t mask= 0xffffffff00000000LL;
12366 uint64_t count = 32; /* Counts number of bits set in mask. */
12367 uint64_t lo = 1; /* Lower bound for number of sign bits. */
12368 uint64_t hi = 64; /* Upper bound for number of sign bits. */
12369
12370 while (lo + 1 < hi)
12371 {
12372 int64_t test = (value & mask);
12373
12374 if (test == 0 || test == mask)
12375 {
12376 lo = count;
12377 count = (lo + hi) / 2;
12378 mask >>= (count - lo);
12379 }
12380 else
12381 {
12382 hi = count;
12383 count = (lo + hi) / 2;
12384 mask <<= hi - count;
12385 }
12386 }
12387
12388 if (lo != hi)
12389 {
12390 int64_t test;
12391
12392 mask >>= 1;
12393 test = (value & mask);
12394
12395 if (test == 0 || test == mask)
12396 count = hi;
12397 else
12398 count = lo;
12399 }
12400
12401 return count;
12402}
12403
12404/* Bit operations. */
12405/* N.B register args may not be SP. */
12406
12407/* 32 bit count leading sign bits. */
12408static void
12409cls32 (sim_cpu *cpu)
12410{
ef0d8ffc
NC
12411 unsigned rn = INSTR (9, 5);
12412 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12413
12414 /* N.B. the result needs to exclude the leading bit. */
12415 aarch64_set_reg_u64
12416 (cpu, rd, NO_SP, leading32 (aarch64_get_reg_u32 (cpu, rn, NO_SP)) - 1);
12417}
12418
12419/* 64 bit count leading sign bits. */
12420static void
12421cls64 (sim_cpu *cpu)
12422{
ef0d8ffc
NC
12423 unsigned rn = INSTR (9, 5);
12424 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12425
12426 /* N.B. the result needs to exclude the leading bit. */
12427 aarch64_set_reg_u64
12428 (cpu, rd, NO_SP, leading64 (aarch64_get_reg_u64 (cpu, rn, NO_SP)) - 1);
12429}
12430
12431/* 32 bit count leading zero bits. */
12432static void
12433clz32 (sim_cpu *cpu)
12434{
ef0d8ffc
NC
12435 unsigned rn = INSTR (9, 5);
12436 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12437 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12438
12439 /* if the sign (top) bit is set then the count is 0. */
12440 if (pick32 (value, 31, 31))
12441 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
12442 else
12443 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading32 (value));
12444}
12445
12446/* 64 bit count leading zero bits. */
12447static void
12448clz64 (sim_cpu *cpu)
12449{
ef0d8ffc
NC
12450 unsigned rn = INSTR (9, 5);
12451 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12452 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12453
12454 /* if the sign (top) bit is set then the count is 0. */
12455 if (pick64 (value, 63, 63))
12456 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
12457 else
12458 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading64 (value));
12459}
12460
12461/* 32 bit reverse bits. */
12462static void
12463rbit32 (sim_cpu *cpu)
12464{
ef0d8ffc
NC
12465 unsigned rn = INSTR (9, 5);
12466 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12467 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12468 uint32_t result = 0;
12469 int i;
12470
12471 for (i = 0; i < 32; i++)
12472 {
12473 result <<= 1;
12474 result |= (value & 1);
12475 value >>= 1;
12476 }
12477 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12478}
12479
12480/* 64 bit reverse bits. */
12481static void
12482rbit64 (sim_cpu *cpu)
12483{
ef0d8ffc
NC
12484 unsigned rn = INSTR (9, 5);
12485 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12486 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12487 uint64_t result = 0;
12488 int i;
12489
12490 for (i = 0; i < 64; i++)
12491 {
12492 result <<= 1;
57aa1742 12493 result |= (value & 1UL);
2e8cf49e
NC
12494 value >>= 1;
12495 }
12496 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12497}
12498
12499/* 32 bit reverse bytes. */
12500static void
12501rev32 (sim_cpu *cpu)
12502{
ef0d8ffc
NC
12503 unsigned rn = INSTR (9, 5);
12504 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12505 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12506 uint32_t result = 0;
12507 int i;
12508
12509 for (i = 0; i < 4; i++)
12510 {
12511 result <<= 8;
12512 result |= (value & 0xff);
12513 value >>= 8;
12514 }
12515 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12516}
12517
12518/* 64 bit reverse bytes. */
12519static void
12520rev64 (sim_cpu *cpu)
12521{
ef0d8ffc
NC
12522 unsigned rn = INSTR (9, 5);
12523 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12524 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12525 uint64_t result = 0;
12526 int i;
12527
12528 for (i = 0; i < 8; i++)
12529 {
12530 result <<= 8;
12531 result |= (value & 0xffULL);
12532 value >>= 8;
12533 }
12534 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12535}
12536
12537/* 32 bit reverse shorts. */
12538/* N.B.this reverses the order of the bytes in each half word. */
12539static void
12540revh32 (sim_cpu *cpu)
12541{
ef0d8ffc
NC
12542 unsigned rn = INSTR (9, 5);
12543 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12544 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12545 uint32_t result = 0;
12546 int i;
12547
12548 for (i = 0; i < 2; i++)
12549 {
12550 result <<= 8;
12551 result |= (value & 0x00ff00ff);
12552 value >>= 8;
12553 }
12554 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12555}
12556
12557/* 64 bit reverse shorts. */
12558/* N.B.this reverses the order of the bytes in each half word. */
12559static void
12560revh64 (sim_cpu *cpu)
12561{
ef0d8ffc
NC
12562 unsigned rn = INSTR (9, 5);
12563 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12564 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12565 uint64_t result = 0;
12566 int i;
12567
12568 for (i = 0; i < 2; i++)
12569 {
12570 result <<= 8;
12571 result |= (value & 0x00ff00ff00ff00ffULL);
12572 value >>= 8;
12573 }
12574 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12575}
12576
12577static void
12578dexDataProc1Source (sim_cpu *cpu)
12579{
ef0d8ffc
NC
12580 /* instr[30] = 1
12581 instr[28,21] = 111010110
12582 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12583 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
2e8cf49e
NC
12584 instr[20,16] = opcode2 : 00000 ==> ok, ow ==> UNALLOC
12585 instr[15,10] = opcode : 000000 ==> RBIT, 000001 ==> REV16,
12586 000010 ==> REV, 000011 ==> UNALLOC
12587 000100 ==> CLZ, 000101 ==> CLS
12588 ow ==> UNALLOC
ef0d8ffc
NC
12589 instr[9,5] = rn : may not be SP
12590 instr[4,0] = rd : may not be SP. */
2e8cf49e 12591
ef0d8ffc
NC
12592 uint32_t S = INSTR (29, 29);
12593 uint32_t opcode2 = INSTR (20, 16);
12594 uint32_t opcode = INSTR (15, 10);
12595 uint32_t dispatch = ((INSTR (31, 31) << 3) | opcode);
2e8cf49e
NC
12596
12597 if (S == 1)
12598 HALT_UNALLOC;
12599
12600 if (opcode2 != 0)
12601 HALT_UNALLOC;
12602
12603 if (opcode & 0x38)
12604 HALT_UNALLOC;
12605
12606 switch (dispatch)
12607 {
12608 case 0: rbit32 (cpu); return;
12609 case 1: revh32 (cpu); return;
12610 case 2: rev32 (cpu); return;
12611 case 4: clz32 (cpu); return;
12612 case 5: cls32 (cpu); return;
12613 case 8: rbit64 (cpu); return;
12614 case 9: revh64 (cpu); return;
12615 case 10:rev32 (cpu); return;
12616 case 11:rev64 (cpu); return;
12617 case 12:clz64 (cpu); return;
12618 case 13:cls64 (cpu); return;
12619 default: HALT_UNALLOC;
12620 }
12621}
12622
12623/* Variable shift.
12624 Shifts by count supplied in register.
12625 N.B register args may not be SP.
12626 These all use the shifted auxiliary function for
12627 simplicity and clarity. Writing the actual shift
12628 inline would avoid a branch and so be faster but
12629 would also necessitate getting signs right. */
12630
12631/* 32 bit arithmetic shift right. */
12632static void
12633asrv32 (sim_cpu *cpu)
12634{
ef0d8ffc
NC
12635 unsigned rm = INSTR (20, 16);
12636 unsigned rn = INSTR (9, 5);
12637 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12638
12639 aarch64_set_reg_u64
12640 (cpu, rd, NO_SP,
12641 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ASR,
12642 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12643}
12644
12645/* 64 bit arithmetic shift right. */
12646static void
12647asrv64 (sim_cpu *cpu)
12648{
ef0d8ffc
NC
12649 unsigned rm = INSTR (20, 16);
12650 unsigned rn = INSTR (9, 5);
12651 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12652
12653 aarch64_set_reg_u64
12654 (cpu, rd, NO_SP,
12655 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ASR,
12656 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12657}
12658
12659/* 32 bit logical shift left. */
12660static void
12661lslv32 (sim_cpu *cpu)
12662{
ef0d8ffc
NC
12663 unsigned rm = INSTR (20, 16);
12664 unsigned rn = INSTR (9, 5);
12665 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12666
12667 aarch64_set_reg_u64
12668 (cpu, rd, NO_SP,
12669 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSL,
12670 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12671}
12672
12673/* 64 bit arithmetic shift left. */
12674static void
12675lslv64 (sim_cpu *cpu)
12676{
ef0d8ffc
NC
12677 unsigned rm = INSTR (20, 16);
12678 unsigned rn = INSTR (9, 5);
12679 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12680
12681 aarch64_set_reg_u64
12682 (cpu, rd, NO_SP,
12683 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSL,
12684 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12685}
12686
12687/* 32 bit logical shift right. */
12688static void
12689lsrv32 (sim_cpu *cpu)
12690{
ef0d8ffc
NC
12691 unsigned rm = INSTR (20, 16);
12692 unsigned rn = INSTR (9, 5);
12693 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12694
12695 aarch64_set_reg_u64
12696 (cpu, rd, NO_SP,
12697 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSR,
12698 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12699}
12700
12701/* 64 bit logical shift right. */
12702static void
12703lsrv64 (sim_cpu *cpu)
12704{
ef0d8ffc
NC
12705 unsigned rm = INSTR (20, 16);
12706 unsigned rn = INSTR (9, 5);
12707 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12708
12709 aarch64_set_reg_u64
12710 (cpu, rd, NO_SP,
12711 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSR,
12712 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12713}
12714
12715/* 32 bit rotate right. */
12716static void
12717rorv32 (sim_cpu *cpu)
12718{
ef0d8ffc
NC
12719 unsigned rm = INSTR (20, 16);
12720 unsigned rn = INSTR (9, 5);
12721 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12722
12723 aarch64_set_reg_u64
12724 (cpu, rd, NO_SP,
12725 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ROR,
12726 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12727}
12728
12729/* 64 bit rotate right. */
12730static void
12731rorv64 (sim_cpu *cpu)
12732{
ef0d8ffc
NC
12733 unsigned rm = INSTR (20, 16);
12734 unsigned rn = INSTR (9, 5);
12735 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12736
12737 aarch64_set_reg_u64
12738 (cpu, rd, NO_SP,
12739 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ROR,
12740 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12741}
12742
12743
12744/* divide. */
12745
12746/* 32 bit signed divide. */
12747static void
12748cpuiv32 (sim_cpu *cpu)
12749{
ef0d8ffc
NC
12750 unsigned rm = INSTR (20, 16);
12751 unsigned rn = INSTR (9, 5);
12752 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12753 /* N.B. the pseudo-code does the divide using 64 bit data. */
12754 /* TODO : check that this rounds towards zero as required. */
12755 int64_t dividend = aarch64_get_reg_s32 (cpu, rn, NO_SP);
12756 int64_t divisor = aarch64_get_reg_s32 (cpu, rm, NO_SP);
12757
12758 aarch64_set_reg_s64 (cpu, rd, NO_SP,
12759 divisor ? ((int32_t) (dividend / divisor)) : 0);
12760}
12761
12762/* 64 bit signed divide. */
12763static void
12764cpuiv64 (sim_cpu *cpu)
12765{
ef0d8ffc
NC
12766 unsigned rm = INSTR (20, 16);
12767 unsigned rn = INSTR (9, 5);
12768 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12769
12770 /* TODO : check that this rounds towards zero as required. */
12771 int64_t divisor = aarch64_get_reg_s64 (cpu, rm, NO_SP);
12772
12773 aarch64_set_reg_s64
12774 (cpu, rd, NO_SP,
12775 divisor ? (aarch64_get_reg_s64 (cpu, rn, NO_SP) / divisor) : 0);
12776}
12777
12778/* 32 bit unsigned divide. */
12779static void
12780udiv32 (sim_cpu *cpu)
12781{
ef0d8ffc
NC
12782 unsigned rm = INSTR (20, 16);
12783 unsigned rn = INSTR (9, 5);
12784 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12785
12786 /* N.B. the pseudo-code does the divide using 64 bit data. */
12787 uint64_t dividend = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12788 uint64_t divisor = aarch64_get_reg_u32 (cpu, rm, NO_SP);
12789
12790 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12791 divisor ? (uint32_t) (dividend / divisor) : 0);
12792}
12793
12794/* 64 bit unsigned divide. */
12795static void
12796udiv64 (sim_cpu *cpu)
12797{
ef0d8ffc
NC
12798 unsigned rm = INSTR (20, 16);
12799 unsigned rn = INSTR (9, 5);
12800 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12801
12802 /* TODO : check that this rounds towards zero as required. */
12803 uint64_t divisor = aarch64_get_reg_u64 (cpu, rm, NO_SP);
12804
12805 aarch64_set_reg_u64
12806 (cpu, rd, NO_SP,
12807 divisor ? (aarch64_get_reg_u64 (cpu, rn, NO_SP) / divisor) : 0);
12808}
12809
12810static void
12811dexDataProc2Source (sim_cpu *cpu)
12812{
12813 /* assert instr[30] == 0
12814 instr[28,21] == 11010110
12815 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12816 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
12817 instr[15,10] = opcode : 000010 ==> UDIV, 000011 ==> CPUIV,
12818 001000 ==> LSLV, 001001 ==> LSRV
12819 001010 ==> ASRV, 001011 ==> RORV
12820 ow ==> UNALLOC. */
12821
12822 uint32_t dispatch;
ef0d8ffc
NC
12823 uint32_t S = INSTR (29, 29);
12824 uint32_t opcode = INSTR (15, 10);
2e8cf49e
NC
12825
12826 if (S == 1)
12827 HALT_UNALLOC;
12828
12829 if (opcode & 0x34)
12830 HALT_UNALLOC;
12831
ef0d8ffc 12832 dispatch = ( (INSTR (31, 31) << 3)
2e8cf49e
NC
12833 | (uimm (opcode, 3, 3) << 2)
12834 | uimm (opcode, 1, 0));
12835 switch (dispatch)
12836 {
12837 case 2: udiv32 (cpu); return;
12838 case 3: cpuiv32 (cpu); return;
12839 case 4: lslv32 (cpu); return;
12840 case 5: lsrv32 (cpu); return;
12841 case 6: asrv32 (cpu); return;
12842 case 7: rorv32 (cpu); return;
12843 case 10: udiv64 (cpu); return;
12844 case 11: cpuiv64 (cpu); return;
12845 case 12: lslv64 (cpu); return;
12846 case 13: lsrv64 (cpu); return;
12847 case 14: asrv64 (cpu); return;
12848 case 15: rorv64 (cpu); return;
12849 default: HALT_UNALLOC;
12850 }
12851}
12852
12853
12854/* Multiply. */
12855
12856/* 32 bit multiply and add. */
12857static void
12858madd32 (sim_cpu *cpu)
12859{
ef0d8ffc
NC
12860 unsigned rm = INSTR (20, 16);
12861 unsigned ra = INSTR (14, 10);
12862 unsigned rn = INSTR (9, 5);
12863 unsigned rd = INSTR (4, 0);
2e8cf49e 12864
2cdad34c 12865 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12866 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12867 aarch64_get_reg_u32 (cpu, ra, NO_SP)
12868 + aarch64_get_reg_u32 (cpu, rn, NO_SP)
12869 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
12870}
12871
12872/* 64 bit multiply and add. */
12873static void
12874madd64 (sim_cpu *cpu)
12875{
ef0d8ffc
NC
12876 unsigned rm = INSTR (20, 16);
12877 unsigned ra = INSTR (14, 10);
12878 unsigned rn = INSTR (9, 5);
12879 unsigned rd = INSTR (4, 0);
2e8cf49e 12880
2cdad34c 12881 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12882 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12883 aarch64_get_reg_u64 (cpu, ra, NO_SP)
2cdad34c
NC
12884 + (aarch64_get_reg_u64 (cpu, rn, NO_SP)
12885 * aarch64_get_reg_u64 (cpu, rm, NO_SP)));
2e8cf49e
NC
12886}
12887
12888/* 32 bit multiply and sub. */
12889static void
12890msub32 (sim_cpu *cpu)
12891{
ef0d8ffc
NC
12892 unsigned rm = INSTR (20, 16);
12893 unsigned ra = INSTR (14, 10);
12894 unsigned rn = INSTR (9, 5);
12895 unsigned rd = INSTR (4, 0);
2e8cf49e 12896
2cdad34c 12897 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12898 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12899 aarch64_get_reg_u32 (cpu, ra, NO_SP)
12900 - aarch64_get_reg_u32 (cpu, rn, NO_SP)
12901 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
12902}
12903
12904/* 64 bit multiply and sub. */
12905static void
12906msub64 (sim_cpu *cpu)
12907{
ef0d8ffc
NC
12908 unsigned rm = INSTR (20, 16);
12909 unsigned ra = INSTR (14, 10);
12910 unsigned rn = INSTR (9, 5);
12911 unsigned rd = INSTR (4, 0);
2e8cf49e 12912
2cdad34c 12913 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12914 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12915 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12916 - aarch64_get_reg_u64 (cpu, rn, NO_SP)
12917 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
12918}
12919
12920/* Signed multiply add long -- source, source2 : 32 bit, source3 : 64 bit. */
12921static void
12922smaddl (sim_cpu *cpu)
12923{
ef0d8ffc
NC
12924 unsigned rm = INSTR (20, 16);
12925 unsigned ra = INSTR (14, 10);
12926 unsigned rn = INSTR (9, 5);
12927 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12928
12929 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12930 obtain a 64 bit product. */
12931 aarch64_set_reg_s64
12932 (cpu, rd, NO_SP,
12933 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12934 + ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12935 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12936}
12937
12938/* Signed multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12939static void
12940smsubl (sim_cpu *cpu)
12941{
ef0d8ffc
NC
12942 unsigned rm = INSTR (20, 16);
12943 unsigned ra = INSTR (14, 10);
12944 unsigned rn = INSTR (9, 5);
12945 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12946
12947 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12948 obtain a 64 bit product. */
12949 aarch64_set_reg_s64
12950 (cpu, rd, NO_SP,
12951 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12952 - ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12953 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12954}
12955
12956/* Integer Multiply/Divide. */
12957
12958/* First some macros and a helper function. */
12959/* Macros to test or access elements of 64 bit words. */
12960
12961/* Mask used to access lo 32 bits of 64 bit unsigned int. */
12962#define LOW_WORD_MASK ((1ULL << 32) - 1)
12963/* Return the lo 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12964#define lowWordToU64(_value_u64) ((_value_u64) & LOW_WORD_MASK)
12965/* Return the hi 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12966#define highWordToU64(_value_u64) ((_value_u64) >> 32)
12967
12968/* Offset of sign bit in 64 bit signed integger. */
12969#define SIGN_SHIFT_U64 63
12970/* The sign bit itself -- also identifies the minimum negative int value. */
12971#define SIGN_BIT_U64 (1UL << SIGN_SHIFT_U64)
12972/* Return true if a 64 bit signed int presented as an unsigned int is the
12973 most negative value. */
12974#define isMinimumU64(_value_u64) ((_value_u64) == SIGN_BIT_U64)
12975/* Return true (non-zero) if a 64 bit signed int presented as an unsigned
12976 int has its sign bit set to false. */
12977#define isSignSetU64(_value_u64) ((_value_u64) & SIGN_BIT_U64)
12978/* Return 1L or -1L according to whether a 64 bit signed int presented as
12979 an unsigned int has its sign bit set or not. */
12980#define signOfU64(_value_u64) (1L + (((value_u64) >> SIGN_SHIFT_U64) * -2L)
12981/* Clear the sign bit of a 64 bit signed int presented as an unsigned int. */
12982#define clearSignU64(_value_u64) ((_value_u64) &= ~SIGN_BIT_U64)
12983
12984/* Multiply two 64 bit ints and return.
12985 the hi 64 bits of the 128 bit product. */
12986
12987static uint64_t
12988mul64hi (uint64_t value1, uint64_t value2)
12989{
12990 uint64_t resultmid1;
12991 uint64_t result;
12992 uint64_t value1_lo = lowWordToU64 (value1);
12993 uint64_t value1_hi = highWordToU64 (value1) ;
12994 uint64_t value2_lo = lowWordToU64 (value2);
12995 uint64_t value2_hi = highWordToU64 (value2);
12996
12997 /* Cross-multiply and collect results. */
2e8cf49e
NC
12998 uint64_t xproductlo = value1_lo * value2_lo;
12999 uint64_t xproductmid1 = value1_lo * value2_hi;
13000 uint64_t xproductmid2 = value1_hi * value2_lo;
13001 uint64_t xproducthi = value1_hi * value2_hi;
13002 uint64_t carry = 0;
13003 /* Start accumulating 64 bit results. */
13004 /* Drop bottom half of lowest cross-product. */
13005 uint64_t resultmid = xproductlo >> 32;
13006 /* Add in middle products. */
13007 resultmid = resultmid + xproductmid1;
13008
13009 /* Check for overflow. */
13010 if (resultmid < xproductmid1)
13011 /* Carry over 1 into top cross-product. */
13012 carry++;
13013
13014 resultmid1 = resultmid + xproductmid2;
13015
13016 /* Check for overflow. */
13017 if (resultmid1 < xproductmid2)
13018 /* Carry over 1 into top cross-product. */
13019 carry++;
13020
13021 /* Drop lowest 32 bits of middle cross-product. */
13022 result = resultmid1 >> 32;
8ecbe595
JW
13023 /* Move carry bit to just above middle cross-product highest bit. */
13024 carry = carry << 32;
2e8cf49e
NC
13025
13026 /* Add top cross-product plus and any carry. */
13027 result += xproducthi + carry;
13028
13029 return result;
13030}
13031
13032/* Signed multiply high, source, source2 :
13033 64 bit, dest <-- high 64-bit of result. */
13034static void
13035smulh (sim_cpu *cpu)
13036{
13037 uint64_t uresult;
ef0d8ffc
NC
13038 int64_t result;
13039 unsigned rm = INSTR (20, 16);
13040 unsigned rn = INSTR (9, 5);
13041 unsigned rd = INSTR (4, 0);
13042 GReg ra = INSTR (14, 10);
13043 int64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
13044 int64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2e8cf49e
NC
13045 uint64_t uvalue1;
13046 uint64_t uvalue2;
8ecbe595 13047 int negate = 0;
2e8cf49e
NC
13048
13049 if (ra != R31)
13050 HALT_UNALLOC;
13051
13052 /* Convert to unsigned and use the unsigned mul64hi routine
13053 the fix the sign up afterwards. */
13054 if (value1 < 0)
13055 {
8ecbe595 13056 negate = !negate;
2e8cf49e
NC
13057 uvalue1 = -value1;
13058 }
13059 else
13060 {
13061 uvalue1 = value1;
13062 }
13063
13064 if (value2 < 0)
13065 {
8ecbe595 13066 negate = !negate;
2e8cf49e
NC
13067 uvalue2 = -value2;
13068 }
13069 else
13070 {
13071 uvalue2 = value2;
13072 }
13073
2cdad34c 13074 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
8ecbe595 13075
2e8cf49e
NC
13076 uresult = mul64hi (uvalue1, uvalue2);
13077 result = uresult;
8ecbe595
JW
13078
13079 if (negate)
13080 {
13081 /* Multiply 128-bit result by -1, which means highpart gets inverted,
13082 and has carry in added only if low part is 0. */
13083 result = ~result;
13084 if ((uvalue1 * uvalue2) == 0)
13085 result += 1;
13086 }
2e8cf49e
NC
13087
13088 aarch64_set_reg_s64 (cpu, rd, NO_SP, result);
13089}
13090
13091/* Unsigned multiply add long -- source, source2 :
13092 32 bit, source3 : 64 bit. */
13093static void
13094umaddl (sim_cpu *cpu)
13095{
ef0d8ffc
NC
13096 unsigned rm = INSTR (20, 16);
13097 unsigned ra = INSTR (14, 10);
13098 unsigned rn = INSTR (9, 5);
13099 unsigned rd = INSTR (4, 0);
2e8cf49e 13100
2cdad34c 13101 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13102 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
13103 obtain a 64 bit product. */
13104 aarch64_set_reg_u64
13105 (cpu, rd, NO_SP,
13106 aarch64_get_reg_u64 (cpu, ra, NO_SP)
13107 + ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
13108 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
13109}
13110
13111/* Unsigned multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
13112static void
13113umsubl (sim_cpu *cpu)
13114{
ef0d8ffc
NC
13115 unsigned rm = INSTR (20, 16);
13116 unsigned ra = INSTR (14, 10);
13117 unsigned rn = INSTR (9, 5);
13118 unsigned rd = INSTR (4, 0);
2e8cf49e 13119
2cdad34c 13120 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13121 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
13122 obtain a 64 bit product. */
13123 aarch64_set_reg_u64
13124 (cpu, rd, NO_SP,
13125 aarch64_get_reg_u64 (cpu, ra, NO_SP)
13126 - ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
13127 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
13128}
13129
13130/* Unsigned multiply high, source, source2 :
13131 64 bit, dest <-- high 64-bit of result. */
13132static void
13133umulh (sim_cpu *cpu)
13134{
ef0d8ffc
NC
13135 unsigned rm = INSTR (20, 16);
13136 unsigned rn = INSTR (9, 5);
13137 unsigned rd = INSTR (4, 0);
13138 GReg ra = INSTR (14, 10);
2e8cf49e
NC
13139
13140 if (ra != R31)
13141 HALT_UNALLOC;
13142
2cdad34c 13143 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13144 aarch64_set_reg_u64 (cpu, rd, NO_SP,
13145 mul64hi (aarch64_get_reg_u64 (cpu, rn, NO_SP),
13146 aarch64_get_reg_u64 (cpu, rm, NO_SP)));
13147}
13148
13149static void
13150dexDataProc3Source (sim_cpu *cpu)
13151{
13152 /* assert instr[28,24] == 11011. */
13153 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit (for rd at least)
13154 instr[30,29] = op54 : 00 ==> ok, ow ==> UNALLOC
13155 instr[23,21] = op31 : 111 ==> UNALLOC, o2 ==> ok
13156 instr[15] = o0 : 0/1 ==> ok
13157 instr[23,21:15] ==> op : 0000 ==> MADD, 0001 ==> MSUB, (32/64 bit)
13158 0010 ==> SMADDL, 0011 ==> SMSUBL, (64 bit only)
13159 0100 ==> SMULH, (64 bit only)
13160 1010 ==> UMADDL, 1011 ==> UNSUBL, (64 bit only)
13161 1100 ==> UMULH (64 bit only)
13162 ow ==> UNALLOC. */
13163
13164 uint32_t dispatch;
ef0d8ffc
NC
13165 uint32_t size = INSTR (31, 31);
13166 uint32_t op54 = INSTR (30, 29);
13167 uint32_t op31 = INSTR (23, 21);
13168 uint32_t o0 = INSTR (15, 15);
2e8cf49e
NC
13169
13170 if (op54 != 0)
13171 HALT_UNALLOC;
13172
13173 if (size == 0)
13174 {
13175 if (op31 != 0)
13176 HALT_UNALLOC;
13177
13178 if (o0 == 0)
13179 madd32 (cpu);
13180 else
13181 msub32 (cpu);
13182 return;
13183 }
13184
13185 dispatch = (op31 << 1) | o0;
13186
13187 switch (dispatch)
13188 {
13189 case 0: madd64 (cpu); return;
13190 case 1: msub64 (cpu); return;
13191 case 2: smaddl (cpu); return;
13192 case 3: smsubl (cpu); return;
13193 case 4: smulh (cpu); return;
13194 case 10: umaddl (cpu); return;
13195 case 11: umsubl (cpu); return;
13196 case 12: umulh (cpu); return;
13197 default: HALT_UNALLOC;
13198 }
13199}
13200
13201static void
13202dexDPReg (sim_cpu *cpu)
13203{
13204 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
13205 assert group == GROUP_DPREG_0101 || group == GROUP_DPREG_1101
13206 bits [28:24:21] of a DPReg are the secondary dispatch vector. */
13207 uint32_t group2 = dispatchDPReg (aarch64_get_instr (cpu));
13208
13209 switch (group2)
13210 {
13211 case DPREG_LOG_000:
13212 case DPREG_LOG_001:
13213 dexLogicalShiftedRegister (cpu); return;
13214
13215 case DPREG_ADDSHF_010:
13216 dexAddSubtractShiftedRegister (cpu); return;
13217
13218 case DPREG_ADDEXT_011:
13219 dexAddSubtractExtendedRegister (cpu); return;
13220
13221 case DPREG_ADDCOND_100:
13222 {
13223 /* This set bundles a variety of different operations. */
13224 /* Check for. */
13225 /* 1) add/sub w carry. */
13226 uint32_t mask1 = 0x1FE00000U;
13227 uint32_t val1 = 0x1A000000U;
13228 /* 2) cond compare register/immediate. */
13229 uint32_t mask2 = 0x1FE00000U;
13230 uint32_t val2 = 0x1A400000U;
13231 /* 3) cond select. */
13232 uint32_t mask3 = 0x1FE00000U;
13233 uint32_t val3 = 0x1A800000U;
13234 /* 4) data proc 1/2 source. */
13235 uint32_t mask4 = 0x1FE00000U;
13236 uint32_t val4 = 0x1AC00000U;
13237
13238 if ((aarch64_get_instr (cpu) & mask1) == val1)
13239 dexAddSubtractWithCarry (cpu);
13240
13241 else if ((aarch64_get_instr (cpu) & mask2) == val2)
13242 CondCompare (cpu);
13243
13244 else if ((aarch64_get_instr (cpu) & mask3) == val3)
13245 dexCondSelect (cpu);
13246
13247 else if ((aarch64_get_instr (cpu) & mask4) == val4)
13248 {
13249 /* Bit 30 is clear for data proc 2 source
13250 and set for data proc 1 source. */
13251 if (aarch64_get_instr (cpu) & (1U << 30))
13252 dexDataProc1Source (cpu);
13253 else
13254 dexDataProc2Source (cpu);
13255 }
13256
13257 else
13258 /* Should not reach here. */
13259 HALT_NYI;
13260
13261 return;
13262 }
13263
13264 case DPREG_3SRC_110:
13265 dexDataProc3Source (cpu); return;
13266
13267 case DPREG_UNALLOC_101:
13268 HALT_UNALLOC;
13269
13270 case DPREG_3SRC_111:
13271 dexDataProc3Source (cpu); return;
13272
13273 default:
13274 /* Should never reach here. */
13275 HALT_NYI;
13276 }
13277}
13278
13279/* Unconditional Branch immediate.
13280 Offset is a PC-relative byte offset in the range +/- 128MiB.
13281 The offset is assumed to be raw from the decode i.e. the
13282 simulator is expected to scale them from word offsets to byte. */
13283
13284/* Unconditional branch. */
13285static void
13286buc (sim_cpu *cpu, int32_t offset)
13287{
13288 aarch64_set_next_PC_by_offset (cpu, offset);
13289}
13290
13291static unsigned stack_depth = 0;
13292
13293/* Unconditional branch and link -- writes return PC to LR. */
13294static void
13295bl (sim_cpu *cpu, int32_t offset)
13296{
2cdad34c 13297 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13298 aarch64_save_LR (cpu);
13299 aarch64_set_next_PC_by_offset (cpu, offset);
13300
13301 if (TRACE_BRANCH_P (cpu))
13302 {
13303 ++ stack_depth;
13304 TRACE_BRANCH (cpu,
13305 " %*scall %" PRIx64 " [%s]"
13306 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
13307 stack_depth, " ", aarch64_get_next_PC (cpu),
5357150c
MF
13308 aarch64_get_func (CPU_STATE (cpu),
13309 aarch64_get_next_PC (cpu)),
2e8cf49e
NC
13310 aarch64_get_reg_u64 (cpu, 0, NO_SP),
13311 aarch64_get_reg_u64 (cpu, 1, NO_SP),
13312 aarch64_get_reg_u64 (cpu, 2, NO_SP)
13313 );
13314 }
13315}
13316
13317/* Unconditional Branch register.
13318 Branch/return address is in source register. */
13319
13320/* Unconditional branch. */
13321static void
13322br (sim_cpu *cpu)
13323{
ef0d8ffc 13324 unsigned rn = INSTR (9, 5);
2cdad34c 13325 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13326 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13327}
13328
13329/* Unconditional branch and link -- writes return PC to LR. */
13330static void
13331blr (sim_cpu *cpu)
13332{
ef0d8ffc 13333 unsigned rn = INSTR (9, 5);
2e8cf49e 13334
2cdad34c 13335 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13336 /* The pseudo code in the spec says we update LR before fetching.
13337 the value from the rn. */
13338 aarch64_save_LR (cpu);
13339 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13340
13341 if (TRACE_BRANCH_P (cpu))
13342 {
13343 ++ stack_depth;
13344 TRACE_BRANCH (cpu,
13345 " %*scall %" PRIx64 " [%s]"
13346 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
13347 stack_depth, " ", aarch64_get_next_PC (cpu),
5357150c
MF
13348 aarch64_get_func (CPU_STATE (cpu),
13349 aarch64_get_next_PC (cpu)),
2e8cf49e
NC
13350 aarch64_get_reg_u64 (cpu, 0, NO_SP),
13351 aarch64_get_reg_u64 (cpu, 1, NO_SP),
13352 aarch64_get_reg_u64 (cpu, 2, NO_SP)
13353 );
13354 }
13355}
13356
13357/* Return -- assembler will default source to LR this is functionally
13358 equivalent to br but, presumably, unlike br it side effects the
13359 branch predictor. */
13360static void
13361ret (sim_cpu *cpu)
13362{
ef0d8ffc 13363 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
13364 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13365
2cdad34c 13366 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13367 if (TRACE_BRANCH_P (cpu))
13368 {
13369 TRACE_BRANCH (cpu,
13370 " %*sreturn [result: %" PRIx64 "]",
13371 stack_depth, " ", aarch64_get_reg_u64 (cpu, 0, NO_SP));
13372 -- stack_depth;
13373 }
13374}
13375
13376/* NOP -- we implement this and call it from the decode in case we
13377 want to intercept it later. */
13378
13379static void
13380nop (sim_cpu *cpu)
13381{
2cdad34c 13382 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13383}
13384
13385/* Data synchronization barrier. */
13386
13387static void
13388dsb (sim_cpu *cpu)
13389{
2cdad34c 13390 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13391}
13392
13393/* Data memory barrier. */
13394
13395static void
13396dmb (sim_cpu *cpu)
13397{
2cdad34c 13398 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13399}
13400
13401/* Instruction synchronization barrier. */
13402
13403static void
13404isb (sim_cpu *cpu)
13405{
2cdad34c 13406 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13407}
13408
13409static void
13410dexBranchImmediate (sim_cpu *cpu)
13411{
13412 /* assert instr[30,26] == 00101
13413 instr[31] ==> 0 == B, 1 == BL
13414 instr[25,0] == imm26 branch offset counted in words. */
13415
ef0d8ffc 13416 uint32_t top = INSTR (31, 31);
2e8cf49e
NC
13417 /* We have a 26 byte signed word offset which we need to pass to the
13418 execute routine as a signed byte offset. */
13419 int32_t offset = simm32 (aarch64_get_instr (cpu), 25, 0) << 2;
13420
13421 if (top)
13422 bl (cpu, offset);
13423 else
13424 buc (cpu, offset);
13425}
13426
13427/* Control Flow. */
13428
13429/* Conditional branch
13430
13431 Offset is a PC-relative byte offset in the range +/- 1MiB pos is
13432 a bit position in the range 0 .. 63
13433
13434 cc is a CondCode enum value as pulled out of the decode
13435
13436 N.B. any offset register (source) can only be Xn or Wn. */
13437
13438static void
13439bcc (sim_cpu *cpu, int32_t offset, CondCode cc)
13440{
2cdad34c
NC
13441 /* The test returns TRUE if CC is met. */
13442 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13443 if (testConditionCode (cpu, cc))
13444 aarch64_set_next_PC_by_offset (cpu, offset);
13445}
13446
13447/* 32 bit branch on register non-zero. */
13448static void
13449cbnz32 (sim_cpu *cpu, int32_t offset)
13450{
ef0d8ffc 13451 unsigned rt = INSTR (4, 0);
2e8cf49e 13452
2cdad34c 13453 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13454 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) != 0)
13455 aarch64_set_next_PC_by_offset (cpu, offset);
13456}
13457
13458/* 64 bit branch on register zero. */
13459static void
13460cbnz (sim_cpu *cpu, int32_t offset)
13461{
ef0d8ffc 13462 unsigned rt = INSTR (4, 0);
2e8cf49e 13463
2cdad34c 13464 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13465 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) != 0)
13466 aarch64_set_next_PC_by_offset (cpu, offset);
13467}
13468
13469/* 32 bit branch on register non-zero. */
13470static void
13471cbz32 (sim_cpu *cpu, int32_t offset)
13472{
ef0d8ffc 13473 unsigned rt = INSTR (4, 0);
2e8cf49e 13474
2cdad34c 13475 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13476 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) == 0)
13477 aarch64_set_next_PC_by_offset (cpu, offset);
13478}
13479
13480/* 64 bit branch on register zero. */
13481static void
13482cbz (sim_cpu *cpu, int32_t offset)
13483{
ef0d8ffc 13484 unsigned rt = INSTR (4, 0);
2e8cf49e 13485
2cdad34c 13486 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13487 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) == 0)
13488 aarch64_set_next_PC_by_offset (cpu, offset);
13489}
13490
13491/* Branch on register bit test non-zero -- one size fits all. */
13492static void
13493tbnz (sim_cpu *cpu, uint32_t pos, int32_t offset)
13494{
ef0d8ffc 13495 unsigned rt = INSTR (4, 0);
2e8cf49e 13496
2cdad34c 13497 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
668650d5 13498 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) & (((uint64_t) 1) << pos))
2e8cf49e
NC
13499 aarch64_set_next_PC_by_offset (cpu, offset);
13500}
13501
2cdad34c 13502/* Branch on register bit test zero -- one size fits all. */
2e8cf49e
NC
13503static void
13504tbz (sim_cpu *cpu, uint32_t pos, int32_t offset)
13505{
ef0d8ffc 13506 unsigned rt = INSTR (4, 0);
2e8cf49e 13507
2cdad34c 13508 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
668650d5 13509 if (!(aarch64_get_reg_u64 (cpu, rt, NO_SP) & (((uint64_t) 1) << pos)))
2e8cf49e
NC
13510 aarch64_set_next_PC_by_offset (cpu, offset);
13511}
13512
13513static void
13514dexCompareBranchImmediate (sim_cpu *cpu)
13515{
13516 /* instr[30,25] = 01 1010
13517 instr[31] = size : 0 ==> 32, 1 ==> 64
13518 instr[24] = op : 0 ==> CBZ, 1 ==> CBNZ
13519 instr[23,5] = simm19 branch offset counted in words
13520 instr[4,0] = rt */
13521
ef0d8ffc
NC
13522 uint32_t size = INSTR (31, 31);
13523 uint32_t op = INSTR (24, 24);
2e8cf49e
NC
13524 int32_t offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
13525
13526 if (size == 0)
13527 {
13528 if (op == 0)
13529 cbz32 (cpu, offset);
13530 else
13531 cbnz32 (cpu, offset);
13532 }
13533 else
13534 {
13535 if (op == 0)
13536 cbz (cpu, offset);
13537 else
13538 cbnz (cpu, offset);
13539 }
13540}
13541
13542static void
13543dexTestBranchImmediate (sim_cpu *cpu)
13544{
13545 /* instr[31] = b5 : bit 5 of test bit idx
13546 instr[30,25] = 01 1011
13547 instr[24] = op : 0 ==> TBZ, 1 == TBNZ
13548 instr[23,19] = b40 : bits 4 to 0 of test bit idx
13549 instr[18,5] = simm14 : signed offset counted in words
13550 instr[4,0] = uimm5 */
13551
668650d5 13552 uint32_t pos = ((INSTR (31, 31) << 5) | INSTR (23, 19));
2e8cf49e
NC
13553 int32_t offset = simm32 (aarch64_get_instr (cpu), 18, 5) << 2;
13554
13555 NYI_assert (30, 25, 0x1b);
13556
ef0d8ffc 13557 if (INSTR (24, 24) == 0)
2e8cf49e
NC
13558 tbz (cpu, pos, offset);
13559 else
13560 tbnz (cpu, pos, offset);
13561}
13562
13563static void
13564dexCondBranchImmediate (sim_cpu *cpu)
13565{
13566 /* instr[31,25] = 010 1010
13567 instr[24] = op1; op => 00 ==> B.cond
13568 instr[23,5] = simm19 : signed offset counted in words
13569 instr[4] = op0
13570 instr[3,0] = cond */
13571
13572 int32_t offset;
ef0d8ffc 13573 uint32_t op = ((INSTR (24, 24) << 1) | INSTR (4, 4));
2e8cf49e
NC
13574
13575 NYI_assert (31, 25, 0x2a);
13576
13577 if (op != 0)
13578 HALT_UNALLOC;
13579
13580 offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
2e8cf49e 13581
ef0d8ffc 13582 bcc (cpu, offset, INSTR (3, 0));
2e8cf49e
NC
13583}
13584
13585static void
13586dexBranchRegister (sim_cpu *cpu)
13587{
13588 /* instr[31,25] = 110 1011
13589 instr[24,21] = op : 0 ==> BR, 1 => BLR, 2 => RET, 3 => ERET, 4 => DRPS
13590 instr[20,16] = op2 : must be 11111
13591 instr[15,10] = op3 : must be 000000
13592 instr[4,0] = op2 : must be 11111. */
13593
ef0d8ffc
NC
13594 uint32_t op = INSTR (24, 21);
13595 uint32_t op2 = INSTR (20, 16);
13596 uint32_t op3 = INSTR (15, 10);
13597 uint32_t op4 = INSTR (4, 0);
2e8cf49e
NC
13598
13599 NYI_assert (31, 25, 0x6b);
13600
13601 if (op2 != 0x1F || op3 != 0 || op4 != 0)
13602 HALT_UNALLOC;
13603
13604 if (op == 0)
13605 br (cpu);
13606
13607 else if (op == 1)
13608 blr (cpu);
13609
13610 else if (op == 2)
13611 ret (cpu);
13612
13613 else
13614 {
ef0d8ffc 13615 /* ERET and DRPS accept 0b11111 for rn = instr [4,0]. */
2e8cf49e 13616 /* anything else is unallocated. */
ef0d8ffc 13617 uint32_t rn = INSTR (4, 0);
2e8cf49e
NC
13618
13619 if (rn != 0x1f)
13620 HALT_UNALLOC;
13621
13622 if (op == 4 || op == 5)
13623 HALT_NYI;
13624
13625 HALT_UNALLOC;
13626 }
13627}
13628
13629/* FIXME: We should get the Angel SWI values from ../../libgloss/aarch64/svc.h
13630 but this may not be available. So instead we define the values we need
13631 here. */
13632#define AngelSVC_Reason_Open 0x01
13633#define AngelSVC_Reason_Close 0x02
13634#define AngelSVC_Reason_Write 0x05
13635#define AngelSVC_Reason_Read 0x06
13636#define AngelSVC_Reason_IsTTY 0x09
13637#define AngelSVC_Reason_Seek 0x0A
13638#define AngelSVC_Reason_FLen 0x0C
13639#define AngelSVC_Reason_Remove 0x0E
13640#define AngelSVC_Reason_Rename 0x0F
13641#define AngelSVC_Reason_Clock 0x10
13642#define AngelSVC_Reason_Time 0x11
13643#define AngelSVC_Reason_System 0x12
13644#define AngelSVC_Reason_Errno 0x13
13645#define AngelSVC_Reason_GetCmdLine 0x15
13646#define AngelSVC_Reason_HeapInfo 0x16
13647#define AngelSVC_Reason_ReportException 0x18
13648#define AngelSVC_Reason_Elapsed 0x30
13649
13650
13651static void
13652handle_halt (sim_cpu *cpu, uint32_t val)
13653{
13654 uint64_t result = 0;
13655
2cdad34c 13656 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13657 if (val != 0xf000)
13658 {
13659 TRACE_SYSCALL (cpu, " HLT [0x%x]", val);
13660 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13661 sim_stopped, SIM_SIGTRAP);
13662 }
13663
13664 /* We have encountered an Angel SVC call. See if we can process it. */
13665 switch (aarch64_get_reg_u32 (cpu, 0, NO_SP))
13666 {
13667 case AngelSVC_Reason_HeapInfo:
13668 {
13669 /* Get the values. */
13670 uint64_t stack_top = aarch64_get_stack_start (cpu);
13671 uint64_t heap_base = aarch64_get_heap_start (cpu);
13672
13673 /* Get the pointer */
13674 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13675 ptr = aarch64_get_mem_u64 (cpu, ptr);
13676
13677 /* Fill in the memory block. */
13678 /* Start addr of heap. */
13679 aarch64_set_mem_u64 (cpu, ptr + 0, heap_base);
13680 /* End addr of heap. */
13681 aarch64_set_mem_u64 (cpu, ptr + 8, stack_top);
13682 /* Lowest stack addr. */
13683 aarch64_set_mem_u64 (cpu, ptr + 16, heap_base);
13684 /* Initial stack addr. */
13685 aarch64_set_mem_u64 (cpu, ptr + 24, stack_top);
13686
13687 TRACE_SYSCALL (cpu, " AngelSVC: Get Heap Info");
13688 }
13689 break;
13690
13691 case AngelSVC_Reason_Open:
13692 {
13693 /* Get the pointer */
13694 /* uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);. */
13695 /* FIXME: For now we just assume that we will only be asked
13696 to open the standard file descriptors. */
13697 static int fd = 0;
13698 result = fd ++;
13699
13700 TRACE_SYSCALL (cpu, " AngelSVC: Open file %d", fd - 1);
13701 }
13702 break;
13703
13704 case AngelSVC_Reason_Close:
13705 {
13706 uint64_t fh = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13707 TRACE_SYSCALL (cpu, " AngelSVC: Close file %d", (int) fh);
13708 result = 0;
13709 }
13710 break;
13711
13712 case AngelSVC_Reason_Errno:
13713 result = 0;
13714 TRACE_SYSCALL (cpu, " AngelSVC: Get Errno");
13715 break;
13716
13717 case AngelSVC_Reason_Clock:
13718 result =
13719#ifdef CLOCKS_PER_SEC
13720 (CLOCKS_PER_SEC >= 100)
13721 ? (clock () / (CLOCKS_PER_SEC / 100))
13722 : ((clock () * 100) / CLOCKS_PER_SEC)
13723#else
13724 /* Presume unix... clock() returns microseconds. */
13725 (clock () / 10000)
13726#endif
13727 ;
13728 TRACE_SYSCALL (cpu, " AngelSVC: Get Clock");
13729 break;
13730
13731 case AngelSVC_Reason_GetCmdLine:
13732 {
13733 /* Get the pointer */
13734 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13735 ptr = aarch64_get_mem_u64 (cpu, ptr);
13736
13737 /* FIXME: No command line for now. */
13738 aarch64_set_mem_u64 (cpu, ptr, 0);
13739 TRACE_SYSCALL (cpu, " AngelSVC: Get Command Line");
13740 }
13741 break;
13742
13743 case AngelSVC_Reason_IsTTY:
13744 result = 1;
13745 TRACE_SYSCALL (cpu, " AngelSVC: IsTTY ?");
13746 break;
13747
13748 case AngelSVC_Reason_Write:
13749 {
13750 /* Get the pointer */
13751 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13752 /* Get the write control block. */
13753 uint64_t fd = aarch64_get_mem_u64 (cpu, ptr);
13754 uint64_t buf = aarch64_get_mem_u64 (cpu, ptr + 8);
13755 uint64_t len = aarch64_get_mem_u64 (cpu, ptr + 16);
13756
13757 TRACE_SYSCALL (cpu, "write of %" PRIx64 " bytes from %"
13758 PRIx64 " on descriptor %" PRIx64,
13759 len, buf, fd);
13760
13761 if (len > 1280)
13762 {
13763 TRACE_SYSCALL (cpu,
13764 " AngelSVC: Write: Suspiciously long write: %ld",
13765 (long) len);
13766 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13767 sim_stopped, SIM_SIGBUS);
13768 }
13769 else if (fd == 1)
13770 {
13771 printf ("%.*s", (int) len, aarch64_get_mem_ptr (cpu, buf));
2e8cf49e
NC
13772 }
13773 else if (fd == 2)
13774 {
13775 TRACE (cpu, 0, "\n");
13776 sim_io_eprintf (CPU_STATE (cpu), "%.*s",
13777 (int) len, aarch64_get_mem_ptr (cpu, buf));
13778 TRACE (cpu, 0, "\n");
13779 }
13780 else
13781 {
13782 TRACE_SYSCALL (cpu,
13783 " AngelSVC: Write: Unexpected file handle: %d",
13784 (int) fd);
13785 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13786 sim_stopped, SIM_SIGABRT);
13787 }
13788 }
13789 break;
13790
13791 case AngelSVC_Reason_ReportException:
13792 {
13793 /* Get the pointer */
13794 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13795 /*ptr = aarch64_get_mem_u64 (cpu, ptr);. */
13796 uint64_t type = aarch64_get_mem_u64 (cpu, ptr);
13797 uint64_t state = aarch64_get_mem_u64 (cpu, ptr + 8);
13798
13799 TRACE_SYSCALL (cpu,
13800 "Angel Exception: type 0x%" PRIx64 " state %" PRIx64,
13801 type, state);
13802
13803 if (type == 0x20026)
13804 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13805 sim_exited, state);
13806 else
13807 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13808 sim_stopped, SIM_SIGINT);
13809 }
13810 break;
13811
13812 case AngelSVC_Reason_Read:
13813 case AngelSVC_Reason_FLen:
13814 case AngelSVC_Reason_Seek:
13815 case AngelSVC_Reason_Remove:
13816 case AngelSVC_Reason_Time:
13817 case AngelSVC_Reason_System:
13818 case AngelSVC_Reason_Rename:
13819 case AngelSVC_Reason_Elapsed:
13820 default:
13821 TRACE_SYSCALL (cpu, " HLT [Unknown angel %x]",
13822 aarch64_get_reg_u32 (cpu, 0, NO_SP));
13823 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13824 sim_stopped, SIM_SIGTRAP);
13825 }
13826
13827 aarch64_set_reg_u64 (cpu, 0, NO_SP, result);
13828}
13829
13830static void
13831dexExcpnGen (sim_cpu *cpu)
13832{
13833 /* instr[31:24] = 11010100
13834 instr[23,21] = opc : 000 ==> GEN EXCPN, 001 ==> BRK
13835 010 ==> HLT, 101 ==> DBG GEN EXCPN
13836 instr[20,5] = imm16
13837 instr[4,2] = opc2 000 ==> OK, ow ==> UNALLOC
13838 instr[1,0] = LL : discriminates opc */
13839
ef0d8ffc
NC
13840 uint32_t opc = INSTR (23, 21);
13841 uint32_t imm16 = INSTR (20, 5);
13842 uint32_t opc2 = INSTR (4, 2);
2e8cf49e
NC
13843 uint32_t LL;
13844
13845 NYI_assert (31, 24, 0xd4);
13846
13847 if (opc2 != 0)
13848 HALT_UNALLOC;
13849
ef0d8ffc 13850 LL = INSTR (1, 0);
2e8cf49e
NC
13851
13852 /* We only implement HLT and BRK for now. */
13853 if (opc == 1 && LL == 0)
13854 {
13855 TRACE_EVENTS (cpu, " BRK [0x%x]", imm16);
13856 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13857 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13858 }
13859
13860 if (opc == 2 && LL == 0)
13861 handle_halt (cpu, imm16);
13862
13863 else if (opc == 0 || opc == 5)
13864 HALT_NYI;
13865
13866 else
13867 HALT_UNALLOC;
13868}
13869
5ab6d79e 13870/* Stub for accessing system registers. */
caa8d700
NC
13871
13872static uint64_t
13873system_get (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
13874 unsigned crm, unsigned op2)
13875{
13876 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 7)
13877 /* DCZID_EL0 - the Data Cache Zero ID register.
13878 We do not support DC ZVA at the moment, so
5ab6d79e
NC
13879 we return a value with the disable bit set.
13880 We implement support for the DCZID register since
13881 it is used by the C library's memset function. */
caa8d700
NC
13882 return ((uint64_t) 1) << 4;
13883
5ab6d79e
NC
13884 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 1)
13885 /* Cache Type Register. */
13886 return 0x80008000UL;
13887
13888 if (crn == 13 && op1 == 3 && crm == 0 && op2 == 2)
13889 /* TPIDR_EL0 - thread pointer id. */
13890 return aarch64_get_thread_id (cpu);
13891
13892 if (op1 == 3 && crm == 4 && op2 == 0)
13893 return aarch64_get_FPCR (cpu);
13894
13895 if (op1 == 3 && crm == 4 && op2 == 1)
13896 return aarch64_get_FPSR (cpu);
13897
13898 else if (op1 == 3 && crm == 2 && op2 == 0)
13899 return aarch64_get_CPSR (cpu);
13900
caa8d700
NC
13901 HALT_NYI;
13902}
13903
5ab6d79e
NC
13904static void
13905system_set (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
13906 unsigned crm, unsigned op2, uint64_t val)
13907{
13908 if (op1 == 3 && crm == 4 && op2 == 0)
13909 aarch64_set_FPCR (cpu, val);
13910
13911 else if (op1 == 3 && crm == 4 && op2 == 1)
13912 aarch64_set_FPSR (cpu, val);
13913
13914 else if (op1 == 3 && crm == 2 && op2 == 0)
13915 aarch64_set_CPSR (cpu, val);
13916
13917 else
13918 HALT_NYI;
13919}
ef0d8ffc 13920
caa8d700
NC
13921static void
13922do_mrs (sim_cpu *cpu)
13923{
5ab6d79e 13924 /* instr[31:20] = 1101 0101 0001 1
caa8d700
NC
13925 instr[19] = op0
13926 instr[18,16] = op1
13927 instr[15,12] = CRn
13928 instr[11,8] = CRm
13929 instr[7,5] = op2
13930 instr[4,0] = Rt */
ef0d8ffc
NC
13931 unsigned sys_op0 = INSTR (19, 19) + 2;
13932 unsigned sys_op1 = INSTR (18, 16);
13933 unsigned sys_crn = INSTR (15, 12);
13934 unsigned sys_crm = INSTR (11, 8);
13935 unsigned sys_op2 = INSTR (7, 5);
13936 unsigned rt = INSTR (4, 0);
caa8d700 13937
2cdad34c 13938 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
caa8d700
NC
13939 aarch64_set_reg_u64 (cpu, rt, NO_SP,
13940 system_get (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2));
13941}
13942
5ab6d79e
NC
13943static void
13944do_MSR_immediate (sim_cpu *cpu)
13945{
13946 /* instr[31:19] = 1101 0101 0000 0
13947 instr[18,16] = op1
13948 instr[15,12] = 0100
13949 instr[11,8] = CRm
13950 instr[7,5] = op2
13951 instr[4,0] = 1 1111 */
13952
ef0d8ffc
NC
13953 unsigned op1 = INSTR (18, 16);
13954 /*unsigned crm = INSTR (11, 8);*/
13955 unsigned op2 = INSTR (7, 5);
5ab6d79e
NC
13956
13957 NYI_assert (31, 19, 0x1AA0);
13958 NYI_assert (15, 12, 0x4);
13959 NYI_assert (4, 0, 0x1F);
13960
13961 if (op1 == 0)
13962 {
13963 if (op2 == 5)
13964 HALT_NYI; /* set SPSel. */
13965 else
13966 HALT_UNALLOC;
13967 }
13968 else if (op1 == 3)
13969 {
13970 if (op2 == 6)
13971 HALT_NYI; /* set DAIFset. */
13972 else if (op2 == 7)
13973 HALT_NYI; /* set DAIFclr. */
13974 else
13975 HALT_UNALLOC;
13976 }
13977 else
13978 HALT_UNALLOC;
13979}
13980
13981static void
13982do_MSR_reg (sim_cpu *cpu)
13983{
13984 /* instr[31:20] = 1101 0101 0001
13985 instr[19] = op0
13986 instr[18,16] = op1
13987 instr[15,12] = CRn
13988 instr[11,8] = CRm
13989 instr[7,5] = op2
13990 instr[4,0] = Rt */
13991
ef0d8ffc
NC
13992 unsigned sys_op0 = INSTR (19, 19) + 2;
13993 unsigned sys_op1 = INSTR (18, 16);
13994 unsigned sys_crn = INSTR (15, 12);
13995 unsigned sys_crm = INSTR (11, 8);
13996 unsigned sys_op2 = INSTR (7, 5);
13997 unsigned rt = INSTR (4, 0);
5ab6d79e
NC
13998
13999 NYI_assert (31, 20, 0xD51);
ef0d8ffc 14000
2cdad34c 14001 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
14002 system_set (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2,
14003 aarch64_get_reg_u64 (cpu, rt, NO_SP));
14004}
14005
14006static void
ef0d8ffc 14007do_SYS (sim_cpu *cpu)
5ab6d79e
NC
14008{
14009 /* instr[31,19] = 1101 0101 0000 1
14010 instr[18,16] = op1
14011 instr[15,12] = CRn
14012 instr[11,8] = CRm
14013 instr[7,5] = op2
14014 instr[4,0] = Rt */
14015 NYI_assert (31, 19, 0x1AA1);
14016
14017 /* FIXME: For now we just silently accept system ops. */
14018}
ef0d8ffc 14019
2e8cf49e
NC
14020static void
14021dexSystem (sim_cpu *cpu)
14022{
14023 /* instr[31:22] = 1101 01010 0
14024 instr[21] = L
14025 instr[20,19] = op0
14026 instr[18,16] = op1
14027 instr[15,12] = CRn
14028 instr[11,8] = CRm
14029 instr[7,5] = op2
14030 instr[4,0] = uimm5 */
14031
14032 /* We are interested in HINT, DSB, DMB and ISB
14033
14034 Hint #0 encodes NOOP (this is the only hint we care about)
14035 L == 0, op0 == 0, op1 = 011, CRn = 0010, Rt = 11111,
14036 CRm op2 != 0000 000 OR CRm op2 == 0000 000 || CRm op > 0000 101
14037
14038 DSB, DMB, ISB are data store barrier, data memory barrier and
14039 instruction store barrier, respectively, where
14040
14041 L == 0, op0 == 0, op1 = 011, CRn = 0011, Rt = 11111,
14042 op2 : DSB ==> 100, DMB ==> 101, ISB ==> 110
14043 CRm<3:2> ==> domain, CRm<1:0> ==> types,
14044 domain : 00 ==> OuterShareable, 01 ==> Nonshareable,
14045 10 ==> InerShareable, 11 ==> FullSystem
14046 types : 01 ==> Reads, 10 ==> Writes,
14047 11 ==> All, 00 ==> All (domain == FullSystem). */
14048
ef0d8ffc 14049 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
14050
14051 NYI_assert (31, 22, 0x354);
14052
5ab6d79e 14053 switch (INSTR (21, 12))
2e8cf49e
NC
14054 {
14055 case 0x032:
14056 if (rt == 0x1F)
14057 {
14058 /* NOP has CRm != 0000 OR. */
14059 /* (CRm == 0000 AND (op2 == 000 OR op2 > 101)). */
ef0d8ffc
NC
14060 uint32_t crm = INSTR (11, 8);
14061 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
14062
14063 if (crm != 0 || (op2 == 0 || op2 > 5))
14064 {
14065 /* Actually call nop method so we can reimplement it later. */
14066 nop (cpu);
14067 return;
14068 }
14069 }
14070 HALT_NYI;
14071
14072 case 0x033:
14073 {
ef0d8ffc 14074 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
14075
14076 switch (op2)
14077 {
caa8d700 14078 case 2: HALT_NYI;
2e8cf49e
NC
14079 case 4: dsb (cpu); return;
14080 case 5: dmb (cpu); return;
14081 case 6: isb (cpu); return;
2e8cf49e
NC
14082 default: HALT_UNALLOC;
14083 }
14084 }
14085
14086 case 0x3B0:
2e8cf49e
NC
14087 case 0x3B4:
14088 case 0x3BD:
caa8d700 14089 do_mrs (cpu);
2e8cf49e
NC
14090 return;
14091
14092 case 0x0B7:
5ab6d79e 14093 do_SYS (cpu); /* DC is an alias of SYS. */
2e8cf49e
NC
14094 return;
14095
14096 default:
ef0d8ffc 14097 if (INSTR (21, 20) == 0x1)
5ab6d79e
NC
14098 do_MSR_reg (cpu);
14099 else if (INSTR (21, 19) == 0 && INSTR (15, 12) == 0x4)
14100 do_MSR_immediate (cpu);
14101 else
14102 HALT_NYI;
caa8d700 14103 return;
2e8cf49e
NC
14104 }
14105}
14106
14107static void
14108dexBr (sim_cpu *cpu)
14109{
14110 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
14111 assert group == GROUP_BREXSYS_1010 || group == GROUP_BREXSYS_1011
14112 bits [31,29] of a BrExSys are the secondary dispatch vector. */
14113 uint32_t group2 = dispatchBrExSys (aarch64_get_instr (cpu));
14114
14115 switch (group2)
14116 {
14117 case BR_IMM_000:
14118 return dexBranchImmediate (cpu);
14119
14120 case BR_IMMCMP_001:
14121 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 14122 if (!INSTR (25, 25))
2e8cf49e
NC
14123 dexCompareBranchImmediate (cpu);
14124 else
14125 dexTestBranchImmediate (cpu);
14126 return;
14127
14128 case BR_IMMCOND_010:
14129 /* This is a conditional branch if bit 25 is clear otherwise
14130 unallocated. */
ef0d8ffc 14131 if (!INSTR (25, 25))
2e8cf49e
NC
14132 dexCondBranchImmediate (cpu);
14133 else
14134 HALT_UNALLOC;
14135 return;
14136
14137 case BR_UNALLOC_011:
14138 HALT_UNALLOC;
14139
14140 case BR_IMM_100:
14141 dexBranchImmediate (cpu);
14142 return;
14143
14144 case BR_IMMCMP_101:
14145 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 14146 if (!INSTR (25, 25))
2e8cf49e
NC
14147 dexCompareBranchImmediate (cpu);
14148 else
14149 dexTestBranchImmediate (cpu);
14150 return;
14151
14152 case BR_REG_110:
14153 /* Unconditional branch reg has bit 25 set. */
ef0d8ffc 14154 if (INSTR (25, 25))
2e8cf49e
NC
14155 dexBranchRegister (cpu);
14156
14157 /* This includes both Excpn Gen, System and unalloc operations.
14158 We need to decode the Excpn Gen operation BRK so we can plant
14159 debugger entry points.
ef0d8ffc 14160 Excpn Gen operations have instr [24] = 0.
2e8cf49e
NC
14161 we need to decode at least one of the System operations NOP
14162 which is an alias for HINT #0.
ef0d8ffc
NC
14163 System operations have instr [24,22] = 100. */
14164 else if (INSTR (24, 24) == 0)
2e8cf49e
NC
14165 dexExcpnGen (cpu);
14166
ef0d8ffc 14167 else if (INSTR (24, 22) == 4)
2e8cf49e
NC
14168 dexSystem (cpu);
14169
14170 else
14171 HALT_UNALLOC;
14172
14173 return;
14174
14175 case BR_UNALLOC_111:
14176 HALT_UNALLOC;
14177
14178 default:
14179 /* Should never reach here. */
14180 HALT_NYI;
14181 }
14182}
14183
14184static void
14185aarch64_decode_and_execute (sim_cpu *cpu, uint64_t pc)
14186{
14187 /* We need to check if gdb wants an in here. */
14188 /* checkBreak (cpu);. */
14189
14190 uint64_t group = dispatchGroup (aarch64_get_instr (cpu));
14191
14192 switch (group)
14193 {
14194 case GROUP_PSEUDO_0000: dexPseudo (cpu); break;
14195 case GROUP_LDST_0100: dexLdSt (cpu); break;
14196 case GROUP_DPREG_0101: dexDPReg (cpu); break;
14197 case GROUP_LDST_0110: dexLdSt (cpu); break;
14198 case GROUP_ADVSIMD_0111: dexAdvSIMD0 (cpu); break;
14199 case GROUP_DPIMM_1000: dexDPImm (cpu); break;
14200 case GROUP_DPIMM_1001: dexDPImm (cpu); break;
14201 case GROUP_BREXSYS_1010: dexBr (cpu); break;
14202 case GROUP_BREXSYS_1011: dexBr (cpu); break;
14203 case GROUP_LDST_1100: dexLdSt (cpu); break;
14204 case GROUP_DPREG_1101: dexDPReg (cpu); break;
14205 case GROUP_LDST_1110: dexLdSt (cpu); break;
14206 case GROUP_ADVSIMD_1111: dexAdvSIMD1 (cpu); break;
14207
14208 case GROUP_UNALLOC_0001:
14209 case GROUP_UNALLOC_0010:
14210 case GROUP_UNALLOC_0011:
14211 HALT_UNALLOC;
14212
14213 default:
14214 /* Should never reach here. */
14215 HALT_NYI;
14216 }
14217}
14218
b14bdb3b 14219static bfd_boolean
2e8cf49e
NC
14220aarch64_step (sim_cpu *cpu)
14221{
14222 uint64_t pc = aarch64_get_PC (cpu);
14223
14224 if (pc == TOP_LEVEL_RETURN_PC)
14225 return FALSE;
14226
14227 aarch64_set_next_PC (cpu, pc + 4);
c7be4414
JW
14228
14229 /* Code is always little-endian. */
14230 sim_core_read_buffer (CPU_STATE (cpu), cpu, read_map,
14231 & aarch64_get_instr (cpu), pc, 4);
14232 aarch64_get_instr (cpu) = endian_le2h_4 (aarch64_get_instr (cpu));
2e8cf49e 14233
57aa1742 14234 TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %08x", pc,
1a846c62
MF
14235 aarch64_get_instr (cpu));
14236 TRACE_DISASM (cpu, pc);
2e8cf49e
NC
14237
14238 aarch64_decode_and_execute (cpu, pc);
14239
14240 return TRUE;
14241}
14242
14243void
14244aarch64_run (SIM_DESC sd)
14245{
14246 sim_cpu *cpu = STATE_CPU (sd, 0);
14247
14248 while (aarch64_step (cpu))
b14bdb3b
NC
14249 {
14250 aarch64_update_PC (cpu);
14251
14252 if (sim_events_tick (sd))
14253 sim_events_process (sd);
14254 }
2e8cf49e 14255
b14bdb3b
NC
14256 sim_engine_halt (sd, cpu, NULL, aarch64_get_PC (cpu),
14257 sim_exited, aarch64_get_reg_s32 (cpu, R0, NO_SP));
2e8cf49e
NC
14258}
14259
14260void
14261aarch64_init (sim_cpu *cpu, uint64_t pc)
14262{
14263 uint64_t sp = aarch64_get_stack_start (cpu);
14264
14265 /* Install SP, FP and PC and set LR to -20
14266 so we can detect a top-level return. */
14267 aarch64_set_reg_u64 (cpu, SP, SP_OK, sp);
14268 aarch64_set_reg_u64 (cpu, FP, SP_OK, sp);
14269 aarch64_set_reg_u64 (cpu, LR, SP_OK, TOP_LEVEL_RETURN_PC);
14270 aarch64_set_next_PC (cpu, pc);
14271 aarch64_update_PC (cpu);
14272 aarch64_init_LIT_table ();
14273}
This page took 0.698085 seconds and 4 git commands to generate.