Fix problems with the implementation of the uzp1 and uzp2 instructions.
[deliverable/binutils-gdb.git] / sim / aarch64 / simulator.c
CommitLineData
2e8cf49e
NC
1/* simulator.c -- Interface for the AArch64 simulator.
2
61baf725 3 Copyright (C) 2015-2017 Free Software Foundation, Inc.
2e8cf49e
NC
4
5 Contributed by Red Hat.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22#include "config.h"
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <sys/types.h>
2e8cf49e
NC
27#include <math.h>
28#include <time.h>
29#include <limits.h>
30
2e8cf49e
NC
31#include "simulator.h"
32#include "cpustate.h"
33#include "memory.h"
34
35#define NO_SP 0
36#define SP_OK 1
37
2e8cf49e 38#define TST(_flag) (aarch64_test_CPSR_bit (cpu, _flag))
e101a78b
NC
39#define IS_SET(_X) (TST (( _X )) ? 1 : 0)
40#define IS_CLEAR(_X) (TST (( _X )) ? 0 : 1)
2e8cf49e 41
ef0d8ffc
NC
42/* Space saver macro. */
43#define INSTR(HIGH, LOW) uimm (aarch64_get_instr (cpu), (HIGH), (LOW))
44
2e8cf49e
NC
45#define HALT_UNALLOC \
46 do \
47 { \
1a846c62
MF
48 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
49 TRACE_INSN (cpu, \
50 "Unallocated instruction detected at sim line %d," \
51 " exe addr %" PRIx64, \
52 __LINE__, aarch64_get_PC (cpu)); \
2e8cf49e
NC
53 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
54 sim_stopped, SIM_SIGILL); \
55 } \
56 while (0)
57
58#define HALT_NYI \
59 do \
60 { \
1a846c62
MF
61 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
62 TRACE_INSN (cpu, \
63 "Unimplemented instruction detected at sim line %d," \
64 " exe addr %" PRIx64, \
65 __LINE__, aarch64_get_PC (cpu)); \
5ab6d79e 66 if (! TRACE_ANY_P (cpu)) \
6a277579
NC
67 sim_io_eprintf (CPU_STATE (cpu), "SIM Error: Unimplemented instruction: %#08x\n", \
68 aarch64_get_instr (cpu)); \
2e8cf49e
NC
69 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
70 sim_stopped, SIM_SIGABRT); \
71 } \
72 while (0)
73
74#define NYI_assert(HI, LO, EXPECTED) \
75 do \
76 { \
ef0d8ffc 77 if (INSTR ((HI), (LO)) != (EXPECTED)) \
2e8cf49e
NC
78 HALT_NYI; \
79 } \
80 while (0)
81
2e8cf49e
NC
82/* Helper functions used by expandLogicalImmediate. */
83
84/* for i = 1, ... N result<i-1> = 1 other bits are zero */
85static inline uint64_t
86ones (int N)
87{
88 return (N == 64 ? (uint64_t)-1UL : ((1UL << N) - 1));
89}
90
91/* result<0> to val<N> */
92static inline uint64_t
93pickbit (uint64_t val, int N)
94{
95 return pickbits64 (val, N, N);
96}
97
98static uint64_t
99expand_logical_immediate (uint32_t S, uint32_t R, uint32_t N)
100{
101 uint64_t mask;
102 uint64_t imm;
103 unsigned simd_size;
104
105 /* The immediate value is S+1 bits to 1, left rotated by SIMDsize - R
106 (in other words, right rotated by R), then replicated. */
107 if (N != 0)
108 {
109 simd_size = 64;
110 mask = 0xffffffffffffffffull;
111 }
112 else
113 {
114 switch (S)
115 {
116 case 0x00 ... 0x1f: /* 0xxxxx */ simd_size = 32; break;
117 case 0x20 ... 0x2f: /* 10xxxx */ simd_size = 16; S &= 0xf; break;
118 case 0x30 ... 0x37: /* 110xxx */ simd_size = 8; S &= 0x7; break;
119 case 0x38 ... 0x3b: /* 1110xx */ simd_size = 4; S &= 0x3; break;
120 case 0x3c ... 0x3d: /* 11110x */ simd_size = 2; S &= 0x1; break;
121 default: return 0;
122 }
123 mask = (1ull << simd_size) - 1;
124 /* Top bits are IGNORED. */
125 R &= simd_size - 1;
126 }
127
128 /* NOTE: if S = simd_size - 1 we get 0xf..f which is rejected. */
129 if (S == simd_size - 1)
130 return 0;
131
132 /* S+1 consecutive bits to 1. */
133 /* NOTE: S can't be 63 due to detection above. */
134 imm = (1ull << (S + 1)) - 1;
135
136 /* Rotate to the left by simd_size - R. */
137 if (R != 0)
138 imm = ((imm << (simd_size - R)) & mask) | (imm >> R);
139
140 /* Replicate the value according to SIMD size. */
141 switch (simd_size)
142 {
143 case 2: imm = (imm << 2) | imm;
144 case 4: imm = (imm << 4) | imm;
145 case 8: imm = (imm << 8) | imm;
146 case 16: imm = (imm << 16) | imm;
147 case 32: imm = (imm << 32) | imm;
148 case 64: break;
149 default: return 0;
150 }
151
152 return imm;
153}
154
155/* Instr[22,10] encodes N immr and imms. we want a lookup table
156 for each possible combination i.e. 13 bits worth of int entries. */
157#define LI_TABLE_SIZE (1 << 13)
158static uint64_t LITable[LI_TABLE_SIZE];
159
160void
161aarch64_init_LIT_table (void)
162{
163 unsigned index;
164
165 for (index = 0; index < LI_TABLE_SIZE; index++)
166 {
167 uint32_t N = uimm (index, 12, 12);
168 uint32_t immr = uimm (index, 11, 6);
169 uint32_t imms = uimm (index, 5, 0);
170
171 LITable [index] = expand_logical_immediate (imms, immr, N);
172 }
173}
174
175static void
176dexNotify (sim_cpu *cpu)
177{
178 /* instr[14,0] == type : 0 ==> method entry, 1 ==> method reentry
179 2 ==> exit Java, 3 ==> start next bytecode. */
ef0d8ffc 180 uint32_t type = INSTR (14, 0);
2e8cf49e
NC
181
182 TRACE_EVENTS (cpu, "Notify Insn encountered, type = 0x%x", type);
183
184 switch (type)
185 {
186 case 0:
187 /* aarch64_notifyMethodEntry (aarch64_get_reg_u64 (cpu, R23, 0),
188 aarch64_get_reg_u64 (cpu, R22, 0)); */
189 break;
190 case 1:
191 /* aarch64_notifyMethodReentry (aarch64_get_reg_u64 (cpu, R23, 0),
192 aarch64_get_reg_u64 (cpu, R22, 0)); */
193 break;
194 case 2:
195 /* aarch64_notifyMethodExit (); */
196 break;
197 case 3:
198 /* aarch64_notifyBCStart (aarch64_get_reg_u64 (cpu, R23, 0),
199 aarch64_get_reg_u64 (cpu, R22, 0)); */
200 break;
201 }
202}
203
204/* secondary decode within top level groups */
205
206static void
207dexPseudo (sim_cpu *cpu)
208{
209 /* assert instr[28,27] = 00
210
211 We provide 2 pseudo instructions:
212
213 HALT stops execution of the simulator causing an immediate
214 return to the x86 code which entered it.
215
216 CALLOUT initiates recursive entry into x86 code. A register
217 argument holds the address of the x86 routine. Immediate
218 values in the instruction identify the number of general
219 purpose and floating point register arguments to be passed
220 and the type of any value to be returned. */
221
222 uint32_t PSEUDO_HALT = 0xE0000000U;
223 uint32_t PSEUDO_CALLOUT = 0x00018000U;
224 uint32_t PSEUDO_CALLOUTR = 0x00018001U;
225 uint32_t PSEUDO_NOTIFY = 0x00014000U;
226 uint32_t dispatch;
227
228 if (aarch64_get_instr (cpu) == PSEUDO_HALT)
229 {
230 TRACE_EVENTS (cpu, " Pseudo Halt Instruction");
231 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
232 sim_stopped, SIM_SIGTRAP);
233 }
234
ef0d8ffc 235 dispatch = INSTR (31, 15);
2e8cf49e
NC
236
237 /* We do not handle callouts at the moment. */
238 if (dispatch == PSEUDO_CALLOUT || dispatch == PSEUDO_CALLOUTR)
239 {
240 TRACE_EVENTS (cpu, " Callout");
241 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
242 sim_stopped, SIM_SIGABRT);
243 }
244
245 else if (dispatch == PSEUDO_NOTIFY)
246 dexNotify (cpu);
247
248 else
249 HALT_UNALLOC;
250}
251
252/* Load-store single register (unscaled offset)
253 These instructions employ a base register plus an unscaled signed
254 9 bit offset.
255
256 N.B. the base register (source) can be Xn or SP. all other
257 registers may not be SP. */
258
259/* 32 bit load 32 bit unscaled signed 9 bit. */
260static void
261ldur32 (sim_cpu *cpu, int32_t offset)
262{
ef0d8ffc
NC
263 unsigned rn = INSTR (9, 5);
264 unsigned rt = INSTR (4, 0);
2e8cf49e 265
2cdad34c 266 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
267 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
268 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
269 + offset));
270}
271
272/* 64 bit load 64 bit unscaled signed 9 bit. */
273static void
274ldur64 (sim_cpu *cpu, int32_t offset)
275{
ef0d8ffc
NC
276 unsigned rn = INSTR (9, 5);
277 unsigned rt = INSTR (4, 0);
2e8cf49e 278
2cdad34c 279 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
280 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
281 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
282 + offset));
283}
284
285/* 32 bit load zero-extended byte unscaled signed 9 bit. */
286static void
287ldurb32 (sim_cpu *cpu, int32_t offset)
288{
ef0d8ffc
NC
289 unsigned rn = INSTR (9, 5);
290 unsigned rt = INSTR (4, 0);
2e8cf49e 291
2cdad34c 292 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
293 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8
294 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
295 + offset));
296}
297
298/* 32 bit load sign-extended byte unscaled signed 9 bit. */
299static void
300ldursb32 (sim_cpu *cpu, int32_t offset)
301{
ef0d8ffc
NC
302 unsigned rn = INSTR (9, 5);
303 unsigned rt = INSTR (4, 0);
2e8cf49e 304
2cdad34c 305 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
306 aarch64_set_reg_u64 (cpu, rt, NO_SP, (uint32_t) aarch64_get_mem_s8
307 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
308 + offset));
309}
310
311/* 64 bit load sign-extended byte unscaled signed 9 bit. */
312static void
313ldursb64 (sim_cpu *cpu, int32_t offset)
314{
ef0d8ffc
NC
315 unsigned rn = INSTR (9, 5);
316 unsigned rt = INSTR (4, 0);
2e8cf49e 317
2cdad34c 318 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
319 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s8
320 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
321 + offset));
322}
323
324/* 32 bit load zero-extended short unscaled signed 9 bit */
325static void
326ldurh32 (sim_cpu *cpu, int32_t offset)
327{
ef0d8ffc
NC
328 unsigned rn = INSTR (9, 5);
329 unsigned rd = INSTR (4, 0);
2e8cf49e 330
2cdad34c 331 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
332 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_mem_u16
333 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
334 + offset));
335}
336
337/* 32 bit load sign-extended short unscaled signed 9 bit */
338static void
339ldursh32 (sim_cpu *cpu, int32_t offset)
340{
ef0d8ffc
NC
341 unsigned rn = INSTR (9, 5);
342 unsigned rd = INSTR (4, 0);
2e8cf49e 343
2cdad34c 344 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
345 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s16
346 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
347 + offset));
348}
349
350/* 64 bit load sign-extended short unscaled signed 9 bit */
351static void
352ldursh64 (sim_cpu *cpu, int32_t offset)
353{
ef0d8ffc
NC
354 unsigned rn = INSTR (9, 5);
355 unsigned rt = INSTR (4, 0);
2e8cf49e 356
2cdad34c 357 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
358 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s16
359 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
360 + offset));
361}
362
363/* 64 bit load sign-extended word unscaled signed 9 bit */
364static void
365ldursw (sim_cpu *cpu, int32_t offset)
366{
ef0d8ffc
NC
367 unsigned rn = INSTR (9, 5);
368 unsigned rd = INSTR (4, 0);
2e8cf49e 369
2cdad34c 370 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
371 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s32
372 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
373 + offset));
374}
375
376/* N.B. with stores the value in source is written to the address
377 identified by source2 modified by offset. */
378
379/* 32 bit store 32 bit unscaled signed 9 bit. */
380static void
381stur32 (sim_cpu *cpu, int32_t offset)
382{
ef0d8ffc
NC
383 unsigned rn = INSTR (9, 5);
384 unsigned rd = INSTR (4, 0);
2e8cf49e 385
2cdad34c 386 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
387 aarch64_set_mem_u32 (cpu,
388 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
389 aarch64_get_reg_u32 (cpu, rd, NO_SP));
390}
391
392/* 64 bit store 64 bit unscaled signed 9 bit */
393static void
394stur64 (sim_cpu *cpu, int32_t offset)
395{
ef0d8ffc
NC
396 unsigned rn = INSTR (9, 5);
397 unsigned rd = INSTR (4, 0);
2e8cf49e 398
2cdad34c 399 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
400 aarch64_set_mem_u64 (cpu,
401 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
402 aarch64_get_reg_u64 (cpu, rd, NO_SP));
403}
404
405/* 32 bit store byte unscaled signed 9 bit */
406static void
407sturb (sim_cpu *cpu, int32_t offset)
408{
ef0d8ffc
NC
409 unsigned rn = INSTR (9, 5);
410 unsigned rd = INSTR (4, 0);
2e8cf49e 411
2cdad34c 412 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
413 aarch64_set_mem_u8 (cpu,
414 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
415 aarch64_get_reg_u8 (cpu, rd, NO_SP));
416}
417
418/* 32 bit store short unscaled signed 9 bit */
419static void
420sturh (sim_cpu *cpu, int32_t offset)
421{
ef0d8ffc
NC
422 unsigned rn = INSTR (9, 5);
423 unsigned rd = INSTR (4, 0);
2e8cf49e 424
2cdad34c 425 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
426 aarch64_set_mem_u16 (cpu,
427 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
428 aarch64_get_reg_u16 (cpu, rd, NO_SP));
429}
430
431/* Load single register pc-relative label
432 Offset is a signed 19 bit immediate count in words
433 rt may not be SP. */
434
435/* 32 bit pc-relative load */
436static void
437ldr32_pcrel (sim_cpu *cpu, int32_t offset)
438{
ef0d8ffc 439 unsigned rd = INSTR (4, 0);
2e8cf49e 440
2cdad34c 441 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
442 aarch64_set_reg_u64 (cpu, rd, NO_SP,
443 aarch64_get_mem_u32
444 (cpu, aarch64_get_PC (cpu) + offset * 4));
445}
446
447/* 64 bit pc-relative load */
448static void
449ldr_pcrel (sim_cpu *cpu, int32_t offset)
450{
ef0d8ffc 451 unsigned rd = INSTR (4, 0);
2e8cf49e 452
2cdad34c 453 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
454 aarch64_set_reg_u64 (cpu, rd, NO_SP,
455 aarch64_get_mem_u64
456 (cpu, aarch64_get_PC (cpu) + offset * 4));
457}
458
459/* sign extended 32 bit pc-relative load */
460static void
461ldrsw_pcrel (sim_cpu *cpu, int32_t offset)
462{
ef0d8ffc 463 unsigned rd = INSTR (4, 0);
2e8cf49e 464
2cdad34c 465 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
466 aarch64_set_reg_u64 (cpu, rd, NO_SP,
467 aarch64_get_mem_s32
468 (cpu, aarch64_get_PC (cpu) + offset * 4));
469}
470
471/* float pc-relative load */
472static void
473fldrs_pcrel (sim_cpu *cpu, int32_t offset)
474{
ef0d8ffc 475 unsigned int rd = INSTR (4, 0);
2e8cf49e 476
2cdad34c 477 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
478 aarch64_set_vec_u32 (cpu, rd, 0,
479 aarch64_get_mem_u32
480 (cpu, aarch64_get_PC (cpu) + offset * 4));
2e8cf49e
NC
481}
482
483/* double pc-relative load */
484static void
485fldrd_pcrel (sim_cpu *cpu, int32_t offset)
486{
ef0d8ffc 487 unsigned int st = INSTR (4, 0);
2e8cf49e 488
2cdad34c 489 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
490 aarch64_set_vec_u64 (cpu, st, 0,
491 aarch64_get_mem_u64
492 (cpu, aarch64_get_PC (cpu) + offset * 4));
2e8cf49e
NC
493}
494
495/* long double pc-relative load. */
496static void
497fldrq_pcrel (sim_cpu *cpu, int32_t offset)
498{
ef0d8ffc 499 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
500 uint64_t addr = aarch64_get_PC (cpu) + offset * 4;
501 FRegister a;
502
2cdad34c 503 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
504 aarch64_get_mem_long_double (cpu, addr, & a);
505 aarch64_set_FP_long_double (cpu, st, a);
506}
507
508/* This can be used to scale an offset by applying
509 the requisite shift. the second argument is either
510 16, 32 or 64. */
511
512#define SCALE(_offset, _elementSize) \
513 ((_offset) << ScaleShift ## _elementSize)
514
515/* This can be used to optionally scale a register derived offset
516 by applying the requisite shift as indicated by the Scaling
7517e550 517 argument. The second argument is either Byte, Short, Word
2e8cf49e
NC
518 or Long. The third argument is either Scaled or Unscaled.
519 N.B. when _Scaling is Scaled the shift gets ANDed with
520 all 1s while when it is Unscaled it gets ANDed with 0. */
521
522#define OPT_SCALE(_offset, _elementType, _Scaling) \
523 ((_offset) << (_Scaling ? ScaleShift ## _elementType : 0))
524
525/* This can be used to zero or sign extend a 32 bit register derived
526 value to a 64 bit value. the first argument must be the value as
527 a uint32_t and the second must be either UXTW or SXTW. The result
528 is returned as an int64_t. */
529
530static inline int64_t
531extend (uint32_t value, Extension extension)
532{
533 union
534 {
535 uint32_t u;
536 int32_t n;
537 } x;
538
539 /* A branchless variant of this ought to be possible. */
540 if (extension == UXTW || extension == NoExtension)
541 return value;
542
543 x.u = value;
544 return x.n;
545}
546
547/* Scalar Floating Point
548
549 FP load/store single register (4 addressing modes)
550
551 N.B. the base register (source) can be the stack pointer.
552 The secondary source register (source2) can only be an Xn register. */
553
554/* Load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
555static void
556fldrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
557{
ef0d8ffc
NC
558 unsigned rn = INSTR (9, 5);
559 unsigned st = INSTR (4, 0);
2e8cf49e
NC
560 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
561
562 if (wb != Post)
563 address += offset;
564
2cdad34c 565 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b 566 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32 (cpu, address));
2e8cf49e
NC
567 if (wb == Post)
568 address += offset;
569
570 if (wb != NoWriteBack)
571 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
572}
573
5ab6d79e
NC
574/* Load 8 bit with unsigned 12 bit offset. */
575static void
576fldrb_abs (sim_cpu *cpu, uint32_t offset)
577{
ef0d8ffc
NC
578 unsigned rd = INSTR (4, 0);
579 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
580 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
581
2cdad34c 582 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
583 aarch64_set_vec_u8 (cpu, rd, 0, aarch64_get_mem_u32 (cpu, addr));
584}
585
586/* Load 16 bit scaled unsigned 12 bit. */
587static void
588fldrh_abs (sim_cpu *cpu, uint32_t offset)
589{
ef0d8ffc
NC
590 unsigned rd = INSTR (4, 0);
591 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
592 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16);
593
2cdad34c 594 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
595 aarch64_set_vec_u16 (cpu, rd, 0, aarch64_get_mem_u16 (cpu, addr));
596}
597
2e8cf49e
NC
598/* Load 32 bit scaled unsigned 12 bit. */
599static void
600fldrs_abs (sim_cpu *cpu, uint32_t offset)
601{
ef0d8ffc
NC
602 unsigned rd = INSTR (4, 0);
603 unsigned rn = INSTR (9, 5);
5ab6d79e 604 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32);
2e8cf49e 605
2cdad34c 606 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
607 aarch64_set_vec_u32 (cpu, rd, 0, aarch64_get_mem_u32 (cpu, addr));
608}
609
610/* Load 64 bit scaled unsigned 12 bit. */
611static void
612fldrd_abs (sim_cpu *cpu, uint32_t offset)
613{
ef0d8ffc
NC
614 unsigned rd = INSTR (4, 0);
615 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
616 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64);
617
2cdad34c 618 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
619 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_mem_u64 (cpu, addr));
620}
621
622/* Load 128 bit scaled unsigned 12 bit. */
623static void
624fldrq_abs (sim_cpu *cpu, uint32_t offset)
625{
ef0d8ffc
NC
626 unsigned rd = INSTR (4, 0);
627 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
628 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
629
2cdad34c 630 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
631 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_mem_u64 (cpu, addr));
632 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_mem_u64 (cpu, addr + 8));
2e8cf49e
NC
633}
634
635/* Load 32 bit scaled or unscaled zero- or sign-extended
636 32-bit register offset. */
637static void
638fldrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
639{
ef0d8ffc
NC
640 unsigned rm = INSTR (20, 16);
641 unsigned rn = INSTR (9, 5);
642 unsigned st = INSTR (4, 0);
2e8cf49e
NC
643 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
644 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
645 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
646
2cdad34c 647 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
648 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
649 (cpu, address + displacement));
2e8cf49e
NC
650}
651
652/* Load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
653static void
654fldrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
655{
ef0d8ffc
NC
656 unsigned rn = INSTR (9, 5);
657 unsigned st = INSTR (4, 0);
2e8cf49e
NC
658 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
659
660 if (wb != Post)
661 address += offset;
662
2cdad34c 663 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b 664 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64 (cpu, address));
2e8cf49e
NC
665
666 if (wb == Post)
667 address += offset;
668
669 if (wb != NoWriteBack)
670 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
671}
672
2e8cf49e
NC
673/* Load 64 bit scaled or unscaled zero- or sign-extended 32-bit register offset. */
674static void
675fldrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
676{
ef0d8ffc 677 unsigned rm = INSTR (20, 16);
2e8cf49e
NC
678 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
679 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
680
681 fldrd_wb (cpu, displacement, NoWriteBack);
682}
683
684/* Load 128 bit unscaled signed 9 bit with pre- or post-writeback. */
685static void
686fldrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
687{
688 FRegister a;
ef0d8ffc
NC
689 unsigned rn = INSTR (9, 5);
690 unsigned st = INSTR (4, 0);
2e8cf49e
NC
691 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
692
693 if (wb != Post)
694 address += offset;
695
2cdad34c 696 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
697 aarch64_get_mem_long_double (cpu, address, & a);
698 aarch64_set_FP_long_double (cpu, st, a);
699
700 if (wb == Post)
701 address += offset;
702
703 if (wb != NoWriteBack)
704 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
705}
706
2e8cf49e
NC
707/* Load 128 bit scaled or unscaled zero- or sign-extended 32-bit register offset */
708static void
709fldrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
710{
ef0d8ffc 711 unsigned rm = INSTR (20, 16);
2e8cf49e
NC
712 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
713 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
714
715 fldrq_wb (cpu, displacement, NoWriteBack);
716}
717
718/* Memory Access
719
720 load-store single register
721 There are four addressing modes available here which all employ a
722 64 bit source (base) register.
723
724 N.B. the base register (source) can be the stack pointer.
725 The secondary source register (source2)can only be an Xn register.
726
727 Scaled, 12-bit, unsigned immediate offset, without pre- and
728 post-index options.
729 Unscaled, 9-bit, signed immediate offset with pre- or post-index
730 writeback.
731 scaled or unscaled 64-bit register offset.
732 scaled or unscaled 32-bit extended register offset.
733
734 All offsets are assumed to be raw from the decode i.e. the
735 simulator is expected to adjust scaled offsets based on the
736 accessed data size with register or extended register offset
737 versions the same applies except that in the latter case the
738 operation may also require a sign extend.
739
740 A separate method is provided for each possible addressing mode. */
741
742/* 32 bit load 32 bit scaled unsigned 12 bit */
743static void
744ldr32_abs (sim_cpu *cpu, uint32_t offset)
745{
ef0d8ffc
NC
746 unsigned rn = INSTR (9, 5);
747 unsigned rt = INSTR (4, 0);
2e8cf49e 748
2cdad34c 749 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
750 /* The target register may not be SP but the source may be. */
751 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
752 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
753 + SCALE (offset, 32)));
754}
755
756/* 32 bit load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
757static void
758ldr32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
759{
ef0d8ffc
NC
760 unsigned rn = INSTR (9, 5);
761 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
762 uint64_t address;
763
764 if (rn == rt && wb != NoWriteBack)
765 HALT_UNALLOC;
766
767 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
768
769 if (wb != Post)
770 address += offset;
771
2cdad34c 772 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
773 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
774
775 if (wb == Post)
776 address += offset;
777
778 if (wb != NoWriteBack)
779 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
780}
781
782/* 32 bit load 32 bit scaled or unscaled
783 zero- or sign-extended 32-bit register offset */
784static void
785ldr32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
786{
ef0d8ffc
NC
787 unsigned rm = INSTR (20, 16);
788 unsigned rn = INSTR (9, 5);
789 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
790 /* rn may reference SP, rm and rt must reference ZR */
791
792 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
793 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
794 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
795
2cdad34c 796 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
797 aarch64_set_reg_u64 (cpu, rt, NO_SP,
798 aarch64_get_mem_u32 (cpu, address + displacement));
799}
800
801/* 64 bit load 64 bit scaled unsigned 12 bit */
802static void
803ldr_abs (sim_cpu *cpu, uint32_t offset)
804{
ef0d8ffc
NC
805 unsigned rn = INSTR (9, 5);
806 unsigned rt = INSTR (4, 0);
2e8cf49e 807
2cdad34c 808 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
809 /* The target register may not be SP but the source may be. */
810 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
811 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
812 + SCALE (offset, 64)));
813}
814
815/* 64 bit load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
816static void
817ldr_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
818{
ef0d8ffc
NC
819 unsigned rn = INSTR (9, 5);
820 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
821 uint64_t address;
822
823 if (rn == rt && wb != NoWriteBack)
824 HALT_UNALLOC;
825
826 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
827
828 if (wb != Post)
829 address += offset;
830
2cdad34c 831 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
832 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
833
834 if (wb == Post)
835 address += offset;
836
837 if (wb != NoWriteBack)
838 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
839}
840
841/* 64 bit load 64 bit scaled or unscaled zero-
842 or sign-extended 32-bit register offset. */
843static void
844ldr_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
845{
ef0d8ffc
NC
846 unsigned rm = INSTR (20, 16);
847 unsigned rn = INSTR (9, 5);
848 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
849 /* rn may reference SP, rm and rt must reference ZR */
850
851 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
852 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
853 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
854
2cdad34c 855 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
856 aarch64_set_reg_u64 (cpu, rt, NO_SP,
857 aarch64_get_mem_u64 (cpu, address + displacement));
858}
859
860/* 32 bit load zero-extended byte scaled unsigned 12 bit. */
861static void
862ldrb32_abs (sim_cpu *cpu, uint32_t offset)
863{
ef0d8ffc
NC
864 unsigned rn = INSTR (9, 5);
865 unsigned rt = INSTR (4, 0);
2e8cf49e 866
2cdad34c 867 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
868 /* The target register may not be SP but the source may be
869 there is no scaling required for a byte load. */
870 aarch64_set_reg_u64 (cpu, rt, NO_SP,
871 aarch64_get_mem_u8
872 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
873}
874
875/* 32 bit load zero-extended byte unscaled signed 9 bit with pre- or post-writeback. */
876static void
877ldrb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
878{
ef0d8ffc
NC
879 unsigned rn = INSTR (9, 5);
880 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
881 uint64_t address;
882
883 if (rn == rt && wb != NoWriteBack)
884 HALT_UNALLOC;
885
886 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
887
888 if (wb != Post)
889 address += offset;
890
2cdad34c 891 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
892 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
893
894 if (wb == Post)
895 address += offset;
896
897 if (wb != NoWriteBack)
898 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
899}
900
901/* 32 bit load zero-extended byte scaled or unscaled zero-
902 or sign-extended 32-bit register offset. */
903static void
904ldrb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
905{
ef0d8ffc
NC
906 unsigned rm = INSTR (20, 16);
907 unsigned rn = INSTR (9, 5);
908 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
909 /* rn may reference SP, rm and rt must reference ZR */
910
911 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
912 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
913 extension);
914
2cdad34c 915 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
916 /* There is no scaling required for a byte load. */
917 aarch64_set_reg_u64 (cpu, rt, NO_SP,
918 aarch64_get_mem_u8 (cpu, address + displacement));
919}
920
921/* 64 bit load sign-extended byte unscaled signed 9 bit
922 with pre- or post-writeback. */
923static void
924ldrsb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
925{
ef0d8ffc
NC
926 unsigned rn = INSTR (9, 5);
927 unsigned rt = INSTR (4, 0);
2e8cf49e 928 uint64_t address;
7517e550 929 int64_t val;
2e8cf49e
NC
930
931 if (rn == rt && wb != NoWriteBack)
932 HALT_UNALLOC;
933
934 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
935
936 if (wb != Post)
937 address += offset;
938
2cdad34c 939 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
940 val = aarch64_get_mem_s8 (cpu, address);
941 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
942
943 if (wb == Post)
944 address += offset;
945
946 if (wb != NoWriteBack)
947 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
948}
949
950/* 64 bit load sign-extended byte scaled unsigned 12 bit. */
951static void
952ldrsb_abs (sim_cpu *cpu, uint32_t offset)
953{
954 ldrsb_wb (cpu, offset, NoWriteBack);
955}
956
957/* 64 bit load sign-extended byte scaled or unscaled zero-
958 or sign-extended 32-bit register offset. */
959static void
960ldrsb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
961{
ef0d8ffc
NC
962 unsigned rm = INSTR (20, 16);
963 unsigned rn = INSTR (9, 5);
964 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
965 /* rn may reference SP, rm and rt must reference ZR */
966
967 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
968 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
969 extension);
2cdad34c 970 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 971 /* There is no scaling required for a byte load. */
7517e550 972 aarch64_set_reg_s64 (cpu, rt, NO_SP,
2e8cf49e
NC
973 aarch64_get_mem_s8 (cpu, address + displacement));
974}
975
976/* 32 bit load zero-extended short scaled unsigned 12 bit. */
977static void
978ldrh32_abs (sim_cpu *cpu, uint32_t offset)
979{
ef0d8ffc
NC
980 unsigned rn = INSTR (9, 5);
981 unsigned rt = INSTR (4, 0);
7517e550 982 uint32_t val;
2e8cf49e 983
2cdad34c 984 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 985 /* The target register may not be SP but the source may be. */
7517e550
NC
986 val = aarch64_get_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
987 + SCALE (offset, 16));
988 aarch64_set_reg_u32 (cpu, rt, NO_SP, val);
2e8cf49e
NC
989}
990
991/* 32 bit load zero-extended short unscaled signed 9 bit
992 with pre- or post-writeback. */
993static void
994ldrh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
995{
ef0d8ffc
NC
996 unsigned rn = INSTR (9, 5);
997 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
998 uint64_t address;
999
1000 if (rn == rt && wb != NoWriteBack)
1001 HALT_UNALLOC;
1002
1003 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1004
1005 if (wb != Post)
1006 address += offset;
1007
2cdad34c 1008 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 1009 aarch64_set_reg_u32 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
2e8cf49e
NC
1010
1011 if (wb == Post)
1012 address += offset;
1013
1014 if (wb != NoWriteBack)
1015 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1016}
1017
1018/* 32 bit load zero-extended short scaled or unscaled zero-
1019 or sign-extended 32-bit register offset. */
1020static void
1021ldrh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1022{
ef0d8ffc
NC
1023 unsigned rm = INSTR (20, 16);
1024 unsigned rn = INSTR (9, 5);
1025 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1026 /* rn may reference SP, rm and rt must reference ZR */
1027
1028 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1029 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1030 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1031
2cdad34c 1032 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 1033 aarch64_set_reg_u32 (cpu, rt, NO_SP,
2e8cf49e
NC
1034 aarch64_get_mem_u16 (cpu, address + displacement));
1035}
1036
1037/* 32 bit load sign-extended short scaled unsigned 12 bit. */
1038static void
1039ldrsh32_abs (sim_cpu *cpu, uint32_t offset)
1040{
ef0d8ffc
NC
1041 unsigned rn = INSTR (9, 5);
1042 unsigned rt = INSTR (4, 0);
7517e550 1043 int32_t val;
2e8cf49e 1044
2cdad34c 1045 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 1046 /* The target register may not be SP but the source may be. */
7517e550
NC
1047 val = aarch64_get_mem_s16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1048 + SCALE (offset, 16));
1049 aarch64_set_reg_s32 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1050}
1051
1052/* 32 bit load sign-extended short unscaled signed 9 bit
1053 with pre- or post-writeback. */
1054static void
1055ldrsh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1056{
ef0d8ffc
NC
1057 unsigned rn = INSTR (9, 5);
1058 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1059 uint64_t address;
1060
1061 if (rn == rt && wb != NoWriteBack)
1062 HALT_UNALLOC;
1063
1064 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1065
1066 if (wb != Post)
1067 address += offset;
1068
2cdad34c 1069 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1070 aarch64_set_reg_s32 (cpu, rt, NO_SP,
1071 (int32_t) aarch64_get_mem_s16 (cpu, address));
2e8cf49e
NC
1072
1073 if (wb == Post)
1074 address += offset;
1075
1076 if (wb != NoWriteBack)
1077 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1078}
1079
1080/* 32 bit load sign-extended short scaled or unscaled zero-
1081 or sign-extended 32-bit register offset. */
1082static void
1083ldrsh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1084{
ef0d8ffc
NC
1085 unsigned rm = INSTR (20, 16);
1086 unsigned rn = INSTR (9, 5);
1087 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1088 /* rn may reference SP, rm and rt must reference ZR */
1089
1090 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1091 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1092 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1093
2cdad34c 1094 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1095 aarch64_set_reg_s32 (cpu, rt, NO_SP,
1096 (int32_t) aarch64_get_mem_s16
2e8cf49e
NC
1097 (cpu, address + displacement));
1098}
1099
1100/* 64 bit load sign-extended short scaled unsigned 12 bit. */
1101static void
1102ldrsh_abs (sim_cpu *cpu, uint32_t offset)
1103{
ef0d8ffc
NC
1104 unsigned rn = INSTR (9, 5);
1105 unsigned rt = INSTR (4, 0);
7517e550 1106 int64_t val;
2e8cf49e 1107
2cdad34c 1108 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 1109 /* The target register may not be SP but the source may be. */
7517e550
NC
1110 val = aarch64_get_mem_s16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1111 + SCALE (offset, 16));
1112 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1113}
1114
1115/* 64 bit load sign-extended short unscaled signed 9 bit
1116 with pre- or post-writeback. */
1117static void
1118ldrsh64_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1119{
ef0d8ffc
NC
1120 unsigned rn = INSTR (9, 5);
1121 unsigned rt = INSTR (4, 0);
2e8cf49e 1122 uint64_t address;
7517e550 1123 int64_t val;
2e8cf49e
NC
1124
1125 if (rn == rt && wb != NoWriteBack)
1126 HALT_UNALLOC;
1127
2cdad34c 1128 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1129 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1130
1131 if (wb != Post)
1132 address += offset;
1133
7517e550
NC
1134 val = aarch64_get_mem_s16 (cpu, address);
1135 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1136
1137 if (wb == Post)
1138 address += offset;
1139
1140 if (wb != NoWriteBack)
1141 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1142}
1143
1144/* 64 bit load sign-extended short scaled or unscaled zero-
1145 or sign-extended 32-bit register offset. */
1146static void
1147ldrsh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1148{
ef0d8ffc
NC
1149 unsigned rm = INSTR (20, 16);
1150 unsigned rn = INSTR (9, 5);
1151 unsigned rt = INSTR (4, 0);
7517e550 1152
2e8cf49e
NC
1153 /* rn may reference SP, rm and rt must reference ZR */
1154
1155 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1156 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1157 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
7517e550 1158 int64_t val;
2e8cf49e 1159
2cdad34c 1160 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1161 val = aarch64_get_mem_s16 (cpu, address + displacement);
1162 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1163}
1164
1165/* 64 bit load sign-extended 32 bit scaled unsigned 12 bit. */
1166static void
1167ldrsw_abs (sim_cpu *cpu, uint32_t offset)
1168{
ef0d8ffc
NC
1169 unsigned rn = INSTR (9, 5);
1170 unsigned rt = INSTR (4, 0);
7517e550 1171 int64_t val;
2e8cf49e 1172
2cdad34c 1173 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1174 val = aarch64_get_mem_s32 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1175 + SCALE (offset, 32));
2e8cf49e 1176 /* The target register may not be SP but the source may be. */
7517e550 1177 return aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1178}
1179
1180/* 64 bit load sign-extended 32 bit unscaled signed 9 bit
1181 with pre- or post-writeback. */
1182static void
1183ldrsw_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1184{
ef0d8ffc
NC
1185 unsigned rn = INSTR (9, 5);
1186 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1187 uint64_t address;
1188
1189 if (rn == rt && wb != NoWriteBack)
1190 HALT_UNALLOC;
1191
1192 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1193
1194 if (wb != Post)
1195 address += offset;
1196
2cdad34c 1197 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1198 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32 (cpu, address));
1199
1200 if (wb == Post)
1201 address += offset;
1202
1203 if (wb != NoWriteBack)
1204 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1205}
1206
1207/* 64 bit load sign-extended 32 bit scaled or unscaled zero-
1208 or sign-extended 32-bit register offset. */
1209static void
1210ldrsw_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1211{
ef0d8ffc
NC
1212 unsigned rm = INSTR (20, 16);
1213 unsigned rn = INSTR (9, 5);
1214 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1215 /* rn may reference SP, rm and rt must reference ZR */
1216
1217 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1218 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1219 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1220
2cdad34c 1221 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1222 aarch64_set_reg_s64 (cpu, rt, NO_SP,
1223 aarch64_get_mem_s32 (cpu, address + displacement));
1224}
1225
1226/* N.B. with stores the value in source is written to the
1227 address identified by source2 modified by source3/offset. */
1228
1229/* 32 bit store scaled unsigned 12 bit. */
1230static void
1231str32_abs (sim_cpu *cpu, uint32_t offset)
1232{
ef0d8ffc
NC
1233 unsigned rn = INSTR (9, 5);
1234 unsigned rt = INSTR (4, 0);
2e8cf49e 1235
2cdad34c 1236 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1237 /* The target register may not be SP but the source may be. */
1238 aarch64_set_mem_u32 (cpu, (aarch64_get_reg_u64 (cpu, rn, SP_OK)
1239 + SCALE (offset, 32)),
1240 aarch64_get_reg_u32 (cpu, rt, NO_SP));
1241}
1242
1243/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
1244static void
1245str32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1246{
ef0d8ffc
NC
1247 unsigned rn = INSTR (9, 5);
1248 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1249 uint64_t address;
1250
1251 if (rn == rt && wb != NoWriteBack)
1252 HALT_UNALLOC;
1253
1254 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1255 if (wb != Post)
1256 address += offset;
1257
2cdad34c 1258 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1259 aarch64_set_mem_u32 (cpu, address, aarch64_get_reg_u32 (cpu, rt, NO_SP));
1260
1261 if (wb == Post)
1262 address += offset;
1263
1264 if (wb != NoWriteBack)
1265 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1266}
1267
1268/* 32 bit store scaled or unscaled zero- or
1269 sign-extended 32-bit register offset. */
1270static void
1271str32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1272{
ef0d8ffc
NC
1273 unsigned rm = INSTR (20, 16);
1274 unsigned rn = INSTR (9, 5);
1275 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1276
1277 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1278 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1279 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1280
2cdad34c 1281 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1282 aarch64_set_mem_u32 (cpu, address + displacement,
1283 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1284}
1285
1286/* 64 bit store scaled unsigned 12 bit. */
1287static void
1288str_abs (sim_cpu *cpu, uint32_t offset)
1289{
ef0d8ffc
NC
1290 unsigned rn = INSTR (9, 5);
1291 unsigned rt = INSTR (4, 0);
2e8cf49e 1292
2cdad34c 1293 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1294 aarch64_set_mem_u64 (cpu,
1295 aarch64_get_reg_u64 (cpu, rn, SP_OK)
1296 + SCALE (offset, 64),
1297 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1298}
1299
1300/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
1301static void
1302str_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1303{
ef0d8ffc
NC
1304 unsigned rn = INSTR (9, 5);
1305 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1306 uint64_t address;
1307
1308 if (rn == rt && wb != NoWriteBack)
1309 HALT_UNALLOC;
1310
1311 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1312
1313 if (wb != Post)
1314 address += offset;
1315
2cdad34c 1316 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1317 aarch64_set_mem_u64 (cpu, address, aarch64_get_reg_u64 (cpu, rt, NO_SP));
1318
1319 if (wb == Post)
1320 address += offset;
1321
1322 if (wb != NoWriteBack)
1323 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1324}
1325
1326/* 64 bit store scaled or unscaled zero-
1327 or sign-extended 32-bit register offset. */
1328static void
1329str_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1330{
ef0d8ffc
NC
1331 unsigned rm = INSTR (20, 16);
1332 unsigned rn = INSTR (9, 5);
1333 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1334 /* rn may reference SP, rm and rt must reference ZR */
1335
1336 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1337 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1338 extension);
1339 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1340
2cdad34c 1341 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1342 aarch64_set_mem_u64 (cpu, address + displacement,
1343 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1344}
1345
1346/* 32 bit store byte scaled unsigned 12 bit. */
1347static void
1348strb_abs (sim_cpu *cpu, uint32_t offset)
1349{
ef0d8ffc
NC
1350 unsigned rn = INSTR (9, 5);
1351 unsigned rt = INSTR (4, 0);
2e8cf49e 1352
2cdad34c 1353 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1354 /* The target register may not be SP but the source may be.
1355 There is no scaling required for a byte load. */
1356 aarch64_set_mem_u8 (cpu,
1357 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
1358 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1359}
1360
1361/* 32 bit store byte unscaled signed 9 bit with pre- or post-writeback. */
1362static void
1363strb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1364{
ef0d8ffc
NC
1365 unsigned rn = INSTR (9, 5);
1366 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1367 uint64_t address;
1368
1369 if (rn == rt && wb != NoWriteBack)
1370 HALT_UNALLOC;
1371
1372 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1373
1374 if (wb != Post)
1375 address += offset;
1376
2cdad34c 1377 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1378 aarch64_set_mem_u8 (cpu, address, aarch64_get_reg_u8 (cpu, rt, NO_SP));
1379
1380 if (wb == Post)
1381 address += offset;
1382
1383 if (wb != NoWriteBack)
1384 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1385}
1386
1387/* 32 bit store byte scaled or unscaled zero-
1388 or sign-extended 32-bit register offset. */
1389static void
1390strb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1391{
ef0d8ffc
NC
1392 unsigned rm = INSTR (20, 16);
1393 unsigned rn = INSTR (9, 5);
1394 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1395 /* rn may reference SP, rm and rt must reference ZR */
1396
1397 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1398 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1399 extension);
1400
2cdad34c 1401 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1402 /* There is no scaling required for a byte load. */
1403 aarch64_set_mem_u8 (cpu, address + displacement,
1404 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1405}
1406
1407/* 32 bit store short scaled unsigned 12 bit. */
1408static void
1409strh_abs (sim_cpu *cpu, uint32_t offset)
1410{
ef0d8ffc
NC
1411 unsigned rn = INSTR (9, 5);
1412 unsigned rt = INSTR (4, 0);
2e8cf49e 1413
2cdad34c 1414 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1415 /* The target register may not be SP but the source may be. */
1416 aarch64_set_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1417 + SCALE (offset, 16),
1418 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1419}
1420
1421/* 32 bit store short unscaled signed 9 bit with pre- or post-writeback. */
1422static void
1423strh_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1424{
ef0d8ffc
NC
1425 unsigned rn = INSTR (9, 5);
1426 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1427 uint64_t address;
1428
1429 if (rn == rt && wb != NoWriteBack)
1430 HALT_UNALLOC;
1431
1432 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1433
1434 if (wb != Post)
1435 address += offset;
1436
2cdad34c 1437 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1438 aarch64_set_mem_u16 (cpu, address, aarch64_get_reg_u16 (cpu, rt, NO_SP));
1439
1440 if (wb == Post)
1441 address += offset;
1442
1443 if (wb != NoWriteBack)
1444 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1445}
1446
1447/* 32 bit store short scaled or unscaled zero-
1448 or sign-extended 32-bit register offset. */
1449static void
1450strh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1451{
ef0d8ffc
NC
1452 unsigned rm = INSTR (20, 16);
1453 unsigned rn = INSTR (9, 5);
1454 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1455 /* rn may reference SP, rm and rt must reference ZR */
1456
1457 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1458 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1459 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1460
2cdad34c 1461 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1462 aarch64_set_mem_u16 (cpu, address + displacement,
1463 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1464}
1465
1466/* Prefetch unsigned 12 bit. */
1467static void
1468prfm_abs (sim_cpu *cpu, uint32_t offset)
1469{
1470 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1471 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1472 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1473 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1474 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1475 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1476 ow ==> UNALLOC
ef0d8ffc 1477 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1478 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK)
1479 + SCALE (offset, 64). */
1480
1481 /* TODO : implement prefetch of address. */
1482}
1483
1484/* Prefetch scaled or unscaled zero- or sign-extended 32-bit register offset. */
1485static void
1486prfm_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1487{
1488 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1489 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1490 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1491 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1492 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1493 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1494 ow ==> UNALLOC
1495 rn may reference SP, rm may only reference ZR
ef0d8ffc 1496 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1497 uint64_t base = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1498 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1499 extension);
1500 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1501 uint64_t address = base + displacement. */
1502
1503 /* TODO : implement prefetch of address */
1504}
1505
1506/* 64 bit pc-relative prefetch. */
1507static void
1508prfm_pcrel (sim_cpu *cpu, int32_t offset)
1509{
1510 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1511 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1512 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1513 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1514 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1515 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1516 ow ==> UNALLOC
ef0d8ffc 1517 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1518 uint64_t address = aarch64_get_PC (cpu) + offset. */
1519
1520 /* TODO : implement this */
1521}
1522
1523/* Load-store exclusive. */
1524
1525static void
1526ldxr (sim_cpu *cpu)
1527{
ef0d8ffc
NC
1528 unsigned rn = INSTR (9, 5);
1529 unsigned rt = INSTR (4, 0);
2e8cf49e 1530 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
ef0d8ffc
NC
1531 int size = INSTR (31, 30);
1532 /* int ordered = INSTR (15, 15); */
1533 /* int exclusive = ! INSTR (23, 23); */
2e8cf49e 1534
2cdad34c 1535 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1536 switch (size)
1537 {
1538 case 0:
1539 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
1540 break;
1541 case 1:
1542 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
1543 break;
1544 case 2:
1545 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
1546 break;
1547 case 3:
1548 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
1549 break;
2e8cf49e
NC
1550 }
1551}
1552
1553static void
1554stxr (sim_cpu *cpu)
1555{
ef0d8ffc
NC
1556 unsigned rn = INSTR (9, 5);
1557 unsigned rt = INSTR (4, 0);
1558 unsigned rs = INSTR (20, 16);
2e8cf49e 1559 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
ef0d8ffc 1560 int size = INSTR (31, 30);
2e8cf49e
NC
1561 uint64_t data = aarch64_get_reg_u64 (cpu, rt, NO_SP);
1562
1563 switch (size)
1564 {
1565 case 0: aarch64_set_mem_u8 (cpu, address, data); break;
1566 case 1: aarch64_set_mem_u16 (cpu, address, data); break;
1567 case 2: aarch64_set_mem_u32 (cpu, address, data); break;
1568 case 3: aarch64_set_mem_u64 (cpu, address, data); break;
2e8cf49e
NC
1569 }
1570
2cdad34c 1571 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1572 aarch64_set_reg_u64 (cpu, rs, NO_SP, 0); /* Always exclusive... */
1573}
1574
1575static void
1576dexLoadLiteral (sim_cpu *cpu)
1577{
1578 /* instr[29,27] == 011
1579 instr[25,24] == 00
1580 instr[31,30:26] = opc: 000 ==> LDRW, 001 ==> FLDRS
1581 010 ==> LDRX, 011 ==> FLDRD
1582 100 ==> LDRSW, 101 ==> FLDRQ
1583 110 ==> PRFM, 111 ==> UNALLOC
1584 instr[26] ==> V : 0 ==> GReg, 1 ==> FReg
1585 instr[23, 5] == simm19 */
1586
ef0d8ffc 1587 /* unsigned rt = INSTR (4, 0); */
7517e550 1588 uint32_t dispatch = (INSTR (31, 30) << 1) | INSTR (26, 26);
2e8cf49e
NC
1589 int32_t imm = simm32 (aarch64_get_instr (cpu), 23, 5);
1590
1591 switch (dispatch)
1592 {
1593 case 0: ldr32_pcrel (cpu, imm); break;
1594 case 1: fldrs_pcrel (cpu, imm); break;
1595 case 2: ldr_pcrel (cpu, imm); break;
1596 case 3: fldrd_pcrel (cpu, imm); break;
1597 case 4: ldrsw_pcrel (cpu, imm); break;
1598 case 5: fldrq_pcrel (cpu, imm); break;
1599 case 6: prfm_pcrel (cpu, imm); break;
1600 case 7:
1601 default:
1602 HALT_UNALLOC;
1603 }
1604}
1605
1606/* Immediate arithmetic
1607 The aimm argument is a 12 bit unsigned value or a 12 bit unsigned
1608 value left shifted by 12 bits (done at decode).
1609
1610 N.B. the register args (dest, source) can normally be Xn or SP.
1611 the exception occurs for flag setting instructions which may
1612 only use Xn for the output (dest). */
1613
1614/* 32 bit add immediate. */
1615static void
1616add32 (sim_cpu *cpu, uint32_t aimm)
1617{
ef0d8ffc
NC
1618 unsigned rn = INSTR (9, 5);
1619 unsigned rd = INSTR (4, 0);
2e8cf49e 1620
2cdad34c 1621 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1622 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1623 aarch64_get_reg_u32 (cpu, rn, SP_OK) + aimm);
1624}
1625
1626/* 64 bit add immediate. */
1627static void
1628add64 (sim_cpu *cpu, uint32_t aimm)
1629{
ef0d8ffc
NC
1630 unsigned rn = INSTR (9, 5);
1631 unsigned rd = INSTR (4, 0);
2e8cf49e 1632
2cdad34c 1633 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1634 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1635 aarch64_get_reg_u64 (cpu, rn, SP_OK) + aimm);
1636}
1637
1638static void
1639set_flags_for_add32 (sim_cpu *cpu, int32_t value1, int32_t value2)
1640{
1641 int32_t result = value1 + value2;
1642 int64_t sresult = (int64_t) value1 + (int64_t) value2;
1643 uint64_t uresult = (uint64_t)(uint32_t) value1
1644 + (uint64_t)(uint32_t) value2;
1645 uint32_t flags = 0;
1646
1647 if (result == 0)
1648 flags |= Z;
1649
1650 if (result & (1 << 31))
1651 flags |= N;
1652
1653 if (uresult != result)
1654 flags |= C;
1655
1656 if (sresult != result)
1657 flags |= V;
1658
1659 aarch64_set_CPSR (cpu, flags);
1660}
1661
963201cf
JW
1662#define NEG(a) (((a) & signbit) == signbit)
1663#define POS(a) (((a) & signbit) == 0)
1664
2e8cf49e
NC
1665static void
1666set_flags_for_add64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1667{
963201cf
JW
1668 uint64_t result = value1 + value2;
1669 uint32_t flags = 0;
1670 uint64_t signbit = 1ULL << 63;
2e8cf49e
NC
1671
1672 if (result == 0)
1673 flags |= Z;
1674
963201cf 1675 if (NEG (result))
2e8cf49e
NC
1676 flags |= N;
1677
963201cf
JW
1678 if ( (NEG (value1) && NEG (value2))
1679 || (NEG (value1) && POS (result))
1680 || (NEG (value2) && POS (result)))
1681 flags |= C;
1682
1683 if ( (NEG (value1) && NEG (value2) && POS (result))
1684 || (POS (value1) && POS (value2) && NEG (result)))
1685 flags |= V;
2e8cf49e
NC
1686
1687 aarch64_set_CPSR (cpu, flags);
1688}
1689
2e8cf49e
NC
1690static void
1691set_flags_for_sub32 (sim_cpu *cpu, uint32_t value1, uint32_t value2)
1692{
1693 uint32_t result = value1 - value2;
1694 uint32_t flags = 0;
57aa1742 1695 uint32_t signbit = 1U << 31;
2e8cf49e
NC
1696
1697 if (result == 0)
1698 flags |= Z;
1699
1700 if (NEG (result))
1701 flags |= N;
1702
1703 if ( (NEG (value1) && POS (value2))
1704 || (NEG (value1) && POS (result))
1705 || (POS (value2) && POS (result)))
1706 flags |= C;
1707
1708 if ( (NEG (value1) && POS (value2) && POS (result))
1709 || (POS (value1) && NEG (value2) && NEG (result)))
1710 flags |= V;
1711
1712 aarch64_set_CPSR (cpu, flags);
1713}
1714
1715static void
1716set_flags_for_sub64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1717{
1718 uint64_t result = value1 - value2;
1719 uint32_t flags = 0;
1720 uint64_t signbit = 1ULL << 63;
1721
1722 if (result == 0)
1723 flags |= Z;
1724
1725 if (NEG (result))
1726 flags |= N;
1727
1728 if ( (NEG (value1) && POS (value2))
1729 || (NEG (value1) && POS (result))
1730 || (POS (value2) && POS (result)))
1731 flags |= C;
1732
1733 if ( (NEG (value1) && POS (value2) && POS (result))
1734 || (POS (value1) && NEG (value2) && NEG (result)))
1735 flags |= V;
1736
1737 aarch64_set_CPSR (cpu, flags);
1738}
1739
1740static void
1741set_flags_for_binop32 (sim_cpu *cpu, uint32_t result)
1742{
1743 uint32_t flags = 0;
1744
1745 if (result == 0)
1746 flags |= Z;
1747 else
1748 flags &= ~ Z;
1749
1750 if (result & (1 << 31))
1751 flags |= N;
1752 else
1753 flags &= ~ N;
1754
1755 aarch64_set_CPSR (cpu, flags);
1756}
1757
1758static void
1759set_flags_for_binop64 (sim_cpu *cpu, uint64_t result)
1760{
1761 uint32_t flags = 0;
1762
1763 if (result == 0)
1764 flags |= Z;
1765 else
1766 flags &= ~ Z;
1767
1768 if (result & (1ULL << 63))
1769 flags |= N;
1770 else
1771 flags &= ~ N;
1772
1773 aarch64_set_CPSR (cpu, flags);
1774}
1775
1776/* 32 bit add immediate set flags. */
1777static void
1778adds32 (sim_cpu *cpu, uint32_t aimm)
1779{
ef0d8ffc
NC
1780 unsigned rn = INSTR (9, 5);
1781 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1782 /* TODO : do we need to worry about signs here? */
1783 int32_t value1 = aarch64_get_reg_s32 (cpu, rn, SP_OK);
1784
2cdad34c 1785 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1786 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + aimm);
1787 set_flags_for_add32 (cpu, value1, aimm);
1788}
1789
1790/* 64 bit add immediate set flags. */
1791static void
1792adds64 (sim_cpu *cpu, uint32_t aimm)
1793{
ef0d8ffc
NC
1794 unsigned rn = INSTR (9, 5);
1795 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1796 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1797 uint64_t value2 = aimm;
1798
2cdad34c 1799 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1800 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1801 set_flags_for_add64 (cpu, value1, value2);
1802}
1803
1804/* 32 bit sub immediate. */
1805static void
1806sub32 (sim_cpu *cpu, uint32_t aimm)
1807{
ef0d8ffc
NC
1808 unsigned rn = INSTR (9, 5);
1809 unsigned rd = INSTR (4, 0);
2e8cf49e 1810
2cdad34c 1811 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1812 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1813 aarch64_get_reg_u32 (cpu, rn, SP_OK) - aimm);
1814}
1815
1816/* 64 bit sub immediate. */
1817static void
1818sub64 (sim_cpu *cpu, uint32_t aimm)
1819{
ef0d8ffc
NC
1820 unsigned rn = INSTR (9, 5);
1821 unsigned rd = INSTR (4, 0);
2e8cf49e 1822
2cdad34c 1823 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1824 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1825 aarch64_get_reg_u64 (cpu, rn, SP_OK) - aimm);
1826}
1827
1828/* 32 bit sub immediate set flags. */
1829static void
1830subs32 (sim_cpu *cpu, uint32_t aimm)
1831{
ef0d8ffc
NC
1832 unsigned rn = INSTR (9, 5);
1833 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1834 uint32_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1835 uint32_t value2 = aimm;
1836
2cdad34c 1837 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1838 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1839 set_flags_for_sub32 (cpu, value1, value2);
1840}
1841
1842/* 64 bit sub immediate set flags. */
1843static void
1844subs64 (sim_cpu *cpu, uint32_t aimm)
1845{
ef0d8ffc
NC
1846 unsigned rn = INSTR (9, 5);
1847 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1848 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1849 uint32_t value2 = aimm;
1850
2cdad34c 1851 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1852 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1853 set_flags_for_sub64 (cpu, value1, value2);
1854}
1855
1856/* Data Processing Register. */
1857
1858/* First two helpers to perform the shift operations. */
1859
1860static inline uint32_t
1861shifted32 (uint32_t value, Shift shift, uint32_t count)
1862{
1863 switch (shift)
1864 {
1865 default:
1866 case LSL:
1867 return (value << count);
1868 case LSR:
1869 return (value >> count);
1870 case ASR:
1871 {
1872 int32_t svalue = value;
1873 return (svalue >> count);
1874 }
1875 case ROR:
1876 {
1877 uint32_t top = value >> count;
1878 uint32_t bottom = value << (32 - count);
1879 return (bottom | top);
1880 }
1881 }
1882}
1883
1884static inline uint64_t
1885shifted64 (uint64_t value, Shift shift, uint32_t count)
1886{
1887 switch (shift)
1888 {
1889 default:
1890 case LSL:
1891 return (value << count);
1892 case LSR:
1893 return (value >> count);
1894 case ASR:
1895 {
1896 int64_t svalue = value;
1897 return (svalue >> count);
1898 }
1899 case ROR:
1900 {
1901 uint64_t top = value >> count;
1902 uint64_t bottom = value << (64 - count);
1903 return (bottom | top);
1904 }
1905 }
1906}
1907
1908/* Arithmetic shifted register.
1909 These allow an optional LSL, ASR or LSR to the second source
1910 register with a count up to the register bit count.
1911
1912 N.B register args may not be SP. */
1913
1914/* 32 bit ADD shifted register. */
1915static void
1916add32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1917{
ef0d8ffc
NC
1918 unsigned rm = INSTR (20, 16);
1919 unsigned rn = INSTR (9, 5);
1920 unsigned rd = INSTR (4, 0);
2e8cf49e 1921
2cdad34c 1922 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1923 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1924 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1925 + shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1926 shift, count));
1927}
1928
1929/* 64 bit ADD shifted register. */
1930static void
1931add64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1932{
ef0d8ffc
NC
1933 unsigned rm = INSTR (20, 16);
1934 unsigned rn = INSTR (9, 5);
1935 unsigned rd = INSTR (4, 0);
2e8cf49e 1936
2cdad34c 1937 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1938 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1939 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1940 + shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1941 shift, count));
1942}
1943
1944/* 32 bit ADD shifted register setting flags. */
1945static void
1946adds32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1947{
ef0d8ffc
NC
1948 unsigned rm = INSTR (20, 16);
1949 unsigned rn = INSTR (9, 5);
1950 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1951
1952 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1953 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1954 shift, count);
1955
2cdad34c 1956 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1957 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1958 set_flags_for_add32 (cpu, value1, value2);
1959}
1960
1961/* 64 bit ADD shifted register setting flags. */
1962static void
1963adds64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1964{
ef0d8ffc
NC
1965 unsigned rm = INSTR (20, 16);
1966 unsigned rn = INSTR (9, 5);
1967 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1968
1969 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1970 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1971 shift, count);
1972
2cdad34c 1973 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1974 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1975 set_flags_for_add64 (cpu, value1, value2);
1976}
1977
1978/* 32 bit SUB shifted register. */
1979static void
1980sub32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1981{
ef0d8ffc
NC
1982 unsigned rm = INSTR (20, 16);
1983 unsigned rn = INSTR (9, 5);
1984 unsigned rd = INSTR (4, 0);
2e8cf49e 1985
2cdad34c 1986 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1987 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1988 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1989 - shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1990 shift, count));
1991}
1992
1993/* 64 bit SUB shifted register. */
1994static void
1995sub64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1996{
ef0d8ffc
NC
1997 unsigned rm = INSTR (20, 16);
1998 unsigned rn = INSTR (9, 5);
1999 unsigned rd = INSTR (4, 0);
2e8cf49e 2000
2cdad34c 2001 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2002 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2003 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2004 - shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
2005 shift, count));
2006}
2007
2008/* 32 bit SUB shifted register setting flags. */
2009static void
2010subs32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
2011{
ef0d8ffc
NC
2012 unsigned rm = INSTR (20, 16);
2013 unsigned rn = INSTR (9, 5);
2014 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2015
2016 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2017 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
2018 shift, count);
2019
2cdad34c 2020 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2021 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2022 set_flags_for_sub32 (cpu, value1, value2);
2023}
2024
2025/* 64 bit SUB shifted register setting flags. */
2026static void
2027subs64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
2028{
ef0d8ffc
NC
2029 unsigned rm = INSTR (20, 16);
2030 unsigned rn = INSTR (9, 5);
2031 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2032
2033 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2034 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
2035 shift, count);
2036
2cdad34c 2037 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2038 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2039 set_flags_for_sub64 (cpu, value1, value2);
2040}
2041
2042/* First a couple more helpers to fetch the
2043 relevant source register element either
2044 sign or zero extended as required by the
2045 extension value. */
2046
2047static uint32_t
2048extreg32 (sim_cpu *cpu, unsigned int lo, Extension extension)
2049{
2050 switch (extension)
2051 {
2052 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
2053 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
2054 case UXTW: /* Fall through. */
2055 case UXTX: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
2056 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
2057 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
2058 case SXTW: /* Fall through. */
2059 case SXTX: /* Fall through. */
2060 default: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
2061 }
2062}
2063
2064static uint64_t
2065extreg64 (sim_cpu *cpu, unsigned int lo, Extension extension)
2066{
2067 switch (extension)
2068 {
2069 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
2070 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
2071 case UXTW: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
2072 case UXTX: return aarch64_get_reg_u64 (cpu, lo, NO_SP);
2073 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
2074 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
2075 case SXTW: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
2076 case SXTX:
2077 default: return aarch64_get_reg_s64 (cpu, lo, NO_SP);
2078 }
2079}
2080
2081/* Arithmetic extending register
2082 These allow an optional sign extension of some portion of the
2083 second source register followed by an optional left shift of
2084 between 1 and 4 bits (i.e. a shift of 0-4 bits???)
2085
2086 N.B output (dest) and first input arg (source) may normally be Xn
2087 or SP. However, for flag setting operations dest can only be
2088 Xn. Second input registers are always Xn. */
2089
2090/* 32 bit ADD extending register. */
2091static void
2092add32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2093{
ef0d8ffc
NC
2094 unsigned rm = INSTR (20, 16);
2095 unsigned rn = INSTR (9, 5);
2096 unsigned rd = INSTR (4, 0);
2e8cf49e 2097
2cdad34c 2098 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2099 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2100 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2101 + (extreg32 (cpu, rm, extension) << shift));
2102}
2103
2104/* 64 bit ADD extending register.
2105 N.B. This subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2106static void
2107add64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2108{
ef0d8ffc
NC
2109 unsigned rm = INSTR (20, 16);
2110 unsigned rn = INSTR (9, 5);
2111 unsigned rd = INSTR (4, 0);
2e8cf49e 2112
2cdad34c 2113 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2114 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2115 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2116 + (extreg64 (cpu, rm, extension) << shift));
2117}
2118
2119/* 32 bit ADD extending register setting flags. */
2120static void
2121adds32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2122{
ef0d8ffc
NC
2123 unsigned rm = INSTR (20, 16);
2124 unsigned rn = INSTR (9, 5);
2125 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2126
2127 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2128 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2129
2cdad34c 2130 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2131 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2132 set_flags_for_add32 (cpu, value1, value2);
2133}
2134
2135/* 64 bit ADD extending register setting flags */
2136/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2137static void
2138adds64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2139{
ef0d8ffc
NC
2140 unsigned rm = INSTR (20, 16);
2141 unsigned rn = INSTR (9, 5);
2142 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2143
2144 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2145 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2146
2cdad34c 2147 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2148 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2149 set_flags_for_add64 (cpu, value1, value2);
2150}
2151
2152/* 32 bit SUB extending register. */
2153static void
2154sub32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2155{
ef0d8ffc
NC
2156 unsigned rm = INSTR (20, 16);
2157 unsigned rn = INSTR (9, 5);
2158 unsigned rd = INSTR (4, 0);
2e8cf49e 2159
2cdad34c 2160 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2161 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2162 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2163 - (extreg32 (cpu, rm, extension) << shift));
2164}
2165
2166/* 64 bit SUB extending register. */
2167/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2168static void
2169sub64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2170{
ef0d8ffc
NC
2171 unsigned rm = INSTR (20, 16);
2172 unsigned rn = INSTR (9, 5);
2173 unsigned rd = INSTR (4, 0);
2e8cf49e 2174
2cdad34c 2175 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2176 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2177 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2178 - (extreg64 (cpu, rm, extension) << shift));
2179}
2180
2181/* 32 bit SUB extending register setting flags. */
2182static void
2183subs32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2184{
ef0d8ffc
NC
2185 unsigned rm = INSTR (20, 16);
2186 unsigned rn = INSTR (9, 5);
2187 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2188
2189 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2190 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2191
2cdad34c 2192 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2193 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2194 set_flags_for_sub32 (cpu, value1, value2);
2195}
2196
2197/* 64 bit SUB extending register setting flags */
2198/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2199static void
2200subs64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2201{
ef0d8ffc
NC
2202 unsigned rm = INSTR (20, 16);
2203 unsigned rn = INSTR (9, 5);
2204 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2205
2206 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2207 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2208
2cdad34c 2209 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2210 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2211 set_flags_for_sub64 (cpu, value1, value2);
2212}
2213
2214static void
2215dexAddSubtractImmediate (sim_cpu *cpu)
2216{
2217 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2218 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2219 instr[29] = set : 0 ==> no flags, 1 ==> set flags
2220 instr[28,24] = 10001
2221 instr[23,22] = shift : 00 == LSL#0, 01 = LSL#12 1x = UNALLOC
2222 instr[21,10] = uimm12
2223 instr[9,5] = Rn
2224 instr[4,0] = Rd */
2225
2226 /* N.B. the shift is applied at decode before calling the add/sub routine. */
ef0d8ffc
NC
2227 uint32_t shift = INSTR (23, 22);
2228 uint32_t imm = INSTR (21, 10);
2229 uint32_t dispatch = INSTR (31, 29);
2e8cf49e
NC
2230
2231 NYI_assert (28, 24, 0x11);
2232
2233 if (shift > 1)
2234 HALT_UNALLOC;
2235
2236 if (shift)
2237 imm <<= 12;
2238
2239 switch (dispatch)
2240 {
2241 case 0: add32 (cpu, imm); break;
2242 case 1: adds32 (cpu, imm); break;
2243 case 2: sub32 (cpu, imm); break;
2244 case 3: subs32 (cpu, imm); break;
2245 case 4: add64 (cpu, imm); break;
2246 case 5: adds64 (cpu, imm); break;
2247 case 6: sub64 (cpu, imm); break;
2248 case 7: subs64 (cpu, imm); break;
2e8cf49e
NC
2249 }
2250}
2251
2252static void
2253dexAddSubtractShiftedRegister (sim_cpu *cpu)
2254{
2255 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2256 instr[30,29] = op : 00 ==> ADD, 01 ==> ADDS, 10 ==> SUB, 11 ==> SUBS
2257 instr[28,24] = 01011
2258 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> UNALLOC
2259 instr[21] = 0
2260 instr[20,16] = Rm
2261 instr[15,10] = count : must be 0xxxxx for 32 bit
2262 instr[9,5] = Rn
2263 instr[4,0] = Rd */
2264
ef0d8ffc
NC
2265 uint32_t size = INSTR (31, 31);
2266 uint32_t count = INSTR (15, 10);
2267 Shift shiftType = INSTR (23, 22);
2e8cf49e
NC
2268
2269 NYI_assert (28, 24, 0x0B);
2270 NYI_assert (21, 21, 0);
2271
ef0d8ffc 2272 /* Shift encoded as ROR is unallocated. */
2e8cf49e
NC
2273 if (shiftType == ROR)
2274 HALT_UNALLOC;
2275
ef0d8ffc
NC
2276 /* 32 bit operations must have count[5] = 0
2277 or else we have an UNALLOC. */
2278 if (size == 0 && uimm (count, 5, 5))
2e8cf49e
NC
2279 HALT_UNALLOC;
2280
ef0d8ffc
NC
2281 /* Dispatch on size:op i.e instr [31,29]. */
2282 switch (INSTR (31, 29))
2e8cf49e
NC
2283 {
2284 case 0: add32_shift (cpu, shiftType, count); break;
2285 case 1: adds32_shift (cpu, shiftType, count); break;
2286 case 2: sub32_shift (cpu, shiftType, count); break;
2287 case 3: subs32_shift (cpu, shiftType, count); break;
2288 case 4: add64_shift (cpu, shiftType, count); break;
2289 case 5: adds64_shift (cpu, shiftType, count); break;
2290 case 6: sub64_shift (cpu, shiftType, count); break;
2291 case 7: subs64_shift (cpu, shiftType, count); break;
2e8cf49e
NC
2292 }
2293}
2294
2295static void
2296dexAddSubtractExtendedRegister (sim_cpu *cpu)
2297{
2298 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2299 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2300 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2301 instr[28,24] = 01011
2302 instr[23,22] = opt : 0 ==> ok, 1,2,3 ==> UNALLOC
2303 instr[21] = 1
2304 instr[20,16] = Rm
2305 instr[15,13] = option : 000 ==> UXTB, 001 ==> UXTH,
2306 000 ==> LSL|UXTW, 001 ==> UXTZ,
2307 000 ==> SXTB, 001 ==> SXTH,
2308 000 ==> SXTW, 001 ==> SXTX,
2309 instr[12,10] = shift : 0,1,2,3,4 ==> ok, 5,6,7 ==> UNALLOC
2310 instr[9,5] = Rn
2311 instr[4,0] = Rd */
2312
ef0d8ffc
NC
2313 Extension extensionType = INSTR (15, 13);
2314 uint32_t shift = INSTR (12, 10);
2e8cf49e
NC
2315
2316 NYI_assert (28, 24, 0x0B);
2317 NYI_assert (21, 21, 1);
2318
2319 /* Shift may not exceed 4. */
2320 if (shift > 4)
2321 HALT_UNALLOC;
2322
ef0d8ffc
NC
2323 /* Dispatch on size:op:set?. */
2324 switch (INSTR (31, 29))
2e8cf49e
NC
2325 {
2326 case 0: add32_ext (cpu, extensionType, shift); break;
2327 case 1: adds32_ext (cpu, extensionType, shift); break;
2328 case 2: sub32_ext (cpu, extensionType, shift); break;
2329 case 3: subs32_ext (cpu, extensionType, shift); break;
2330 case 4: add64_ext (cpu, extensionType, shift); break;
2331 case 5: adds64_ext (cpu, extensionType, shift); break;
2332 case 6: sub64_ext (cpu, extensionType, shift); break;
2333 case 7: subs64_ext (cpu, extensionType, shift); break;
2e8cf49e
NC
2334 }
2335}
2336
2337/* Conditional data processing
2338 Condition register is implicit 3rd source. */
2339
2340/* 32 bit add with carry. */
2341/* N.B register args may not be SP. */
2342
2343static void
2344adc32 (sim_cpu *cpu)
2345{
ef0d8ffc
NC
2346 unsigned rm = INSTR (20, 16);
2347 unsigned rn = INSTR (9, 5);
2348 unsigned rd = INSTR (4, 0);
2e8cf49e 2349
2cdad34c 2350 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2351 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2352 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2353 + aarch64_get_reg_u32 (cpu, rm, NO_SP)
2354 + IS_SET (C));
2355}
2356
2357/* 64 bit add with carry */
2358static void
2359adc64 (sim_cpu *cpu)
2360{
ef0d8ffc
NC
2361 unsigned rm = INSTR (20, 16);
2362 unsigned rn = INSTR (9, 5);
2363 unsigned rd = INSTR (4, 0);
2e8cf49e 2364
2cdad34c 2365 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2366 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2367 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2368 + aarch64_get_reg_u64 (cpu, rm, NO_SP)
2369 + IS_SET (C));
2370}
2371
2372/* 32 bit add with carry setting flags. */
2373static void
2374adcs32 (sim_cpu *cpu)
2375{
ef0d8ffc
NC
2376 unsigned rm = INSTR (20, 16);
2377 unsigned rn = INSTR (9, 5);
2378 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2379
2380 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2381 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2382 uint32_t carry = IS_SET (C);
2383
2cdad34c 2384 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2385 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2386 set_flags_for_add32 (cpu, value1, value2 + carry);
2387}
2388
2389/* 64 bit add with carry setting flags. */
2390static void
2391adcs64 (sim_cpu *cpu)
2392{
ef0d8ffc
NC
2393 unsigned rm = INSTR (20, 16);
2394 unsigned rn = INSTR (9, 5);
2395 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2396
2397 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2398 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2399 uint64_t carry = IS_SET (C);
2400
2cdad34c 2401 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2402 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2403 set_flags_for_add64 (cpu, value1, value2 + carry);
2404}
2405
2406/* 32 bit sub with carry. */
2407static void
2408sbc32 (sim_cpu *cpu)
2409{
ef0d8ffc
NC
2410 unsigned rm = INSTR (20, 16);
2411 unsigned rn = INSTR (9, 5); /* ngc iff rn == 31. */
2412 unsigned rd = INSTR (4, 0);
2e8cf49e 2413
2cdad34c 2414 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2415 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2416 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2417 - aarch64_get_reg_u32 (cpu, rm, NO_SP)
2418 - 1 + IS_SET (C));
2419}
2420
2421/* 64 bit sub with carry */
2422static void
2423sbc64 (sim_cpu *cpu)
2424{
ef0d8ffc
NC
2425 unsigned rm = INSTR (20, 16);
2426 unsigned rn = INSTR (9, 5);
2427 unsigned rd = INSTR (4, 0);
2e8cf49e 2428
2cdad34c 2429 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2430 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2431 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2432 - aarch64_get_reg_u64 (cpu, rm, NO_SP)
2433 - 1 + IS_SET (C));
2434}
2435
2436/* 32 bit sub with carry setting flags */
2437static void
2438sbcs32 (sim_cpu *cpu)
2439{
ef0d8ffc
NC
2440 unsigned rm = INSTR (20, 16);
2441 unsigned rn = INSTR (9, 5);
2442 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2443
2444 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2445 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2446 uint32_t carry = IS_SET (C);
2447 uint32_t result = value1 - value2 + 1 - carry;
2448
2cdad34c 2449 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2450 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2451 set_flags_for_sub32 (cpu, value1, value2 + 1 - carry);
2452}
2453
2454/* 64 bit sub with carry setting flags */
2455static void
2456sbcs64 (sim_cpu *cpu)
2457{
ef0d8ffc
NC
2458 unsigned rm = INSTR (20, 16);
2459 unsigned rn = INSTR (9, 5);
2460 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2461
2462 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2463 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2464 uint64_t carry = IS_SET (C);
2465 uint64_t result = value1 - value2 + 1 - carry;
2466
2cdad34c 2467 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2468 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2469 set_flags_for_sub64 (cpu, value1, value2 + 1 - carry);
2470}
2471
2472static void
2473dexAddSubtractWithCarry (sim_cpu *cpu)
2474{
2475 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2476 instr[30] = op : 0 ==> ADC, 1 ==> SBC
2477 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2478 instr[28,21] = 1 1010 000
2479 instr[20,16] = Rm
2480 instr[15,10] = op2 : 00000 ==> ok, ow ==> UNALLOC
2481 instr[9,5] = Rn
2482 instr[4,0] = Rd */
2483
ef0d8ffc 2484 uint32_t op2 = INSTR (15, 10);
2e8cf49e
NC
2485
2486 NYI_assert (28, 21, 0xD0);
2487
2488 if (op2 != 0)
2489 HALT_UNALLOC;
2490
ef0d8ffc
NC
2491 /* Dispatch on size:op:set?. */
2492 switch (INSTR (31, 29))
2e8cf49e
NC
2493 {
2494 case 0: adc32 (cpu); break;
2495 case 1: adcs32 (cpu); break;
2496 case 2: sbc32 (cpu); break;
2497 case 3: sbcs32 (cpu); break;
2498 case 4: adc64 (cpu); break;
2499 case 5: adcs64 (cpu); break;
2500 case 6: sbc64 (cpu); break;
2501 case 7: sbcs64 (cpu); break;
2e8cf49e
NC
2502 }
2503}
2504
2505static uint32_t
2506testConditionCode (sim_cpu *cpu, CondCode cc)
2507{
2508 /* This should be reduceable to branchless logic
2509 by some careful testing of bits in CC followed
2510 by the requisite masking and combining of bits
2511 from the flag register.
2512
2513 For now we do it with a switch. */
2514 int res;
2515
2516 switch (cc)
2517 {
2518 case EQ: res = IS_SET (Z); break;
2519 case NE: res = IS_CLEAR (Z); break;
2520 case CS: res = IS_SET (C); break;
2521 case CC: res = IS_CLEAR (C); break;
2522 case MI: res = IS_SET (N); break;
2523 case PL: res = IS_CLEAR (N); break;
2524 case VS: res = IS_SET (V); break;
2525 case VC: res = IS_CLEAR (V); break;
2526 case HI: res = IS_SET (C) && IS_CLEAR (Z); break;
2527 case LS: res = IS_CLEAR (C) || IS_SET (Z); break;
2528 case GE: res = IS_SET (N) == IS_SET (V); break;
2529 case LT: res = IS_SET (N) != IS_SET (V); break;
2530 case GT: res = IS_CLEAR (Z) && (IS_SET (N) == IS_SET (V)); break;
2531 case LE: res = IS_SET (Z) || (IS_SET (N) != IS_SET (V)); break;
2532 case AL:
2533 case NV:
2534 default:
2535 res = 1;
2536 break;
2537 }
2538 return res;
2539}
2540
2541static void
2542CondCompare (sim_cpu *cpu) /* aka: ccmp and ccmn */
2543{
2544 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
57aa1742 2545 instr[30] = compare with positive (1) or negative value (0)
2e8cf49e
NC
2546 instr[29,21] = 1 1101 0010
2547 instr[20,16] = Rm or const
2548 instr[15,12] = cond
2549 instr[11] = compare reg (0) or const (1)
2550 instr[10] = 0
2551 instr[9,5] = Rn
2552 instr[4] = 0
2553 instr[3,0] = value for CPSR bits if the comparison does not take place. */
2554 signed int negate;
2555 unsigned rm;
2556 unsigned rn;
2557
2558 NYI_assert (29, 21, 0x1d2);
2559 NYI_assert (10, 10, 0);
2560 NYI_assert (4, 4, 0);
2561
2cdad34c 2562 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2563 if (! testConditionCode (cpu, INSTR (15, 12)))
2e8cf49e 2564 {
ef0d8ffc 2565 aarch64_set_CPSR (cpu, INSTR (3, 0));
2e8cf49e
NC
2566 return;
2567 }
2568
ef0d8ffc
NC
2569 negate = INSTR (30, 30) ? 1 : -1;
2570 rm = INSTR (20, 16);
2571 rn = INSTR ( 9, 5);
2e8cf49e 2572
ef0d8ffc 2573 if (INSTR (31, 31))
2e8cf49e 2574 {
ef0d8ffc 2575 if (INSTR (11, 11))
2e8cf49e
NC
2576 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2577 negate * (uint64_t) rm);
2578 else
2579 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2580 negate * aarch64_get_reg_u64 (cpu, rm, SP_OK));
2581 }
2582 else
2583 {
ef0d8ffc 2584 if (INSTR (11, 11))
2e8cf49e
NC
2585 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2586 negate * rm);
2587 else
2588 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2589 negate * aarch64_get_reg_u32 (cpu, rm, SP_OK));
2590 }
2591}
2592
2593static void
2594do_vec_MOV_whole_vector (sim_cpu *cpu)
2595{
2596 /* MOV Vd.T, Vs.T (alias for ORR Vd.T, Vn.T, Vm.T where Vn == Vm)
2597
2598 instr[31] = 0
2599 instr[30] = half(0)/full(1)
2600 instr[29,21] = 001110101
2601 instr[20,16] = Vs
2602 instr[15,10] = 000111
2603 instr[9,5] = Vs
2604 instr[4,0] = Vd */
2605
ef0d8ffc
NC
2606 unsigned vs = INSTR (9, 5);
2607 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2608
2609 NYI_assert (29, 21, 0x075);
2610 NYI_assert (15, 10, 0x07);
2611
ef0d8ffc 2612 if (INSTR (20, 16) != vs)
2e8cf49e
NC
2613 HALT_NYI;
2614
2cdad34c 2615 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2616 if (INSTR (30, 30))
2e8cf49e
NC
2617 aarch64_set_vec_u64 (cpu, vd, 1, aarch64_get_vec_u64 (cpu, vs, 1));
2618
2619 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vs, 0));
2620}
2621
2622static void
2623do_vec_MOV_into_scalar (sim_cpu *cpu)
2624{
2625 /* instr[31] = 0
2626 instr[30] = word(0)/long(1)
2627 instr[29,21] = 00 1110 000
2628 instr[20,18] = element size and index
2629 instr[17,10] = 00 0011 11
2630 instr[9,5] = V source
2631 instr[4,0] = R dest */
2632
ef0d8ffc
NC
2633 unsigned vs = INSTR (9, 5);
2634 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2635
2636 NYI_assert (29, 21, 0x070);
2637 NYI_assert (17, 10, 0x0F);
2638
2cdad34c 2639 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2640 switch (INSTR (20, 18))
2e8cf49e
NC
2641 {
2642 case 0x2:
2643 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 0));
2644 break;
2645
2646 case 0x6:
2647 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 1));
2648 break;
2649
2650 case 0x1:
2651 case 0x3:
2652 case 0x5:
2653 case 0x7:
2654 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u32
ef0d8ffc 2655 (cpu, vs, INSTR (20, 19)));
2e8cf49e
NC
2656 break;
2657
2658 default:
2659 HALT_NYI;
2660 }
2661}
2662
2663static void
2664do_vec_INS (sim_cpu *cpu)
2665{
2666 /* instr[31,21] = 01001110000
2667 instr[20,16] = element size and index
2668 instr[15,10] = 000111
2669 instr[9,5] = W source
2670 instr[4,0] = V dest */
2671
2672 int index;
ef0d8ffc
NC
2673 unsigned rs = INSTR (9, 5);
2674 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2675
2676 NYI_assert (31, 21, 0x270);
2677 NYI_assert (15, 10, 0x07);
2678
2cdad34c 2679 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2680 if (INSTR (16, 16))
2e8cf49e 2681 {
ef0d8ffc 2682 index = INSTR (20, 17);
2e8cf49e
NC
2683 aarch64_set_vec_u8 (cpu, vd, index,
2684 aarch64_get_reg_u8 (cpu, rs, NO_SP));
2685 }
ef0d8ffc 2686 else if (INSTR (17, 17))
2e8cf49e 2687 {
ef0d8ffc 2688 index = INSTR (20, 18);
2e8cf49e
NC
2689 aarch64_set_vec_u16 (cpu, vd, index,
2690 aarch64_get_reg_u16 (cpu, rs, NO_SP));
2691 }
ef0d8ffc 2692 else if (INSTR (18, 18))
2e8cf49e 2693 {
ef0d8ffc 2694 index = INSTR (20, 19);
2e8cf49e
NC
2695 aarch64_set_vec_u32 (cpu, vd, index,
2696 aarch64_get_reg_u32 (cpu, rs, NO_SP));
2697 }
ef0d8ffc 2698 else if (INSTR (19, 19))
2e8cf49e 2699 {
ef0d8ffc 2700 index = INSTR (20, 20);
2e8cf49e
NC
2701 aarch64_set_vec_u64 (cpu, vd, index,
2702 aarch64_get_reg_u64 (cpu, rs, NO_SP));
2703 }
2704 else
2705 HALT_NYI;
2706}
2707
2708static void
2709do_vec_DUP_vector_into_vector (sim_cpu *cpu)
2710{
2711 /* instr[31] = 0
2712 instr[30] = half(0)/full(1)
2713 instr[29,21] = 00 1110 000
2714 instr[20,16] = element size and index
2715 instr[15,10] = 0000 01
2716 instr[9,5] = V source
2717 instr[4,0] = V dest. */
2718
ef0d8ffc
NC
2719 unsigned full = INSTR (30, 30);
2720 unsigned vs = INSTR (9, 5);
2721 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2722 int i, index;
2723
2724 NYI_assert (29, 21, 0x070);
2725 NYI_assert (15, 10, 0x01);
2726
2cdad34c 2727 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2728 if (INSTR (16, 16))
2e8cf49e 2729 {
ef0d8ffc 2730 index = INSTR (20, 17);
2e8cf49e
NC
2731
2732 for (i = 0; i < (full ? 16 : 8); i++)
2733 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, index));
2734 }
ef0d8ffc 2735 else if (INSTR (17, 17))
2e8cf49e 2736 {
ef0d8ffc 2737 index = INSTR (20, 18);
2e8cf49e
NC
2738
2739 for (i = 0; i < (full ? 8 : 4); i++)
2740 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, index));
2741 }
ef0d8ffc 2742 else if (INSTR (18, 18))
2e8cf49e 2743 {
ef0d8ffc 2744 index = INSTR (20, 19);
2e8cf49e
NC
2745
2746 for (i = 0; i < (full ? 4 : 2); i++)
2747 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, index));
2748 }
2749 else
2750 {
ef0d8ffc 2751 if (INSTR (19, 19) == 0)
2e8cf49e
NC
2752 HALT_UNALLOC;
2753
2754 if (! full)
2755 HALT_UNALLOC;
2756
ef0d8ffc 2757 index = INSTR (20, 20);
2e8cf49e
NC
2758
2759 for (i = 0; i < 2; i++)
2760 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, index));
2761 }
2762}
2763
2764static void
2765do_vec_TBL (sim_cpu *cpu)
2766{
2767 /* instr[31] = 0
2768 instr[30] = half(0)/full(1)
2769 instr[29,21] = 00 1110 000
2770 instr[20,16] = Vm
2771 instr[15] = 0
2772 instr[14,13] = vec length
2773 instr[12,10] = 000
2774 instr[9,5] = V start
2775 instr[4,0] = V dest */
2776
ef0d8ffc
NC
2777 int full = INSTR (30, 30);
2778 int len = INSTR (14, 13) + 1;
2779 unsigned vm = INSTR (20, 16);
2780 unsigned vn = INSTR (9, 5);
2781 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2782 unsigned i;
2783
2784 NYI_assert (29, 21, 0x070);
2785 NYI_assert (12, 10, 0);
2786
2cdad34c 2787 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2788 for (i = 0; i < (full ? 16 : 8); i++)
2789 {
2790 unsigned int selector = aarch64_get_vec_u8 (cpu, vm, i);
2791 uint8_t val;
2792
2793 if (selector < 16)
2794 val = aarch64_get_vec_u8 (cpu, vn, selector);
2795 else if (selector < 32)
2796 val = len < 2 ? 0 : aarch64_get_vec_u8 (cpu, vn + 1, selector - 16);
2797 else if (selector < 48)
2798 val = len < 3 ? 0 : aarch64_get_vec_u8 (cpu, vn + 2, selector - 32);
2799 else if (selector < 64)
2800 val = len < 4 ? 0 : aarch64_get_vec_u8 (cpu, vn + 3, selector - 48);
2801 else
2802 val = 0;
2803
2804 aarch64_set_vec_u8 (cpu, vd, i, val);
2805 }
2806}
2807
2808static void
2809do_vec_TRN (sim_cpu *cpu)
2810{
2811 /* instr[31] = 0
2812 instr[30] = half(0)/full(1)
2813 instr[29,24] = 00 1110
2814 instr[23,22] = size
2815 instr[21] = 0
2816 instr[20,16] = Vm
2817 instr[15] = 0
2818 instr[14] = TRN1 (0) / TRN2 (1)
2819 instr[13,10] = 1010
2820 instr[9,5] = V source
2821 instr[4,0] = V dest. */
2822
ef0d8ffc
NC
2823 int full = INSTR (30, 30);
2824 int second = INSTR (14, 14);
2825 unsigned vm = INSTR (20, 16);
2826 unsigned vn = INSTR (9, 5);
2827 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2828 unsigned i;
2829
2830 NYI_assert (29, 24, 0x0E);
2831 NYI_assert (13, 10, 0xA);
2832
2cdad34c 2833 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2834 switch (INSTR (23, 22))
2e8cf49e
NC
2835 {
2836 case 0:
2837 for (i = 0; i < (full ? 8 : 4); i++)
2838 {
2839 aarch64_set_vec_u8
2840 (cpu, vd, i * 2,
2841 aarch64_get_vec_u8 (cpu, second ? vm : vn, i * 2));
2842 aarch64_set_vec_u8
2843 (cpu, vd, 1 * 2 + 1,
2844 aarch64_get_vec_u8 (cpu, second ? vn : vm, i * 2 + 1));
2845 }
2846 break;
2847
2848 case 1:
2849 for (i = 0; i < (full ? 4 : 2); i++)
2850 {
2851 aarch64_set_vec_u16
2852 (cpu, vd, i * 2,
2853 aarch64_get_vec_u16 (cpu, second ? vm : vn, i * 2));
2854 aarch64_set_vec_u16
2855 (cpu, vd, 1 * 2 + 1,
2856 aarch64_get_vec_u16 (cpu, second ? vn : vm, i * 2 + 1));
2857 }
2858 break;
2859
2860 case 2:
2861 aarch64_set_vec_u32
2862 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, second ? vm : vn, 0));
2863 aarch64_set_vec_u32
2864 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, second ? vn : vm, 1));
2865 aarch64_set_vec_u32
2866 (cpu, vd, 2, aarch64_get_vec_u32 (cpu, second ? vm : vn, 2));
2867 aarch64_set_vec_u32
2868 (cpu, vd, 3, aarch64_get_vec_u32 (cpu, second ? vn : vm, 3));
2869 break;
2870
2871 case 3:
2872 if (! full)
2873 HALT_UNALLOC;
2874
2875 aarch64_set_vec_u64 (cpu, vd, 0,
2876 aarch64_get_vec_u64 (cpu, second ? vm : vn, 0));
2877 aarch64_set_vec_u64 (cpu, vd, 1,
2878 aarch64_get_vec_u64 (cpu, second ? vn : vm, 1));
2879 break;
2e8cf49e
NC
2880 }
2881}
2882
2883static void
2884do_vec_DUP_scalar_into_vector (sim_cpu *cpu)
2885{
2886 /* instr[31] = 0
2887 instr[30] = 0=> zero top 64-bits, 1=> duplicate into top 64-bits
2888 [must be 1 for 64-bit xfer]
2889 instr[29,20] = 00 1110 0000
2890 instr[19,16] = element size: 0001=> 8-bits, 0010=> 16-bits,
2891 0100=> 32-bits. 1000=>64-bits
2892 instr[15,10] = 0000 11
2893 instr[9,5] = W source
2894 instr[4,0] = V dest. */
2895
2896 unsigned i;
ef0d8ffc
NC
2897 unsigned Vd = INSTR (4, 0);
2898 unsigned Rs = INSTR (9, 5);
2899 int both = INSTR (30, 30);
2e8cf49e
NC
2900
2901 NYI_assert (29, 20, 0x0E0);
2902 NYI_assert (15, 10, 0x03);
2903
2cdad34c 2904 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2905 switch (INSTR (19, 16))
2e8cf49e
NC
2906 {
2907 case 1:
2908 for (i = 0; i < (both ? 16 : 8); i++)
2909 aarch64_set_vec_u8 (cpu, Vd, i, aarch64_get_reg_u8 (cpu, Rs, NO_SP));
2910 break;
2911
2912 case 2:
2913 for (i = 0; i < (both ? 8 : 4); i++)
2914 aarch64_set_vec_u16 (cpu, Vd, i, aarch64_get_reg_u16 (cpu, Rs, NO_SP));
2915 break;
2916
2917 case 4:
2918 for (i = 0; i < (both ? 4 : 2); i++)
2919 aarch64_set_vec_u32 (cpu, Vd, i, aarch64_get_reg_u32 (cpu, Rs, NO_SP));
2920 break;
2921
2922 case 8:
2923 if (!both)
2924 HALT_NYI;
2925 aarch64_set_vec_u64 (cpu, Vd, 0, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2926 aarch64_set_vec_u64 (cpu, Vd, 1, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2927 break;
2928
2929 default:
2930 HALT_NYI;
2931 }
2932}
2933
2934static void
2935do_vec_UZP (sim_cpu *cpu)
2936{
2937 /* instr[31] = 0
2938 instr[30] = half(0)/full(1)
2939 instr[29,24] = 00 1110
2940 instr[23,22] = size: byte(00), half(01), word (10), long (11)
2941 instr[21] = 0
2942 instr[20,16] = Vm
2943 instr[15] = 0
2944 instr[14] = lower (0) / upper (1)
2945 instr[13,10] = 0110
2946 instr[9,5] = Vn
2947 instr[4,0] = Vd. */
2948
ef0d8ffc
NC
2949 int full = INSTR (30, 30);
2950 int upper = INSTR (14, 14);
2e8cf49e 2951
ef0d8ffc
NC
2952 unsigned vm = INSTR (20, 16);
2953 unsigned vn = INSTR (9, 5);
2954 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2955
2956 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2957 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2958 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2959 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2960
a4fb5981
JW
2961 uint64_t val1;
2962 uint64_t val2;
2e8cf49e 2963
a4fb5981 2964 uint64_t input2 = full ? val_n2 : val_m1;
2e8cf49e
NC
2965
2966 NYI_assert (29, 24, 0x0E);
2967 NYI_assert (21, 21, 0);
2968 NYI_assert (15, 15, 0);
2969 NYI_assert (13, 10, 6);
2970
2cdad34c 2971 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
a4fb5981 2972 switch (INSTR (23, 22))
2e8cf49e
NC
2973 {
2974 case 0:
a4fb5981
JW
2975 val1 = (val_n1 >> (upper * 8)) & 0xFFULL;
2976 val1 |= (val_n1 >> ((upper * 8) + 8)) & 0xFF00ULL;
2977 val1 |= (val_n1 >> ((upper * 8) + 16)) & 0xFF0000ULL;
2978 val1 |= (val_n1 >> ((upper * 8) + 24)) & 0xFF000000ULL;
2979
2980 val1 |= (input2 << (32 - (upper * 8))) & 0xFF00000000ULL;
2981 val1 |= (input2 << (24 - (upper * 8))) & 0xFF0000000000ULL;
2982 val1 |= (input2 << (16 - (upper * 8))) & 0xFF000000000000ULL;
2983 val1 |= (input2 << (8 - (upper * 8))) & 0xFF00000000000000ULL;
2984
2985 if (full)
2e8cf49e 2986 {
a4fb5981
JW
2987 val2 = (val_m1 >> (upper * 8)) & 0xFFULL;
2988 val2 |= (val_m1 >> ((upper * 8) + 8)) & 0xFF00ULL;
2989 val2 |= (val_m1 >> ((upper * 8) + 16)) & 0xFF0000ULL;
2990 val2 |= (val_m1 >> ((upper * 8) + 24)) & 0xFF000000ULL;
2991
2992 val2 |= (val_m2 << (32 - (upper * 8))) & 0xFF00000000ULL;
2993 val2 |= (val_m2 << (24 - (upper * 8))) & 0xFF0000000000ULL;
2994 val2 |= (val_m2 << (16 - (upper * 8))) & 0xFF000000000000ULL;
2995 val2 |= (val_m2 << (8 - (upper * 8))) & 0xFF00000000000000ULL;
2e8cf49e
NC
2996 }
2997 break;
2998
2999 case 1:
a4fb5981
JW
3000 val1 = (val_n1 >> (upper * 16)) & 0xFFFFULL;
3001 val1 |= (val_n1 >> ((upper * 16) + 16)) & 0xFFFF0000ULL;
3002
3003 val1 |= (input2 << (32 - (upper * 16))) & 0xFFFF00000000ULL;;
3004 val1 |= (input2 << (16 - (upper * 16))) & 0xFFFF000000000000ULL;
3005
3006 if (full)
2e8cf49e 3007 {
a4fb5981
JW
3008 val2 = (val_m1 >> (upper * 16)) & 0xFFFFULL;
3009 val2 |= (val_m1 >> ((upper * 16) + 16)) & 0xFFFF0000ULL;
3010
3011 val2 |= (val_m2 << (32 - (upper * 16))) & 0xFFFF00000000ULL;
3012 val2 |= (val_m2 << (16 - (upper * 16))) & 0xFFFF000000000000ULL;
2e8cf49e
NC
3013 }
3014 break;
3015
3016 case 2:
a4fb5981
JW
3017 val1 = (val_n1 >> (upper * 32)) & 0xFFFFFFFF;
3018 val1 |= (input2 << (32 - (upper * 32))) & 0xFFFFFFFF00000000ULL;
3019
3020 if (full)
3021 {
3022 val2 = (val_m1 >> (upper * 32)) & 0xFFFFFFFF;
3023 val2 |= (val_m2 << (32 - (upper * 32))) & 0xFFFFFFFF00000000ULL;
3024 }
3025 break;
2e8cf49e
NC
3026
3027 case 3:
a4fb5981
JW
3028 if (! full)
3029 HALT_UNALLOC;
3030
3031 val1 = upper ? val_n2 : val_n1;
3032 val2 = upper ? val_m2 : val_m1;
3033 break;
2e8cf49e
NC
3034 }
3035
3036 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3037 if (full)
3038 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3039}
3040
3041static void
3042do_vec_ZIP (sim_cpu *cpu)
3043{
3044 /* instr[31] = 0
3045 instr[30] = half(0)/full(1)
3046 instr[29,24] = 00 1110
3047 instr[23,22] = size: byte(00), hald(01), word (10), long (11)
3048 instr[21] = 0
3049 instr[20,16] = Vm
3050 instr[15] = 0
3051 instr[14] = lower (0) / upper (1)
3052 instr[13,10] = 1110
3053 instr[9,5] = Vn
3054 instr[4,0] = Vd. */
3055
ef0d8ffc
NC
3056 int full = INSTR (30, 30);
3057 int upper = INSTR (14, 14);
2e8cf49e 3058
ef0d8ffc
NC
3059 unsigned vm = INSTR (20, 16);
3060 unsigned vn = INSTR (9, 5);
3061 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3062
3063 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
3064 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
3065 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
3066 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
3067
3068 uint64_t val1 = 0;
3069 uint64_t val2 = 0;
3070
3071 uint64_t input1 = upper ? val_n1 : val_m1;
3072 uint64_t input2 = upper ? val_n2 : val_m2;
3073
3074 NYI_assert (29, 24, 0x0E);
3075 NYI_assert (21, 21, 0);
3076 NYI_assert (15, 15, 0);
3077 NYI_assert (13, 10, 0xE);
3078
2cdad34c 3079 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3080 switch (INSTR (23, 23))
2e8cf49e
NC
3081 {
3082 case 0:
3083 val1 =
3084 ((input1 << 0) & (0xFF << 0))
3085 | ((input2 << 8) & (0xFF << 8))
3086 | ((input1 << 8) & (0xFF << 16))
3087 | ((input2 << 16) & (0xFF << 24))
3088 | ((input1 << 16) & (0xFFULL << 32))
3089 | ((input2 << 24) & (0xFFULL << 40))
3090 | ((input1 << 24) & (0xFFULL << 48))
3091 | ((input2 << 32) & (0xFFULL << 56));
3092
3093 val2 =
3094 ((input1 >> 32) & (0xFF << 0))
3095 | ((input2 >> 24) & (0xFF << 8))
3096 | ((input1 >> 24) & (0xFF << 16))
3097 | ((input2 >> 16) & (0xFF << 24))
3098 | ((input1 >> 16) & (0xFFULL << 32))
3099 | ((input2 >> 8) & (0xFFULL << 40))
3100 | ((input1 >> 8) & (0xFFULL << 48))
3101 | ((input2 >> 0) & (0xFFULL << 56));
3102 break;
3103
3104 case 1:
3105 val1 =
3106 ((input1 << 0) & (0xFFFF << 0))
3107 | ((input2 << 16) & (0xFFFF << 16))
3108 | ((input1 << 16) & (0xFFFFULL << 32))
3109 | ((input2 << 32) & (0xFFFFULL << 48));
3110
3111 val2 =
3112 ((input1 >> 32) & (0xFFFF << 0))
3113 | ((input2 >> 16) & (0xFFFF << 16))
3114 | ((input1 >> 16) & (0xFFFFULL << 32))
3115 | ((input2 >> 0) & (0xFFFFULL << 48));
3116 break;
3117
3118 case 2:
3119 val1 = (input1 & 0xFFFFFFFFULL) | (input2 << 32);
3120 val2 = (input2 & 0xFFFFFFFFULL) | (input1 << 32);
3121 break;
3122
3123 case 3:
3124 val1 = input1;
3125 val2 = input2;
3126 break;
3127 }
3128
3129 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3130 if (full)
3131 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3132}
3133
3134/* Floating point immediates are encoded in 8 bits.
3135 fpimm[7] = sign bit.
3136 fpimm[6:4] = signed exponent.
3137 fpimm[3:0] = fraction (assuming leading 1).
3138 i.e. F = s * 1.f * 2^(e - b). */
3139
3140static float
3141fp_immediate_for_encoding_32 (uint32_t imm8)
3142{
3143 float u;
3144 uint32_t s, e, f, i;
3145
3146 s = (imm8 >> 7) & 0x1;
3147 e = (imm8 >> 4) & 0x7;
3148 f = imm8 & 0xf;
3149
3150 /* The fp value is s * n/16 * 2r where n is 16+e. */
3151 u = (16.0 + f) / 16.0;
3152
3153 /* N.B. exponent is signed. */
3154 if (e < 4)
3155 {
3156 int epos = e;
3157
3158 for (i = 0; i <= epos; i++)
3159 u *= 2.0;
3160 }
3161 else
3162 {
3163 int eneg = 7 - e;
3164
3165 for (i = 0; i < eneg; i++)
3166 u /= 2.0;
3167 }
3168
3169 if (s)
3170 u = - u;
3171
3172 return u;
3173}
3174
3175static double
3176fp_immediate_for_encoding_64 (uint32_t imm8)
3177{
3178 double u;
3179 uint32_t s, e, f, i;
3180
3181 s = (imm8 >> 7) & 0x1;
3182 e = (imm8 >> 4) & 0x7;
3183 f = imm8 & 0xf;
3184
3185 /* The fp value is s * n/16 * 2r where n is 16+e. */
3186 u = (16.0 + f) / 16.0;
3187
3188 /* N.B. exponent is signed. */
3189 if (e < 4)
3190 {
3191 int epos = e;
3192
3193 for (i = 0; i <= epos; i++)
3194 u *= 2.0;
3195 }
3196 else
3197 {
3198 int eneg = 7 - e;
3199
3200 for (i = 0; i < eneg; i++)
3201 u /= 2.0;
3202 }
3203
3204 if (s)
3205 u = - u;
3206
3207 return u;
3208}
3209
3210static void
3211do_vec_MOV_immediate (sim_cpu *cpu)
3212{
3213 /* instr[31] = 0
3214 instr[30] = full/half selector
3215 instr[29,19] = 00111100000
3216 instr[18,16] = high 3 bits of uimm8
3217 instr[15,12] = size & shift:
3218 0000 => 32-bit
3219 0010 => 32-bit + LSL#8
3220 0100 => 32-bit + LSL#16
3221 0110 => 32-bit + LSL#24
3222 1010 => 16-bit + LSL#8
3223 1000 => 16-bit
3224 1101 => 32-bit + MSL#16
3225 1100 => 32-bit + MSL#8
3226 1110 => 8-bit
3227 1111 => double
3228 instr[11,10] = 01
3229 instr[9,5] = low 5-bits of uimm8
3230 instr[4,0] = Vd. */
3231
ef0d8ffc
NC
3232 int full = INSTR (30, 30);
3233 unsigned vd = INSTR (4, 0);
7517e550 3234 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3235 unsigned i;
3236
3237 NYI_assert (29, 19, 0x1E0);
3238 NYI_assert (11, 10, 1);
3239
2cdad34c 3240 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3241 switch (INSTR (15, 12))
2e8cf49e
NC
3242 {
3243 case 0x0: /* 32-bit, no shift. */
3244 case 0x2: /* 32-bit, shift by 8. */
3245 case 0x4: /* 32-bit, shift by 16. */
3246 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3247 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3248 for (i = 0; i < (full ? 4 : 2); i++)
3249 aarch64_set_vec_u32 (cpu, vd, i, val);
3250 break;
3251
3252 case 0xa: /* 16-bit, shift by 8. */
3253 val <<= 8;
3254 /* Fall through. */
3255 case 0x8: /* 16-bit, no shift. */
3256 for (i = 0; i < (full ? 8 : 4); i++)
3257 aarch64_set_vec_u16 (cpu, vd, i, val);
c0386d4d
JW
3258 break;
3259
2e8cf49e
NC
3260 case 0xd: /* 32-bit, mask shift by 16. */
3261 val <<= 8;
3262 val |= 0xFF;
3263 /* Fall through. */
3264 case 0xc: /* 32-bit, mask shift by 8. */
3265 val <<= 8;
3266 val |= 0xFF;
3267 for (i = 0; i < (full ? 4 : 2); i++)
3268 aarch64_set_vec_u32 (cpu, vd, i, val);
3269 break;
3270
3271 case 0xe: /* 8-bit, no shift. */
3272 for (i = 0; i < (full ? 16 : 8); i++)
3273 aarch64_set_vec_u8 (cpu, vd, i, val);
3274 break;
3275
3276 case 0xf: /* FMOV Vs.{2|4}S, #fpimm. */
3277 {
3278 float u = fp_immediate_for_encoding_32 (val);
3279 for (i = 0; i < (full ? 4 : 2); i++)
3280 aarch64_set_vec_float (cpu, vd, i, u);
3281 break;
3282 }
3283
3284 default:
3285 HALT_NYI;
3286 }
3287}
3288
3289static void
3290do_vec_MVNI (sim_cpu *cpu)
3291{
3292 /* instr[31] = 0
3293 instr[30] = full/half selector
3294 instr[29,19] = 10111100000
3295 instr[18,16] = high 3 bits of uimm8
3296 instr[15,12] = selector
3297 instr[11,10] = 01
3298 instr[9,5] = low 5-bits of uimm8
3299 instr[4,0] = Vd. */
3300
ef0d8ffc
NC
3301 int full = INSTR (30, 30);
3302 unsigned vd = INSTR (4, 0);
7517e550 3303 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3304 unsigned i;
3305
3306 NYI_assert (29, 19, 0x5E0);
3307 NYI_assert (11, 10, 1);
3308
2cdad34c 3309 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3310 switch (INSTR (15, 12))
2e8cf49e
NC
3311 {
3312 case 0x0: /* 32-bit, no shift. */
3313 case 0x2: /* 32-bit, shift by 8. */
3314 case 0x4: /* 32-bit, shift by 16. */
3315 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3316 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3317 val = ~ val;
3318 for (i = 0; i < (full ? 4 : 2); i++)
3319 aarch64_set_vec_u32 (cpu, vd, i, val);
3320 return;
3321
3322 case 0xa: /* 16-bit, 8 bit shift. */
3323 val <<= 8;
3324 case 0x8: /* 16-bit, no shift. */
3325 val = ~ val;
3326 for (i = 0; i < (full ? 8 : 4); i++)
3327 aarch64_set_vec_u16 (cpu, vd, i, val);
3328 return;
3329
3330 case 0xd: /* 32-bit, mask shift by 16. */
3331 val <<= 8;
3332 val |= 0xFF;
3333 case 0xc: /* 32-bit, mask shift by 8. */
3334 val <<= 8;
3335 val |= 0xFF;
3336 val = ~ val;
3337 for (i = 0; i < (full ? 4 : 2); i++)
3338 aarch64_set_vec_u32 (cpu, vd, i, val);
3339 return;
3340
3341 case 0xE: /* MOVI Dn, #mask64 */
3342 {
3343 uint64_t mask = 0;
3344
3345 for (i = 0; i < 8; i++)
3346 if (val & (1 << i))
7517e550 3347 mask |= (0xFFUL << (i * 8));
2e8cf49e 3348 aarch64_set_vec_u64 (cpu, vd, 0, mask);
7517e550 3349 aarch64_set_vec_u64 (cpu, vd, 1, mask);
2e8cf49e
NC
3350 return;
3351 }
3352
3353 case 0xf: /* FMOV Vd.2D, #fpimm. */
3354 {
3355 double u = fp_immediate_for_encoding_64 (val);
3356
3357 if (! full)
3358 HALT_UNALLOC;
3359
3360 aarch64_set_vec_double (cpu, vd, 0, u);
3361 aarch64_set_vec_double (cpu, vd, 1, u);
3362 return;
3363 }
3364
3365 default:
3366 HALT_NYI;
3367 }
3368}
3369
3370#define ABS(A) ((A) < 0 ? - (A) : (A))
3371
3372static void
3373do_vec_ABS (sim_cpu *cpu)
3374{
3375 /* instr[31] = 0
3376 instr[30] = half(0)/full(1)
3377 instr[29,24] = 00 1110
3378 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3379 instr[21,10] = 10 0000 1011 10
3380 instr[9,5] = Vn
3381 instr[4.0] = Vd. */
3382
ef0d8ffc
NC
3383 unsigned vn = INSTR (9, 5);
3384 unsigned vd = INSTR (4, 0);
3385 unsigned full = INSTR (30, 30);
2e8cf49e
NC
3386 unsigned i;
3387
3388 NYI_assert (29, 24, 0x0E);
3389 NYI_assert (21, 10, 0x82E);
3390
2cdad34c 3391 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3392 switch (INSTR (23, 22))
2e8cf49e
NC
3393 {
3394 case 0:
3395 for (i = 0; i < (full ? 16 : 8); i++)
3396 aarch64_set_vec_s8 (cpu, vd, i,
3397 ABS (aarch64_get_vec_s8 (cpu, vn, i)));
3398 break;
3399
3400 case 1:
3401 for (i = 0; i < (full ? 8 : 4); i++)
3402 aarch64_set_vec_s16 (cpu, vd, i,
3403 ABS (aarch64_get_vec_s16 (cpu, vn, i)));
3404 break;
3405
3406 case 2:
3407 for (i = 0; i < (full ? 4 : 2); i++)
3408 aarch64_set_vec_s32 (cpu, vd, i,
3409 ABS (aarch64_get_vec_s32 (cpu, vn, i)));
3410 break;
3411
3412 case 3:
3413 if (! full)
3414 HALT_NYI;
3415 for (i = 0; i < 2; i++)
3416 aarch64_set_vec_s64 (cpu, vd, i,
3417 ABS (aarch64_get_vec_s64 (cpu, vn, i)));
3418 break;
3419 }
3420}
3421
3422static void
3423do_vec_ADDV (sim_cpu *cpu)
3424{
3425 /* instr[31] = 0
3426 instr[30] = full/half selector
3427 instr[29,24] = 00 1110
3428 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3429 instr[21,10] = 11 0001 1011 10
3430 instr[9,5] = Vm
3431 instr[4.0] = Rd. */
3432
ef0d8ffc
NC
3433 unsigned vm = INSTR (9, 5);
3434 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
3435 unsigned i;
3436 uint64_t val = 0;
ef0d8ffc 3437 int full = INSTR (30, 30);
2e8cf49e
NC
3438
3439 NYI_assert (29, 24, 0x0E);
3440 NYI_assert (21, 10, 0xC6E);
3441
2cdad34c 3442 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3443 switch (INSTR (23, 22))
2e8cf49e
NC
3444 {
3445 case 0:
3446 for (i = 0; i < (full ? 16 : 8); i++)
3447 val += aarch64_get_vec_u8 (cpu, vm, i);
3448 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3449 return;
3450
3451 case 1:
3452 for (i = 0; i < (full ? 8 : 4); i++)
3453 val += aarch64_get_vec_u16 (cpu, vm, i);
3454 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3455 return;
3456
3457 case 2:
3458 for (i = 0; i < (full ? 4 : 2); i++)
3459 val += aarch64_get_vec_u32 (cpu, vm, i);
3460 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3461 return;
3462
3463 case 3:
3464 if (! full)
3465 HALT_UNALLOC;
3466 val = aarch64_get_vec_u64 (cpu, vm, 0);
3467 val += aarch64_get_vec_u64 (cpu, vm, 1);
3468 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3469 return;
2e8cf49e
NC
3470 }
3471}
3472
3473static void
3474do_vec_ins_2 (sim_cpu *cpu)
3475{
3476 /* instr[31,21] = 01001110000
3477 instr[20,18] = size & element selector
3478 instr[17,14] = 0000
3479 instr[13] = direction: to vec(0), from vec (1)
3480 instr[12,10] = 111
3481 instr[9,5] = Vm
3482 instr[4,0] = Vd. */
3483
3484 unsigned elem;
ef0d8ffc
NC
3485 unsigned vm = INSTR (9, 5);
3486 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3487
3488 NYI_assert (31, 21, 0x270);
3489 NYI_assert (17, 14, 0);
3490 NYI_assert (12, 10, 7);
3491
2cdad34c 3492 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3493 if (INSTR (13, 13) == 1)
2e8cf49e 3494 {
ef0d8ffc 3495 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3496 {
3497 /* 32-bit moves. */
ef0d8ffc 3498 elem = INSTR (20, 19);
2e8cf49e
NC
3499 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3500 aarch64_get_vec_u32 (cpu, vm, elem));
3501 }
3502 else
3503 {
3504 /* 64-bit moves. */
ef0d8ffc 3505 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3506 HALT_NYI;
3507
ef0d8ffc 3508 elem = INSTR (20, 20);
2e8cf49e
NC
3509 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3510 aarch64_get_vec_u64 (cpu, vm, elem));
3511 }
3512 }
3513 else
3514 {
ef0d8ffc 3515 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3516 {
3517 /* 32-bit moves. */
ef0d8ffc 3518 elem = INSTR (20, 19);
2e8cf49e
NC
3519 aarch64_set_vec_u32 (cpu, vd, elem,
3520 aarch64_get_reg_u32 (cpu, vm, NO_SP));
3521 }
3522 else
3523 {
3524 /* 64-bit moves. */
ef0d8ffc 3525 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3526 HALT_NYI;
3527
ef0d8ffc 3528 elem = INSTR (20, 20);
2e8cf49e
NC
3529 aarch64_set_vec_u64 (cpu, vd, elem,
3530 aarch64_get_reg_u64 (cpu, vm, NO_SP));
3531 }
3532 }
3533}
3534
7517e550
NC
3535#define DO_VEC_WIDENING_MUL(N, DST_TYPE, READ_TYPE, WRITE_TYPE) \
3536 do \
3537 { \
3538 DST_TYPE a[N], b[N]; \
3539 \
3540 for (i = 0; i < (N); i++) \
3541 { \
3542 a[i] = aarch64_get_vec_##READ_TYPE (cpu, vn, i + bias); \
3543 b[i] = aarch64_get_vec_##READ_TYPE (cpu, vm, i + bias); \
3544 } \
3545 for (i = 0; i < (N); i++) \
3546 aarch64_set_vec_##WRITE_TYPE (cpu, vd, i, a[i] * b[i]); \
3547 } \
3548 while (0)
3549
2e8cf49e
NC
3550static void
3551do_vec_mull (sim_cpu *cpu)
3552{
3553 /* instr[31] = 0
3554 instr[30] = lower(0)/upper(1) selector
3555 instr[29] = signed(0)/unsigned(1)
3556 instr[28,24] = 0 1110
3557 instr[23,22] = size: 8-bit (00), 16-bit (01), 32-bit (10)
3558 instr[21] = 1
3559 instr[20,16] = Vm
3560 instr[15,10] = 11 0000
3561 instr[9,5] = Vn
3562 instr[4.0] = Vd. */
3563
ef0d8ffc
NC
3564 int unsign = INSTR (29, 29);
3565 int bias = INSTR (30, 30);
3566 unsigned vm = INSTR (20, 16);
3567 unsigned vn = INSTR ( 9, 5);
3568 unsigned vd = INSTR ( 4, 0);
2e8cf49e
NC
3569 unsigned i;
3570
3571 NYI_assert (28, 24, 0x0E);
3572 NYI_assert (15, 10, 0x30);
3573
2cdad34c 3574 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
3575 /* NB: Read source values before writing results, in case
3576 the source and destination vectors are the same. */
ef0d8ffc 3577 switch (INSTR (23, 22))
2e8cf49e
NC
3578 {
3579 case 0:
3580 if (bias)
3581 bias = 8;
3582 if (unsign)
7517e550 3583 DO_VEC_WIDENING_MUL (8, uint16_t, u8, u16);
2e8cf49e 3584 else
7517e550 3585 DO_VEC_WIDENING_MUL (8, int16_t, s8, s16);
2e8cf49e
NC
3586 return;
3587
3588 case 1:
3589 if (bias)
3590 bias = 4;
3591 if (unsign)
7517e550 3592 DO_VEC_WIDENING_MUL (4, uint32_t, u16, u32);
2e8cf49e 3593 else
7517e550 3594 DO_VEC_WIDENING_MUL (4, int32_t, s16, s32);
2e8cf49e
NC
3595 return;
3596
3597 case 2:
3598 if (bias)
3599 bias = 2;
3600 if (unsign)
7517e550 3601 DO_VEC_WIDENING_MUL (2, uint64_t, u32, u64);
2e8cf49e 3602 else
7517e550 3603 DO_VEC_WIDENING_MUL (2, int64_t, s32, s64);
2e8cf49e
NC
3604 return;
3605
3606 case 3:
2e8cf49e
NC
3607 HALT_NYI;
3608 }
3609}
3610
3611static void
3612do_vec_fadd (sim_cpu *cpu)
3613{
3614 /* instr[31] = 0
3615 instr[30] = half(0)/full(1)
3616 instr[29,24] = 001110
3617 instr[23] = FADD(0)/FSUB(1)
3618 instr[22] = float (0)/double(1)
3619 instr[21] = 1
3620 instr[20,16] = Vm
3621 instr[15,10] = 110101
3622 instr[9,5] = Vn
3623 instr[4.0] = Vd. */
3624
ef0d8ffc
NC
3625 unsigned vm = INSTR (20, 16);
3626 unsigned vn = INSTR (9, 5);
3627 unsigned vd = INSTR (4, 0);
2e8cf49e 3628 unsigned i;
ef0d8ffc 3629 int full = INSTR (30, 30);
2e8cf49e
NC
3630
3631 NYI_assert (29, 24, 0x0E);
3632 NYI_assert (21, 21, 1);
3633 NYI_assert (15, 10, 0x35);
3634
2cdad34c 3635 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3636 if (INSTR (23, 23))
2e8cf49e 3637 {
ef0d8ffc 3638 if (INSTR (22, 22))
2e8cf49e
NC
3639 {
3640 if (! full)
3641 HALT_NYI;
3642
3643 for (i = 0; i < 2; i++)
3644 aarch64_set_vec_double (cpu, vd, i,
3645 aarch64_get_vec_double (cpu, vn, i)
3646 - aarch64_get_vec_double (cpu, vm, i));
3647 }
3648 else
3649 {
3650 for (i = 0; i < (full ? 4 : 2); i++)
3651 aarch64_set_vec_float (cpu, vd, i,
3652 aarch64_get_vec_float (cpu, vn, i)
3653 - aarch64_get_vec_float (cpu, vm, i));
3654 }
3655 }
3656 else
3657 {
ef0d8ffc 3658 if (INSTR (22, 22))
2e8cf49e
NC
3659 {
3660 if (! full)
3661 HALT_NYI;
3662
3663 for (i = 0; i < 2; i++)
3664 aarch64_set_vec_double (cpu, vd, i,
3665 aarch64_get_vec_double (cpu, vm, i)
3666 + aarch64_get_vec_double (cpu, vn, i));
3667 }
3668 else
3669 {
3670 for (i = 0; i < (full ? 4 : 2); i++)
3671 aarch64_set_vec_float (cpu, vd, i,
3672 aarch64_get_vec_float (cpu, vm, i)
3673 + aarch64_get_vec_float (cpu, vn, i));
3674 }
3675 }
3676}
3677
3678static void
3679do_vec_add (sim_cpu *cpu)
3680{
3681 /* instr[31] = 0
3682 instr[30] = full/half selector
3683 instr[29,24] = 001110
3684 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3685 instr[21] = 1
3686 instr[20,16] = Vn
3687 instr[15,10] = 100001
3688 instr[9,5] = Vm
3689 instr[4.0] = Vd. */
3690
ef0d8ffc
NC
3691 unsigned vm = INSTR (20, 16);
3692 unsigned vn = INSTR (9, 5);
3693 unsigned vd = INSTR (4, 0);
2e8cf49e 3694 unsigned i;
ef0d8ffc 3695 int full = INSTR (30, 30);
2e8cf49e
NC
3696
3697 NYI_assert (29, 24, 0x0E);
3698 NYI_assert (21, 21, 1);
3699 NYI_assert (15, 10, 0x21);
3700
2cdad34c 3701 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3702 switch (INSTR (23, 22))
2e8cf49e
NC
3703 {
3704 case 0:
3705 for (i = 0; i < (full ? 16 : 8); i++)
3706 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
3707 + aarch64_get_vec_u8 (cpu, vm, i));
3708 return;
3709
3710 case 1:
3711 for (i = 0; i < (full ? 8 : 4); i++)
3712 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
3713 + aarch64_get_vec_u16 (cpu, vm, i));
3714 return;
3715
3716 case 2:
3717 for (i = 0; i < (full ? 4 : 2); i++)
3718 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
3719 + aarch64_get_vec_u32 (cpu, vm, i));
3720 return;
3721
3722 case 3:
3723 if (! full)
3724 HALT_UNALLOC;
3725 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vn, 0)
3726 + aarch64_get_vec_u64 (cpu, vm, 0));
3727 aarch64_set_vec_u64 (cpu, vd, 1,
3728 aarch64_get_vec_u64 (cpu, vn, 1)
3729 + aarch64_get_vec_u64 (cpu, vm, 1));
3730 return;
2e8cf49e
NC
3731 }
3732}
3733
3734static void
3735do_vec_mul (sim_cpu *cpu)
3736{
3737 /* instr[31] = 0
3738 instr[30] = full/half selector
3739 instr[29,24] = 00 1110
3740 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3741 instr[21] = 1
3742 instr[20,16] = Vn
3743 instr[15,10] = 10 0111
3744 instr[9,5] = Vm
3745 instr[4.0] = Vd. */
3746
ef0d8ffc
NC
3747 unsigned vm = INSTR (20, 16);
3748 unsigned vn = INSTR (9, 5);
3749 unsigned vd = INSTR (4, 0);
2e8cf49e 3750 unsigned i;
ef0d8ffc 3751 int full = INSTR (30, 30);
7517e550 3752 int bias = 0;
2e8cf49e
NC
3753
3754 NYI_assert (29, 24, 0x0E);
3755 NYI_assert (21, 21, 1);
3756 NYI_assert (15, 10, 0x27);
3757
2cdad34c 3758 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3759 switch (INSTR (23, 22))
2e8cf49e
NC
3760 {
3761 case 0:
c0386d4d 3762 DO_VEC_WIDENING_MUL (full ? 16 : 8, uint8_t, u8, u8);
2e8cf49e
NC
3763 return;
3764
3765 case 1:
c0386d4d 3766 DO_VEC_WIDENING_MUL (full ? 8 : 4, uint16_t, u16, u16);
2e8cf49e
NC
3767 return;
3768
3769 case 2:
c0386d4d 3770 DO_VEC_WIDENING_MUL (full ? 4 : 2, uint32_t, u32, u32);
2e8cf49e
NC
3771 return;
3772
2e8cf49e
NC
3773 case 3:
3774 HALT_UNALLOC;
3775 }
3776}
3777
3778static void
3779do_vec_MLA (sim_cpu *cpu)
3780{
3781 /* instr[31] = 0
3782 instr[30] = full/half selector
3783 instr[29,24] = 00 1110
3784 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3785 instr[21] = 1
3786 instr[20,16] = Vn
3787 instr[15,10] = 1001 01
3788 instr[9,5] = Vm
3789 instr[4.0] = Vd. */
3790
ef0d8ffc
NC
3791 unsigned vm = INSTR (20, 16);
3792 unsigned vn = INSTR (9, 5);
3793 unsigned vd = INSTR (4, 0);
2e8cf49e 3794 unsigned i;
ef0d8ffc 3795 int full = INSTR (30, 30);
2e8cf49e
NC
3796
3797 NYI_assert (29, 24, 0x0E);
3798 NYI_assert (21, 21, 1);
3799 NYI_assert (15, 10, 0x25);
3800
2cdad34c 3801 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3802 switch (INSTR (23, 22))
2e8cf49e
NC
3803 {
3804 case 0:
7517e550
NC
3805 {
3806 uint16_t a[16], b[16];
2e8cf49e 3807
7517e550
NC
3808 for (i = 0; i < (full ? 16 : 8); i++)
3809 {
3810 a[i] = aarch64_get_vec_u8 (cpu, vn, i);
3811 b[i] = aarch64_get_vec_u8 (cpu, vm, i);
3812 }
3813
3814 for (i = 0; i < (full ? 16 : 8); i++)
3815 {
3816 uint16_t v = aarch64_get_vec_u8 (cpu, vd, i);
3817
3818 aarch64_set_vec_u16 (cpu, vd, i, v + (a[i] * b[i]));
3819 }
3820 }
2e8cf49e
NC
3821 return;
3822
3823 case 1:
7517e550
NC
3824 {
3825 uint32_t a[8], b[8];
2e8cf49e 3826
7517e550
NC
3827 for (i = 0; i < (full ? 8 : 4); i++)
3828 {
3829 a[i] = aarch64_get_vec_u16 (cpu, vn, i);
3830 b[i] = aarch64_get_vec_u16 (cpu, vm, i);
3831 }
3832
3833 for (i = 0; i < (full ? 8 : 4); i++)
3834 {
3835 uint32_t v = aarch64_get_vec_u16 (cpu, vd, i);
3836
3837 aarch64_set_vec_u32 (cpu, vd, i, v + (a[i] * b[i]));
3838 }
3839 }
2e8cf49e
NC
3840 return;
3841
3842 case 2:
7517e550
NC
3843 {
3844 uint64_t a[4], b[4];
2e8cf49e 3845
7517e550
NC
3846 for (i = 0; i < (full ? 4 : 2); i++)
3847 {
3848 a[i] = aarch64_get_vec_u32 (cpu, vn, i);
3849 b[i] = aarch64_get_vec_u32 (cpu, vm, i);
3850 }
3851
3852 for (i = 0; i < (full ? 4 : 2); i++)
3853 {
3854 uint64_t v = aarch64_get_vec_u32 (cpu, vd, i);
3855
3856 aarch64_set_vec_u64 (cpu, vd, i, v + (a[i] * b[i]));
3857 }
3858 }
2e8cf49e
NC
3859 return;
3860
2e8cf49e
NC
3861 case 3:
3862 HALT_UNALLOC;
3863 }
3864}
3865
3866static float
3867fmaxnm (float a, float b)
3868{
c0386d4d 3869 if (! isnan (a))
2e8cf49e 3870 {
c0386d4d 3871 if (! isnan (b))
2e8cf49e
NC
3872 return a > b ? a : b;
3873 return a;
3874 }
c0386d4d 3875 else if (! isnan (b))
2e8cf49e
NC
3876 return b;
3877 return a;
3878}
3879
3880static float
3881fminnm (float a, float b)
3882{
c0386d4d 3883 if (! isnan (a))
2e8cf49e 3884 {
c0386d4d 3885 if (! isnan (b))
2e8cf49e
NC
3886 return a < b ? a : b;
3887 return a;
3888 }
c0386d4d 3889 else if (! isnan (b))
2e8cf49e
NC
3890 return b;
3891 return a;
3892}
3893
3894static double
3895dmaxnm (double a, double b)
3896{
c0386d4d 3897 if (! isnan (a))
2e8cf49e 3898 {
c0386d4d 3899 if (! isnan (b))
2e8cf49e
NC
3900 return a > b ? a : b;
3901 return a;
3902 }
c0386d4d 3903 else if (! isnan (b))
2e8cf49e
NC
3904 return b;
3905 return a;
3906}
3907
3908static double
3909dminnm (double a, double b)
3910{
c0386d4d 3911 if (! isnan (a))
2e8cf49e 3912 {
c0386d4d 3913 if (! isnan (b))
2e8cf49e
NC
3914 return a < b ? a : b;
3915 return a;
3916 }
c0386d4d 3917 else if (! isnan (b))
2e8cf49e
NC
3918 return b;
3919 return a;
3920}
3921
3922static void
3923do_vec_FminmaxNMP (sim_cpu *cpu)
3924{
ef0d8ffc
NC
3925 /* instr [31] = 0
3926 instr [30] = half (0)/full (1)
3927 instr [29,24] = 10 1110
3928 instr [23] = max(0)/min(1)
3929 instr [22] = float (0)/double (1)
3930 instr [21] = 1
3931 instr [20,16] = Vn
3932 instr [15,10] = 1100 01
3933 instr [9,5] = Vm
3934 instr [4.0] = Vd. */
3935
3936 unsigned vm = INSTR (20, 16);
3937 unsigned vn = INSTR (9, 5);
3938 unsigned vd = INSTR (4, 0);
3939 int full = INSTR (30, 30);
2e8cf49e
NC
3940
3941 NYI_assert (29, 24, 0x2E);
3942 NYI_assert (21, 21, 1);
3943 NYI_assert (15, 10, 0x31);
3944
2cdad34c 3945 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3946 if (INSTR (22, 22))
2e8cf49e 3947 {
ef0d8ffc 3948 double (* fn)(double, double) = INSTR (23, 23)
2e8cf49e
NC
3949 ? dminnm : dmaxnm;
3950
3951 if (! full)
3952 HALT_NYI;
3953 aarch64_set_vec_double (cpu, vd, 0,
3954 fn (aarch64_get_vec_double (cpu, vn, 0),
3955 aarch64_get_vec_double (cpu, vn, 1)));
3956 aarch64_set_vec_double (cpu, vd, 0,
3957 fn (aarch64_get_vec_double (cpu, vm, 0),
3958 aarch64_get_vec_double (cpu, vm, 1)));
3959 }
3960 else
3961 {
ef0d8ffc 3962 float (* fn)(float, float) = INSTR (23, 23)
2e8cf49e
NC
3963 ? fminnm : fmaxnm;
3964
3965 aarch64_set_vec_float (cpu, vd, 0,
3966 fn (aarch64_get_vec_float (cpu, vn, 0),
3967 aarch64_get_vec_float (cpu, vn, 1)));
3968 if (full)
3969 aarch64_set_vec_float (cpu, vd, 1,
3970 fn (aarch64_get_vec_float (cpu, vn, 2),
3971 aarch64_get_vec_float (cpu, vn, 3)));
3972
3973 aarch64_set_vec_float (cpu, vd, (full ? 2 : 1),
3974 fn (aarch64_get_vec_float (cpu, vm, 0),
3975 aarch64_get_vec_float (cpu, vm, 1)));
3976 if (full)
3977 aarch64_set_vec_float (cpu, vd, 3,
3978 fn (aarch64_get_vec_float (cpu, vm, 2),
3979 aarch64_get_vec_float (cpu, vm, 3)));
3980 }
3981}
3982
3983static void
3984do_vec_AND (sim_cpu *cpu)
3985{
3986 /* instr[31] = 0
3987 instr[30] = half (0)/full (1)
3988 instr[29,21] = 001110001
3989 instr[20,16] = Vm
3990 instr[15,10] = 000111
3991 instr[9,5] = Vn
3992 instr[4.0] = Vd. */
3993
ef0d8ffc
NC
3994 unsigned vm = INSTR (20, 16);
3995 unsigned vn = INSTR (9, 5);
3996 unsigned vd = INSTR (4, 0);
2e8cf49e 3997 unsigned i;
ef0d8ffc 3998 int full = INSTR (30, 30);
2e8cf49e
NC
3999
4000 NYI_assert (29, 21, 0x071);
4001 NYI_assert (15, 10, 0x07);
4002
2cdad34c 4003 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4004 for (i = 0; i < (full ? 4 : 2); i++)
4005 aarch64_set_vec_u32 (cpu, vd, i,
4006 aarch64_get_vec_u32 (cpu, vn, i)
4007 & aarch64_get_vec_u32 (cpu, vm, i));
4008}
4009
4010static void
4011do_vec_BSL (sim_cpu *cpu)
4012{
4013 /* instr[31] = 0
4014 instr[30] = half (0)/full (1)
4015 instr[29,21] = 101110011
4016 instr[20,16] = Vm
4017 instr[15,10] = 000111
4018 instr[9,5] = Vn
4019 instr[4.0] = Vd. */
4020
ef0d8ffc
NC
4021 unsigned vm = INSTR (20, 16);
4022 unsigned vn = INSTR (9, 5);
4023 unsigned vd = INSTR (4, 0);
2e8cf49e 4024 unsigned i;
ef0d8ffc 4025 int full = INSTR (30, 30);
2e8cf49e
NC
4026
4027 NYI_assert (29, 21, 0x173);
4028 NYI_assert (15, 10, 0x07);
4029
2cdad34c 4030 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4031 for (i = 0; i < (full ? 16 : 8); i++)
4032 aarch64_set_vec_u8 (cpu, vd, i,
4033 ( aarch64_get_vec_u8 (cpu, vd, i)
4034 & aarch64_get_vec_u8 (cpu, vn, i))
4035 | ((~ aarch64_get_vec_u8 (cpu, vd, i))
4036 & aarch64_get_vec_u8 (cpu, vm, i)));
4037}
4038
4039static void
4040do_vec_EOR (sim_cpu *cpu)
4041{
4042 /* instr[31] = 0
4043 instr[30] = half (0)/full (1)
4044 instr[29,21] = 10 1110 001
4045 instr[20,16] = Vm
4046 instr[15,10] = 000111
4047 instr[9,5] = Vn
4048 instr[4.0] = Vd. */
4049
ef0d8ffc
NC
4050 unsigned vm = INSTR (20, 16);
4051 unsigned vn = INSTR (9, 5);
4052 unsigned vd = INSTR (4, 0);
2e8cf49e 4053 unsigned i;
ef0d8ffc 4054 int full = INSTR (30, 30);
2e8cf49e
NC
4055
4056 NYI_assert (29, 21, 0x171);
4057 NYI_assert (15, 10, 0x07);
4058
2cdad34c 4059 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4060 for (i = 0; i < (full ? 4 : 2); i++)
4061 aarch64_set_vec_u32 (cpu, vd, i,
4062 aarch64_get_vec_u32 (cpu, vn, i)
4063 ^ aarch64_get_vec_u32 (cpu, vm, i));
4064}
4065
4066static void
4067do_vec_bit (sim_cpu *cpu)
4068{
4069 /* instr[31] = 0
4070 instr[30] = half (0)/full (1)
4071 instr[29,23] = 10 1110 1
4072 instr[22] = BIT (0) / BIF (1)
4073 instr[21] = 1
4074 instr[20,16] = Vm
4075 instr[15,10] = 0001 11
4076 instr[9,5] = Vn
4077 instr[4.0] = Vd. */
4078
ef0d8ffc
NC
4079 unsigned vm = INSTR (20, 16);
4080 unsigned vn = INSTR (9, 5);
4081 unsigned vd = INSTR (4, 0);
4082 unsigned full = INSTR (30, 30);
4083 unsigned test_false = INSTR (22, 22);
2e8cf49e
NC
4084 unsigned i;
4085
4086 NYI_assert (29, 23, 0x5D);
4087 NYI_assert (21, 21, 1);
4088 NYI_assert (15, 10, 0x07);
4089
2cdad34c 4090 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4091 if (test_false)
4092 {
4093 for (i = 0; i < (full ? 16 : 8); i++)
4094 if (aarch64_get_vec_u32 (cpu, vn, i) == 0)
4095 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
4096 }
4097 else
4098 {
4099 for (i = 0; i < (full ? 16 : 8); i++)
4100 if (aarch64_get_vec_u32 (cpu, vn, i) != 0)
4101 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
4102 }
4103}
4104
4105static void
4106do_vec_ORN (sim_cpu *cpu)
4107{
4108 /* instr[31] = 0
4109 instr[30] = half (0)/full (1)
4110 instr[29,21] = 00 1110 111
4111 instr[20,16] = Vm
4112 instr[15,10] = 00 0111
4113 instr[9,5] = Vn
4114 instr[4.0] = Vd. */
4115
ef0d8ffc
NC
4116 unsigned vm = INSTR (20, 16);
4117 unsigned vn = INSTR (9, 5);
4118 unsigned vd = INSTR (4, 0);
2e8cf49e 4119 unsigned i;
ef0d8ffc 4120 int full = INSTR (30, 30);
2e8cf49e
NC
4121
4122 NYI_assert (29, 21, 0x077);
4123 NYI_assert (15, 10, 0x07);
4124
2cdad34c 4125 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4126 for (i = 0; i < (full ? 16 : 8); i++)
4127 aarch64_set_vec_u8 (cpu, vd, i,
4128 aarch64_get_vec_u8 (cpu, vn, i)
4129 | ~ aarch64_get_vec_u8 (cpu, vm, i));
4130}
4131
4132static void
4133do_vec_ORR (sim_cpu *cpu)
4134{
4135 /* instr[31] = 0
4136 instr[30] = half (0)/full (1)
4137 instr[29,21] = 00 1110 101
4138 instr[20,16] = Vm
4139 instr[15,10] = 0001 11
4140 instr[9,5] = Vn
4141 instr[4.0] = Vd. */
4142
ef0d8ffc
NC
4143 unsigned vm = INSTR (20, 16);
4144 unsigned vn = INSTR (9, 5);
4145 unsigned vd = INSTR (4, 0);
2e8cf49e 4146 unsigned i;
ef0d8ffc 4147 int full = INSTR (30, 30);
2e8cf49e
NC
4148
4149 NYI_assert (29, 21, 0x075);
4150 NYI_assert (15, 10, 0x07);
4151
2cdad34c 4152 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4153 for (i = 0; i < (full ? 16 : 8); i++)
4154 aarch64_set_vec_u8 (cpu, vd, i,
4155 aarch64_get_vec_u8 (cpu, vn, i)
4156 | aarch64_get_vec_u8 (cpu, vm, i));
4157}
4158
4159static void
4160do_vec_BIC (sim_cpu *cpu)
4161{
4162 /* instr[31] = 0
4163 instr[30] = half (0)/full (1)
4164 instr[29,21] = 00 1110 011
4165 instr[20,16] = Vm
4166 instr[15,10] = 00 0111
4167 instr[9,5] = Vn
4168 instr[4.0] = Vd. */
4169
ef0d8ffc
NC
4170 unsigned vm = INSTR (20, 16);
4171 unsigned vn = INSTR (9, 5);
4172 unsigned vd = INSTR (4, 0);
2e8cf49e 4173 unsigned i;
ef0d8ffc 4174 int full = INSTR (30, 30);
2e8cf49e
NC
4175
4176 NYI_assert (29, 21, 0x073);
4177 NYI_assert (15, 10, 0x07);
4178
2cdad34c 4179 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4180 for (i = 0; i < (full ? 16 : 8); i++)
4181 aarch64_set_vec_u8 (cpu, vd, i,
4182 aarch64_get_vec_u8 (cpu, vn, i)
4183 & ~ aarch64_get_vec_u8 (cpu, vm, i));
4184}
4185
4186static void
4187do_vec_XTN (sim_cpu *cpu)
4188{
4189 /* instr[31] = 0
4190 instr[30] = first part (0)/ second part (1)
4191 instr[29,24] = 00 1110
4192 instr[23,22] = size: byte(00), half(01), word (10)
4193 instr[21,10] = 1000 0100 1010
4194 instr[9,5] = Vs
4195 instr[4,0] = Vd. */
4196
ef0d8ffc
NC
4197 unsigned vs = INSTR (9, 5);
4198 unsigned vd = INSTR (4, 0);
4199 unsigned bias = INSTR (30, 30);
2e8cf49e
NC
4200 unsigned i;
4201
4202 NYI_assert (29, 24, 0x0E);
4203 NYI_assert (21, 10, 0x84A);
4204
2cdad34c 4205 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4206 switch (INSTR (23, 22))
2e8cf49e
NC
4207 {
4208 case 0:
4209 if (bias)
4210 for (i = 0; i < 8; i++)
4211 aarch64_set_vec_u8 (cpu, vd, i + 8,
4212 aarch64_get_vec_u16 (cpu, vs, i) >> 8);
4213 else
4214 for (i = 0; i < 8; i++)
4215 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i));
4216 return;
4217
4218 case 1:
4219 if (bias)
4220 for (i = 0; i < 4; i++)
4221 aarch64_set_vec_u16 (cpu, vd, i + 4,
4222 aarch64_get_vec_u32 (cpu, vs, i) >> 16);
4223 else
4224 for (i = 0; i < 4; i++)
4225 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, i));
4226 return;
4227
4228 case 2:
4229 if (bias)
4230 for (i = 0; i < 2; i++)
4231 aarch64_set_vec_u32 (cpu, vd, i + 4,
4232 aarch64_get_vec_u64 (cpu, vs, i) >> 32);
4233 else
4234 for (i = 0; i < 2; i++)
4235 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, i));
4236 return;
2e8cf49e
NC
4237 }
4238}
4239
2e8cf49e
NC
4240static void
4241do_vec_maxv (sim_cpu *cpu)
4242{
4243 /* instr[31] = 0
4244 instr[30] = half(0)/full(1)
4245 instr[29] = signed (0)/unsigned(1)
4246 instr[28,24] = 0 1110
4247 instr[23,22] = size: byte(00), half(01), word (10)
4248 instr[21] = 1
4249 instr[20,17] = 1 000
4250 instr[16] = max(0)/min(1)
4251 instr[15,10] = 1010 10
4252 instr[9,5] = V source
4253 instr[4.0] = R dest. */
4254
ef0d8ffc
NC
4255 unsigned vs = INSTR (9, 5);
4256 unsigned rd = INSTR (4, 0);
4257 unsigned full = INSTR (30, 30);
2e8cf49e
NC
4258 unsigned i;
4259
4260 NYI_assert (28, 24, 0x0E);
4261 NYI_assert (21, 21, 1);
4262 NYI_assert (20, 17, 8);
4263 NYI_assert (15, 10, 0x2A);
4264
2cdad34c 4265 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 4266 switch ((INSTR (29, 29) << 1) | INSTR (16, 16))
2e8cf49e
NC
4267 {
4268 case 0: /* SMAXV. */
4269 {
4270 int64_t smax;
ef0d8ffc 4271 switch (INSTR (23, 22))
2e8cf49e
NC
4272 {
4273 case 0:
4274 smax = aarch64_get_vec_s8 (cpu, vs, 0);
4275 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4276 smax = max (smax, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4277 break;
4278 case 1:
4279 smax = aarch64_get_vec_s16 (cpu, vs, 0);
4280 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4281 smax = max (smax, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4282 break;
4283 case 2:
4284 smax = aarch64_get_vec_s32 (cpu, vs, 0);
4285 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4286 smax = max (smax, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4287 break;
2e8cf49e
NC
4288 case 3:
4289 HALT_UNALLOC;
4290 }
4291 aarch64_set_reg_s64 (cpu, rd, NO_SP, smax);
4292 return;
4293 }
4294
4295 case 1: /* SMINV. */
4296 {
4297 int64_t smin;
ef0d8ffc 4298 switch (INSTR (23, 22))
2e8cf49e
NC
4299 {
4300 case 0:
4301 smin = aarch64_get_vec_s8 (cpu, vs, 0);
4302 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4303 smin = min (smin, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4304 break;
4305 case 1:
4306 smin = aarch64_get_vec_s16 (cpu, vs, 0);
4307 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4308 smin = min (smin, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4309 break;
4310 case 2:
4311 smin = aarch64_get_vec_s32 (cpu, vs, 0);
4312 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4313 smin = min (smin, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4314 break;
5ab6d79e 4315
2e8cf49e
NC
4316 case 3:
4317 HALT_UNALLOC;
4318 }
4319 aarch64_set_reg_s64 (cpu, rd, NO_SP, smin);
4320 return;
4321 }
4322
4323 case 2: /* UMAXV. */
4324 {
4325 uint64_t umax;
ef0d8ffc 4326 switch (INSTR (23, 22))
2e8cf49e
NC
4327 {
4328 case 0:
4329 umax = aarch64_get_vec_u8 (cpu, vs, 0);
4330 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4331 umax = max (umax, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4332 break;
4333 case 1:
4334 umax = aarch64_get_vec_u16 (cpu, vs, 0);
4335 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4336 umax = max (umax, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4337 break;
4338 case 2:
4339 umax = aarch64_get_vec_u32 (cpu, vs, 0);
4340 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4341 umax = max (umax, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4342 break;
5ab6d79e 4343
2e8cf49e
NC
4344 case 3:
4345 HALT_UNALLOC;
4346 }
4347 aarch64_set_reg_u64 (cpu, rd, NO_SP, umax);
4348 return;
4349 }
4350
4351 case 3: /* UMINV. */
4352 {
4353 uint64_t umin;
ef0d8ffc 4354 switch (INSTR (23, 22))
2e8cf49e
NC
4355 {
4356 case 0:
4357 umin = aarch64_get_vec_u8 (cpu, vs, 0);
4358 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4359 umin = min (umin, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4360 break;
4361 case 1:
4362 umin = aarch64_get_vec_u16 (cpu, vs, 0);
4363 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4364 umin = min (umin, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4365 break;
4366 case 2:
4367 umin = aarch64_get_vec_u32 (cpu, vs, 0);
4368 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4369 umin = min (umin, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4370 break;
5ab6d79e 4371
2e8cf49e
NC
4372 case 3:
4373 HALT_UNALLOC;
4374 }
4375 aarch64_set_reg_u64 (cpu, rd, NO_SP, umin);
4376 return;
4377 }
2e8cf49e
NC
4378 }
4379}
4380
4381static void
4382do_vec_fminmaxV (sim_cpu *cpu)
4383{
4384 /* instr[31,24] = 0110 1110
4385 instr[23] = max(0)/min(1)
4386 instr[22,14] = 011 0000 11
4387 instr[13,12] = nm(00)/normal(11)
4388 instr[11,10] = 10
4389 instr[9,5] = V source
4390 instr[4.0] = R dest. */
4391
ef0d8ffc
NC
4392 unsigned vs = INSTR (9, 5);
4393 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
4394 unsigned i;
4395 float res = aarch64_get_vec_float (cpu, vs, 0);
4396
4397 NYI_assert (31, 24, 0x6E);
4398 NYI_assert (22, 14, 0x0C3);
4399 NYI_assert (11, 10, 2);
4400
2cdad34c 4401 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4402 if (INSTR (23, 23))
2e8cf49e 4403 {
ef0d8ffc 4404 switch (INSTR (13, 12))
2e8cf49e
NC
4405 {
4406 case 0: /* FMNINNMV. */
4407 for (i = 1; i < 4; i++)
4408 res = fminnm (res, aarch64_get_vec_float (cpu, vs, i));
4409 break;
4410
4411 case 3: /* FMINV. */
4412 for (i = 1; i < 4; i++)
bc273e17 4413 res = min (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4414 break;
4415
4416 default:
4417 HALT_NYI;
4418 }
4419 }
4420 else
4421 {
ef0d8ffc 4422 switch (INSTR (13, 12))
2e8cf49e
NC
4423 {
4424 case 0: /* FMNAXNMV. */
4425 for (i = 1; i < 4; i++)
4426 res = fmaxnm (res, aarch64_get_vec_float (cpu, vs, i));
4427 break;
4428
4429 case 3: /* FMAXV. */
4430 for (i = 1; i < 4; i++)
bc273e17 4431 res = max (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4432 break;
4433
4434 default:
4435 HALT_NYI;
4436 }
4437 }
4438
4439 aarch64_set_FP_float (cpu, rd, res);
4440}
4441
4442static void
4443do_vec_Fminmax (sim_cpu *cpu)
4444{
4445 /* instr[31] = 0
4446 instr[30] = half(0)/full(1)
4447 instr[29,24] = 00 1110
4448 instr[23] = max(0)/min(1)
4449 instr[22] = float(0)/double(1)
4450 instr[21] = 1
4451 instr[20,16] = Vm
4452 instr[15,14] = 11
4453 instr[13,12] = nm(00)/normal(11)
4454 instr[11,10] = 01
4455 instr[9,5] = Vn
4456 instr[4,0] = Vd. */
4457
ef0d8ffc
NC
4458 unsigned vm = INSTR (20, 16);
4459 unsigned vn = INSTR (9, 5);
4460 unsigned vd = INSTR (4, 0);
4461 unsigned full = INSTR (30, 30);
4462 unsigned min = INSTR (23, 23);
2e8cf49e
NC
4463 unsigned i;
4464
4465 NYI_assert (29, 24, 0x0E);
4466 NYI_assert (21, 21, 1);
4467 NYI_assert (15, 14, 3);
4468 NYI_assert (11, 10, 1);
4469
2cdad34c 4470 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4471 if (INSTR (22, 22))
2e8cf49e
NC
4472 {
4473 double (* func)(double, double);
4474
4475 if (! full)
4476 HALT_NYI;
4477
ef0d8ffc 4478 if (INSTR (13, 12) == 0)
2e8cf49e 4479 func = min ? dminnm : dmaxnm;
ef0d8ffc 4480 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4481 func = min ? fmin : fmax;
4482 else
4483 HALT_NYI;
4484
4485 for (i = 0; i < 2; i++)
4486 aarch64_set_vec_double (cpu, vd, i,
4487 func (aarch64_get_vec_double (cpu, vn, i),
4488 aarch64_get_vec_double (cpu, vm, i)));
4489 }
4490 else
4491 {
4492 float (* func)(float, float);
4493
ef0d8ffc 4494 if (INSTR (13, 12) == 0)
2e8cf49e 4495 func = min ? fminnm : fmaxnm;
ef0d8ffc 4496 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4497 func = min ? fminf : fmaxf;
4498 else
4499 HALT_NYI;
4500
4501 for (i = 0; i < (full ? 4 : 2); i++)
4502 aarch64_set_vec_float (cpu, vd, i,
4503 func (aarch64_get_vec_float (cpu, vn, i),
4504 aarch64_get_vec_float (cpu, vm, i)));
4505 }
4506}
4507
4508static void
4509do_vec_SCVTF (sim_cpu *cpu)
4510{
4511 /* instr[31] = 0
4512 instr[30] = Q
4513 instr[29,23] = 00 1110 0
4514 instr[22] = float(0)/double(1)
4515 instr[21,10] = 10 0001 1101 10
4516 instr[9,5] = Vn
4517 instr[4,0] = Vd. */
4518
ef0d8ffc
NC
4519 unsigned vn = INSTR (9, 5);
4520 unsigned vd = INSTR (4, 0);
4521 unsigned full = INSTR (30, 30);
4522 unsigned size = INSTR (22, 22);
2e8cf49e
NC
4523 unsigned i;
4524
4525 NYI_assert (29, 23, 0x1C);
4526 NYI_assert (21, 10, 0x876);
4527
2cdad34c 4528 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4529 if (size)
4530 {
4531 if (! full)
4532 HALT_UNALLOC;
4533
4534 for (i = 0; i < 2; i++)
4535 {
4536 double val = (double) aarch64_get_vec_u64 (cpu, vn, i);
4537 aarch64_set_vec_double (cpu, vd, i, val);
4538 }
4539 }
4540 else
4541 {
4542 for (i = 0; i < (full ? 4 : 2); i++)
4543 {
4544 float val = (float) aarch64_get_vec_u32 (cpu, vn, i);
4545 aarch64_set_vec_float (cpu, vd, i, val);
4546 }
4547 }
4548}
4549
4550#define VEC_CMP(SOURCE, CMP) \
4551 do \
4552 { \
4553 switch (size) \
4554 { \
4555 case 0: \
4556 for (i = 0; i < (full ? 16 : 8); i++) \
4557 aarch64_set_vec_u8 (cpu, vd, i, \
4558 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4559 CMP \
4560 aarch64_get_vec_##SOURCE##8 (cpu, vm, i) \
4561 ? -1 : 0); \
4562 return; \
4563 case 1: \
4564 for (i = 0; i < (full ? 8 : 4); i++) \
4565 aarch64_set_vec_u16 (cpu, vd, i, \
4566 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4567 CMP \
4568 aarch64_get_vec_##SOURCE##16 (cpu, vm, i) \
4569 ? -1 : 0); \
4570 return; \
4571 case 2: \
4572 for (i = 0; i < (full ? 4 : 2); i++) \
4573 aarch64_set_vec_u32 (cpu, vd, i, \
4574 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4575 CMP \
4576 aarch64_get_vec_##SOURCE##32 (cpu, vm, i) \
4577 ? -1 : 0); \
4578 return; \
4579 case 3: \
4580 if (! full) \
4581 HALT_UNALLOC; \
4582 for (i = 0; i < 2; i++) \
4583 aarch64_set_vec_u64 (cpu, vd, i, \
4584 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4585 CMP \
4586 aarch64_get_vec_##SOURCE##64 (cpu, vm, i) \
4587 ? -1ULL : 0); \
4588 return; \
2e8cf49e
NC
4589 } \
4590 } \
4591 while (0)
4592
4593#define VEC_CMP0(SOURCE, CMP) \
4594 do \
4595 { \
4596 switch (size) \
4597 { \
4598 case 0: \
4599 for (i = 0; i < (full ? 16 : 8); i++) \
4600 aarch64_set_vec_u8 (cpu, vd, i, \
4601 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4602 CMP 0 ? -1 : 0); \
4603 return; \
4604 case 1: \
4605 for (i = 0; i < (full ? 8 : 4); i++) \
4606 aarch64_set_vec_u16 (cpu, vd, i, \
4607 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4608 CMP 0 ? -1 : 0); \
4609 return; \
4610 case 2: \
4611 for (i = 0; i < (full ? 4 : 2); i++) \
4612 aarch64_set_vec_u32 (cpu, vd, i, \
4613 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4614 CMP 0 ? -1 : 0); \
4615 return; \
4616 case 3: \
4617 if (! full) \
4618 HALT_UNALLOC; \
4619 for (i = 0; i < 2; i++) \
4620 aarch64_set_vec_u64 (cpu, vd, i, \
4621 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4622 CMP 0 ? -1ULL : 0); \
4623 return; \
2e8cf49e
NC
4624 } \
4625 } \
4626 while (0)
4627
4628#define VEC_FCMP0(CMP) \
4629 do \
4630 { \
4631 if (vm != 0) \
4632 HALT_NYI; \
2cdad34c 4633 if (INSTR (22, 22)) \
2e8cf49e
NC
4634 { \
4635 if (! full) \
4636 HALT_NYI; \
4637 for (i = 0; i < 2; i++) \
4638 aarch64_set_vec_u64 (cpu, vd, i, \
4639 aarch64_get_vec_double (cpu, vn, i) \
4640 CMP 0.0 ? -1 : 0); \
4641 } \
4642 else \
4643 { \
4644 for (i = 0; i < (full ? 4 : 2); i++) \
4645 aarch64_set_vec_u32 (cpu, vd, i, \
4646 aarch64_get_vec_float (cpu, vn, i) \
4647 CMP 0.0 ? -1 : 0); \
4648 } \
4649 return; \
4650 } \
4651 while (0)
4652
4653#define VEC_FCMP(CMP) \
4654 do \
4655 { \
2cdad34c 4656 if (INSTR (22, 22)) \
2e8cf49e
NC
4657 { \
4658 if (! full) \
4659 HALT_NYI; \
4660 for (i = 0; i < 2; i++) \
4661 aarch64_set_vec_u64 (cpu, vd, i, \
4662 aarch64_get_vec_double (cpu, vn, i) \
4663 CMP \
4664 aarch64_get_vec_double (cpu, vm, i) \
4665 ? -1 : 0); \
4666 } \
4667 else \
4668 { \
4669 for (i = 0; i < (full ? 4 : 2); i++) \
4670 aarch64_set_vec_u32 (cpu, vd, i, \
4671 aarch64_get_vec_float (cpu, vn, i) \
4672 CMP \
4673 aarch64_get_vec_float (cpu, vm, i) \
4674 ? -1 : 0); \
4675 } \
4676 return; \
4677 } \
4678 while (0)
4679
4680static void
4681do_vec_compare (sim_cpu *cpu)
4682{
4683 /* instr[31] = 0
4684 instr[30] = half(0)/full(1)
4685 instr[29] = part-of-comparison-type
4686 instr[28,24] = 0 1110
4687 instr[23,22] = size of integer compares: byte(00), half(01), word (10), long (11)
4688 type of float compares: single (-0) / double (-1)
4689 instr[21] = 1
4690 instr[20,16] = Vm or 00000 (compare vs 0)
4691 instr[15,10] = part-of-comparison-type
4692 instr[9,5] = Vn
4693 instr[4.0] = Vd. */
4694
ef0d8ffc
NC
4695 int full = INSTR (30, 30);
4696 int size = INSTR (23, 22);
4697 unsigned vm = INSTR (20, 16);
4698 unsigned vn = INSTR (9, 5);
4699 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
4700 unsigned i;
4701
4702 NYI_assert (28, 24, 0x0E);
4703 NYI_assert (21, 21, 1);
4704
2cdad34c 4705 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc
NC
4706 if ((INSTR (11, 11)
4707 && INSTR (14, 14))
4708 || ((INSTR (11, 11) == 0
4709 && INSTR (10, 10) == 0)))
2e8cf49e
NC
4710 {
4711 /* A compare vs 0. */
4712 if (vm != 0)
4713 {
ef0d8ffc 4714 if (INSTR (15, 10) == 0x2A)
2e8cf49e 4715 do_vec_maxv (cpu);
ef0d8ffc
NC
4716 else if (INSTR (15, 10) == 0x32
4717 || INSTR (15, 10) == 0x3E)
2e8cf49e 4718 do_vec_fminmaxV (cpu);
ef0d8ffc
NC
4719 else if (INSTR (29, 23) == 0x1C
4720 && INSTR (21, 10) == 0x876)
2e8cf49e
NC
4721 do_vec_SCVTF (cpu);
4722 else
4723 HALT_NYI;
4724 return;
4725 }
4726 }
4727
ef0d8ffc 4728 if (INSTR (14, 14))
2e8cf49e
NC
4729 {
4730 /* A floating point compare. */
7517e550 4731 unsigned decode = (INSTR (29, 29) << 5) | (INSTR (23, 23) << 4)
ef0d8ffc 4732 | INSTR (13, 10);
2e8cf49e
NC
4733
4734 NYI_assert (15, 15, 1);
4735
4736 switch (decode)
4737 {
4738 case /* 0b010010: GT#0 */ 0x12: VEC_FCMP0 (>);
4739 case /* 0b110010: GE#0 */ 0x32: VEC_FCMP0 (>=);
4740 case /* 0b010110: EQ#0 */ 0x16: VEC_FCMP0 (==);
4741 case /* 0b110110: LE#0 */ 0x36: VEC_FCMP0 (<=);
4742 case /* 0b011010: LT#0 */ 0x1A: VEC_FCMP0 (<);
4743 case /* 0b111001: GT */ 0x39: VEC_FCMP (>);
4744 case /* 0b101001: GE */ 0x29: VEC_FCMP (>=);
4745 case /* 0b001001: EQ */ 0x09: VEC_FCMP (==);
4746
4747 default:
4748 HALT_NYI;
4749 }
4750 }
4751 else
4752 {
7517e550 4753 unsigned decode = (INSTR (29, 29) << 6) | INSTR (15, 10);
2e8cf49e
NC
4754
4755 switch (decode)
4756 {
4757 case 0x0D: /* 0001101 GT */ VEC_CMP (s, > );
4758 case 0x0F: /* 0001111 GE */ VEC_CMP (s, >= );
4759 case 0x22: /* 0100010 GT #0 */ VEC_CMP0 (s, > );
4760 case 0x26: /* 0100110 EQ #0 */ VEC_CMP0 (s, == );
4761 case 0x2A: /* 0101010 LT #0 */ VEC_CMP0 (s, < );
4762 case 0x4D: /* 1001101 HI */ VEC_CMP (u, > );
4763 case 0x4F: /* 1001111 HS */ VEC_CMP (u, >= );
4764 case 0x62: /* 1100010 GE #0 */ VEC_CMP0 (s, >= );
4765 case 0x63: /* 1100011 EQ */ VEC_CMP (u, == );
4766 case 0x66: /* 1100110 LE #0 */ VEC_CMP0 (s, <= );
4767 default:
4768 if (vm == 0)
4769 HALT_NYI;
4770 do_vec_maxv (cpu);
4771 }
4772 }
4773}
4774
4775static void
4776do_vec_SSHL (sim_cpu *cpu)
4777{
4778 /* instr[31] = 0
4779 instr[30] = first part (0)/ second part (1)
4780 instr[29,24] = 00 1110
4781 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4782 instr[21] = 1
4783 instr[20,16] = Vm
4784 instr[15,10] = 0100 01
4785 instr[9,5] = Vn
4786 instr[4,0] = Vd. */
4787
ef0d8ffc
NC
4788 unsigned full = INSTR (30, 30);
4789 unsigned vm = INSTR (20, 16);
4790 unsigned vn = INSTR (9, 5);
4791 unsigned vd = INSTR (4, 0);
2e8cf49e 4792 unsigned i;
5ab6d79e 4793 signed int shift;
2e8cf49e
NC
4794
4795 NYI_assert (29, 24, 0x0E);
4796 NYI_assert (21, 21, 1);
4797 NYI_assert (15, 10, 0x11);
4798
4799 /* FIXME: What is a signed shift left in this context ?. */
4800
2cdad34c 4801 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4802 switch (INSTR (23, 22))
2e8cf49e
NC
4803 {
4804 case 0:
4805 for (i = 0; i < (full ? 16 : 8); i++)
5ab6d79e
NC
4806 {
4807 shift = aarch64_get_vec_s8 (cpu, vm, i);
4808 if (shift >= 0)
4809 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4810 << shift);
4811 else
4812 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4813 >> - shift);
4814 }
2e8cf49e
NC
4815 return;
4816
4817 case 1:
4818 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 4819 {
7517e550 4820 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
4821 if (shift >= 0)
4822 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4823 << shift);
4824 else
4825 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4826 >> - shift);
4827 }
2e8cf49e
NC
4828 return;
4829
4830 case 2:
4831 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 4832 {
7517e550 4833 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
4834 if (shift >= 0)
4835 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4836 << shift);
4837 else
4838 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4839 >> - shift);
4840 }
2e8cf49e
NC
4841 return;
4842
4843 case 3:
4844 if (! full)
4845 HALT_UNALLOC;
4846 for (i = 0; i < 2; i++)
5ab6d79e 4847 {
7517e550 4848 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
4849 if (shift >= 0)
4850 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4851 << shift);
4852 else
4853 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4854 >> - shift);
4855 }
2e8cf49e 4856 return;
2e8cf49e
NC
4857 }
4858}
4859
4860static void
4861do_vec_USHL (sim_cpu *cpu)
4862{
4863 /* instr[31] = 0
4864 instr[30] = first part (0)/ second part (1)
4865 instr[29,24] = 10 1110
4866 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4867 instr[21] = 1
4868 instr[20,16] = Vm
4869 instr[15,10] = 0100 01
4870 instr[9,5] = Vn
4871 instr[4,0] = Vd */
4872
ef0d8ffc
NC
4873 unsigned full = INSTR (30, 30);
4874 unsigned vm = INSTR (20, 16);
4875 unsigned vn = INSTR (9, 5);
4876 unsigned vd = INSTR (4, 0);
2e8cf49e 4877 unsigned i;
5ab6d79e 4878 signed int shift;
2e8cf49e
NC
4879
4880 NYI_assert (29, 24, 0x2E);
4881 NYI_assert (15, 10, 0x11);
4882
2cdad34c 4883 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4884 switch (INSTR (23, 22))
2e8cf49e
NC
4885 {
4886 case 0:
5ab6d79e
NC
4887 for (i = 0; i < (full ? 16 : 8); i++)
4888 {
4889 shift = aarch64_get_vec_s8 (cpu, vm, i);
4890 if (shift >= 0)
4891 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4892 << shift);
4893 else
4894 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4895 >> - shift);
4896 }
2e8cf49e
NC
4897 return;
4898
4899 case 1:
4900 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 4901 {
7517e550 4902 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
4903 if (shift >= 0)
4904 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4905 << shift);
4906 else
4907 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4908 >> - shift);
4909 }
2e8cf49e
NC
4910 return;
4911
4912 case 2:
4913 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 4914 {
7517e550 4915 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
4916 if (shift >= 0)
4917 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4918 << shift);
4919 else
4920 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4921 >> - shift);
4922 }
2e8cf49e
NC
4923 return;
4924
4925 case 3:
4926 if (! full)
4927 HALT_UNALLOC;
4928 for (i = 0; i < 2; i++)
5ab6d79e 4929 {
7517e550 4930 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
4931 if (shift >= 0)
4932 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4933 << shift);
4934 else
4935 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4936 >> - shift);
4937 }
2e8cf49e 4938 return;
2e8cf49e
NC
4939 }
4940}
4941
4942static void
4943do_vec_FMLA (sim_cpu *cpu)
4944{
4945 /* instr[31] = 0
4946 instr[30] = full/half selector
4947 instr[29,23] = 0011100
4948 instr[22] = size: 0=>float, 1=>double
4949 instr[21] = 1
4950 instr[20,16] = Vn
4951 instr[15,10] = 1100 11
4952 instr[9,5] = Vm
4953 instr[4.0] = Vd. */
4954
ef0d8ffc
NC
4955 unsigned vm = INSTR (20, 16);
4956 unsigned vn = INSTR (9, 5);
4957 unsigned vd = INSTR (4, 0);
2e8cf49e 4958 unsigned i;
ef0d8ffc 4959 int full = INSTR (30, 30);
2e8cf49e
NC
4960
4961 NYI_assert (29, 23, 0x1C);
4962 NYI_assert (21, 21, 1);
4963 NYI_assert (15, 10, 0x33);
4964
2cdad34c 4965 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4966 if (INSTR (22, 22))
2e8cf49e
NC
4967 {
4968 if (! full)
4969 HALT_UNALLOC;
4970 for (i = 0; i < 2; i++)
4971 aarch64_set_vec_double (cpu, vd, i,
4972 aarch64_get_vec_double (cpu, vn, i) *
4973 aarch64_get_vec_double (cpu, vm, i) +
4974 aarch64_get_vec_double (cpu, vd, i));
4975 }
4976 else
4977 {
4978 for (i = 0; i < (full ? 4 : 2); i++)
4979 aarch64_set_vec_float (cpu, vd, i,
4980 aarch64_get_vec_float (cpu, vn, i) *
4981 aarch64_get_vec_float (cpu, vm, i) +
4982 aarch64_get_vec_float (cpu, vd, i));
4983 }
4984}
4985
4986static void
4987do_vec_max (sim_cpu *cpu)
4988{
4989 /* instr[31] = 0
4990 instr[30] = full/half selector
4991 instr[29] = SMAX (0) / UMAX (1)
4992 instr[28,24] = 0 1110
4993 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4994 instr[21] = 1
4995 instr[20,16] = Vn
4996 instr[15,10] = 0110 01
4997 instr[9,5] = Vm
4998 instr[4.0] = Vd. */
4999
ef0d8ffc
NC
5000 unsigned vm = INSTR (20, 16);
5001 unsigned vn = INSTR (9, 5);
5002 unsigned vd = INSTR (4, 0);
2e8cf49e 5003 unsigned i;
ef0d8ffc 5004 int full = INSTR (30, 30);
2e8cf49e
NC
5005
5006 NYI_assert (28, 24, 0x0E);
5007 NYI_assert (21, 21, 1);
5008 NYI_assert (15, 10, 0x19);
5009
2cdad34c 5010 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5011 if (INSTR (29, 29))
2e8cf49e 5012 {
ef0d8ffc 5013 switch (INSTR (23, 22))
2e8cf49e
NC
5014 {
5015 case 0:
5016 for (i = 0; i < (full ? 16 : 8); i++)
5017 aarch64_set_vec_u8 (cpu, vd, i,
5018 aarch64_get_vec_u8 (cpu, vn, i)
5019 > aarch64_get_vec_u8 (cpu, vm, i)
5020 ? aarch64_get_vec_u8 (cpu, vn, i)
5021 : aarch64_get_vec_u8 (cpu, vm, i));
5022 return;
5023
5024 case 1:
5025 for (i = 0; i < (full ? 8 : 4); i++)
5026 aarch64_set_vec_u16 (cpu, vd, i,
5027 aarch64_get_vec_u16 (cpu, vn, i)
5028 > aarch64_get_vec_u16 (cpu, vm, i)
5029 ? aarch64_get_vec_u16 (cpu, vn, i)
5030 : aarch64_get_vec_u16 (cpu, vm, i));
5031 return;
5032
5033 case 2:
5034 for (i = 0; i < (full ? 4 : 2); i++)
5035 aarch64_set_vec_u32 (cpu, vd, i,
5036 aarch64_get_vec_u32 (cpu, vn, i)
5037 > aarch64_get_vec_u32 (cpu, vm, i)
5038 ? aarch64_get_vec_u32 (cpu, vn, i)
5039 : aarch64_get_vec_u32 (cpu, vm, i));
5040 return;
5041
2e8cf49e
NC
5042 case 3:
5043 HALT_UNALLOC;
5044 }
5045 }
5046 else
5047 {
ef0d8ffc 5048 switch (INSTR (23, 22))
2e8cf49e
NC
5049 {
5050 case 0:
5051 for (i = 0; i < (full ? 16 : 8); i++)
5052 aarch64_set_vec_s8 (cpu, vd, i,
5053 aarch64_get_vec_s8 (cpu, vn, i)
5054 > aarch64_get_vec_s8 (cpu, vm, i)
5055 ? aarch64_get_vec_s8 (cpu, vn, i)
5056 : aarch64_get_vec_s8 (cpu, vm, i));
5057 return;
5058
5059 case 1:
5060 for (i = 0; i < (full ? 8 : 4); i++)
5061 aarch64_set_vec_s16 (cpu, vd, i,
5062 aarch64_get_vec_s16 (cpu, vn, i)
5063 > aarch64_get_vec_s16 (cpu, vm, i)
5064 ? aarch64_get_vec_s16 (cpu, vn, i)
5065 : aarch64_get_vec_s16 (cpu, vm, i));
5066 return;
5067
5068 case 2:
5069 for (i = 0; i < (full ? 4 : 2); i++)
5070 aarch64_set_vec_s32 (cpu, vd, i,
5071 aarch64_get_vec_s32 (cpu, vn, i)
5072 > aarch64_get_vec_s32 (cpu, vm, i)
5073 ? aarch64_get_vec_s32 (cpu, vn, i)
5074 : aarch64_get_vec_s32 (cpu, vm, i));
5075 return;
5076
2e8cf49e
NC
5077 case 3:
5078 HALT_UNALLOC;
5079 }
5080 }
5081}
5082
5083static void
5084do_vec_min (sim_cpu *cpu)
5085{
5086 /* instr[31] = 0
5087 instr[30] = full/half selector
5088 instr[29] = SMIN (0) / UMIN (1)
5089 instr[28,24] = 0 1110
5090 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
5091 instr[21] = 1
5092 instr[20,16] = Vn
5093 instr[15,10] = 0110 11
5094 instr[9,5] = Vm
5095 instr[4.0] = Vd. */
5096
ef0d8ffc
NC
5097 unsigned vm = INSTR (20, 16);
5098 unsigned vn = INSTR (9, 5);
5099 unsigned vd = INSTR (4, 0);
2e8cf49e 5100 unsigned i;
ef0d8ffc 5101 int full = INSTR (30, 30);
2e8cf49e
NC
5102
5103 NYI_assert (28, 24, 0x0E);
5104 NYI_assert (21, 21, 1);
5105 NYI_assert (15, 10, 0x1B);
5106
2cdad34c 5107 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5108 if (INSTR (29, 29))
2e8cf49e 5109 {
ef0d8ffc 5110 switch (INSTR (23, 22))
2e8cf49e
NC
5111 {
5112 case 0:
5113 for (i = 0; i < (full ? 16 : 8); i++)
5114 aarch64_set_vec_u8 (cpu, vd, i,
5115 aarch64_get_vec_u8 (cpu, vn, i)
5116 < aarch64_get_vec_u8 (cpu, vm, i)
5117 ? aarch64_get_vec_u8 (cpu, vn, i)
5118 : aarch64_get_vec_u8 (cpu, vm, i));
5119 return;
5120
5121 case 1:
5122 for (i = 0; i < (full ? 8 : 4); i++)
5123 aarch64_set_vec_u16 (cpu, vd, i,
5124 aarch64_get_vec_u16 (cpu, vn, i)
5125 < aarch64_get_vec_u16 (cpu, vm, i)
5126 ? aarch64_get_vec_u16 (cpu, vn, i)
5127 : aarch64_get_vec_u16 (cpu, vm, i));
5128 return;
5129
5130 case 2:
5131 for (i = 0; i < (full ? 4 : 2); i++)
5132 aarch64_set_vec_u32 (cpu, vd, i,
5133 aarch64_get_vec_u32 (cpu, vn, i)
5134 < aarch64_get_vec_u32 (cpu, vm, i)
5135 ? aarch64_get_vec_u32 (cpu, vn, i)
5136 : aarch64_get_vec_u32 (cpu, vm, i));
5137 return;
5138
2e8cf49e
NC
5139 case 3:
5140 HALT_UNALLOC;
5141 }
5142 }
5143 else
5144 {
ef0d8ffc 5145 switch (INSTR (23, 22))
2e8cf49e
NC
5146 {
5147 case 0:
5148 for (i = 0; i < (full ? 16 : 8); i++)
5149 aarch64_set_vec_s8 (cpu, vd, i,
5150 aarch64_get_vec_s8 (cpu, vn, i)
5151 < aarch64_get_vec_s8 (cpu, vm, i)
5152 ? aarch64_get_vec_s8 (cpu, vn, i)
5153 : aarch64_get_vec_s8 (cpu, vm, i));
5154 return;
5155
5156 case 1:
5157 for (i = 0; i < (full ? 8 : 4); i++)
5158 aarch64_set_vec_s16 (cpu, vd, i,
5159 aarch64_get_vec_s16 (cpu, vn, i)
5160 < aarch64_get_vec_s16 (cpu, vm, i)
5161 ? aarch64_get_vec_s16 (cpu, vn, i)
5162 : aarch64_get_vec_s16 (cpu, vm, i));
5163 return;
5164
5165 case 2:
5166 for (i = 0; i < (full ? 4 : 2); i++)
5167 aarch64_set_vec_s32 (cpu, vd, i,
5168 aarch64_get_vec_s32 (cpu, vn, i)
5169 < aarch64_get_vec_s32 (cpu, vm, i)
5170 ? aarch64_get_vec_s32 (cpu, vn, i)
5171 : aarch64_get_vec_s32 (cpu, vm, i));
5172 return;
5173
2e8cf49e
NC
5174 case 3:
5175 HALT_UNALLOC;
5176 }
5177 }
5178}
5179
5180static void
5181do_vec_sub_long (sim_cpu *cpu)
5182{
5183 /* instr[31] = 0
5184 instr[30] = lower (0) / upper (1)
5185 instr[29] = signed (0) / unsigned (1)
5186 instr[28,24] = 0 1110
5187 instr[23,22] = size: bytes (00), half (01), word (10)
5188 instr[21] = 1
5189 insrt[20,16] = Vm
5190 instr[15,10] = 0010 00
5191 instr[9,5] = Vn
5192 instr[4,0] = V dest. */
5193
ef0d8ffc
NC
5194 unsigned size = INSTR (23, 22);
5195 unsigned vm = INSTR (20, 16);
5196 unsigned vn = INSTR (9, 5);
5197 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5198 unsigned bias = 0;
5199 unsigned i;
5200
5201 NYI_assert (28, 24, 0x0E);
5202 NYI_assert (21, 21, 1);
5203 NYI_assert (15, 10, 0x08);
5204
5205 if (size == 3)
5206 HALT_UNALLOC;
5207
2cdad34c 5208 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5209 switch (INSTR (30, 29))
2e8cf49e
NC
5210 {
5211 case 2: /* SSUBL2. */
5212 bias = 2;
5213 case 0: /* SSUBL. */
5214 switch (size)
5215 {
5216 case 0:
5217 bias *= 3;
5218 for (i = 0; i < 8; i++)
5219 aarch64_set_vec_s16 (cpu, vd, i,
5220 aarch64_get_vec_s8 (cpu, vn, i + bias)
5221 - aarch64_get_vec_s8 (cpu, vm, i + bias));
5222 break;
5223
5224 case 1:
5225 bias *= 2;
5226 for (i = 0; i < 4; i++)
5227 aarch64_set_vec_s32 (cpu, vd, i,
5228 aarch64_get_vec_s16 (cpu, vn, i + bias)
5229 - aarch64_get_vec_s16 (cpu, vm, i + bias));
5230 break;
5231
5232 case 2:
5233 for (i = 0; i < 2; i++)
5234 aarch64_set_vec_s64 (cpu, vd, i,
5235 aarch64_get_vec_s32 (cpu, vn, i + bias)
5236 - aarch64_get_vec_s32 (cpu, vm, i + bias));
5237 break;
5238
5239 default:
5240 HALT_UNALLOC;
5241 }
5242 break;
5243
5244 case 3: /* USUBL2. */
5245 bias = 2;
5246 case 1: /* USUBL. */
5247 switch (size)
5248 {
5249 case 0:
5250 bias *= 3;
5251 for (i = 0; i < 8; i++)
5252 aarch64_set_vec_u16 (cpu, vd, i,
5253 aarch64_get_vec_u8 (cpu, vn, i + bias)
5254 - aarch64_get_vec_u8 (cpu, vm, i + bias));
5255 break;
5256
5257 case 1:
5258 bias *= 2;
5259 for (i = 0; i < 4; i++)
5260 aarch64_set_vec_u32 (cpu, vd, i,
5261 aarch64_get_vec_u16 (cpu, vn, i + bias)
5262 - aarch64_get_vec_u16 (cpu, vm, i + bias));
5263 break;
5264
5265 case 2:
5266 for (i = 0; i < 2; i++)
5267 aarch64_set_vec_u64 (cpu, vd, i,
5268 aarch64_get_vec_u32 (cpu, vn, i + bias)
5269 - aarch64_get_vec_u32 (cpu, vm, i + bias));
5270 break;
5271
5272 default:
5273 HALT_UNALLOC;
5274 }
5275 break;
5276 }
5277}
5278
2e8cf49e
NC
5279static void
5280do_vec_ADDP (sim_cpu *cpu)
5281{
5282 /* instr[31] = 0
5283 instr[30] = half(0)/full(1)
5284 instr[29,24] = 00 1110
5285 instr[23,22] = size: bytes (00), half (01), word (10), long (11)
5286 instr[21] = 1
5287 insrt[20,16] = Vm
5288 instr[15,10] = 1011 11
5289 instr[9,5] = Vn
5290 instr[4,0] = V dest. */
5291
57aa1742
NC
5292 FRegister copy_vn;
5293 FRegister copy_vm;
ef0d8ffc
NC
5294 unsigned full = INSTR (30, 30);
5295 unsigned size = INSTR (23, 22);
5296 unsigned vm = INSTR (20, 16);
5297 unsigned vn = INSTR (9, 5);
5298 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5299 unsigned i, range;
5300
5301 NYI_assert (29, 24, 0x0E);
5302 NYI_assert (21, 21, 1);
5303 NYI_assert (15, 10, 0x2F);
5304
57aa1742
NC
5305 /* Make copies of the source registers in case vd == vn/vm. */
5306 copy_vn = cpu->fr[vn];
5307 copy_vm = cpu->fr[vm];
5308
2cdad34c 5309 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
5310 switch (size)
5311 {
5312 case 0:
5313 range = full ? 8 : 4;
57aa1742
NC
5314 for (i = 0; i < range; i++)
5315 {
5316 aarch64_set_vec_u8 (cpu, vd, i,
5317 copy_vn.b[i * 2] + copy_vn.b[i * 2 + 1]);
5318 aarch64_set_vec_u8 (cpu, vd, i + range,
5319 copy_vm.b[i * 2] + copy_vm.b[i * 2 + 1]);
5320 }
2e8cf49e
NC
5321 return;
5322
5323 case 1:
5324 range = full ? 4 : 2;
57aa1742
NC
5325 for (i = 0; i < range; i++)
5326 {
5327 aarch64_set_vec_u16 (cpu, vd, i,
5328 copy_vn.h[i * 2] + copy_vn.h[i * 2 + 1]);
5329 aarch64_set_vec_u16 (cpu, vd, i + range,
5330 copy_vm.h[i * 2] + copy_vm.h[i * 2 + 1]);
5331 }
2e8cf49e
NC
5332 return;
5333
5334 case 2:
5335 range = full ? 2 : 1;
57aa1742
NC
5336 for (i = 0; i < range; i++)
5337 {
5338 aarch64_set_vec_u32 (cpu, vd, i,
5339 copy_vn.w[i * 2] + copy_vn.w[i * 2 + 1]);
5340 aarch64_set_vec_u32 (cpu, vd, i + range,
5341 copy_vm.w[i * 2] + copy_vm.w[i * 2 + 1]);
5342 }
2e8cf49e
NC
5343 return;
5344
5345 case 3:
5346 if (! full)
5347 HALT_UNALLOC;
57aa1742
NC
5348 aarch64_set_vec_u64 (cpu, vd, 0, copy_vn.v[0] + copy_vn.v[1]);
5349 aarch64_set_vec_u64 (cpu, vd, 1, copy_vm.v[0] + copy_vm.v[1]);
2e8cf49e 5350 return;
2e8cf49e
NC
5351 }
5352}
5353
5354static void
5355do_vec_UMOV (sim_cpu *cpu)
5356{
5357 /* instr[31] = 0
5358 instr[30] = 32-bit(0)/64-bit(1)
5359 instr[29,21] = 00 1110 000
5360 insrt[20,16] = size & index
5361 instr[15,10] = 0011 11
5362 instr[9,5] = V source
5363 instr[4,0] = R dest. */
5364
ef0d8ffc
NC
5365 unsigned vs = INSTR (9, 5);
5366 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
5367 unsigned index;
5368
5369 NYI_assert (29, 21, 0x070);
5370 NYI_assert (15, 10, 0x0F);
5371
2cdad34c 5372 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5373 if (INSTR (16, 16))
2e8cf49e
NC
5374 {
5375 /* Byte transfer. */
ef0d8ffc 5376 index = INSTR (20, 17);
2e8cf49e
NC
5377 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5378 aarch64_get_vec_u8 (cpu, vs, index));
5379 }
ef0d8ffc 5380 else if (INSTR (17, 17))
2e8cf49e 5381 {
ef0d8ffc 5382 index = INSTR (20, 18);
2e8cf49e
NC
5383 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5384 aarch64_get_vec_u16 (cpu, vs, index));
5385 }
ef0d8ffc 5386 else if (INSTR (18, 18))
2e8cf49e 5387 {
ef0d8ffc 5388 index = INSTR (20, 19);
2e8cf49e
NC
5389 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5390 aarch64_get_vec_u32 (cpu, vs, index));
5391 }
5392 else
5393 {
ef0d8ffc 5394 if (INSTR (30, 30) != 1)
2e8cf49e
NC
5395 HALT_UNALLOC;
5396
ef0d8ffc 5397 index = INSTR (20, 20);
2e8cf49e
NC
5398 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5399 aarch64_get_vec_u64 (cpu, vs, index));
5400 }
5401}
5402
5403static void
5404do_vec_FABS (sim_cpu *cpu)
5405{
5406 /* instr[31] = 0
5407 instr[30] = half(0)/full(1)
5408 instr[29,23] = 00 1110 1
5409 instr[22] = float(0)/double(1)
5410 instr[21,16] = 10 0000
5411 instr[15,10] = 1111 10
5412 instr[9,5] = Vn
5413 instr[4,0] = Vd. */
5414
ef0d8ffc
NC
5415 unsigned vn = INSTR (9, 5);
5416 unsigned vd = INSTR (4, 0);
5417 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5418 unsigned i;
5419
5420 NYI_assert (29, 23, 0x1D);
5421 NYI_assert (21, 10, 0x83E);
5422
2cdad34c 5423 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5424 if (INSTR (22, 22))
2e8cf49e
NC
5425 {
5426 if (! full)
5427 HALT_NYI;
5428
5429 for (i = 0; i < 2; i++)
5430 aarch64_set_vec_double (cpu, vd, i,
5431 fabs (aarch64_get_vec_double (cpu, vn, i)));
5432 }
5433 else
5434 {
5435 for (i = 0; i < (full ? 4 : 2); i++)
5436 aarch64_set_vec_float (cpu, vd, i,
5437 fabsf (aarch64_get_vec_float (cpu, vn, i)));
5438 }
5439}
5440
5441static void
5442do_vec_FCVTZS (sim_cpu *cpu)
5443{
5444 /* instr[31] = 0
5445 instr[30] = half (0) / all (1)
5446 instr[29,23] = 00 1110 1
5447 instr[22] = single (0) / double (1)
5448 instr[21,10] = 10 0001 1011 10
5449 instr[9,5] = Rn
5450 instr[4,0] = Rd. */
5451
ef0d8ffc
NC
5452 unsigned rn = INSTR (9, 5);
5453 unsigned rd = INSTR (4, 0);
5454 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5455 unsigned i;
5456
5457 NYI_assert (31, 31, 0);
5458 NYI_assert (29, 23, 0x1D);
5459 NYI_assert (21, 10, 0x86E);
5460
2cdad34c 5461 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5462 if (INSTR (22, 22))
2e8cf49e
NC
5463 {
5464 if (! full)
5465 HALT_UNALLOC;
5466
5467 for (i = 0; i < 2; i++)
5468 aarch64_set_vec_s64 (cpu, rd, i,
5469 (int64_t) aarch64_get_vec_double (cpu, rn, i));
5470 }
5471 else
5472 for (i = 0; i < (full ? 4 : 2); i++)
5473 aarch64_set_vec_s32 (cpu, rd, i,
5474 (int32_t) aarch64_get_vec_float (cpu, rn, i));
5475}
5476
67f101ee
NC
5477static void
5478do_vec_REV64 (sim_cpu *cpu)
5479{
5480 /* instr[31] = 0
5481 instr[30] = full/half
5482 instr[29,24] = 00 1110
5483 instr[23,22] = size
5484 instr[21,10] = 10 0000 0000 10
5485 instr[9,5] = Rn
5486 instr[4,0] = Rd. */
5487
5488 unsigned rn = INSTR (9, 5);
5489 unsigned rd = INSTR (4, 0);
5490 unsigned size = INSTR (23, 22);
5491 unsigned full = INSTR (30, 30);
5492 unsigned i;
5493 FRegister val;
5494
5495 NYI_assert (29, 24, 0x0E);
5496 NYI_assert (21, 10, 0x802);
5497
2cdad34c 5498 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
5499 switch (size)
5500 {
5501 case 0:
5502 for (i = 0; i < (full ? 16 : 8); i++)
5503 val.b[i ^ 0x7] = aarch64_get_vec_u8 (cpu, rn, i);
5504 break;
5505
5506 case 1:
5507 for (i = 0; i < (full ? 8 : 4); i++)
5508 val.h[i ^ 0x3] = aarch64_get_vec_u16 (cpu, rn, i);
5509 break;
5510
5511 case 2:
5512 for (i = 0; i < (full ? 4 : 2); i++)
5513 val.w[i ^ 0x1] = aarch64_get_vec_u32 (cpu, rn, i);
5514 break;
5515
5516 case 3:
5517 HALT_UNALLOC;
5518 }
5519
5520 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5521 if (full)
5522 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5523}
5524
5525static void
5526do_vec_REV16 (sim_cpu *cpu)
5527{
5528 /* instr[31] = 0
5529 instr[30] = full/half
5530 instr[29,24] = 00 1110
5531 instr[23,22] = size
5532 instr[21,10] = 10 0000 0001 10
5533 instr[9,5] = Rn
5534 instr[4,0] = Rd. */
5535
5536 unsigned rn = INSTR (9, 5);
5537 unsigned rd = INSTR (4, 0);
5538 unsigned size = INSTR (23, 22);
5539 unsigned full = INSTR (30, 30);
5540 unsigned i;
5541 FRegister val;
5542
5543 NYI_assert (29, 24, 0x0E);
5544 NYI_assert (21, 10, 0x806);
5545
2cdad34c 5546 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
5547 switch (size)
5548 {
5549 case 0:
5550 for (i = 0; i < (full ? 16 : 8); i++)
5551 val.b[i ^ 0x1] = aarch64_get_vec_u8 (cpu, rn, i);
5552 break;
5553
5554 default:
5555 HALT_UNALLOC;
5556 }
5557
5558 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5559 if (full)
5560 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5561}
5562
2e8cf49e
NC
5563static void
5564do_vec_op1 (sim_cpu *cpu)
5565{
5566 /* instr[31] = 0
5567 instr[30] = half/full
5568 instr[29,24] = 00 1110
5569 instr[23,21] = ???
5570 instr[20,16] = Vm
5571 instr[15,10] = sub-opcode
5572 instr[9,5] = Vn
5573 instr[4,0] = Vd */
5574 NYI_assert (29, 24, 0x0E);
5575
ef0d8ffc 5576 if (INSTR (21, 21) == 0)
2e8cf49e 5577 {
ef0d8ffc 5578 if (INSTR (23, 22) == 0)
2e8cf49e 5579 {
ef0d8ffc
NC
5580 if (INSTR (30, 30) == 1
5581 && INSTR (17, 14) == 0
5582 && INSTR (12, 10) == 7)
2e8cf49e
NC
5583 return do_vec_ins_2 (cpu);
5584
ef0d8ffc 5585 switch (INSTR (15, 10))
2e8cf49e
NC
5586 {
5587 case 0x01: do_vec_DUP_vector_into_vector (cpu); return;
5588 case 0x03: do_vec_DUP_scalar_into_vector (cpu); return;
5589 case 0x07: do_vec_INS (cpu); return;
5590 case 0x0A: do_vec_TRN (cpu); return;
5591
5592 case 0x0F:
ef0d8ffc 5593 if (INSTR (17, 16) == 0)
2e8cf49e
NC
5594 {
5595 do_vec_MOV_into_scalar (cpu);
5596 return;
5597 }
5598 break;
5599
5600 case 0x00:
5601 case 0x08:
5602 case 0x10:
5603 case 0x18:
5604 do_vec_TBL (cpu); return;
5605
5606 case 0x06:
5607 case 0x16:
5608 do_vec_UZP (cpu); return;
5609
5610 case 0x0E:
5611 case 0x1E:
5612 do_vec_ZIP (cpu); return;
5613
5614 default:
5615 HALT_NYI;
5616 }
5617 }
5618
ef0d8ffc 5619 switch (INSTR (13, 10))
2e8cf49e
NC
5620 {
5621 case 0x6: do_vec_UZP (cpu); return;
5622 case 0xE: do_vec_ZIP (cpu); return;
5623 case 0xA: do_vec_TRN (cpu); return;
5624 case 0xF: do_vec_UMOV (cpu); return;
5625 default: HALT_NYI;
5626 }
5627 }
5628
ef0d8ffc 5629 switch (INSTR (15, 10))
2e8cf49e 5630 {
67f101ee
NC
5631 case 0x02: do_vec_REV64 (cpu); return;
5632 case 0x06: do_vec_REV16 (cpu); return;
5633
2e8cf49e 5634 case 0x07:
ef0d8ffc 5635 switch (INSTR (23, 21))
2e8cf49e
NC
5636 {
5637 case 1: do_vec_AND (cpu); return;
5638 case 3: do_vec_BIC (cpu); return;
5639 case 5: do_vec_ORR (cpu); return;
5640 case 7: do_vec_ORN (cpu); return;
5641 default: HALT_NYI;
5642 }
5643
5644 case 0x08: do_vec_sub_long (cpu); return;
5645 case 0x0a: do_vec_XTN (cpu); return;
5646 case 0x11: do_vec_SSHL (cpu); return;
5647 case 0x19: do_vec_max (cpu); return;
5648 case 0x1B: do_vec_min (cpu); return;
5649 case 0x21: do_vec_add (cpu); return;
5650 case 0x25: do_vec_MLA (cpu); return;
5651 case 0x27: do_vec_mul (cpu); return;
5652 case 0x2F: do_vec_ADDP (cpu); return;
5653 case 0x30: do_vec_mull (cpu); return;
5654 case 0x33: do_vec_FMLA (cpu); return;
5655 case 0x35: do_vec_fadd (cpu); return;
5656
5657 case 0x2E:
ef0d8ffc 5658 switch (INSTR (20, 16))
2e8cf49e
NC
5659 {
5660 case 0x00: do_vec_ABS (cpu); return;
5661 case 0x01: do_vec_FCVTZS (cpu); return;
5662 case 0x11: do_vec_ADDV (cpu); return;
5663 default: HALT_NYI;
5664 }
5665
5666 case 0x31:
5667 case 0x3B:
5668 do_vec_Fminmax (cpu); return;
5669
5670 case 0x0D:
5671 case 0x0F:
5672 case 0x22:
5673 case 0x23:
5674 case 0x26:
5675 case 0x2A:
5676 case 0x32:
5677 case 0x36:
5678 case 0x39:
5679 case 0x3A:
5680 do_vec_compare (cpu); return;
5681
5682 case 0x3E:
5683 do_vec_FABS (cpu); return;
5684
5685 default:
5686 HALT_NYI;
5687 }
5688}
5689
5690static void
5691do_vec_xtl (sim_cpu *cpu)
5692{
5693 /* instr[31] = 0
5694 instr[30,29] = SXTL (00), UXTL (01), SXTL2 (10), UXTL2 (11)
5695 instr[28,22] = 0 1111 00
5696 instr[21,16] = size & shift (USHLL, SSHLL, USHLL2, SSHLL2)
5697 instr[15,10] = 1010 01
5698 instr[9,5] = V source
5699 instr[4,0] = V dest. */
5700
ef0d8ffc
NC
5701 unsigned vs = INSTR (9, 5);
5702 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5703 unsigned i, shift, bias = 0;
5704
5705 NYI_assert (28, 22, 0x3C);
5706 NYI_assert (15, 10, 0x29);
5707
2cdad34c 5708 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5709 switch (INSTR (30, 29))
2e8cf49e
NC
5710 {
5711 case 2: /* SXTL2, SSHLL2. */
5712 bias = 2;
5713 case 0: /* SXTL, SSHLL. */
ef0d8ffc 5714 if (INSTR (21, 21))
2e8cf49e 5715 {
7517e550
NC
5716 int64_t val1, val2;
5717
ef0d8ffc 5718 shift = INSTR (20, 16);
7517e550
NC
5719 /* Get the source values before setting the destination values
5720 in case the source and destination are the same. */
5721 val1 = aarch64_get_vec_s32 (cpu, vs, bias) << shift;
5722 val2 = aarch64_get_vec_s32 (cpu, vs, bias + 1) << shift;
5723 aarch64_set_vec_s64 (cpu, vd, 0, val1);
5724 aarch64_set_vec_s64 (cpu, vd, 1, val2);
2e8cf49e 5725 }
ef0d8ffc 5726 else if (INSTR (20, 20))
2e8cf49e 5727 {
7517e550
NC
5728 int32_t v[4];
5729 int32_t v1,v2,v3,v4;
5730
ef0d8ffc 5731 shift = INSTR (19, 16);
2e8cf49e
NC
5732 bias *= 2;
5733 for (i = 0; i < 4; i++)
7517e550
NC
5734 v[i] = aarch64_get_vec_s16 (cpu, vs, bias + i) << shift;
5735 for (i = 0; i < 4; i++)
5736 aarch64_set_vec_s32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5737 }
5738 else
5739 {
7517e550 5740 int16_t v[8];
2e8cf49e
NC
5741 NYI_assert (19, 19, 1);
5742
ef0d8ffc 5743 shift = INSTR (18, 16);
2e8cf49e
NC
5744 bias *= 3;
5745 for (i = 0; i < 8; i++)
7517e550
NC
5746 v[i] = aarch64_get_vec_s8 (cpu, vs, i + bias) << shift;
5747 for (i = 0; i < 8; i++)
5748 aarch64_set_vec_s16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5749 }
5750 return;
5751
5752 case 3: /* UXTL2, USHLL2. */
5753 bias = 2;
5754 case 1: /* UXTL, USHLL. */
ef0d8ffc 5755 if (INSTR (21, 21))
2e8cf49e 5756 {
7517e550 5757 uint64_t v1, v2;
ef0d8ffc 5758 shift = INSTR (20, 16);
7517e550
NC
5759 v1 = aarch64_get_vec_u32 (cpu, vs, bias) << shift;
5760 v2 = aarch64_get_vec_u32 (cpu, vs, bias + 1) << shift;
5761 aarch64_set_vec_u64 (cpu, vd, 0, v1);
5762 aarch64_set_vec_u64 (cpu, vd, 1, v2);
2e8cf49e 5763 }
ef0d8ffc 5764 else if (INSTR (20, 20))
2e8cf49e 5765 {
7517e550 5766 uint32_t v[4];
ef0d8ffc 5767 shift = INSTR (19, 16);
2e8cf49e
NC
5768 bias *= 2;
5769 for (i = 0; i < 4; i++)
7517e550
NC
5770 v[i] = aarch64_get_vec_u16 (cpu, vs, i + bias) << shift;
5771 for (i = 0; i < 4; i++)
5772 aarch64_set_vec_u32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5773 }
5774 else
5775 {
7517e550 5776 uint16_t v[8];
2e8cf49e
NC
5777 NYI_assert (19, 19, 1);
5778
ef0d8ffc 5779 shift = INSTR (18, 16);
2e8cf49e
NC
5780 bias *= 3;
5781 for (i = 0; i < 8; i++)
7517e550
NC
5782 v[i] = aarch64_get_vec_u8 (cpu, vs, i + bias) << shift;
5783 for (i = 0; i < 8; i++)
5784 aarch64_set_vec_u16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5785 }
5786 return;
2e8cf49e
NC
5787 }
5788}
5789
5790static void
5791do_vec_SHL (sim_cpu *cpu)
5792{
5793 /* instr [31] = 0
5794 instr [30] = half(0)/full(1)
5795 instr [29,23] = 001 1110
5796 instr [22,16] = size and shift amount
5797 instr [15,10] = 01 0101
5798 instr [9, 5] = Vs
5799 instr [4, 0] = Vd. */
5800
5801 int shift;
ef0d8ffc
NC
5802 int full = INSTR (30, 30);
5803 unsigned vs = INSTR (9, 5);
5804 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5805 unsigned i;
5806
5807 NYI_assert (29, 23, 0x1E);
5808 NYI_assert (15, 10, 0x15);
5809
2cdad34c 5810 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5811 if (INSTR (22, 22))
2e8cf49e 5812 {
ef0d8ffc 5813 shift = INSTR (21, 16);
2e8cf49e
NC
5814
5815 if (full == 0)
5816 HALT_UNALLOC;
5817
5818 for (i = 0; i < 2; i++)
5819 {
5820 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5821 aarch64_set_vec_u64 (cpu, vd, i, val << shift);
5822 }
5823
5824 return;
5825 }
5826
ef0d8ffc 5827 if (INSTR (21, 21))
2e8cf49e 5828 {
ef0d8ffc 5829 shift = INSTR (20, 16);
2e8cf49e
NC
5830
5831 for (i = 0; i < (full ? 4 : 2); i++)
5832 {
5833 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5834 aarch64_set_vec_u32 (cpu, vd, i, val << shift);
5835 }
5836
5837 return;
5838 }
5839
ef0d8ffc 5840 if (INSTR (20, 20))
2e8cf49e 5841 {
ef0d8ffc 5842 shift = INSTR (19, 16);
2e8cf49e
NC
5843
5844 for (i = 0; i < (full ? 8 : 4); i++)
5845 {
5846 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5847 aarch64_set_vec_u16 (cpu, vd, i, val << shift);
5848 }
5849
5850 return;
5851 }
5852
ef0d8ffc 5853 if (INSTR (19, 19) == 0)
2e8cf49e
NC
5854 HALT_UNALLOC;
5855
ef0d8ffc 5856 shift = INSTR (18, 16);
2e8cf49e
NC
5857
5858 for (i = 0; i < (full ? 16 : 8); i++)
5859 {
5860 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5861 aarch64_set_vec_u8 (cpu, vd, i, val << shift);
5862 }
5863}
5864
5865static void
5866do_vec_SSHR_USHR (sim_cpu *cpu)
5867{
5868 /* instr [31] = 0
5869 instr [30] = half(0)/full(1)
5870 instr [29] = signed(0)/unsigned(1)
5ab6d79e 5871 instr [28,23] = 0 1111 0
2e8cf49e
NC
5872 instr [22,16] = size and shift amount
5873 instr [15,10] = 0000 01
5874 instr [9, 5] = Vs
5875 instr [4, 0] = Vd. */
5876
5ab6d79e
NC
5877 int full = INSTR (30, 30);
5878 int sign = ! INSTR (29, 29);
5879 unsigned shift = INSTR (22, 16);
5880 unsigned vs = INSTR (9, 5);
5881 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5882 unsigned i;
5883
5884 NYI_assert (28, 23, 0x1E);
5885 NYI_assert (15, 10, 0x01);
5886
2cdad34c 5887 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5888 if (INSTR (22, 22))
2e8cf49e 5889 {
5ab6d79e 5890 shift = 128 - shift;
2e8cf49e
NC
5891
5892 if (full == 0)
5893 HALT_UNALLOC;
5894
5895 if (sign)
5896 for (i = 0; i < 2; i++)
5897 {
5898 int64_t val = aarch64_get_vec_s64 (cpu, vs, i);
5899 aarch64_set_vec_s64 (cpu, vd, i, val >> shift);
5900 }
5901 else
5902 for (i = 0; i < 2; i++)
5903 {
5904 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5905 aarch64_set_vec_u64 (cpu, vd, i, val >> shift);
5906 }
5907
5908 return;
5909 }
5910
ef0d8ffc 5911 if (INSTR (21, 21))
2e8cf49e 5912 {
5ab6d79e 5913 shift = 64 - shift;
2e8cf49e
NC
5914
5915 if (sign)
5916 for (i = 0; i < (full ? 4 : 2); i++)
5917 {
5918 int32_t val = aarch64_get_vec_s32 (cpu, vs, i);
5919 aarch64_set_vec_s32 (cpu, vd, i, val >> shift);
5920 }
5921 else
5922 for (i = 0; i < (full ? 4 : 2); i++)
5923 {
5924 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5925 aarch64_set_vec_u32 (cpu, vd, i, val >> shift);
5926 }
5927
5928 return;
5929 }
5930
ef0d8ffc 5931 if (INSTR (20, 20))
2e8cf49e 5932 {
5ab6d79e 5933 shift = 32 - shift;
2e8cf49e
NC
5934
5935 if (sign)
5936 for (i = 0; i < (full ? 8 : 4); i++)
5937 {
5938 int16_t val = aarch64_get_vec_s16 (cpu, vs, i);
5939 aarch64_set_vec_s16 (cpu, vd, i, val >> shift);
5940 }
5941 else
5942 for (i = 0; i < (full ? 8 : 4); i++)
5943 {
5944 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5945 aarch64_set_vec_u16 (cpu, vd, i, val >> shift);
5946 }
5947
5948 return;
5949 }
5950
ef0d8ffc 5951 if (INSTR (19, 19) == 0)
2e8cf49e
NC
5952 HALT_UNALLOC;
5953
5ab6d79e 5954 shift = 16 - shift;
2e8cf49e
NC
5955
5956 if (sign)
5957 for (i = 0; i < (full ? 16 : 8); i++)
5958 {
5959 int8_t val = aarch64_get_vec_s8 (cpu, vs, i);
5960 aarch64_set_vec_s8 (cpu, vd, i, val >> shift);
5961 }
5962 else
5963 for (i = 0; i < (full ? 16 : 8); i++)
5964 {
5965 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5966 aarch64_set_vec_u8 (cpu, vd, i, val >> shift);
5967 }
5968}
5969
e101a78b
NC
5970static void
5971do_vec_MUL_by_element (sim_cpu *cpu)
5972{
5973 /* instr[31] = 0
5974 instr[30] = half/full
5975 instr[29,24] = 00 1111
5976 instr[23,22] = size
5977 instr[21] = L
5978 instr[20] = M
5979 instr[19,16] = m
5980 instr[15,12] = 1000
5981 instr[11] = H
5982 instr[10] = 0
5983 instr[9,5] = Vn
5984 instr[4,0] = Vd */
5985
ef0d8ffc
NC
5986 unsigned full = INSTR (30, 30);
5987 unsigned L = INSTR (21, 21);
5988 unsigned H = INSTR (11, 11);
5989 unsigned vn = INSTR (9, 5);
5990 unsigned vd = INSTR (4, 0);
5991 unsigned size = INSTR (23, 22);
e101a78b
NC
5992 unsigned index;
5993 unsigned vm;
5994 unsigned e;
5995
5996 NYI_assert (29, 24, 0x0F);
5997 NYI_assert (15, 12, 0x8);
5998 NYI_assert (10, 10, 0);
5999
2cdad34c 6000 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
6001 switch (size)
6002 {
6003 case 1:
6004 {
6005 /* 16 bit products. */
6006 uint16_t product;
6007 uint16_t element1;
6008 uint16_t element2;
6009
ef0d8ffc
NC
6010 index = (H << 2) | (L << 1) | INSTR (20, 20);
6011 vm = INSTR (19, 16);
e101a78b
NC
6012 element2 = aarch64_get_vec_u16 (cpu, vm, index);
6013
6014 for (e = 0; e < (full ? 8 : 4); e ++)
6015 {
6016 element1 = aarch64_get_vec_u16 (cpu, vn, e);
6017 product = element1 * element2;
6018 aarch64_set_vec_u16 (cpu, vd, e, product);
6019 }
6020 }
6021 break;
6022
6023 case 2:
6024 {
6025 /* 32 bit products. */
6026 uint32_t product;
6027 uint32_t element1;
6028 uint32_t element2;
6029
6030 index = (H << 1) | L;
ef0d8ffc 6031 vm = INSTR (20, 16);
e101a78b
NC
6032 element2 = aarch64_get_vec_u32 (cpu, vm, index);
6033
6034 for (e = 0; e < (full ? 4 : 2); e ++)
6035 {
6036 element1 = aarch64_get_vec_u32 (cpu, vn, e);
6037 product = element1 * element2;
6038 aarch64_set_vec_u32 (cpu, vd, e, product);
6039 }
6040 }
6041 break;
6042
6043 default:
6044 HALT_UNALLOC;
6045 }
6046}
6047
fd7ed446
NC
6048static void
6049do_FMLA_by_element (sim_cpu *cpu)
6050{
6051 /* instr[31] = 0
6052 instr[30] = half/full
6053 instr[29,23] = 00 1111 1
6054 instr[22] = size
6055 instr[21] = L
6056 instr[20,16] = m
6057 instr[15,12] = 0001
6058 instr[11] = H
6059 instr[10] = 0
6060 instr[9,5] = Vn
6061 instr[4,0] = Vd */
6062
6063 unsigned full = INSTR (30, 30);
6064 unsigned size = INSTR (22, 22);
6065 unsigned L = INSTR (21, 21);
6066 unsigned vm = INSTR (20, 16);
6067 unsigned H = INSTR (11, 11);
6068 unsigned vn = INSTR (9, 5);
6069 unsigned vd = INSTR (4, 0);
6070 unsigned e;
6071
6072 NYI_assert (29, 23, 0x1F);
6073 NYI_assert (15, 12, 0x1);
6074 NYI_assert (10, 10, 0);
6075
6076 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
6077 if (size)
6078 {
6079 double element1, element2;
6080
6081 if (! full || L)
6082 HALT_UNALLOC;
6083
6084 element2 = aarch64_get_vec_double (cpu, vm, H);
6085
6086 for (e = 0; e < 2; e++)
6087 {
6088 element1 = aarch64_get_vec_double (cpu, vn, e);
6089 element1 *= element2;
6090 element1 += aarch64_get_vec_double (cpu, vd, e);
6091 aarch64_set_vec_double (cpu, vd, e, element1);
6092 }
6093 }
6094 else
6095 {
6096 float element1;
6097 float element2 = aarch64_get_vec_float (cpu, vm, (H << 1) | L);
6098
6099 for (e = 0; e < (full ? 4 : 2); e++)
6100 {
6101 element1 = aarch64_get_vec_float (cpu, vn, e);
6102 element1 *= element2;
6103 element1 += aarch64_get_vec_float (cpu, vd, e);
6104 aarch64_set_vec_float (cpu, vd, e, element1);
6105 }
6106 }
6107}
6108
2e8cf49e
NC
6109static void
6110do_vec_op2 (sim_cpu *cpu)
6111{
6112 /* instr[31] = 0
6113 instr[30] = half/full
6114 instr[29,24] = 00 1111
6115 instr[23] = ?
6116 instr[22,16] = element size & index
6117 instr[15,10] = sub-opcode
6118 instr[9,5] = Vm
e101a78b 6119 instr[4,0] = Vd */
2e8cf49e
NC
6120
6121 NYI_assert (29, 24, 0x0F);
6122
ef0d8ffc 6123 if (INSTR (23, 23) != 0)
2e8cf49e 6124 {
ef0d8ffc 6125 switch (INSTR (15, 10))
e101a78b 6126 {
fd7ed446
NC
6127 case 0x04:
6128 case 0x06:
6129 do_FMLA_by_element (cpu);
6130 return;
6131
e101a78b 6132 case 0x20:
fd7ed446
NC
6133 case 0x22:
6134 do_vec_MUL_by_element (cpu);
6135 return;
6136
6137 default:
6138 HALT_NYI;
e101a78b
NC
6139 }
6140 }
6141 else
6142 {
ef0d8ffc 6143 switch (INSTR (15, 10))
e101a78b
NC
6144 {
6145 case 0x01: do_vec_SSHR_USHR (cpu); return;
6146 case 0x15: do_vec_SHL (cpu); return;
6147 case 0x20:
6148 case 0x22: do_vec_MUL_by_element (cpu); return;
6149 case 0x29: do_vec_xtl (cpu); return;
6150 default: HALT_NYI;
6151 }
2e8cf49e
NC
6152 }
6153}
6154
6155static void
6156do_vec_neg (sim_cpu *cpu)
6157{
6158 /* instr[31] = 0
6159 instr[30] = full(1)/half(0)
6160 instr[29,24] = 10 1110
6161 instr[23,22] = size: byte(00), half (01), word (10), long (11)
6162 instr[21,10] = 1000 0010 1110
6163 instr[9,5] = Vs
6164 instr[4,0] = Vd */
6165
ef0d8ffc
NC
6166 int full = INSTR (30, 30);
6167 unsigned vs = INSTR (9, 5);
6168 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6169 unsigned i;
6170
6171 NYI_assert (29, 24, 0x2E);
6172 NYI_assert (21, 10, 0x82E);
6173
2cdad34c 6174 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6175 switch (INSTR (23, 22))
2e8cf49e
NC
6176 {
6177 case 0:
6178 for (i = 0; i < (full ? 16 : 8); i++)
6179 aarch64_set_vec_s8 (cpu, vd, i, - aarch64_get_vec_s8 (cpu, vs, i));
6180 return;
6181
6182 case 1:
6183 for (i = 0; i < (full ? 8 : 4); i++)
6184 aarch64_set_vec_s16 (cpu, vd, i, - aarch64_get_vec_s16 (cpu, vs, i));
6185 return;
6186
6187 case 2:
6188 for (i = 0; i < (full ? 4 : 2); i++)
6189 aarch64_set_vec_s32 (cpu, vd, i, - aarch64_get_vec_s32 (cpu, vs, i));
6190 return;
6191
6192 case 3:
6193 if (! full)
6194 HALT_NYI;
6195 for (i = 0; i < 2; i++)
6196 aarch64_set_vec_s64 (cpu, vd, i, - aarch64_get_vec_s64 (cpu, vs, i));
6197 return;
2e8cf49e
NC
6198 }
6199}
6200
6201static void
6202do_vec_sqrt (sim_cpu *cpu)
6203{
6204 /* instr[31] = 0
6205 instr[30] = full(1)/half(0)
6206 instr[29,23] = 101 1101
6207 instr[22] = single(0)/double(1)
6208 instr[21,10] = 1000 0111 1110
6209 instr[9,5] = Vs
6210 instr[4,0] = Vd. */
6211
ef0d8ffc
NC
6212 int full = INSTR (30, 30);
6213 unsigned vs = INSTR (9, 5);
6214 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6215 unsigned i;
6216
6217 NYI_assert (29, 23, 0x5B);
6218 NYI_assert (21, 10, 0x87E);
6219
2cdad34c 6220 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6221 if (INSTR (22, 22) == 0)
2e8cf49e
NC
6222 for (i = 0; i < (full ? 4 : 2); i++)
6223 aarch64_set_vec_float (cpu, vd, i,
6224 sqrtf (aarch64_get_vec_float (cpu, vs, i)));
6225 else
6226 for (i = 0; i < 2; i++)
6227 aarch64_set_vec_double (cpu, vd, i,
6228 sqrt (aarch64_get_vec_double (cpu, vs, i)));
6229}
6230
6231static void
6232do_vec_mls_indexed (sim_cpu *cpu)
6233{
6234 /* instr[31] = 0
6235 instr[30] = half(0)/full(1)
6236 instr[29,24] = 10 1111
6237 instr[23,22] = 16-bit(01)/32-bit(10)
6238 instr[21,20+11] = index (if 16-bit)
6239 instr[21+11] = index (if 32-bit)
6240 instr[20,16] = Vm
6241 instr[15,12] = 0100
6242 instr[11] = part of index
6243 instr[10] = 0
6244 instr[9,5] = Vs
6245 instr[4,0] = Vd. */
6246
ef0d8ffc
NC
6247 int full = INSTR (30, 30);
6248 unsigned vs = INSTR (9, 5);
6249 unsigned vd = INSTR (4, 0);
6250 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
6251 unsigned i;
6252
6253 NYI_assert (15, 12, 4);
6254 NYI_assert (10, 10, 0);
6255
2cdad34c 6256 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6257 switch (INSTR (23, 22))
2e8cf49e
NC
6258 {
6259 case 1:
6260 {
6261 unsigned elem;
6262 uint32_t val;
6263
6264 if (vm > 15)
6265 HALT_NYI;
6266
7517e550 6267 elem = (INSTR (21, 20) << 1) | INSTR (11, 11);
2e8cf49e
NC
6268 val = aarch64_get_vec_u16 (cpu, vm, elem);
6269
6270 for (i = 0; i < (full ? 8 : 4); i++)
6271 aarch64_set_vec_u32 (cpu, vd, i,
6272 aarch64_get_vec_u32 (cpu, vd, i) -
6273 (aarch64_get_vec_u32 (cpu, vs, i) * val));
6274 return;
6275 }
6276
6277 case 2:
6278 {
7517e550 6279 unsigned elem = (INSTR (21, 21) << 1) | INSTR (11, 11);
2e8cf49e
NC
6280 uint64_t val = aarch64_get_vec_u32 (cpu, vm, elem);
6281
6282 for (i = 0; i < (full ? 4 : 2); i++)
6283 aarch64_set_vec_u64 (cpu, vd, i,
6284 aarch64_get_vec_u64 (cpu, vd, i) -
6285 (aarch64_get_vec_u64 (cpu, vs, i) * val));
6286 return;
6287 }
6288
6289 case 0:
6290 case 3:
6291 default:
6292 HALT_NYI;
6293 }
6294}
6295
6296static void
6297do_vec_SUB (sim_cpu *cpu)
6298{
6299 /* instr [31] = 0
6300 instr [30] = half(0)/full(1)
6301 instr [29,24] = 10 1110
6302 instr [23,22] = size: byte(00, half(01), word (10), long (11)
6303 instr [21] = 1
6304 instr [20,16] = Vm
6305 instr [15,10] = 10 0001
6306 instr [9, 5] = Vn
6307 instr [4, 0] = Vd. */
6308
ef0d8ffc
NC
6309 unsigned full = INSTR (30, 30);
6310 unsigned vm = INSTR (20, 16);
6311 unsigned vn = INSTR (9, 5);
6312 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6313 unsigned i;
6314
6315 NYI_assert (29, 24, 0x2E);
6316 NYI_assert (21, 21, 1);
6317 NYI_assert (15, 10, 0x21);
6318
2cdad34c 6319 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6320 switch (INSTR (23, 22))
2e8cf49e
NC
6321 {
6322 case 0:
6323 for (i = 0; i < (full ? 16 : 8); i++)
6324 aarch64_set_vec_s8 (cpu, vd, i,
6325 aarch64_get_vec_s8 (cpu, vn, i)
6326 - aarch64_get_vec_s8 (cpu, vm, i));
6327 return;
6328
6329 case 1:
6330 for (i = 0; i < (full ? 8 : 4); i++)
6331 aarch64_set_vec_s16 (cpu, vd, i,
6332 aarch64_get_vec_s16 (cpu, vn, i)
6333 - aarch64_get_vec_s16 (cpu, vm, i));
6334 return;
6335
6336 case 2:
6337 for (i = 0; i < (full ? 4 : 2); i++)
6338 aarch64_set_vec_s32 (cpu, vd, i,
6339 aarch64_get_vec_s32 (cpu, vn, i)
6340 - aarch64_get_vec_s32 (cpu, vm, i));
6341 return;
6342
6343 case 3:
6344 if (full == 0)
6345 HALT_UNALLOC;
6346
6347 for (i = 0; i < 2; i++)
6348 aarch64_set_vec_s64 (cpu, vd, i,
6349 aarch64_get_vec_s64 (cpu, vn, i)
6350 - aarch64_get_vec_s64 (cpu, vm, i));
6351 return;
2e8cf49e
NC
6352 }
6353}
6354
6355static void
6356do_vec_MLS (sim_cpu *cpu)
6357{
6358 /* instr [31] = 0
6359 instr [30] = half(0)/full(1)
6360 instr [29,24] = 10 1110
6361 instr [23,22] = size: byte(00, half(01), word (10)
6362 instr [21] = 1
6363 instr [20,16] = Vm
6364 instr [15,10] = 10 0101
6365 instr [9, 5] = Vn
6366 instr [4, 0] = Vd. */
6367
ef0d8ffc
NC
6368 unsigned full = INSTR (30, 30);
6369 unsigned vm = INSTR (20, 16);
6370 unsigned vn = INSTR (9, 5);
6371 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6372 unsigned i;
6373
6374 NYI_assert (29, 24, 0x2E);
6375 NYI_assert (21, 21, 1);
6376 NYI_assert (15, 10, 0x25);
6377
2cdad34c 6378 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6379 switch (INSTR (23, 22))
2e8cf49e
NC
6380 {
6381 case 0:
6382 for (i = 0; i < (full ? 16 : 8); i++)
6383 aarch64_set_vec_u8 (cpu, vd, i,
c0386d4d
JW
6384 aarch64_get_vec_u8 (cpu, vd, i)
6385 - (aarch64_get_vec_u8 (cpu, vn, i)
6386 * aarch64_get_vec_u8 (cpu, vm, i)));
2e8cf49e
NC
6387 return;
6388
6389 case 1:
6390 for (i = 0; i < (full ? 8 : 4); i++)
6391 aarch64_set_vec_u16 (cpu, vd, i,
c0386d4d
JW
6392 aarch64_get_vec_u16 (cpu, vd, i)
6393 - (aarch64_get_vec_u16 (cpu, vn, i)
6394 * aarch64_get_vec_u16 (cpu, vm, i)));
2e8cf49e
NC
6395 return;
6396
6397 case 2:
6398 for (i = 0; i < (full ? 4 : 2); i++)
6399 aarch64_set_vec_u32 (cpu, vd, i,
c0386d4d
JW
6400 aarch64_get_vec_u32 (cpu, vd, i)
6401 - (aarch64_get_vec_u32 (cpu, vn, i)
6402 * aarch64_get_vec_u32 (cpu, vm, i)));
2e8cf49e
NC
6403 return;
6404
6405 default:
6406 HALT_UNALLOC;
6407 }
6408}
6409
6410static void
6411do_vec_FDIV (sim_cpu *cpu)
6412{
6413 /* instr [31] = 0
6414 instr [30] = half(0)/full(1)
6415 instr [29,23] = 10 1110 0
6416 instr [22] = float()/double(1)
6417 instr [21] = 1
6418 instr [20,16] = Vm
6419 instr [15,10] = 1111 11
6420 instr [9, 5] = Vn
6421 instr [4, 0] = Vd. */
6422
ef0d8ffc
NC
6423 unsigned full = INSTR (30, 30);
6424 unsigned vm = INSTR (20, 16);
6425 unsigned vn = INSTR (9, 5);
6426 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6427 unsigned i;
6428
6429 NYI_assert (29, 23, 0x5C);
6430 NYI_assert (21, 21, 1);
6431 NYI_assert (15, 10, 0x3F);
6432
2cdad34c 6433 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6434 if (INSTR (22, 22))
2e8cf49e
NC
6435 {
6436 if (! full)
6437 HALT_UNALLOC;
6438
6439 for (i = 0; i < 2; i++)
6440 aarch64_set_vec_double (cpu, vd, i,
6441 aarch64_get_vec_double (cpu, vn, i)
6442 / aarch64_get_vec_double (cpu, vm, i));
6443 }
6444 else
6445 for (i = 0; i < (full ? 4 : 2); i++)
6446 aarch64_set_vec_float (cpu, vd, i,
6447 aarch64_get_vec_float (cpu, vn, i)
6448 / aarch64_get_vec_float (cpu, vm, i));
6449}
6450
6451static void
6452do_vec_FMUL (sim_cpu *cpu)
6453{
6454 /* instr [31] = 0
6455 instr [30] = half(0)/full(1)
6456 instr [29,23] = 10 1110 0
6457 instr [22] = float(0)/double(1)
6458 instr [21] = 1
6459 instr [20,16] = Vm
6460 instr [15,10] = 1101 11
6461 instr [9, 5] = Vn
6462 instr [4, 0] = Vd. */
6463
ef0d8ffc
NC
6464 unsigned full = INSTR (30, 30);
6465 unsigned vm = INSTR (20, 16);
6466 unsigned vn = INSTR (9, 5);
6467 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6468 unsigned i;
6469
6470 NYI_assert (29, 23, 0x5C);
6471 NYI_assert (21, 21, 1);
6472 NYI_assert (15, 10, 0x37);
6473
2cdad34c 6474 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6475 if (INSTR (22, 22))
2e8cf49e
NC
6476 {
6477 if (! full)
6478 HALT_UNALLOC;
6479
6480 for (i = 0; i < 2; i++)
6481 aarch64_set_vec_double (cpu, vd, i,
6482 aarch64_get_vec_double (cpu, vn, i)
6483 * aarch64_get_vec_double (cpu, vm, i));
6484 }
6485 else
6486 for (i = 0; i < (full ? 4 : 2); i++)
6487 aarch64_set_vec_float (cpu, vd, i,
6488 aarch64_get_vec_float (cpu, vn, i)
6489 * aarch64_get_vec_float (cpu, vm, i));
6490}
6491
6492static void
6493do_vec_FADDP (sim_cpu *cpu)
6494{
6495 /* instr [31] = 0
6496 instr [30] = half(0)/full(1)
6497 instr [29,23] = 10 1110 0
6498 instr [22] = float(0)/double(1)
6499 instr [21] = 1
6500 instr [20,16] = Vm
6501 instr [15,10] = 1101 01
6502 instr [9, 5] = Vn
6503 instr [4, 0] = Vd. */
6504
ef0d8ffc
NC
6505 unsigned full = INSTR (30, 30);
6506 unsigned vm = INSTR (20, 16);
6507 unsigned vn = INSTR (9, 5);
6508 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6509
6510 NYI_assert (29, 23, 0x5C);
6511 NYI_assert (21, 21, 1);
6512 NYI_assert (15, 10, 0x35);
6513
2cdad34c 6514 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6515 if (INSTR (22, 22))
2e8cf49e 6516 {
57aa1742
NC
6517 /* Extract values before adding them incase vd == vn/vm. */
6518 double tmp1 = aarch64_get_vec_double (cpu, vn, 0);
6519 double tmp2 = aarch64_get_vec_double (cpu, vn, 1);
6520 double tmp3 = aarch64_get_vec_double (cpu, vm, 0);
6521 double tmp4 = aarch64_get_vec_double (cpu, vm, 1);
6522
2e8cf49e
NC
6523 if (! full)
6524 HALT_UNALLOC;
6525
57aa1742
NC
6526 aarch64_set_vec_double (cpu, vd, 0, tmp1 + tmp2);
6527 aarch64_set_vec_double (cpu, vd, 1, tmp3 + tmp4);
2e8cf49e
NC
6528 }
6529 else
6530 {
57aa1742
NC
6531 /* Extract values before adding them incase vd == vn/vm. */
6532 float tmp1 = aarch64_get_vec_float (cpu, vn, 0);
6533 float tmp2 = aarch64_get_vec_float (cpu, vn, 1);
6534 float tmp5 = aarch64_get_vec_float (cpu, vm, 0);
6535 float tmp6 = aarch64_get_vec_float (cpu, vm, 1);
6536
2e8cf49e 6537 if (full)
57aa1742
NC
6538 {
6539 float tmp3 = aarch64_get_vec_float (cpu, vn, 2);
6540 float tmp4 = aarch64_get_vec_float (cpu, vn, 3);
6541 float tmp7 = aarch64_get_vec_float (cpu, vm, 2);
6542 float tmp8 = aarch64_get_vec_float (cpu, vm, 3);
6543
6544 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6545 aarch64_set_vec_float (cpu, vd, 1, tmp3 + tmp4);
6546 aarch64_set_vec_float (cpu, vd, 2, tmp5 + tmp6);
6547 aarch64_set_vec_float (cpu, vd, 3, tmp7 + tmp8);
6548 }
6549 else
6550 {
6551 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6552 aarch64_set_vec_float (cpu, vd, 1, tmp5 + tmp6);
6553 }
2e8cf49e
NC
6554 }
6555}
6556
6557static void
6558do_vec_FSQRT (sim_cpu *cpu)
6559{
6560 /* instr[31] = 0
6561 instr[30] = half(0)/full(1)
6562 instr[29,23] = 10 1110 1
6563 instr[22] = single(0)/double(1)
6564 instr[21,10] = 10 0001 1111 10
6565 instr[9,5] = Vsrc
6566 instr[4,0] = Vdest. */
6567
ef0d8ffc
NC
6568 unsigned vn = INSTR (9, 5);
6569 unsigned vd = INSTR (4, 0);
6570 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6571 int i;
6572
6573 NYI_assert (29, 23, 0x5D);
6574 NYI_assert (21, 10, 0x87E);
6575
2cdad34c 6576 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6577 if (INSTR (22, 22))
2e8cf49e
NC
6578 {
6579 if (! full)
6580 HALT_UNALLOC;
6581
6582 for (i = 0; i < 2; i++)
6583 aarch64_set_vec_double (cpu, vd, i,
6584 sqrt (aarch64_get_vec_double (cpu, vn, i)));
6585 }
6586 else
6587 {
6588 for (i = 0; i < (full ? 4 : 2); i++)
6589 aarch64_set_vec_float (cpu, vd, i,
6590 sqrtf (aarch64_get_vec_float (cpu, vn, i)));
6591 }
6592}
6593
6594static void
6595do_vec_FNEG (sim_cpu *cpu)
6596{
6597 /* instr[31] = 0
6598 instr[30] = half (0)/full (1)
6599 instr[29,23] = 10 1110 1
6600 instr[22] = single (0)/double (1)
6601 instr[21,10] = 10 0000 1111 10
6602 instr[9,5] = Vsrc
6603 instr[4,0] = Vdest. */
6604
ef0d8ffc
NC
6605 unsigned vn = INSTR (9, 5);
6606 unsigned vd = INSTR (4, 0);
6607 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6608 int i;
6609
6610 NYI_assert (29, 23, 0x5D);
6611 NYI_assert (21, 10, 0x83E);
6612
2cdad34c 6613 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6614 if (INSTR (22, 22))
2e8cf49e
NC
6615 {
6616 if (! full)
6617 HALT_UNALLOC;
6618
6619 for (i = 0; i < 2; i++)
6620 aarch64_set_vec_double (cpu, vd, i,
6621 - aarch64_get_vec_double (cpu, vn, i));
6622 }
6623 else
6624 {
6625 for (i = 0; i < (full ? 4 : 2); i++)
6626 aarch64_set_vec_float (cpu, vd, i,
6627 - aarch64_get_vec_float (cpu, vn, i));
6628 }
6629}
6630
6631static void
6632do_vec_NOT (sim_cpu *cpu)
6633{
6634 /* instr[31] = 0
6635 instr[30] = half (0)/full (1)
5ab6d79e 6636 instr[29,10] = 10 1110 0010 0000 0101 10
2e8cf49e
NC
6637 instr[9,5] = Vn
6638 instr[4.0] = Vd. */
6639
ef0d8ffc
NC
6640 unsigned vn = INSTR (9, 5);
6641 unsigned vd = INSTR (4, 0);
2e8cf49e 6642 unsigned i;
ef0d8ffc 6643 int full = INSTR (30, 30);
2e8cf49e
NC
6644
6645 NYI_assert (29, 10, 0xB8816);
6646
2cdad34c 6647 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
6648 for (i = 0; i < (full ? 16 : 8); i++)
6649 aarch64_set_vec_u8 (cpu, vd, i, ~ aarch64_get_vec_u8 (cpu, vn, i));
6650}
6651
5ab6d79e
NC
6652static unsigned int
6653clz (uint64_t val, unsigned size)
6654{
6655 uint64_t mask = 1;
6656 int count;
6657
6658 mask <<= (size - 1);
6659 count = 0;
6660 do
6661 {
6662 if (val & mask)
6663 break;
6664 mask >>= 1;
6665 count ++;
6666 }
6667 while (mask);
6668
6669 return count;
6670}
6671
6672static void
6673do_vec_CLZ (sim_cpu *cpu)
6674{
6675 /* instr[31] = 0
6676 instr[30] = half (0)/full (1)
6677 instr[29,24] = 10 1110
6678 instr[23,22] = size
6679 instr[21,10] = 10 0000 0100 10
6680 instr[9,5] = Vn
6681 instr[4.0] = Vd. */
6682
6683 unsigned vn = INSTR (9, 5);
6684 unsigned vd = INSTR (4, 0);
6685 unsigned i;
6686 int full = INSTR (30,30);
6687
6688 NYI_assert (29, 24, 0x2E);
6689 NYI_assert (21, 10, 0x812);
6690
2cdad34c 6691 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
6692 switch (INSTR (23, 22))
6693 {
6694 case 0:
6695 for (i = 0; i < (full ? 16 : 8); i++)
6696 aarch64_set_vec_u8 (cpu, vd, i, clz (aarch64_get_vec_u8 (cpu, vn, i), 8));
6697 break;
6698 case 1:
6699 for (i = 0; i < (full ? 8 : 4); i++)
6700 aarch64_set_vec_u16 (cpu, vd, i, clz (aarch64_get_vec_u16 (cpu, vn, i), 16));
6701 break;
6702 case 2:
6703 for (i = 0; i < (full ? 4 : 2); i++)
6704 aarch64_set_vec_u32 (cpu, vd, i, clz (aarch64_get_vec_u32 (cpu, vn, i), 32));
6705 break;
6706 case 3:
6707 if (! full)
6708 HALT_UNALLOC;
6709 aarch64_set_vec_u64 (cpu, vd, 0, clz (aarch64_get_vec_u64 (cpu, vn, 0), 64));
6710 aarch64_set_vec_u64 (cpu, vd, 1, clz (aarch64_get_vec_u64 (cpu, vn, 1), 64));
6711 break;
6712 }
6713}
6714
2e8cf49e
NC
6715static void
6716do_vec_MOV_element (sim_cpu *cpu)
6717{
6718 /* instr[31,21] = 0110 1110 000
6719 instr[20,16] = size & dest index
6720 instr[15] = 0
6721 instr[14,11] = source index
6722 instr[10] = 1
6723 instr[9,5] = Vs
6724 instr[4.0] = Vd. */
6725
ef0d8ffc
NC
6726 unsigned vs = INSTR (9, 5);
6727 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6728 unsigned src_index;
6729 unsigned dst_index;
6730
6731 NYI_assert (31, 21, 0x370);
6732 NYI_assert (15, 15, 0);
6733 NYI_assert (10, 10, 1);
6734
2cdad34c 6735 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6736 if (INSTR (16, 16))
2e8cf49e
NC
6737 {
6738 /* Move a byte. */
ef0d8ffc
NC
6739 src_index = INSTR (14, 11);
6740 dst_index = INSTR (20, 17);
2e8cf49e
NC
6741 aarch64_set_vec_u8 (cpu, vd, dst_index,
6742 aarch64_get_vec_u8 (cpu, vs, src_index));
6743 }
ef0d8ffc 6744 else if (INSTR (17, 17))
2e8cf49e
NC
6745 {
6746 /* Move 16-bits. */
6747 NYI_assert (11, 11, 0);
ef0d8ffc
NC
6748 src_index = INSTR (14, 12);
6749 dst_index = INSTR (20, 18);
2e8cf49e
NC
6750 aarch64_set_vec_u16 (cpu, vd, dst_index,
6751 aarch64_get_vec_u16 (cpu, vs, src_index));
6752 }
ef0d8ffc 6753 else if (INSTR (18, 18))
2e8cf49e
NC
6754 {
6755 /* Move 32-bits. */
6756 NYI_assert (12, 11, 0);
ef0d8ffc
NC
6757 src_index = INSTR (14, 13);
6758 dst_index = INSTR (20, 19);
2e8cf49e
NC
6759 aarch64_set_vec_u32 (cpu, vd, dst_index,
6760 aarch64_get_vec_u32 (cpu, vs, src_index));
6761 }
6762 else
6763 {
6764 NYI_assert (19, 19, 1);
6765 NYI_assert (13, 11, 0);
ef0d8ffc
NC
6766 src_index = INSTR (14, 14);
6767 dst_index = INSTR (20, 20);
2e8cf49e
NC
6768 aarch64_set_vec_u64 (cpu, vd, dst_index,
6769 aarch64_get_vec_u64 (cpu, vs, src_index));
6770 }
6771}
6772
67f101ee
NC
6773static void
6774do_vec_REV32 (sim_cpu *cpu)
6775{
6776 /* instr[31] = 0
6777 instr[30] = full/half
6778 instr[29,24] = 10 1110
6779 instr[23,22] = size
6780 instr[21,10] = 10 0000 0000 10
6781 instr[9,5] = Rn
6782 instr[4,0] = Rd. */
6783
6784 unsigned rn = INSTR (9, 5);
6785 unsigned rd = INSTR (4, 0);
6786 unsigned size = INSTR (23, 22);
6787 unsigned full = INSTR (30, 30);
6788 unsigned i;
6789 FRegister val;
6790
6791 NYI_assert (29, 24, 0x2E);
6792 NYI_assert (21, 10, 0x802);
6793
2cdad34c 6794 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
6795 switch (size)
6796 {
6797 case 0:
6798 for (i = 0; i < (full ? 16 : 8); i++)
6799 val.b[i ^ 0x3] = aarch64_get_vec_u8 (cpu, rn, i);
6800 break;
6801
6802 case 1:
6803 for (i = 0; i < (full ? 8 : 4); i++)
6804 val.h[i ^ 0x1] = aarch64_get_vec_u16 (cpu, rn, i);
6805 break;
6806
6807 default:
6808 HALT_UNALLOC;
6809 }
6810
6811 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
6812 if (full)
6813 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
6814}
6815
6816static void
6817do_vec_EXT (sim_cpu *cpu)
6818{
6819 /* instr[31] = 0
6820 instr[30] = full/half
6821 instr[29,21] = 10 1110 000
6822 instr[20,16] = Vm
6823 instr[15] = 0
6824 instr[14,11] = source index
6825 instr[10] = 0
6826 instr[9,5] = Vn
6827 instr[4.0] = Vd. */
6828
6829 unsigned vm = INSTR (20, 16);
6830 unsigned vn = INSTR (9, 5);
6831 unsigned vd = INSTR (4, 0);
6832 unsigned src_index = INSTR (14, 11);
6833 unsigned full = INSTR (30, 30);
6834 unsigned i;
6835 unsigned j;
6836 FRegister val;
6837
6838 NYI_assert (31, 21, 0x370);
6839 NYI_assert (15, 15, 0);
6840 NYI_assert (10, 10, 0);
6841
6842 if (!full && (src_index & 0x8))
6843 HALT_UNALLOC;
6844
6845 j = 0;
6846
2cdad34c 6847 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
6848 for (i = src_index; i < (full ? 16 : 8); i++)
6849 val.b[j ++] = aarch64_get_vec_u8 (cpu, vn, i);
6850 for (i = 0; i < src_index; i++)
6851 val.b[j ++] = aarch64_get_vec_u8 (cpu, vm, i);
6852
6853 aarch64_set_vec_u64 (cpu, vd, 0, val.v[0]);
6854 if (full)
6855 aarch64_set_vec_u64 (cpu, vd, 1, val.v[1]);
6856}
6857
2e8cf49e
NC
6858static void
6859dexAdvSIMD0 (sim_cpu *cpu)
6860{
6861 /* instr [28,25] = 0 111. */
ef0d8ffc
NC
6862 if ( INSTR (15, 10) == 0x07
6863 && (INSTR (9, 5) ==
6864 INSTR (20, 16)))
2e8cf49e 6865 {
ef0d8ffc
NC
6866 if (INSTR (31, 21) == 0x075
6867 || INSTR (31, 21) == 0x275)
2e8cf49e
NC
6868 {
6869 do_vec_MOV_whole_vector (cpu);
6870 return;
6871 }
6872 }
6873
ef0d8ffc 6874 if (INSTR (29, 19) == 0x1E0)
2e8cf49e
NC
6875 {
6876 do_vec_MOV_immediate (cpu);
6877 return;
6878 }
6879
ef0d8ffc 6880 if (INSTR (29, 19) == 0x5E0)
2e8cf49e
NC
6881 {
6882 do_vec_MVNI (cpu);
6883 return;
6884 }
6885
ef0d8ffc
NC
6886 if (INSTR (29, 19) == 0x1C0
6887 || INSTR (29, 19) == 0x1C1)
2e8cf49e 6888 {
ef0d8ffc 6889 if (INSTR (15, 10) == 0x03)
2e8cf49e
NC
6890 {
6891 do_vec_DUP_scalar_into_vector (cpu);
6892 return;
6893 }
6894 }
6895
ef0d8ffc 6896 switch (INSTR (29, 24))
2e8cf49e
NC
6897 {
6898 case 0x0E: do_vec_op1 (cpu); return;
6899 case 0x0F: do_vec_op2 (cpu); return;
6900
2e8cf49e 6901 case 0x2E:
ef0d8ffc 6902 if (INSTR (21, 21) == 1)
2e8cf49e 6903 {
ef0d8ffc 6904 switch (INSTR (15, 10))
2e8cf49e 6905 {
67f101ee
NC
6906 case 0x02:
6907 do_vec_REV32 (cpu);
6908 return;
6909
2e8cf49e 6910 case 0x07:
ef0d8ffc 6911 switch (INSTR (23, 22))
2e8cf49e
NC
6912 {
6913 case 0: do_vec_EOR (cpu); return;
6914 case 1: do_vec_BSL (cpu); return;
6915 case 2:
6916 case 3: do_vec_bit (cpu); return;
6917 }
6918 break;
6919
6920 case 0x08: do_vec_sub_long (cpu); return;
6921 case 0x11: do_vec_USHL (cpu); return;
5ab6d79e 6922 case 0x12: do_vec_CLZ (cpu); return;
2e8cf49e
NC
6923 case 0x16: do_vec_NOT (cpu); return;
6924 case 0x19: do_vec_max (cpu); return;
6925 case 0x1B: do_vec_min (cpu); return;
6926 case 0x21: do_vec_SUB (cpu); return;
6927 case 0x25: do_vec_MLS (cpu); return;
6928 case 0x31: do_vec_FminmaxNMP (cpu); return;
6929 case 0x35: do_vec_FADDP (cpu); return;
6930 case 0x37: do_vec_FMUL (cpu); return;
6931 case 0x3F: do_vec_FDIV (cpu); return;
6932
6933 case 0x3E:
ef0d8ffc 6934 switch (INSTR (20, 16))
2e8cf49e
NC
6935 {
6936 case 0x00: do_vec_FNEG (cpu); return;
6937 case 0x01: do_vec_FSQRT (cpu); return;
6938 default: HALT_NYI;
6939 }
6940
6941 case 0x0D:
6942 case 0x0F:
6943 case 0x22:
6944 case 0x23:
6945 case 0x26:
6946 case 0x2A:
6947 case 0x32:
6948 case 0x36:
6949 case 0x39:
6950 case 0x3A:
6951 do_vec_compare (cpu); return;
6952
5ab6d79e
NC
6953 default:
6954 break;
2e8cf49e
NC
6955 }
6956 }
6957
ef0d8ffc 6958 if (INSTR (31, 21) == 0x370)
2e8cf49e 6959 {
67f101ee
NC
6960 if (INSTR (10, 10))
6961 do_vec_MOV_element (cpu);
6962 else
6963 do_vec_EXT (cpu);
2e8cf49e
NC
6964 return;
6965 }
6966
ef0d8ffc 6967 switch (INSTR (21, 10))
2e8cf49e
NC
6968 {
6969 case 0x82E: do_vec_neg (cpu); return;
6970 case 0x87E: do_vec_sqrt (cpu); return;
6971 default:
ef0d8ffc 6972 if (INSTR (15, 10) == 0x30)
2e8cf49e
NC
6973 {
6974 do_vec_mull (cpu);
6975 return;
6976 }
6977 break;
6978 }
6979 break;
6980
67f101ee
NC
6981 case 0x2f:
6982 switch (INSTR (15, 10))
6983 {
6984 case 0x01: do_vec_SSHR_USHR (cpu); return;
6985 case 0x10:
6986 case 0x12: do_vec_mls_indexed (cpu); return;
6987 case 0x29: do_vec_xtl (cpu); return;
6988 default:
6989 HALT_NYI;
6990 }
6991
2e8cf49e
NC
6992 default:
6993 break;
6994 }
6995
6996 HALT_NYI;
6997}
6998
6999/* 3 sources. */
7000
7001/* Float multiply add. */
7002static void
7003fmadds (sim_cpu *cpu)
7004{
ef0d8ffc
NC
7005 unsigned sa = INSTR (14, 10);
7006 unsigned sm = INSTR (20, 16);
7007 unsigned sn = INSTR ( 9, 5);
7008 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7009
2cdad34c 7010 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7011 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
7012 + aarch64_get_FP_float (cpu, sn)
7013 * aarch64_get_FP_float (cpu, sm));
7014}
7015
7016/* Double multiply add. */
7017static void
7018fmaddd (sim_cpu *cpu)
7019{
ef0d8ffc
NC
7020 unsigned sa = INSTR (14, 10);
7021 unsigned sm = INSTR (20, 16);
7022 unsigned sn = INSTR ( 9, 5);
7023 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7024
2cdad34c 7025 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7026 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
7027 + aarch64_get_FP_double (cpu, sn)
7028 * aarch64_get_FP_double (cpu, sm));
7029}
7030
7031/* Float multiply subtract. */
7032static void
7033fmsubs (sim_cpu *cpu)
7034{
ef0d8ffc
NC
7035 unsigned sa = INSTR (14, 10);
7036 unsigned sm = INSTR (20, 16);
7037 unsigned sn = INSTR ( 9, 5);
7038 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7039
2cdad34c 7040 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7041 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
7042 - aarch64_get_FP_float (cpu, sn)
7043 * aarch64_get_FP_float (cpu, sm));
7044}
7045
7046/* Double multiply subtract. */
7047static void
7048fmsubd (sim_cpu *cpu)
7049{
ef0d8ffc
NC
7050 unsigned sa = INSTR (14, 10);
7051 unsigned sm = INSTR (20, 16);
7052 unsigned sn = INSTR ( 9, 5);
7053 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7054
2cdad34c 7055 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7056 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
7057 - aarch64_get_FP_double (cpu, sn)
7058 * aarch64_get_FP_double (cpu, sm));
7059}
7060
7061/* Float negative multiply add. */
7062static void
7063fnmadds (sim_cpu *cpu)
7064{
ef0d8ffc
NC
7065 unsigned sa = INSTR (14, 10);
7066 unsigned sm = INSTR (20, 16);
7067 unsigned sn = INSTR ( 9, 5);
7068 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7069
2cdad34c 7070 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7071 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
7072 + (- aarch64_get_FP_float (cpu, sn))
7073 * aarch64_get_FP_float (cpu, sm));
7074}
7075
7076/* Double negative multiply add. */
7077static void
7078fnmaddd (sim_cpu *cpu)
7079{
ef0d8ffc
NC
7080 unsigned sa = INSTR (14, 10);
7081 unsigned sm = INSTR (20, 16);
7082 unsigned sn = INSTR ( 9, 5);
7083 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7084
2cdad34c 7085 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7086 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
7087 + (- aarch64_get_FP_double (cpu, sn))
7088 * aarch64_get_FP_double (cpu, sm));
7089}
7090
7091/* Float negative multiply subtract. */
7092static void
7093fnmsubs (sim_cpu *cpu)
7094{
ef0d8ffc
NC
7095 unsigned sa = INSTR (14, 10);
7096 unsigned sm = INSTR (20, 16);
7097 unsigned sn = INSTR ( 9, 5);
7098 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7099
2cdad34c 7100 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7101 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
7102 + aarch64_get_FP_float (cpu, sn)
7103 * aarch64_get_FP_float (cpu, sm));
7104}
7105
7106/* Double negative multiply subtract. */
7107static void
7108fnmsubd (sim_cpu *cpu)
7109{
ef0d8ffc
NC
7110 unsigned sa = INSTR (14, 10);
7111 unsigned sm = INSTR (20, 16);
7112 unsigned sn = INSTR ( 9, 5);
7113 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7114
2cdad34c 7115 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7116 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
7117 + aarch64_get_FP_double (cpu, sn)
7118 * aarch64_get_FP_double (cpu, sm));
7119}
7120
7121static void
7122dexSimpleFPDataProc3Source (sim_cpu *cpu)
7123{
7124 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7125 instr[30] = 0
7126 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7127 instr[28,25] = 1111
7128 instr[24] = 1
7129 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7130 instr[21] ==> o1 : 0 ==> unnegated, 1 ==> negated
7131 instr[15] ==> o2 : 0 ==> ADD, 1 ==> SUB */
7132
7517e550 7133 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
2e8cf49e 7134 /* dispatch on combined type:o1:o2. */
7517e550 7135 uint32_t dispatch = (INSTR (23, 21) << 1) | INSTR (15, 15);
2e8cf49e
NC
7136
7137 if (M_S != 0)
7138 HALT_UNALLOC;
7139
7140 switch (dispatch)
7141 {
7142 case 0: fmadds (cpu); return;
7143 case 1: fmsubs (cpu); return;
7144 case 2: fnmadds (cpu); return;
7145 case 3: fnmsubs (cpu); return;
7146 case 4: fmaddd (cpu); return;
7147 case 5: fmsubd (cpu); return;
7148 case 6: fnmaddd (cpu); return;
7149 case 7: fnmsubd (cpu); return;
7150 default:
7151 /* type > 1 is currently unallocated. */
7152 HALT_UNALLOC;
7153 }
7154}
7155
7156static void
7157dexSimpleFPFixedConvert (sim_cpu *cpu)
7158{
7159 HALT_NYI;
7160}
7161
7162static void
7163dexSimpleFPCondCompare (sim_cpu *cpu)
7164{
5ab6d79e
NC
7165 /* instr [31,23] = 0001 1110 0
7166 instr [22] = type
7167 instr [21] = 1
7168 instr [20,16] = Rm
7169 instr [15,12] = condition
7170 instr [11,10] = 01
7171 instr [9,5] = Rn
7172 instr [4] = 0
7173 instr [3,0] = nzcv */
7174
7175 unsigned rm = INSTR (20, 16);
7176 unsigned rn = INSTR (9, 5);
7177
7178 NYI_assert (31, 23, 0x3C);
7179 NYI_assert (11, 10, 0x1);
7180 NYI_assert (4, 4, 0);
7181
2cdad34c 7182 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7183 if (! testConditionCode (cpu, INSTR (15, 12)))
7184 {
7185 aarch64_set_CPSR (cpu, INSTR (3, 0));
7186 return;
7187 }
7188
7189 if (INSTR (22, 22))
7190 {
7191 /* Double precision. */
7192 double val1 = aarch64_get_vec_double (cpu, rn, 0);
7193 double val2 = aarch64_get_vec_double (cpu, rm, 0);
7194
7195 /* FIXME: Check for NaNs. */
7196 if (val1 == val2)
7197 aarch64_set_CPSR (cpu, (Z | C));
7198 else if (val1 < val2)
7199 aarch64_set_CPSR (cpu, N);
7200 else /* val1 > val2 */
7201 aarch64_set_CPSR (cpu, C);
7202 }
7203 else
7204 {
7205 /* Single precision. */
7206 float val1 = aarch64_get_vec_float (cpu, rn, 0);
7207 float val2 = aarch64_get_vec_float (cpu, rm, 0);
ef0d8ffc 7208
5ab6d79e
NC
7209 /* FIXME: Check for NaNs. */
7210 if (val1 == val2)
7211 aarch64_set_CPSR (cpu, (Z | C));
7212 else if (val1 < val2)
7213 aarch64_set_CPSR (cpu, N);
7214 else /* val1 > val2 */
7215 aarch64_set_CPSR (cpu, C);
7216 }
2e8cf49e
NC
7217}
7218
7219/* 2 sources. */
7220
7221/* Float add. */
7222static void
7223fadds (sim_cpu *cpu)
7224{
ef0d8ffc
NC
7225 unsigned sm = INSTR (20, 16);
7226 unsigned sn = INSTR ( 9, 5);
7227 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7228
2cdad34c 7229 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7230 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7231 + aarch64_get_FP_float (cpu, sm));
7232}
7233
7234/* Double add. */
7235static void
7236faddd (sim_cpu *cpu)
7237{
ef0d8ffc
NC
7238 unsigned sm = INSTR (20, 16);
7239 unsigned sn = INSTR ( 9, 5);
7240 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7241
2cdad34c 7242 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7243 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7244 + aarch64_get_FP_double (cpu, sm));
7245}
7246
7247/* Float divide. */
7248static void
7249fdivs (sim_cpu *cpu)
7250{
ef0d8ffc
NC
7251 unsigned sm = INSTR (20, 16);
7252 unsigned sn = INSTR ( 9, 5);
7253 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7254
2cdad34c 7255 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7256 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7257 / aarch64_get_FP_float (cpu, sm));
7258}
7259
7260/* Double divide. */
7261static void
7262fdivd (sim_cpu *cpu)
7263{
ef0d8ffc
NC
7264 unsigned sm = INSTR (20, 16);
7265 unsigned sn = INSTR ( 9, 5);
7266 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7267
2cdad34c 7268 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7269 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7270 / aarch64_get_FP_double (cpu, sm));
7271}
7272
7273/* Float multiply. */
7274static void
7275fmuls (sim_cpu *cpu)
7276{
ef0d8ffc
NC
7277 unsigned sm = INSTR (20, 16);
7278 unsigned sn = INSTR ( 9, 5);
7279 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7280
2cdad34c 7281 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7282 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7283 * aarch64_get_FP_float (cpu, sm));
7284}
7285
7286/* Double multiply. */
7287static void
7288fmuld (sim_cpu *cpu)
7289{
ef0d8ffc
NC
7290 unsigned sm = INSTR (20, 16);
7291 unsigned sn = INSTR ( 9, 5);
7292 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7293
2cdad34c 7294 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7295 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7296 * aarch64_get_FP_double (cpu, sm));
7297}
7298
7299/* Float negate and multiply. */
7300static void
7301fnmuls (sim_cpu *cpu)
7302{
ef0d8ffc
NC
7303 unsigned sm = INSTR (20, 16);
7304 unsigned sn = INSTR ( 9, 5);
7305 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7306
2cdad34c 7307 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7308 aarch64_set_FP_float (cpu, sd, - (aarch64_get_FP_float (cpu, sn)
7309 * aarch64_get_FP_float (cpu, sm)));
7310}
7311
7312/* Double negate and multiply. */
7313static void
7314fnmuld (sim_cpu *cpu)
7315{
ef0d8ffc
NC
7316 unsigned sm = INSTR (20, 16);
7317 unsigned sn = INSTR ( 9, 5);
7318 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7319
2cdad34c 7320 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7321 aarch64_set_FP_double (cpu, sd, - (aarch64_get_FP_double (cpu, sn)
7322 * aarch64_get_FP_double (cpu, sm)));
7323}
7324
7325/* Float subtract. */
7326static void
7327fsubs (sim_cpu *cpu)
7328{
ef0d8ffc
NC
7329 unsigned sm = INSTR (20, 16);
7330 unsigned sn = INSTR ( 9, 5);
7331 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7332
2cdad34c 7333 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7334 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7335 - aarch64_get_FP_float (cpu, sm));
7336}
7337
7338/* Double subtract. */
7339static void
7340fsubd (sim_cpu *cpu)
7341{
ef0d8ffc
NC
7342 unsigned sm = INSTR (20, 16);
7343 unsigned sn = INSTR ( 9, 5);
7344 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7345
2cdad34c 7346 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7347 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7348 - aarch64_get_FP_double (cpu, sm));
7349}
7350
7351static void
7352do_FMINNM (sim_cpu *cpu)
7353{
7354 /* instr[31,23] = 0 0011 1100
7355 instr[22] = float(0)/double(1)
7356 instr[21] = 1
7357 instr[20,16] = Sm
7358 instr[15,10] = 01 1110
7359 instr[9,5] = Sn
7360 instr[4,0] = Cpu */
7361
ef0d8ffc
NC
7362 unsigned sm = INSTR (20, 16);
7363 unsigned sn = INSTR ( 9, 5);
7364 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7365
7366 NYI_assert (31, 23, 0x03C);
7367 NYI_assert (15, 10, 0x1E);
7368
2cdad34c 7369 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7370 if (INSTR (22, 22))
2e8cf49e
NC
7371 aarch64_set_FP_double (cpu, sd,
7372 dminnm (aarch64_get_FP_double (cpu, sn),
7373 aarch64_get_FP_double (cpu, sm)));
7374 else
7375 aarch64_set_FP_float (cpu, sd,
7376 fminnm (aarch64_get_FP_float (cpu, sn),
7377 aarch64_get_FP_float (cpu, sm)));
7378}
7379
7380static void
7381do_FMAXNM (sim_cpu *cpu)
7382{
7383 /* instr[31,23] = 0 0011 1100
7384 instr[22] = float(0)/double(1)
7385 instr[21] = 1
7386 instr[20,16] = Sm
7387 instr[15,10] = 01 1010
7388 instr[9,5] = Sn
7389 instr[4,0] = Cpu */
7390
ef0d8ffc
NC
7391 unsigned sm = INSTR (20, 16);
7392 unsigned sn = INSTR ( 9, 5);
7393 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7394
7395 NYI_assert (31, 23, 0x03C);
7396 NYI_assert (15, 10, 0x1A);
7397
2cdad34c 7398 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7399 if (INSTR (22, 22))
2e8cf49e
NC
7400 aarch64_set_FP_double (cpu, sd,
7401 dmaxnm (aarch64_get_FP_double (cpu, sn),
7402 aarch64_get_FP_double (cpu, sm)));
7403 else
7404 aarch64_set_FP_float (cpu, sd,
7405 fmaxnm (aarch64_get_FP_float (cpu, sn),
7406 aarch64_get_FP_float (cpu, sm)));
7407}
7408
7409static void
7410dexSimpleFPDataProc2Source (sim_cpu *cpu)
7411{
7412 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7413 instr[30] = 0
7414 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7415 instr[28,25] = 1111
7416 instr[24] = 0
7417 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7418 instr[21] = 1
7419 instr[20,16] = Vm
7420 instr[15,12] ==> opcode : 0000 ==> FMUL, 0001 ==> FDIV
7421 0010 ==> FADD, 0011 ==> FSUB,
7422 0100 ==> FMAX, 0101 ==> FMIN
7423 0110 ==> FMAXNM, 0111 ==> FMINNM
7424 1000 ==> FNMUL, ow ==> UNALLOC
7425 instr[11,10] = 10
7426 instr[9,5] = Vn
7427 instr[4,0] = Vd */
7428
7517e550 7429 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc 7430 uint32_t type = INSTR (23, 22);
2e8cf49e 7431 /* Dispatch on opcode. */
ef0d8ffc 7432 uint32_t dispatch = INSTR (15, 12);
2e8cf49e
NC
7433
7434 if (type > 1)
7435 HALT_UNALLOC;
7436
7437 if (M_S != 0)
7438 HALT_UNALLOC;
7439
7440 if (type)
7441 switch (dispatch)
7442 {
7443 case 0: fmuld (cpu); return;
7444 case 1: fdivd (cpu); return;
7445 case 2: faddd (cpu); return;
7446 case 3: fsubd (cpu); return;
7447 case 6: do_FMAXNM (cpu); return;
7448 case 7: do_FMINNM (cpu); return;
7449 case 8: fnmuld (cpu); return;
7450
7451 /* Have not yet implemented fmax and fmin. */
7452 case 4:
7453 case 5:
7454 HALT_NYI;
7455
7456 default:
7457 HALT_UNALLOC;
7458 }
7459 else /* type == 0 => floats. */
7460 switch (dispatch)
7461 {
7462 case 0: fmuls (cpu); return;
7463 case 1: fdivs (cpu); return;
7464 case 2: fadds (cpu); return;
7465 case 3: fsubs (cpu); return;
7466 case 6: do_FMAXNM (cpu); return;
7467 case 7: do_FMINNM (cpu); return;
7468 case 8: fnmuls (cpu); return;
7469
7470 case 4:
7471 case 5:
7472 HALT_NYI;
7473
7474 default:
7475 HALT_UNALLOC;
7476 }
7477}
7478
7479static void
7480dexSimpleFPCondSelect (sim_cpu *cpu)
7481{
7482 /* FCSEL
7483 instr[31,23] = 0 0011 1100
7484 instr[22] = 0=>single 1=>double
7485 instr[21] = 1
7486 instr[20,16] = Sm
7487 instr[15,12] = cond
7488 instr[11,10] = 11
7489 instr[9,5] = Sn
7490 instr[4,0] = Cpu */
ef0d8ffc
NC
7491 unsigned sm = INSTR (20, 16);
7492 unsigned sn = INSTR ( 9, 5);
7493 unsigned sd = INSTR ( 4, 0);
7494 uint32_t set = testConditionCode (cpu, INSTR (15, 12));
2e8cf49e
NC
7495
7496 NYI_assert (31, 23, 0x03C);
7497 NYI_assert (11, 10, 0x3);
7498
2cdad34c 7499 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7500 if (INSTR (22, 22))
c0386d4d
JW
7501 aarch64_set_FP_double (cpu, sd, (set ? aarch64_get_FP_double (cpu, sn)
7502 : aarch64_get_FP_double (cpu, sm)));
2e8cf49e 7503 else
c0386d4d
JW
7504 aarch64_set_FP_float (cpu, sd, (set ? aarch64_get_FP_float (cpu, sn)
7505 : aarch64_get_FP_float (cpu, sm)));
2e8cf49e
NC
7506}
7507
7508/* Store 32 bit unscaled signed 9 bit. */
7509static void
7510fsturs (sim_cpu *cpu, int32_t offset)
7511{
ef0d8ffc
NC
7512 unsigned int rn = INSTR (9, 5);
7513 unsigned int st = INSTR (4, 0);
2e8cf49e 7514
2cdad34c 7515 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1
JW
7516 aarch64_set_mem_u32 (cpu, aarch64_get_reg_u64 (cpu, rn, 1) + offset,
7517 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
7518}
7519
7520/* Store 64 bit unscaled signed 9 bit. */
7521static void
7522fsturd (sim_cpu *cpu, int32_t offset)
7523{
ef0d8ffc
NC
7524 unsigned int rn = INSTR (9, 5);
7525 unsigned int st = INSTR (4, 0);
2e8cf49e 7526
2cdad34c 7527 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1
JW
7528 aarch64_set_mem_u64 (cpu, aarch64_get_reg_u64 (cpu, rn, 1) + offset,
7529 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
7530}
7531
7532/* Store 128 bit unscaled signed 9 bit. */
7533static void
7534fsturq (sim_cpu *cpu, int32_t offset)
7535{
ef0d8ffc
NC
7536 unsigned int rn = INSTR (9, 5);
7537 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7538 FRegister a;
7539
2cdad34c 7540 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1 7541 aarch64_get_FP_long_double (cpu, st, & a);
2e8cf49e 7542 aarch64_set_mem_long_double (cpu,
88ddd4a1 7543 aarch64_get_reg_u64 (cpu, rn, 1)
2e8cf49e
NC
7544 + offset, a);
7545}
7546
7547/* TODO FP move register. */
7548
7549/* 32 bit fp to fp move register. */
7550static void
7551ffmovs (sim_cpu *cpu)
7552{
ef0d8ffc
NC
7553 unsigned int rn = INSTR (9, 5);
7554 unsigned int st = INSTR (4, 0);
2e8cf49e 7555
2cdad34c 7556 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7557 aarch64_set_FP_float (cpu, st, aarch64_get_FP_float (cpu, rn));
7558}
7559
7560/* 64 bit fp to fp move register. */
7561static void
7562ffmovd (sim_cpu *cpu)
7563{
ef0d8ffc
NC
7564 unsigned int rn = INSTR (9, 5);
7565 unsigned int st = INSTR (4, 0);
2e8cf49e 7566
2cdad34c 7567 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7568 aarch64_set_FP_double (cpu, st, aarch64_get_FP_double (cpu, rn));
7569}
7570
7571/* 32 bit GReg to Vec move register. */
7572static void
7573fgmovs (sim_cpu *cpu)
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__);
2e8cf49e
NC
7579 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_reg_u32 (cpu, rn, NO_SP));
7580}
7581
7582/* 64 bit g to fp move register. */
7583static void
7584fgmovd (sim_cpu *cpu)
7585{
ef0d8ffc
NC
7586 unsigned int rn = INSTR (9, 5);
7587 unsigned int st = INSTR (4, 0);
2e8cf49e 7588
2cdad34c 7589 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7590 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_reg_u64 (cpu, rn, NO_SP));
7591}
7592
7593/* 32 bit fp to g move register. */
7594static void
7595gfmovs (sim_cpu *cpu)
7596{
ef0d8ffc
NC
7597 unsigned int rn = INSTR (9, 5);
7598 unsigned int st = INSTR (4, 0);
2e8cf49e 7599
2cdad34c 7600 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7601 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u32 (cpu, rn, 0));
7602}
7603
7604/* 64 bit fp to g move register. */
7605static void
7606gfmovd (sim_cpu *cpu)
7607{
ef0d8ffc
NC
7608 unsigned int rn = INSTR (9, 5);
7609 unsigned int st = INSTR (4, 0);
2e8cf49e 7610
2cdad34c 7611 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7612 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u64 (cpu, rn, 0));
7613}
7614
7615/* FP move immediate
7616
7617 These install an immediate 8 bit value in the target register
7618 where the 8 bits comprise 1 sign bit, 4 bits of fraction and a 3
7619 bit exponent. */
7620
7621static void
7622fmovs (sim_cpu *cpu)
7623{
ef0d8ffc
NC
7624 unsigned int sd = INSTR (4, 0);
7625 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7626 float f = fp_immediate_for_encoding_32 (imm);
7627
2cdad34c 7628 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7629 aarch64_set_FP_float (cpu, sd, f);
7630}
7631
7632static void
7633fmovd (sim_cpu *cpu)
7634{
ef0d8ffc
NC
7635 unsigned int sd = INSTR (4, 0);
7636 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7637 double d = fp_immediate_for_encoding_64 (imm);
7638
2cdad34c 7639 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7640 aarch64_set_FP_double (cpu, sd, d);
7641}
7642
7643static void
7644dexSimpleFPImmediate (sim_cpu *cpu)
7645{
7646 /* instr[31,23] == 00111100
7647 instr[22] == type : single(0)/double(1)
7648 instr[21] == 1
7649 instr[20,13] == imm8
7650 instr[12,10] == 100
7651 instr[9,5] == imm5 : 00000 ==> PK, ow ==> UNALLOC
7652 instr[4,0] == Rd */
ef0d8ffc 7653 uint32_t imm5 = INSTR (9, 5);
2e8cf49e
NC
7654
7655 NYI_assert (31, 23, 0x3C);
7656
7657 if (imm5 != 0)
7658 HALT_UNALLOC;
7659
ef0d8ffc 7660 if (INSTR (22, 22))
2e8cf49e
NC
7661 fmovd (cpu);
7662 else
7663 fmovs (cpu);
7664}
7665
7666/* TODO specific decode and execute for group Load Store. */
7667
7668/* TODO FP load/store single register (unscaled offset). */
7669
7670/* TODO load 8 bit unscaled signed 9 bit. */
7671/* TODO load 16 bit unscaled signed 9 bit. */
7672
7673/* Load 32 bit unscaled signed 9 bit. */
7674static void
7675fldurs (sim_cpu *cpu, int32_t offset)
7676{
ef0d8ffc
NC
7677 unsigned int rn = INSTR (9, 5);
7678 unsigned int st = INSTR (4, 0);
2e8cf49e 7679
2cdad34c 7680 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
7681 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
7682 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7683}
7684
7685/* Load 64 bit unscaled signed 9 bit. */
7686static void
7687fldurd (sim_cpu *cpu, int32_t offset)
7688{
ef0d8ffc
NC
7689 unsigned int rn = INSTR (9, 5);
7690 unsigned int st = INSTR (4, 0);
2e8cf49e 7691
2cdad34c 7692 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
7693 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64
7694 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7695}
7696
7697/* Load 128 bit unscaled signed 9 bit. */
7698static void
7699fldurq (sim_cpu *cpu, int32_t offset)
7700{
ef0d8ffc
NC
7701 unsigned int rn = INSTR (9, 5);
7702 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7703 FRegister a;
7704 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
7705
2cdad34c 7706 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7707 aarch64_get_mem_long_double (cpu, addr, & a);
7708 aarch64_set_FP_long_double (cpu, st, a);
7709}
7710
7711/* TODO store 8 bit unscaled signed 9 bit. */
7712/* TODO store 16 bit unscaled signed 9 bit. */
7713
7714
7715/* 1 source. */
7716
7717/* Float absolute value. */
7718static void
7719fabss (sim_cpu *cpu)
7720{
ef0d8ffc
NC
7721 unsigned sn = INSTR (9, 5);
7722 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7723 float value = aarch64_get_FP_float (cpu, sn);
7724
2cdad34c 7725 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7726 aarch64_set_FP_float (cpu, sd, fabsf (value));
7727}
7728
7729/* Double absolute value. */
7730static void
7731fabcpu (sim_cpu *cpu)
7732{
ef0d8ffc
NC
7733 unsigned sn = INSTR (9, 5);
7734 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7735 double value = aarch64_get_FP_double (cpu, sn);
7736
2cdad34c 7737 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7738 aarch64_set_FP_double (cpu, sd, fabs (value));
7739}
7740
7741/* Float negative value. */
7742static void
7743fnegs (sim_cpu *cpu)
7744{
ef0d8ffc
NC
7745 unsigned sn = INSTR (9, 5);
7746 unsigned sd = INSTR (4, 0);
2e8cf49e 7747
2cdad34c 7748 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7749 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sn));
7750}
7751
7752/* Double negative value. */
7753static void
7754fnegd (sim_cpu *cpu)
7755{
ef0d8ffc
NC
7756 unsigned sn = INSTR (9, 5);
7757 unsigned sd = INSTR (4, 0);
2e8cf49e 7758
2cdad34c 7759 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7760 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sn));
7761}
7762
7763/* Float square root. */
7764static void
7765fsqrts (sim_cpu *cpu)
7766{
ef0d8ffc
NC
7767 unsigned sn = INSTR (9, 5);
7768 unsigned sd = INSTR (4, 0);
2e8cf49e 7769
2cdad34c 7770 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
0f118bc7 7771 aarch64_set_FP_float (cpu, sd, sqrtf (aarch64_get_FP_float (cpu, sn)));
2e8cf49e
NC
7772}
7773
7774/* Double square root. */
7775static void
7776fsqrtd (sim_cpu *cpu)
7777{
ef0d8ffc
NC
7778 unsigned sn = INSTR (9, 5);
7779 unsigned sd = INSTR (4, 0);
2e8cf49e 7780
2cdad34c 7781 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7782 aarch64_set_FP_double (cpu, sd,
7783 sqrt (aarch64_get_FP_double (cpu, sn)));
7784}
7785
7786/* Convert double to float. */
7787static void
7788fcvtds (sim_cpu *cpu)
7789{
ef0d8ffc
NC
7790 unsigned sn = INSTR (9, 5);
7791 unsigned sd = INSTR (4, 0);
2e8cf49e 7792
2cdad34c 7793 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7794 aarch64_set_FP_float (cpu, sd, (float) aarch64_get_FP_double (cpu, sn));
7795}
7796
7797/* Convert float to double. */
7798static void
7799fcvtcpu (sim_cpu *cpu)
7800{
ef0d8ffc
NC
7801 unsigned sn = INSTR (9, 5);
7802 unsigned sd = INSTR (4, 0);
2e8cf49e 7803
2cdad34c 7804 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7805 aarch64_set_FP_double (cpu, sd, (double) aarch64_get_FP_float (cpu, sn));
7806}
7807
7808static void
7809do_FRINT (sim_cpu *cpu)
7810{
7811 /* instr[31,23] = 0001 1110 0
7812 instr[22] = single(0)/double(1)
7813 instr[21,18] = 1001
7814 instr[17,15] = rounding mode
7815 instr[14,10] = 10000
7816 instr[9,5] = source
7817 instr[4,0] = dest */
7818
7819 float val;
ef0d8ffc
NC
7820 unsigned rs = INSTR (9, 5);
7821 unsigned rd = INSTR (4, 0);
7822 unsigned int rmode = INSTR (17, 15);
2e8cf49e
NC
7823
7824 NYI_assert (31, 23, 0x03C);
7825 NYI_assert (21, 18, 0x9);
7826 NYI_assert (14, 10, 0x10);
7827
7828 if (rmode == 6 || rmode == 7)
7829 /* FIXME: Add support for rmode == 6 exactness check. */
7830 rmode = uimm (aarch64_get_FPSR (cpu), 23, 22);
7831
2cdad34c 7832 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7833 if (INSTR (22, 22))
2e8cf49e
NC
7834 {
7835 double val = aarch64_get_FP_double (cpu, rs);
7836
7837 switch (rmode)
7838 {
7839 case 0: /* mode N: nearest or even. */
7840 {
7841 double rval = round (val);
7842
7843 if (val - rval == 0.5)
7844 {
7845 if (((rval / 2.0) * 2.0) != rval)
7846 rval += 1.0;
7847 }
7848
7849 aarch64_set_FP_double (cpu, rd, round (val));
7850 return;
7851 }
7852
7853 case 1: /* mode P: towards +inf. */
7854 if (val < 0.0)
7855 aarch64_set_FP_double (cpu, rd, trunc (val));
7856 else
7857 aarch64_set_FP_double (cpu, rd, round (val));
7858 return;
7859
7860 case 2: /* mode M: towards -inf. */
7861 if (val < 0.0)
7862 aarch64_set_FP_double (cpu, rd, round (val));
7863 else
7864 aarch64_set_FP_double (cpu, rd, trunc (val));
7865 return;
7866
7867 case 3: /* mode Z: towards 0. */
7868 aarch64_set_FP_double (cpu, rd, trunc (val));
7869 return;
7870
7871 case 4: /* mode A: away from 0. */
7872 aarch64_set_FP_double (cpu, rd, round (val));
7873 return;
7874
7875 case 6: /* mode X: use FPCR with exactness check. */
7876 case 7: /* mode I: use FPCR mode. */
7877 HALT_NYI;
7878
7879 default:
7880 HALT_UNALLOC;
7881 }
7882 }
7883
7884 val = aarch64_get_FP_float (cpu, rs);
7885
7886 switch (rmode)
7887 {
7888 case 0: /* mode N: nearest or even. */
7889 {
7890 float rval = roundf (val);
7891
7892 if (val - rval == 0.5)
7893 {
7894 if (((rval / 2.0) * 2.0) != rval)
7895 rval += 1.0;
7896 }
7897
7898 aarch64_set_FP_float (cpu, rd, rval);
7899 return;
7900 }
7901
7902 case 1: /* mode P: towards +inf. */
7903 if (val < 0.0)
7904 aarch64_set_FP_float (cpu, rd, truncf (val));
7905 else
7906 aarch64_set_FP_float (cpu, rd, roundf (val));
7907 return;
7908
7909 case 2: /* mode M: towards -inf. */
7910 if (val < 0.0)
7911 aarch64_set_FP_float (cpu, rd, truncf (val));
7912 else
7913 aarch64_set_FP_float (cpu, rd, roundf (val));
7914 return;
7915
7916 case 3: /* mode Z: towards 0. */
7917 aarch64_set_FP_float (cpu, rd, truncf (val));
7918 return;
7919
7920 case 4: /* mode A: away from 0. */
7921 aarch64_set_FP_float (cpu, rd, roundf (val));
7922 return;
7923
7924 case 6: /* mode X: use FPCR with exactness check. */
7925 case 7: /* mode I: use FPCR mode. */
7926 HALT_NYI;
7927
7928 default:
7929 HALT_UNALLOC;
7930 }
7931}
7932
5ab6d79e
NC
7933/* Convert half to float. */
7934static void
ef0d8ffc 7935do_FCVT_half_to_single (sim_cpu *cpu)
5ab6d79e
NC
7936{
7937 unsigned rn = INSTR (9, 5);
7938 unsigned rd = INSTR (4, 0);
7939
7940 NYI_assert (31, 10, 0x7B890);
7941
2cdad34c 7942 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7943 aarch64_set_FP_float (cpu, rd, (float) aarch64_get_FP_half (cpu, rn));
7944}
7945
7517e550 7946/* Convert half to double. */
5ab6d79e 7947static void
ef0d8ffc 7948do_FCVT_half_to_double (sim_cpu *cpu)
5ab6d79e
NC
7949{
7950 unsigned rn = INSTR (9, 5);
7951 unsigned rd = INSTR (4, 0);
7952
7953 NYI_assert (31, 10, 0x7B8B0);
ef0d8ffc 7954
2cdad34c 7955 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7956 aarch64_set_FP_double (cpu, rd, (double) aarch64_get_FP_half (cpu, rn));
7957}
7958
7959static void
ef0d8ffc 7960do_FCVT_single_to_half (sim_cpu *cpu)
5ab6d79e
NC
7961{
7962 unsigned rn = INSTR (9, 5);
7963 unsigned rd = INSTR (4, 0);
7964
7965 NYI_assert (31, 10, 0x788F0);
7966
2cdad34c 7967 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7968 aarch64_set_FP_half (cpu, rd, aarch64_get_FP_float (cpu, rn));
7969}
7970
7517e550 7971/* Convert double to half. */
5ab6d79e 7972static void
ef0d8ffc 7973do_FCVT_double_to_half (sim_cpu *cpu)
5ab6d79e
NC
7974{
7975 unsigned rn = INSTR (9, 5);
7976 unsigned rd = INSTR (4, 0);
7977
7978 NYI_assert (31, 10, 0x798F0);
ef0d8ffc 7979
2cdad34c 7980 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7981 aarch64_set_FP_half (cpu, rd, (float) aarch64_get_FP_double (cpu, rn));
7982}
7983
2e8cf49e
NC
7984static void
7985dexSimpleFPDataProc1Source (sim_cpu *cpu)
7986{
7987 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7988 instr[30] = 0
7989 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7990 instr[28,25] = 1111
7991 instr[24] = 0
7992 instr[23,22] ==> type : 00 ==> source is single,
7993 01 ==> source is double
7994 10 ==> UNALLOC
7995 11 ==> UNALLOC or source is half
7996 instr[21] = 1
7997 instr[20,15] ==> opcode : with type 00 or 01
7998 000000 ==> FMOV, 000001 ==> FABS,
7999 000010 ==> FNEG, 000011 ==> FSQRT,
8000 000100 ==> UNALLOC, 000101 ==> FCVT,(to single/double)
8001 000110 ==> UNALLOC, 000111 ==> FCVT (to half)
8002 001000 ==> FRINTN, 001001 ==> FRINTP,
8003 001010 ==> FRINTM, 001011 ==> FRINTZ,
8004 001100 ==> FRINTA, 001101 ==> UNALLOC
8005 001110 ==> FRINTX, 001111 ==> FRINTI
8006 with type 11
8007 000100 ==> FCVT (half-to-single)
8008 000101 ==> FCVT (half-to-double)
8009 instr[14,10] = 10000. */
8010
7517e550 8011 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
8012 uint32_t type = INSTR (23, 22);
8013 uint32_t opcode = INSTR (20, 15);
2e8cf49e
NC
8014
8015 if (M_S != 0)
8016 HALT_UNALLOC;
8017
8018 if (type == 3)
8019 {
5ab6d79e
NC
8020 if (opcode == 4)
8021 do_FCVT_half_to_single (cpu);
8022 else if (opcode == 5)
8023 do_FCVT_half_to_double (cpu);
2e8cf49e
NC
8024 else
8025 HALT_UNALLOC;
5ab6d79e 8026 return;
2e8cf49e
NC
8027 }
8028
8029 if (type == 2)
8030 HALT_UNALLOC;
8031
8032 switch (opcode)
8033 {
8034 case 0:
8035 if (type)
8036 ffmovd (cpu);
8037 else
8038 ffmovs (cpu);
8039 return;
8040
8041 case 1:
8042 if (type)
8043 fabcpu (cpu);
8044 else
8045 fabss (cpu);
8046 return;
8047
8048 case 2:
8049 if (type)
8050 fnegd (cpu);
8051 else
8052 fnegs (cpu);
8053 return;
8054
8055 case 3:
8056 if (type)
8057 fsqrtd (cpu);
8058 else
8059 fsqrts (cpu);
8060 return;
8061
8062 case 4:
8063 if (type)
8064 fcvtds (cpu);
8065 else
8066 HALT_UNALLOC;
8067 return;
8068
8069 case 5:
8070 if (type)
8071 HALT_UNALLOC;
8072 fcvtcpu (cpu);
8073 return;
8074
8075 case 8: /* FRINTN etc. */
8076 case 9:
8077 case 10:
8078 case 11:
8079 case 12:
8080 case 14:
8081 case 15:
8082 do_FRINT (cpu);
8083 return;
8084
5ab6d79e
NC
8085 case 7:
8086 if (INSTR (22, 22))
8087 do_FCVT_double_to_half (cpu);
8088 else
8089 do_FCVT_single_to_half (cpu);
8090 return;
8091
2e8cf49e
NC
8092 case 13:
8093 HALT_NYI;
8094
8095 default:
8096 HALT_UNALLOC;
8097 }
8098}
8099
8100/* 32 bit signed int to float. */
8101static void
8102scvtf32 (sim_cpu *cpu)
8103{
ef0d8ffc
NC
8104 unsigned rn = INSTR (9, 5);
8105 unsigned sd = INSTR (4, 0);
2e8cf49e 8106
2cdad34c 8107 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8108 aarch64_set_FP_float
8109 (cpu, sd, (float) aarch64_get_reg_s32 (cpu, rn, NO_SP));
8110}
8111
8112/* signed int to float. */
8113static void
8114scvtf (sim_cpu *cpu)
8115{
ef0d8ffc
NC
8116 unsigned rn = INSTR (9, 5);
8117 unsigned sd = INSTR (4, 0);
2e8cf49e 8118
2cdad34c 8119 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8120 aarch64_set_FP_float
8121 (cpu, sd, (float) aarch64_get_reg_s64 (cpu, rn, NO_SP));
8122}
8123
8124/* 32 bit signed int to double. */
8125static void
8126scvtd32 (sim_cpu *cpu)
8127{
ef0d8ffc
NC
8128 unsigned rn = INSTR (9, 5);
8129 unsigned sd = INSTR (4, 0);
2e8cf49e 8130
2cdad34c 8131 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8132 aarch64_set_FP_double
8133 (cpu, sd, (double) aarch64_get_reg_s32 (cpu, rn, NO_SP));
8134}
8135
8136/* signed int to double. */
8137static void
8138scvtd (sim_cpu *cpu)
8139{
ef0d8ffc
NC
8140 unsigned rn = INSTR (9, 5);
8141 unsigned sd = INSTR (4, 0);
2e8cf49e 8142
2cdad34c 8143 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8144 aarch64_set_FP_double
8145 (cpu, sd, (double) aarch64_get_reg_s64 (cpu, rn, NO_SP));
8146}
8147
8148static const float FLOAT_INT_MAX = (float) INT_MAX;
8149static const float FLOAT_INT_MIN = (float) INT_MIN;
8150static const double DOUBLE_INT_MAX = (double) INT_MAX;
8151static const double DOUBLE_INT_MIN = (double) INT_MIN;
8152static const float FLOAT_LONG_MAX = (float) LONG_MAX;
8153static const float FLOAT_LONG_MIN = (float) LONG_MIN;
8154static const double DOUBLE_LONG_MAX = (double) LONG_MAX;
8155static const double DOUBLE_LONG_MIN = (double) LONG_MIN;
8156
c0386d4d
JW
8157#define UINT_MIN 0
8158#define ULONG_MIN 0
8159static const float FLOAT_UINT_MAX = (float) UINT_MAX;
8160static const float FLOAT_UINT_MIN = (float) UINT_MIN;
8161static const double DOUBLE_UINT_MAX = (double) UINT_MAX;
8162static const double DOUBLE_UINT_MIN = (double) UINT_MIN;
8163static const float FLOAT_ULONG_MAX = (float) ULONG_MAX;
8164static const float FLOAT_ULONG_MIN = (float) ULONG_MIN;
8165static const double DOUBLE_ULONG_MAX = (double) ULONG_MAX;
8166static const double DOUBLE_ULONG_MIN = (double) ULONG_MIN;
8167
2e8cf49e
NC
8168/* Check for FP exception conditions:
8169 NaN raises IO
8170 Infinity raises IO
8171 Out of Range raises IO and IX and saturates value
8172 Denormal raises ID and IX and sets to zero. */
8173#define RAISE_EXCEPTIONS(F, VALUE, FTYPE, ITYPE) \
8174 do \
8175 { \
8176 switch (fpclassify (F)) \
8177 { \
8178 case FP_INFINITE: \
8179 case FP_NAN: \
8180 aarch64_set_FPSR (cpu, IO); \
8181 if (signbit (F)) \
8182 VALUE = ITYPE##_MAX; \
8183 else \
8184 VALUE = ITYPE##_MIN; \
8185 break; \
8186 \
8187 case FP_NORMAL: \
8188 if (F >= FTYPE##_##ITYPE##_MAX) \
8189 { \
8190 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
8191 VALUE = ITYPE##_MAX; \
8192 } \
8193 else if (F <= FTYPE##_##ITYPE##_MIN) \
8194 { \
8195 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
8196 VALUE = ITYPE##_MIN; \
8197 } \
8198 break; \
8199 \
8200 case FP_SUBNORMAL: \
8201 aarch64_set_FPSR_bits (cpu, IO | IX | ID, IX | ID); \
8202 VALUE = 0; \
8203 break; \
8204 \
8205 default: \
8206 case FP_ZERO: \
8207 VALUE = 0; \
8208 break; \
8209 } \
8210 } \
8211 while (0)
8212
8213/* 32 bit convert float to signed int truncate towards zero. */
8214static void
8215fcvtszs32 (sim_cpu *cpu)
8216{
ef0d8ffc
NC
8217 unsigned sn = INSTR (9, 5);
8218 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8219 /* TODO : check that this rounds toward zero. */
8220 float f = aarch64_get_FP_float (cpu, sn);
8221 int32_t value = (int32_t) f;
8222
8223 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
8224
2cdad34c 8225 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8226 /* Avoid sign extension to 64 bit. */
8227 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8228}
8229
8230/* 64 bit convert float to signed int truncate towards zero. */
8231static void
8232fcvtszs (sim_cpu *cpu)
8233{
ef0d8ffc
NC
8234 unsigned sn = INSTR (9, 5);
8235 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8236 float f = aarch64_get_FP_float (cpu, sn);
8237 int64_t value = (int64_t) f;
8238
8239 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
8240
2cdad34c 8241 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8242 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8243}
8244
8245/* 32 bit convert double to signed int truncate towards zero. */
8246static void
8247fcvtszd32 (sim_cpu *cpu)
8248{
ef0d8ffc
NC
8249 unsigned sn = INSTR (9, 5);
8250 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8251 /* TODO : check that this rounds toward zero. */
8252 double d = aarch64_get_FP_double (cpu, sn);
8253 int32_t value = (int32_t) d;
8254
8255 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
8256
2cdad34c 8257 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8258 /* Avoid sign extension to 64 bit. */
8259 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8260}
8261
8262/* 64 bit convert double to signed int truncate towards zero. */
8263static void
8264fcvtszd (sim_cpu *cpu)
8265{
ef0d8ffc
NC
8266 unsigned sn = INSTR (9, 5);
8267 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8268 /* TODO : check that this rounds toward zero. */
8269 double d = aarch64_get_FP_double (cpu, sn);
8270 int64_t value;
8271
8272 value = (int64_t) d;
8273
8274 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
8275
2cdad34c 8276 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8277 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8278}
8279
8280static void
8281do_fcvtzu (sim_cpu *cpu)
8282{
8283 /* instr[31] = size: 32-bit (0), 64-bit (1)
8284 instr[30,23] = 00111100
8285 instr[22] = type: single (0)/ double (1)
8286 instr[21] = enable (0)/disable(1) precision
8287 instr[20,16] = 11001
8288 instr[15,10] = precision
8289 instr[9,5] = Rs
8290 instr[4,0] = Rd. */
8291
ef0d8ffc
NC
8292 unsigned rs = INSTR (9, 5);
8293 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8294
8295 NYI_assert (30, 23, 0x3C);
8296 NYI_assert (20, 16, 0x19);
8297
ef0d8ffc 8298 if (INSTR (21, 21) != 1)
2e8cf49e
NC
8299 /* Convert to fixed point. */
8300 HALT_NYI;
8301
2cdad34c 8302 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8303 if (INSTR (31, 31))
2e8cf49e
NC
8304 {
8305 /* Convert to unsigned 64-bit integer. */
ef0d8ffc 8306 if (INSTR (22, 22))
2e8cf49e
NC
8307 {
8308 double d = aarch64_get_FP_double (cpu, rs);
8309 uint64_t value = (uint64_t) d;
8310
8311 /* Do not raise an exception if we have reached ULONG_MAX. */
8312 if (value != (1UL << 63))
c0386d4d 8313 RAISE_EXCEPTIONS (d, value, DOUBLE, ULONG);
2e8cf49e
NC
8314
8315 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8316 }
8317 else
8318 {
8319 float f = aarch64_get_FP_float (cpu, rs);
8320 uint64_t value = (uint64_t) f;
8321
8322 /* Do not raise an exception if we have reached ULONG_MAX. */
8323 if (value != (1UL << 63))
c0386d4d 8324 RAISE_EXCEPTIONS (f, value, FLOAT, ULONG);
2e8cf49e
NC
8325
8326 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8327 }
8328 }
8329 else
8330 {
8331 uint32_t value;
8332
8333 /* Convert to unsigned 32-bit integer. */
ef0d8ffc 8334 if (INSTR (22, 22))
2e8cf49e
NC
8335 {
8336 double d = aarch64_get_FP_double (cpu, rs);
8337
8338 value = (uint32_t) d;
8339 /* Do not raise an exception if we have reached UINT_MAX. */
8340 if (value != (1UL << 31))
c0386d4d 8341 RAISE_EXCEPTIONS (d, value, DOUBLE, UINT);
2e8cf49e
NC
8342 }
8343 else
8344 {
8345 float f = aarch64_get_FP_float (cpu, rs);
8346
8347 value = (uint32_t) f;
8348 /* Do not raise an exception if we have reached UINT_MAX. */
8349 if (value != (1UL << 31))
c0386d4d 8350 RAISE_EXCEPTIONS (f, value, FLOAT, UINT);
2e8cf49e
NC
8351 }
8352
8353 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8354 }
8355}
8356
8357static void
8358do_UCVTF (sim_cpu *cpu)
8359{
8360 /* instr[31] = size: 32-bit (0), 64-bit (1)
8361 instr[30,23] = 001 1110 0
8362 instr[22] = type: single (0)/ double (1)
8363 instr[21] = enable (0)/disable(1) precision
8364 instr[20,16] = 0 0011
8365 instr[15,10] = precision
8366 instr[9,5] = Rs
8367 instr[4,0] = Rd. */
8368
ef0d8ffc
NC
8369 unsigned rs = INSTR (9, 5);
8370 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8371
8372 NYI_assert (30, 23, 0x3C);
8373 NYI_assert (20, 16, 0x03);
8374
ef0d8ffc 8375 if (INSTR (21, 21) != 1)
2e8cf49e
NC
8376 HALT_NYI;
8377
8378 /* FIXME: Add exception raising. */
2cdad34c 8379 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8380 if (INSTR (31, 31))
2e8cf49e
NC
8381 {
8382 uint64_t value = aarch64_get_reg_u64 (cpu, rs, NO_SP);
8383
ef0d8ffc 8384 if (INSTR (22, 22))
2e8cf49e
NC
8385 aarch64_set_FP_double (cpu, rd, (double) value);
8386 else
8387 aarch64_set_FP_float (cpu, rd, (float) value);
8388 }
8389 else
8390 {
8391 uint32_t value = aarch64_get_reg_u32 (cpu, rs, NO_SP);
8392
ef0d8ffc 8393 if (INSTR (22, 22))
2e8cf49e
NC
8394 aarch64_set_FP_double (cpu, rd, (double) value);
8395 else
8396 aarch64_set_FP_float (cpu, rd, (float) value);
8397 }
8398}
8399
8400static void
8401float_vector_move (sim_cpu *cpu)
8402{
8403 /* instr[31,17] == 100 1111 0101 0111
8404 instr[16] ==> direction 0=> to GR, 1=> from GR
8405 instr[15,10] => ???
8406 instr[9,5] ==> source
8407 instr[4,0] ==> dest. */
8408
ef0d8ffc
NC
8409 unsigned rn = INSTR (9, 5);
8410 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8411
8412 NYI_assert (31, 17, 0x4F57);
8413
ef0d8ffc 8414 if (INSTR (15, 10) != 0)
2e8cf49e
NC
8415 HALT_UNALLOC;
8416
2cdad34c 8417 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8418 if (INSTR (16, 16))
2e8cf49e
NC
8419 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_reg_u64 (cpu, rn, NO_SP));
8420 else
8421 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, rn, 1));
8422}
8423
8424static void
8425dexSimpleFPIntegerConvert (sim_cpu *cpu)
8426{
8427 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8428 instr[30 = 0
8429 instr[29] = S : 0 ==> OK, 1 ==> UNALLOC
8430 instr[28,25] = 1111
8431 instr[24] = 0
8432 instr[23,22] = type : 00 ==> single, 01 ==> double, 1x ==> UNALLOC
8433 instr[21] = 1
8434 instr[20,19] = rmode
8435 instr[18,16] = opcode
8436 instr[15,10] = 10 0000 */
8437
8438 uint32_t rmode_opcode;
8439 uint32_t size_type;
8440 uint32_t type;
8441 uint32_t size;
8442 uint32_t S;
8443
ef0d8ffc 8444 if (INSTR (31, 17) == 0x4F57)
2e8cf49e
NC
8445 {
8446 float_vector_move (cpu);
8447 return;
8448 }
8449
ef0d8ffc
NC
8450 size = INSTR (31, 31);
8451 S = INSTR (29, 29);
2e8cf49e
NC
8452 if (S != 0)
8453 HALT_UNALLOC;
8454
ef0d8ffc 8455 type = INSTR (23, 22);
2e8cf49e
NC
8456 if (type > 1)
8457 HALT_UNALLOC;
8458
ef0d8ffc 8459 rmode_opcode = INSTR (20, 16);
2e8cf49e
NC
8460 size_type = (size << 1) | type; /* 0==32f, 1==32d, 2==64f, 3==64d. */
8461
8462 switch (rmode_opcode)
8463 {
8464 case 2: /* SCVTF. */
8465 switch (size_type)
8466 {
8467 case 0: scvtf32 (cpu); return;
8468 case 1: scvtd32 (cpu); return;
8469 case 2: scvtf (cpu); return;
8470 case 3: scvtd (cpu); return;
2e8cf49e
NC
8471 }
8472
8473 case 6: /* FMOV GR, Vec. */
8474 switch (size_type)
8475 {
8476 case 0: gfmovs (cpu); return;
8477 case 3: gfmovd (cpu); return;
8478 default: HALT_UNALLOC;
8479 }
8480
8481 case 7: /* FMOV vec, GR. */
8482 switch (size_type)
8483 {
8484 case 0: fgmovs (cpu); return;
8485 case 3: fgmovd (cpu); return;
8486 default: HALT_UNALLOC;
8487 }
8488
8489 case 24: /* FCVTZS. */
8490 switch (size_type)
8491 {
8492 case 0: fcvtszs32 (cpu); return;
8493 case 1: fcvtszd32 (cpu); return;
8494 case 2: fcvtszs (cpu); return;
8495 case 3: fcvtszd (cpu); return;
2e8cf49e
NC
8496 }
8497
8498 case 25: do_fcvtzu (cpu); return;
8499 case 3: do_UCVTF (cpu); return;
8500
8501 case 0: /* FCVTNS. */
8502 case 1: /* FCVTNU. */
8503 case 4: /* FCVTAS. */
8504 case 5: /* FCVTAU. */
8505 case 8: /* FCVPTS. */
8506 case 9: /* FCVTPU. */
8507 case 16: /* FCVTMS. */
8508 case 17: /* FCVTMU. */
8509 default:
8510 HALT_NYI;
8511 }
8512}
8513
8514static void
8515set_flags_for_float_compare (sim_cpu *cpu, float fvalue1, float fvalue2)
8516{
8517 uint32_t flags;
8518
87903eaf 8519 /* FIXME: Add exception raising. */
2e8cf49e
NC
8520 if (isnan (fvalue1) || isnan (fvalue2))
8521 flags = C|V;
87903eaf
JW
8522 else if (isinf (fvalue1) && isinf (fvalue2))
8523 {
8524 /* Subtracting two infinities may give a NaN. We only need to compare
8525 the signs, which we can get from isinf. */
8526 int result = isinf (fvalue1) - isinf (fvalue2);
8527
8528 if (result == 0)
8529 flags = Z|C;
8530 else if (result < 0)
8531 flags = N;
8532 else /* (result > 0). */
8533 flags = C;
8534 }
2e8cf49e
NC
8535 else
8536 {
8537 float result = fvalue1 - fvalue2;
8538
8539 if (result == 0.0)
8540 flags = Z|C;
8541 else if (result < 0)
8542 flags = N;
8543 else /* (result > 0). */
8544 flags = C;
8545 }
8546
8547 aarch64_set_CPSR (cpu, flags);
8548}
8549
8550static void
8551fcmps (sim_cpu *cpu)
8552{
ef0d8ffc
NC
8553 unsigned sm = INSTR (20, 16);
8554 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8555
8556 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8557 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8558
2cdad34c 8559 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8560 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8561}
8562
8563/* Float compare to zero -- Invalid Operation exception
8564 only on signaling NaNs. */
8565static void
8566fcmpzs (sim_cpu *cpu)
8567{
ef0d8ffc 8568 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8569 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8570
2cdad34c 8571 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8572 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8573}
8574
8575/* Float compare -- Invalid Operation exception on all NaNs. */
8576static void
8577fcmpes (sim_cpu *cpu)
8578{
ef0d8ffc
NC
8579 unsigned sm = INSTR (20, 16);
8580 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8581
8582 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8583 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8584
2cdad34c 8585 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8586 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8587}
8588
8589/* Float compare to zero -- Invalid Operation exception on all NaNs. */
8590static void
8591fcmpzes (sim_cpu *cpu)
8592{
ef0d8ffc 8593 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8594 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8595
2cdad34c 8596 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8597 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8598}
8599
8600static void
8601set_flags_for_double_compare (sim_cpu *cpu, double dval1, double dval2)
8602{
8603 uint32_t flags;
8604
87903eaf 8605 /* FIXME: Add exception raising. */
2e8cf49e
NC
8606 if (isnan (dval1) || isnan (dval2))
8607 flags = C|V;
87903eaf
JW
8608 else if (isinf (dval1) && isinf (dval2))
8609 {
8610 /* Subtracting two infinities may give a NaN. We only need to compare
8611 the signs, which we can get from isinf. */
8612 int result = isinf (dval1) - isinf (dval2);
8613
8614 if (result == 0)
8615 flags = Z|C;
8616 else if (result < 0)
8617 flags = N;
8618 else /* (result > 0). */
8619 flags = C;
8620 }
2e8cf49e
NC
8621 else
8622 {
8623 double result = dval1 - dval2;
8624
8625 if (result == 0.0)
8626 flags = Z|C;
8627 else if (result < 0)
8628 flags = N;
8629 else /* (result > 0). */
8630 flags = C;
8631 }
8632
8633 aarch64_set_CPSR (cpu, flags);
8634}
8635
8636/* Double compare -- Invalid Operation exception only on signaling NaNs. */
8637static void
8638fcmpd (sim_cpu *cpu)
8639{
ef0d8ffc
NC
8640 unsigned sm = INSTR (20, 16);
8641 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8642
8643 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8644 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8645
2cdad34c 8646 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8647 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8648}
8649
8650/* Double compare to zero -- Invalid Operation exception
8651 only on signaling NaNs. */
8652static void
8653fcmpzd (sim_cpu *cpu)
8654{
ef0d8ffc 8655 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8656 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8657
2cdad34c 8658 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8659 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8660}
8661
8662/* Double compare -- Invalid Operation exception on all NaNs. */
8663static void
8664fcmped (sim_cpu *cpu)
8665{
ef0d8ffc
NC
8666 unsigned sm = INSTR (20, 16);
8667 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8668
8669 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8670 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8671
2cdad34c 8672 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8673 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8674}
8675
8676/* Double compare to zero -- Invalid Operation exception on all NaNs. */
8677static void
8678fcmpzed (sim_cpu *cpu)
8679{
ef0d8ffc 8680 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8681 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8682
2cdad34c 8683 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8684 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8685}
8686
8687static void
8688dexSimpleFPCompare (sim_cpu *cpu)
8689{
8690 /* assert instr[28,25] == 1111
8691 instr[30:24:21:13,10] = 0011000
8692 instr[31] = M : 0 ==> OK, 1 ==> UNALLOC
8693 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
8694 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
8695 instr[15,14] ==> op : 00 ==> OK, ow ==> UNALLOC
8696 instr[4,0] ==> opcode2 : 00000 ==> FCMP, 10000 ==> FCMPE,
8697 01000 ==> FCMPZ, 11000 ==> FCMPEZ,
8698 ow ==> UNALLOC */
8699 uint32_t dispatch;
7517e550 8700 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
8701 uint32_t type = INSTR (23, 22);
8702 uint32_t op = INSTR (15, 14);
8703 uint32_t op2_2_0 = INSTR (2, 0);
2e8cf49e
NC
8704
8705 if (op2_2_0 != 0)
8706 HALT_UNALLOC;
8707
8708 if (M_S != 0)
8709 HALT_UNALLOC;
8710
8711 if (type > 1)
8712 HALT_UNALLOC;
8713
8714 if (op != 0)
8715 HALT_UNALLOC;
8716
8717 /* dispatch on type and top 2 bits of opcode. */
ef0d8ffc 8718 dispatch = (type << 2) | INSTR (4, 3);
2e8cf49e
NC
8719
8720 switch (dispatch)
8721 {
8722 case 0: fcmps (cpu); return;
8723 case 1: fcmpzs (cpu); return;
8724 case 2: fcmpes (cpu); return;
8725 case 3: fcmpzes (cpu); return;
8726 case 4: fcmpd (cpu); return;
8727 case 5: fcmpzd (cpu); return;
8728 case 6: fcmped (cpu); return;
8729 case 7: fcmpzed (cpu); return;
2e8cf49e
NC
8730 }
8731}
8732
8733static void
8734do_scalar_FADDP (sim_cpu *cpu)
8735{
7517e550 8736 /* instr [31,23] = 0111 1110 0
2e8cf49e 8737 instr [22] = single(0)/double(1)
7517e550 8738 instr [21,10] = 11 0000 1101 10
2e8cf49e
NC
8739 instr [9,5] = Fn
8740 instr [4,0] = Fd. */
8741
ef0d8ffc
NC
8742 unsigned Fn = INSTR (9, 5);
8743 unsigned Fd = INSTR (4, 0);
2e8cf49e
NC
8744
8745 NYI_assert (31, 23, 0x0FC);
8746 NYI_assert (21, 10, 0xC36);
8747
2cdad34c 8748 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8749 if (INSTR (22, 22))
2e8cf49e
NC
8750 {
8751 double val1 = aarch64_get_vec_double (cpu, Fn, 0);
8752 double val2 = aarch64_get_vec_double (cpu, Fn, 1);
8753
8754 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8755 }
8756 else
8757 {
8758 float val1 = aarch64_get_vec_float (cpu, Fn, 0);
8759 float val2 = aarch64_get_vec_float (cpu, Fn, 1);
8760
8761 aarch64_set_FP_float (cpu, Fd, val1 + val2);
8762 }
8763}
8764
8765/* Floating point absolute difference. */
8766
8767static void
8768do_scalar_FABD (sim_cpu *cpu)
8769{
8770 /* instr [31,23] = 0111 1110 1
8771 instr [22] = float(0)/double(1)
8772 instr [21] = 1
8773 instr [20,16] = Rm
8774 instr [15,10] = 1101 01
8775 instr [9, 5] = Rn
8776 instr [4, 0] = Rd. */
8777
ef0d8ffc
NC
8778 unsigned rm = INSTR (20, 16);
8779 unsigned rn = INSTR (9, 5);
8780 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8781
8782 NYI_assert (31, 23, 0x0FD);
8783 NYI_assert (21, 21, 1);
8784 NYI_assert (15, 10, 0x35);
8785
2cdad34c 8786 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8787 if (INSTR (22, 22))
2e8cf49e
NC
8788 aarch64_set_FP_double (cpu, rd,
8789 fabs (aarch64_get_FP_double (cpu, rn)
8790 - aarch64_get_FP_double (cpu, rm)));
8791 else
8792 aarch64_set_FP_float (cpu, rd,
8793 fabsf (aarch64_get_FP_float (cpu, rn)
8794 - aarch64_get_FP_float (cpu, rm)));
8795}
8796
8797static void
8798do_scalar_CMGT (sim_cpu *cpu)
8799{
8800 /* instr [31,21] = 0101 1110 111
8801 instr [20,16] = Rm
8802 instr [15,10] = 00 1101
8803 instr [9, 5] = Rn
8804 instr [4, 0] = Rd. */
8805
ef0d8ffc
NC
8806 unsigned rm = INSTR (20, 16);
8807 unsigned rn = INSTR (9, 5);
8808 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8809
8810 NYI_assert (31, 21, 0x2F7);
8811 NYI_assert (15, 10, 0x0D);
8812
2cdad34c 8813 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8814 aarch64_set_vec_u64 (cpu, rd, 0,
8815 aarch64_get_vec_u64 (cpu, rn, 0) >
8816 aarch64_get_vec_u64 (cpu, rm, 0) ? -1L : 0L);
8817}
8818
8819static void
8820do_scalar_USHR (sim_cpu *cpu)
8821{
8822 /* instr [31,23] = 0111 1111 0
8823 instr [22,16] = shift amount
8824 instr [15,10] = 0000 01
8825 instr [9, 5] = Rn
8826 instr [4, 0] = Rd. */
8827
5ab6d79e
NC
8828 unsigned amount = 128 - INSTR (22, 16);
8829 unsigned rn = INSTR (9, 5);
8830 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8831
8832 NYI_assert (31, 23, 0x0FE);
8833 NYI_assert (15, 10, 0x01);
8834
2cdad34c 8835 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8836 aarch64_set_vec_u64 (cpu, rd, 0,
8837 aarch64_get_vec_u64 (cpu, rn, 0) >> amount);
8838}
8839
8840static void
5ab6d79e
NC
8841do_scalar_SSHL (sim_cpu *cpu)
8842{
8843 /* instr [31,21] = 0101 1110 111
8844 instr [20,16] = Rm
8845 instr [15,10] = 0100 01
8846 instr [9, 5] = Rn
8847 instr [4, 0] = Rd. */
8848
8849 unsigned rm = INSTR (20, 16);
8850 unsigned rn = INSTR (9, 5);
8851 unsigned rd = INSTR (4, 0);
8852 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
8853
8854 NYI_assert (31, 21, 0x2F7);
8855 NYI_assert (15, 10, 0x11);
8856
2cdad34c 8857 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8858 if (shift >= 0)
8859 aarch64_set_vec_s64 (cpu, rd, 0,
8860 aarch64_get_vec_s64 (cpu, rn, 0) << shift);
8861 else
8862 aarch64_set_vec_s64 (cpu, rd, 0,
ef0d8ffc 8863 aarch64_get_vec_s64 (cpu, rn, 0) >> - shift);
5ab6d79e
NC
8864}
8865
8866static void
8867do_scalar_shift (sim_cpu *cpu)
2e8cf49e 8868{
5ab6d79e 8869 /* instr [31,23] = 0101 1111 0
2e8cf49e 8870 instr [22,16] = shift amount
5ab6d79e
NC
8871 instr [15,10] = 0101 01 [SHL]
8872 instr [15,10] = 0000 01 [SSHR]
2e8cf49e
NC
8873 instr [9, 5] = Rn
8874 instr [4, 0] = Rd. */
8875
5ab6d79e
NC
8876 unsigned rn = INSTR (9, 5);
8877 unsigned rd = INSTR (4, 0);
8878 unsigned amount;
2e8cf49e
NC
8879
8880 NYI_assert (31, 23, 0x0BE);
2e8cf49e 8881
5ab6d79e 8882 if (INSTR (22, 22) == 0)
2e8cf49e
NC
8883 HALT_UNALLOC;
8884
2cdad34c 8885 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8886 switch (INSTR (15, 10))
8887 {
8888 case 0x01: /* SSHR */
8889 amount = 128 - INSTR (22, 16);
8890 aarch64_set_vec_s64 (cpu, rd, 0,
8891 aarch64_get_vec_s64 (cpu, rn, 0) >> amount);
8892 return;
8893 case 0x15: /* SHL */
8894 amount = INSTR (22, 16) - 64;
8895 aarch64_set_vec_u64 (cpu, rd, 0,
8896 aarch64_get_vec_u64 (cpu, rn, 0) << amount);
8897 return;
8898 default:
8899 HALT_NYI;
8900 }
2e8cf49e
NC
8901}
8902
8903/* FCMEQ FCMGT FCMGE. */
8904static void
8905do_scalar_FCM (sim_cpu *cpu)
8906{
8907 /* instr [31,30] = 01
8908 instr [29] = U
8909 instr [28,24] = 1 1110
8910 instr [23] = E
8911 instr [22] = size
8912 instr [21] = 1
8913 instr [20,16] = Rm
8914 instr [15,12] = 1110
8915 instr [11] = AC
8916 instr [10] = 1
8917 instr [9, 5] = Rn
8918 instr [4, 0] = Rd. */
8919
ef0d8ffc
NC
8920 unsigned rm = INSTR (20, 16);
8921 unsigned rn = INSTR (9, 5);
8922 unsigned rd = INSTR (4, 0);
7517e550 8923 unsigned EUac = (INSTR (23, 23) << 2) | (INSTR (29, 29) << 1) | INSTR (11, 11);
2e8cf49e
NC
8924 unsigned result;
8925 float val1;
8926 float val2;
8927
8928 NYI_assert (31, 30, 1);
8929 NYI_assert (28, 24, 0x1E);
8930 NYI_assert (21, 21, 1);
8931 NYI_assert (15, 12, 0xE);
8932 NYI_assert (10, 10, 1);
8933
2cdad34c 8934 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8935 if (INSTR (22, 22))
2e8cf49e
NC
8936 {
8937 double val1 = aarch64_get_FP_double (cpu, rn);
8938 double val2 = aarch64_get_FP_double (cpu, rm);
8939
8940 switch (EUac)
8941 {
8942 case 0: /* 000 */
8943 result = val1 == val2;
8944 break;
8945
8946 case 3: /* 011 */
8947 val1 = fabs (val1);
8948 val2 = fabs (val2);
8949 /* Fall through. */
8950 case 2: /* 010 */
8951 result = val1 >= val2;
8952 break;
8953
8954 case 7: /* 111 */
8955 val1 = fabs (val1);
8956 val2 = fabs (val2);
8957 /* Fall through. */
8958 case 6: /* 110 */
8959 result = val1 > val2;
8960 break;
8961
8962 default:
8963 HALT_UNALLOC;
8964 }
8965
8966 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8967 return;
8968 }
8969
8970 val1 = aarch64_get_FP_float (cpu, rn);
8971 val2 = aarch64_get_FP_float (cpu, rm);
8972
8973 switch (EUac)
8974 {
8975 case 0: /* 000 */
8976 result = val1 == val2;
8977 break;
8978
8979 case 3: /* 011 */
8980 val1 = fabsf (val1);
8981 val2 = fabsf (val2);
8982 /* Fall through. */
8983 case 2: /* 010 */
8984 result = val1 >= val2;
8985 break;
8986
8987 case 7: /* 111 */
8988 val1 = fabsf (val1);
8989 val2 = fabsf (val2);
8990 /* Fall through. */
8991 case 6: /* 110 */
8992 result = val1 > val2;
8993 break;
8994
8995 default:
8996 HALT_UNALLOC;
8997 }
8998
8999 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
9000}
9001
9002/* An alias of DUP. */
9003static void
9004do_scalar_MOV (sim_cpu *cpu)
9005{
9006 /* instr [31,21] = 0101 1110 000
9007 instr [20,16] = imm5
9008 instr [15,10] = 0000 01
9009 instr [9, 5] = Rn
9010 instr [4, 0] = Rd. */
9011
ef0d8ffc
NC
9012 unsigned rn = INSTR (9, 5);
9013 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9014 unsigned index;
9015
9016 NYI_assert (31, 21, 0x2F0);
9017 NYI_assert (15, 10, 0x01);
9018
2cdad34c 9019 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9020 if (INSTR (16, 16))
2e8cf49e
NC
9021 {
9022 /* 8-bit. */
ef0d8ffc 9023 index = INSTR (20, 17);
2e8cf49e
NC
9024 aarch64_set_vec_u8
9025 (cpu, rd, 0, aarch64_get_vec_u8 (cpu, rn, index));
9026 }
ef0d8ffc 9027 else if (INSTR (17, 17))
2e8cf49e
NC
9028 {
9029 /* 16-bit. */
ef0d8ffc 9030 index = INSTR (20, 18);
2e8cf49e
NC
9031 aarch64_set_vec_u16
9032 (cpu, rd, 0, aarch64_get_vec_u16 (cpu, rn, index));
9033 }
ef0d8ffc 9034 else if (INSTR (18, 18))
2e8cf49e
NC
9035 {
9036 /* 32-bit. */
ef0d8ffc 9037 index = INSTR (20, 19);
2e8cf49e
NC
9038 aarch64_set_vec_u32
9039 (cpu, rd, 0, aarch64_get_vec_u32 (cpu, rn, index));
9040 }
ef0d8ffc 9041 else if (INSTR (19, 19))
2e8cf49e
NC
9042 {
9043 /* 64-bit. */
ef0d8ffc 9044 index = INSTR (20, 20);
2e8cf49e
NC
9045 aarch64_set_vec_u64
9046 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, index));
9047 }
9048 else
9049 HALT_UNALLOC;
9050}
9051
e101a78b
NC
9052static void
9053do_scalar_NEG (sim_cpu *cpu)
9054{
5ab6d79e 9055 /* instr [31,10] = 0111 1110 1110 0000 1011 10
e101a78b
NC
9056 instr [9, 5] = Rn
9057 instr [4, 0] = Rd. */
9058
ef0d8ffc
NC
9059 unsigned rn = INSTR (9, 5);
9060 unsigned rd = INSTR (4, 0);
e101a78b 9061
5ab6d79e 9062 NYI_assert (31, 10, 0x1FB82E);
e101a78b 9063
2cdad34c 9064 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
9065 aarch64_set_vec_u64 (cpu, rd, 0, - aarch64_get_vec_u64 (cpu, rn, 0));
9066}
9067
5ab6d79e
NC
9068static void
9069do_scalar_USHL (sim_cpu *cpu)
9070{
9071 /* instr [31,21] = 0111 1110 111
9072 instr [20,16] = Rm
9073 instr [15,10] = 0100 01
9074 instr [9, 5] = Rn
9075 instr [4, 0] = Rd. */
9076
9077 unsigned rm = INSTR (20, 16);
9078 unsigned rn = INSTR (9, 5);
9079 unsigned rd = INSTR (4, 0);
9080 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
9081
9082 NYI_assert (31, 21, 0x3F7);
9083 NYI_assert (15, 10, 0x11);
9084
2cdad34c 9085 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
9086 if (shift >= 0)
9087 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) << shift);
9088 else
9089 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) >> - shift);
9090}
9091
2e8cf49e
NC
9092static void
9093do_double_add (sim_cpu *cpu)
9094{
5ab6d79e
NC
9095 /* instr [31,21] = 0101 1110 111
9096 instr [20,16] = Fn
9097 instr [15,10] = 1000 01
9098 instr [9,5] = Fm
9099 instr [4,0] = Fd. */
2e8cf49e
NC
9100 unsigned Fd;
9101 unsigned Fm;
9102 unsigned Fn;
9103 double val1;
9104 double val2;
9105
5ab6d79e
NC
9106 NYI_assert (31, 21, 0x2F7);
9107 NYI_assert (15, 10, 0x21);
9108
9109 Fd = INSTR (4, 0);
9110 Fm = INSTR (9, 5);
9111 Fn = INSTR (20, 16);
9112
2cdad34c 9113 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
9114 val1 = aarch64_get_FP_double (cpu, Fm);
9115 val2 = aarch64_get_FP_double (cpu, Fn);
9116
9117 aarch64_set_FP_double (cpu, Fd, val1 + val2);
9118}
9119
7517e550
NC
9120static void
9121do_scalar_UCVTF (sim_cpu *cpu)
9122{
9123 /* instr [31,23] = 0111 1110 0
9124 instr [22] = single(0)/double(1)
9125 instr [21,10] = 10 0001 1101 10
9126 instr [9,5] = rn
9127 instr [4,0] = rd. */
9128
9129 unsigned rn = INSTR (9, 5);
9130 unsigned rd = INSTR (4, 0);
9131
9132 NYI_assert (31, 23, 0x0FC);
9133 NYI_assert (21, 10, 0x876);
9134
2cdad34c 9135 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
9136 if (INSTR (22, 22))
9137 {
9138 uint64_t val = aarch64_get_vec_u64 (cpu, rn, 0);
9139
9140 aarch64_set_vec_double (cpu, rd, 0, (double) val);
9141 }
9142 else
9143 {
9144 uint32_t val = aarch64_get_vec_u32 (cpu, rn, 0);
9145
9146 aarch64_set_vec_float (cpu, rd, 0, (float) val);
9147 }
9148}
9149
5ab6d79e
NC
9150static void
9151do_scalar_vec (sim_cpu *cpu)
9152{
9153 /* instr [30] = 1. */
9154 /* instr [28,25] = 1111. */
ef0d8ffc 9155 switch (INSTR (31, 23))
2e8cf49e
NC
9156 {
9157 case 0xBC:
ef0d8ffc 9158 switch (INSTR (15, 10))
2e8cf49e
NC
9159 {
9160 case 0x01: do_scalar_MOV (cpu); return;
9161 case 0x39: do_scalar_FCM (cpu); return;
9162 case 0x3B: do_scalar_FCM (cpu); return;
9163 }
9164 break;
9165
5ab6d79e 9166 case 0xBE: do_scalar_shift (cpu); return;
2e8cf49e
NC
9167
9168 case 0xFC:
ef0d8ffc 9169 switch (INSTR (15, 10))
2e8cf49e 9170 {
7517e550
NC
9171 case 0x36:
9172 switch (INSTR (21, 16))
9173 {
9174 case 0x30: do_scalar_FADDP (cpu); return;
9175 case 0x21: do_scalar_UCVTF (cpu); return;
9176 }
9177 HALT_NYI;
2e8cf49e
NC
9178 case 0x39: do_scalar_FCM (cpu); return;
9179 case 0x3B: do_scalar_FCM (cpu); return;
9180 }
9181 break;
9182
9183 case 0xFD:
ef0d8ffc 9184 switch (INSTR (15, 10))
2e8cf49e
NC
9185 {
9186 case 0x0D: do_scalar_CMGT (cpu); return;
5ab6d79e
NC
9187 case 0x11: do_scalar_USHL (cpu); return;
9188 case 0x2E: do_scalar_NEG (cpu); return;
2e8cf49e
NC
9189 case 0x35: do_scalar_FABD (cpu); return;
9190 case 0x39: do_scalar_FCM (cpu); return;
9191 case 0x3B: do_scalar_FCM (cpu); return;
9192 default:
9193 HALT_NYI;
9194 }
9195
9196 case 0xFE: do_scalar_USHR (cpu); return;
5ab6d79e
NC
9197
9198 case 0xBD:
9199 switch (INSTR (15, 10))
9200 {
9201 case 0x21: do_double_add (cpu); return;
9202 case 0x11: do_scalar_SSHL (cpu); return;
9203 default:
9204 HALT_NYI;
9205 }
ef0d8ffc 9206
2e8cf49e 9207 default:
5ab6d79e 9208 HALT_NYI;
2e8cf49e 9209 }
2e8cf49e
NC
9210}
9211
9212static void
9213dexAdvSIMD1 (sim_cpu *cpu)
9214{
9215 /* instr [28,25] = 1 111. */
9216
5ab6d79e 9217 /* We are currently only interested in the basic
2e8cf49e 9218 scalar fp routines which all have bit 30 = 0. */
ef0d8ffc 9219 if (INSTR (30, 30))
5ab6d79e 9220 do_scalar_vec (cpu);
2e8cf49e
NC
9221
9222 /* instr[24] is set for FP data processing 3-source and clear for
9223 all other basic scalar fp instruction groups. */
ef0d8ffc 9224 else if (INSTR (24, 24))
2e8cf49e
NC
9225 dexSimpleFPDataProc3Source (cpu);
9226
9227 /* instr[21] is clear for floating <-> fixed conversions and set for
9228 all other basic scalar fp instruction groups. */
ef0d8ffc 9229 else if (!INSTR (21, 21))
2e8cf49e
NC
9230 dexSimpleFPFixedConvert (cpu);
9231
9232 /* instr[11,10] : 01 ==> cond compare, 10 ==> Data Proc 2 Source
9233 11 ==> cond select, 00 ==> other. */
9234 else
ef0d8ffc 9235 switch (INSTR (11, 10))
2e8cf49e
NC
9236 {
9237 case 1: dexSimpleFPCondCompare (cpu); return;
9238 case 2: dexSimpleFPDataProc2Source (cpu); return;
9239 case 3: dexSimpleFPCondSelect (cpu); return;
9240
9241 default:
9242 /* Now an ordered cascade of tests.
ef0d8ffc
NC
9243 FP immediate has instr [12] == 1.
9244 FP compare has instr [13] == 1.
9245 FP Data Proc 1 Source has instr [14] == 1.
9246 FP floating <--> integer conversions has instr [15] == 0. */
9247 if (INSTR (12, 12))
2e8cf49e
NC
9248 dexSimpleFPImmediate (cpu);
9249
ef0d8ffc 9250 else if (INSTR (13, 13))
2e8cf49e
NC
9251 dexSimpleFPCompare (cpu);
9252
ef0d8ffc 9253 else if (INSTR (14, 14))
2e8cf49e
NC
9254 dexSimpleFPDataProc1Source (cpu);
9255
ef0d8ffc 9256 else if (!INSTR (15, 15))
2e8cf49e
NC
9257 dexSimpleFPIntegerConvert (cpu);
9258
9259 else
9260 /* If we get here then instr[15] == 1 which means UNALLOC. */
9261 HALT_UNALLOC;
9262 }
9263}
9264
9265/* PC relative addressing. */
9266
9267static void
9268pcadr (sim_cpu *cpu)
9269{
9270 /* instr[31] = op : 0 ==> ADR, 1 ==> ADRP
9271 instr[30,29] = immlo
9272 instr[23,5] = immhi. */
9273 uint64_t address;
ef0d8ffc
NC
9274 unsigned rd = INSTR (4, 0);
9275 uint32_t isPage = INSTR (31, 31);
2e8cf49e
NC
9276 union { int64_t u64; uint64_t s64; } imm;
9277 uint64_t offset;
9278
9279 imm.s64 = simm64 (aarch64_get_instr (cpu), 23, 5);
9280 offset = imm.u64;
ef0d8ffc 9281 offset = (offset << 2) | INSTR (30, 29);
2e8cf49e
NC
9282
9283 address = aarch64_get_PC (cpu);
9284
9285 if (isPage)
9286 {
9287 offset <<= 12;
9288 address &= ~0xfff;
9289 }
9290
2cdad34c 9291 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9292 aarch64_set_reg_u64 (cpu, rd, NO_SP, address + offset);
9293}
9294
9295/* Specific decode and execute for group Data Processing Immediate. */
9296
9297static void
9298dexPCRelAddressing (sim_cpu *cpu)
9299{
9300 /* assert instr[28,24] = 10000. */
9301 pcadr (cpu);
9302}
9303
9304/* Immediate logical.
9305 The bimm32/64 argument is constructed by replicating a 2, 4, 8,
9306 16, 32 or 64 bit sequence pulled out at decode and possibly
9307 inverting it..
9308
9309 N.B. the output register (dest) can normally be Xn or SP
9310 the exception occurs for flag setting instructions which may
9311 only use Xn for the output (dest). The input register can
9312 never be SP. */
9313
9314/* 32 bit and immediate. */
9315static void
9316and32 (sim_cpu *cpu, uint32_t bimm)
9317{
ef0d8ffc
NC
9318 unsigned rn = INSTR (9, 5);
9319 unsigned rd = INSTR (4, 0);
2e8cf49e 9320
2cdad34c 9321 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9322 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9323 aarch64_get_reg_u32 (cpu, rn, NO_SP) & bimm);
9324}
9325
9326/* 64 bit and immediate. */
9327static void
9328and64 (sim_cpu *cpu, uint64_t bimm)
9329{
ef0d8ffc
NC
9330 unsigned rn = INSTR (9, 5);
9331 unsigned rd = INSTR (4, 0);
2e8cf49e 9332
2cdad34c 9333 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9334 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9335 aarch64_get_reg_u64 (cpu, rn, NO_SP) & bimm);
9336}
9337
9338/* 32 bit and immediate set flags. */
9339static void
9340ands32 (sim_cpu *cpu, uint32_t bimm)
9341{
ef0d8ffc
NC
9342 unsigned rn = INSTR (9, 5);
9343 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9344
9345 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9346 uint32_t value2 = bimm;
9347
2cdad34c 9348 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9349 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9350 set_flags_for_binop32 (cpu, value1 & value2);
9351}
9352
9353/* 64 bit and immediate set flags. */
9354static void
9355ands64 (sim_cpu *cpu, uint64_t bimm)
9356{
ef0d8ffc
NC
9357 unsigned rn = INSTR (9, 5);
9358 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9359
9360 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9361 uint64_t value2 = bimm;
9362
2cdad34c 9363 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9364 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9365 set_flags_for_binop64 (cpu, value1 & value2);
9366}
9367
9368/* 32 bit exclusive or immediate. */
9369static void
9370eor32 (sim_cpu *cpu, uint32_t bimm)
9371{
ef0d8ffc
NC
9372 unsigned rn = INSTR (9, 5);
9373 unsigned rd = INSTR (4, 0);
2e8cf49e 9374
2cdad34c 9375 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9376 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9377 aarch64_get_reg_u32 (cpu, rn, NO_SP) ^ bimm);
9378}
9379
9380/* 64 bit exclusive or immediate. */
9381static void
9382eor64 (sim_cpu *cpu, uint64_t bimm)
9383{
ef0d8ffc
NC
9384 unsigned rn = INSTR (9, 5);
9385 unsigned rd = INSTR (4, 0);
2e8cf49e 9386
2cdad34c 9387 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9388 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9389 aarch64_get_reg_u64 (cpu, rn, NO_SP) ^ bimm);
9390}
9391
9392/* 32 bit or immediate. */
9393static void
9394orr32 (sim_cpu *cpu, uint32_t bimm)
9395{
ef0d8ffc
NC
9396 unsigned rn = INSTR (9, 5);
9397 unsigned rd = INSTR (4, 0);
2e8cf49e 9398
2cdad34c 9399 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9400 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9401 aarch64_get_reg_u32 (cpu, rn, NO_SP) | bimm);
9402}
9403
9404/* 64 bit or immediate. */
9405static void
9406orr64 (sim_cpu *cpu, uint64_t bimm)
9407{
ef0d8ffc
NC
9408 unsigned rn = INSTR (9, 5);
9409 unsigned rd = INSTR (4, 0);
2e8cf49e 9410
2cdad34c 9411 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9412 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9413 aarch64_get_reg_u64 (cpu, rn, NO_SP) | bimm);
9414}
9415
9416/* Logical shifted register.
9417 These allow an optional LSL, ASR, LSR or ROR to the second source
9418 register with a count up to the register bit count.
9419 N.B register args may not be SP. */
9420
9421/* 32 bit AND shifted register. */
9422static void
9423and32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9424{
ef0d8ffc
NC
9425 unsigned rm = INSTR (20, 16);
9426 unsigned rn = INSTR (9, 5);
9427 unsigned rd = INSTR (4, 0);
2e8cf49e 9428
2cdad34c 9429 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9430 aarch64_set_reg_u64
9431 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9432 & shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9433}
9434
9435/* 64 bit AND shifted register. */
9436static void
9437and64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9438{
ef0d8ffc
NC
9439 unsigned rm = INSTR (20, 16);
9440 unsigned rn = INSTR (9, 5);
9441 unsigned rd = INSTR (4, 0);
2e8cf49e 9442
2cdad34c 9443 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9444 aarch64_set_reg_u64
9445 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9446 & shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9447}
9448
9449/* 32 bit AND shifted register setting flags. */
9450static void
9451ands32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9452{
ef0d8ffc
NC
9453 unsigned rm = INSTR (20, 16);
9454 unsigned rn = INSTR (9, 5);
9455 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9456
9457 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9458 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9459 shift, count);
9460
2cdad34c 9461 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9462 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9463 set_flags_for_binop32 (cpu, value1 & value2);
9464}
9465
9466/* 64 bit AND shifted register setting flags. */
9467static void
9468ands64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9469{
ef0d8ffc
NC
9470 unsigned rm = INSTR (20, 16);
9471 unsigned rn = INSTR (9, 5);
9472 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9473
9474 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9475 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9476 shift, count);
9477
2cdad34c 9478 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9479 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9480 set_flags_for_binop64 (cpu, value1 & value2);
9481}
9482
9483/* 32 bit BIC shifted register. */
9484static void
9485bic32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9486{
ef0d8ffc
NC
9487 unsigned rm = INSTR (20, 16);
9488 unsigned rn = INSTR (9, 5);
9489 unsigned rd = INSTR (4, 0);
2e8cf49e 9490
2cdad34c 9491 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9492 aarch64_set_reg_u64
9493 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9494 & ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9495}
9496
9497/* 64 bit BIC shifted register. */
9498static void
9499bic64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9500{
ef0d8ffc
NC
9501 unsigned rm = INSTR (20, 16);
9502 unsigned rn = INSTR (9, 5);
9503 unsigned rd = INSTR (4, 0);
2e8cf49e 9504
2cdad34c 9505 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9506 aarch64_set_reg_u64
9507 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9508 & ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9509}
9510
9511/* 32 bit BIC shifted register setting flags. */
9512static void
9513bics32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9514{
ef0d8ffc
NC
9515 unsigned rm = INSTR (20, 16);
9516 unsigned rn = INSTR (9, 5);
9517 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9518
9519 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9520 uint32_t value2 = ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9521 shift, count);
9522
2cdad34c 9523 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9524 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9525 set_flags_for_binop32 (cpu, value1 & value2);
9526}
9527
9528/* 64 bit BIC shifted register setting flags. */
9529static void
9530bics64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9531{
ef0d8ffc
NC
9532 unsigned rm = INSTR (20, 16);
9533 unsigned rn = INSTR (9, 5);
9534 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9535
9536 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9537 uint64_t value2 = ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9538 shift, count);
9539
2cdad34c 9540 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9541 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9542 set_flags_for_binop64 (cpu, value1 & value2);
9543}
9544
9545/* 32 bit EON shifted register. */
9546static void
9547eon32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9548{
ef0d8ffc
NC
9549 unsigned rm = INSTR (20, 16);
9550 unsigned rn = INSTR (9, 5);
9551 unsigned rd = INSTR (4, 0);
2e8cf49e 9552
2cdad34c 9553 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9554 aarch64_set_reg_u64
9555 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9556 ^ ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9557}
9558
9559/* 64 bit EON shifted register. */
9560static void
9561eon64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9562{
ef0d8ffc
NC
9563 unsigned rm = INSTR (20, 16);
9564 unsigned rn = INSTR (9, 5);
9565 unsigned rd = INSTR (4, 0);
2e8cf49e 9566
2cdad34c 9567 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9568 aarch64_set_reg_u64
9569 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9570 ^ ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9571}
9572
9573/* 32 bit EOR shifted register. */
9574static void
9575eor32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9576{
ef0d8ffc
NC
9577 unsigned rm = INSTR (20, 16);
9578 unsigned rn = INSTR (9, 5);
9579 unsigned rd = INSTR (4, 0);
2e8cf49e 9580
2cdad34c 9581 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9582 aarch64_set_reg_u64
9583 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9584 ^ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9585}
9586
9587/* 64 bit EOR shifted register. */
9588static void
9589eor64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9590{
ef0d8ffc
NC
9591 unsigned rm = INSTR (20, 16);
9592 unsigned rn = INSTR (9, 5);
9593 unsigned rd = INSTR (4, 0);
2e8cf49e 9594
2cdad34c 9595 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9596 aarch64_set_reg_u64
9597 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9598 ^ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9599}
9600
9601/* 32 bit ORR shifted register. */
9602static void
9603orr32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9604{
ef0d8ffc
NC
9605 unsigned rm = INSTR (20, 16);
9606 unsigned rn = INSTR (9, 5);
9607 unsigned rd = INSTR (4, 0);
2e8cf49e 9608
2cdad34c 9609 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9610 aarch64_set_reg_u64
9611 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9612 | shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9613}
9614
9615/* 64 bit ORR shifted register. */
9616static void
9617orr64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9618{
ef0d8ffc
NC
9619 unsigned rm = INSTR (20, 16);
9620 unsigned rn = INSTR (9, 5);
9621 unsigned rd = INSTR (4, 0);
2e8cf49e 9622
2cdad34c 9623 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9624 aarch64_set_reg_u64
9625 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9626 | shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9627}
9628
9629/* 32 bit ORN shifted register. */
9630static void
9631orn32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9632{
ef0d8ffc
NC
9633 unsigned rm = INSTR (20, 16);
9634 unsigned rn = INSTR (9, 5);
9635 unsigned rd = INSTR (4, 0);
2e8cf49e 9636
2cdad34c 9637 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9638 aarch64_set_reg_u64
9639 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9640 | ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9641}
9642
9643/* 64 bit ORN shifted register. */
9644static void
9645orn64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9646{
ef0d8ffc
NC
9647 unsigned rm = INSTR (20, 16);
9648 unsigned rn = INSTR (9, 5);
9649 unsigned rd = INSTR (4, 0);
2e8cf49e 9650
2cdad34c 9651 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9652 aarch64_set_reg_u64
9653 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9654 | ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9655}
9656
9657static void
9658dexLogicalImmediate (sim_cpu *cpu)
9659{
9660 /* assert instr[28,23] = 1001000
9661 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9662 instr[30,29] = op : 0 ==> AND, 1 ==> ORR, 2 ==> EOR, 3 ==> ANDS
9663 instr[22] = N : used to construct immediate mask
9664 instr[21,16] = immr
9665 instr[15,10] = imms
9666 instr[9,5] = Rn
9667 instr[4,0] = Rd */
9668
9669 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
ef0d8ffc
NC
9670 uint32_t size = INSTR (31, 31);
9671 uint32_t N = INSTR (22, 22);
9672 /* uint32_t immr = INSTR (21, 16);. */
9673 /* uint32_t imms = INSTR (15, 10);. */
9674 uint32_t index = INSTR (22, 10);
2e8cf49e 9675 uint64_t bimm64 = LITable [index];
ef0d8ffc 9676 uint32_t dispatch = INSTR (30, 29);
2e8cf49e
NC
9677
9678 if (~size & N)
9679 HALT_UNALLOC;
9680
9681 if (!bimm64)
9682 HALT_UNALLOC;
9683
9684 if (size == 0)
9685 {
9686 uint32_t bimm = (uint32_t) bimm64;
9687
9688 switch (dispatch)
9689 {
9690 case 0: and32 (cpu, bimm); return;
9691 case 1: orr32 (cpu, bimm); return;
9692 case 2: eor32 (cpu, bimm); return;
9693 case 3: ands32 (cpu, bimm); return;
9694 }
9695 }
9696 else
9697 {
9698 switch (dispatch)
9699 {
9700 case 0: and64 (cpu, bimm64); return;
9701 case 1: orr64 (cpu, bimm64); return;
9702 case 2: eor64 (cpu, bimm64); return;
9703 case 3: ands64 (cpu, bimm64); return;
9704 }
9705 }
9706 HALT_UNALLOC;
9707}
9708
9709/* Immediate move.
9710 The uimm argument is a 16 bit value to be inserted into the
9711 target register the pos argument locates the 16 bit word in the
9712 dest register i.e. it is in {0, 1} for 32 bit and {0, 1, 2,
9713 3} for 64 bit.
9714 N.B register arg may not be SP so it should be.
9715 accessed using the setGZRegisterXXX accessors. */
9716
9717/* 32 bit move 16 bit immediate zero remaining shorts. */
9718static void
9719movz32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9720{
ef0d8ffc 9721 unsigned rd = INSTR (4, 0);
2e8cf49e 9722
2cdad34c 9723 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9724 aarch64_set_reg_u64 (cpu, rd, NO_SP, val << (pos * 16));
9725}
9726
9727/* 64 bit move 16 bit immediate zero remaining shorts. */
9728static void
9729movz64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9730{
ef0d8ffc 9731 unsigned rd = INSTR (4, 0);
2e8cf49e 9732
2cdad34c 9733 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9734 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((uint64_t) val) << (pos * 16));
9735}
9736
9737/* 32 bit move 16 bit immediate negated. */
9738static void
9739movn32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9740{
ef0d8ffc 9741 unsigned rd = INSTR (4, 0);
2e8cf49e 9742
2cdad34c 9743 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9744 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((val << (pos * 16)) ^ 0xffffffffU));
9745}
9746
9747/* 64 bit move 16 bit immediate negated. */
9748static void
9749movn64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9750{
ef0d8ffc 9751 unsigned rd = INSTR (4, 0);
2e8cf49e 9752
2cdad34c 9753 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9754 aarch64_set_reg_u64
9755 (cpu, rd, NO_SP, ((((uint64_t) val) << (pos * 16))
9756 ^ 0xffffffffffffffffULL));
9757}
9758
9759/* 32 bit move 16 bit immediate keep remaining shorts. */
9760static void
9761movk32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9762{
ef0d8ffc 9763 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9764 uint32_t current = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9765 uint32_t value = val << (pos * 16);
9766 uint32_t mask = ~(0xffffU << (pos * 16));
9767
2cdad34c 9768 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9769 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
9770}
9771
9772/* 64 bit move 16 it immediate keep remaining shorts. */
9773static void
9774movk64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9775{
ef0d8ffc 9776 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9777 uint64_t current = aarch64_get_reg_u64 (cpu, rd, NO_SP);
9778 uint64_t value = (uint64_t) val << (pos * 16);
9779 uint64_t mask = ~(0xffffULL << (pos * 16));
9780
2cdad34c 9781 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9782 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
9783}
9784
9785static void
9786dexMoveWideImmediate (sim_cpu *cpu)
9787{
9788 /* assert instr[28:23] = 100101
9789 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9790 instr[30,29] = op : 0 ==> MOVN, 1 ==> UNALLOC, 2 ==> MOVZ, 3 ==> MOVK
9791 instr[22,21] = shift : 00 == LSL#0, 01 = LSL#16, 10 = LSL#32, 11 = LSL#48
9792 instr[20,5] = uimm16
9793 instr[4,0] = Rd */
9794
9795 /* N.B. the (multiple of 16) shift is applied by the called routine,
9796 we just pass the multiplier. */
9797
9798 uint32_t imm;
ef0d8ffc
NC
9799 uint32_t size = INSTR (31, 31);
9800 uint32_t op = INSTR (30, 29);
9801 uint32_t shift = INSTR (22, 21);
2e8cf49e
NC
9802
9803 /* 32 bit can only shift 0 or 1 lot of 16.
9804 anything else is an unallocated instruction. */
9805 if (size == 0 && (shift > 1))
9806 HALT_UNALLOC;
9807
9808 if (op == 1)
9809 HALT_UNALLOC;
9810
ef0d8ffc 9811 imm = INSTR (20, 5);
2e8cf49e
NC
9812
9813 if (size == 0)
9814 {
9815 if (op == 0)
9816 movn32 (cpu, imm, shift);
9817 else if (op == 2)
9818 movz32 (cpu, imm, shift);
9819 else
9820 movk32 (cpu, imm, shift);
9821 }
9822 else
9823 {
9824 if (op == 0)
9825 movn64 (cpu, imm, shift);
9826 else if (op == 2)
9827 movz64 (cpu, imm, shift);
9828 else
9829 movk64 (cpu, imm, shift);
9830 }
9831}
9832
9833/* Bitfield operations.
9834 These take a pair of bit positions r and s which are in {0..31}
9835 or {0..63} depending on the instruction word size.
9836 N.B register args may not be SP. */
9837
9838/* OK, we start with ubfm which just needs to pick
9839 some bits out of source zero the rest and write
9840 the result to dest. Just need two logical shifts. */
9841
9842/* 32 bit bitfield move, left and right of affected zeroed
9843 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9844static void
9845ubfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9846{
9847 unsigned rd;
ef0d8ffc 9848 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9849 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9850
9851 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
9852 if (r <= s)
9853 {
9854 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
9855 We want only bits s:xxx:r at the bottom of the word
9856 so we LSL bit s up to bit 31 i.e. by 31 - s
9857 and then we LSR to bring bit 31 down to bit s - r
9858 i.e. by 31 + r - s. */
9859 value <<= 31 - s;
9860 value >>= 31 + r - s;
9861 }
9862 else
9863 {
9864 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0
9865 We want only bits s:xxx:0 starting at it 31-(r-1)
9866 so we LSL bit s up to bit 31 i.e. by 31 - s
9867 and then we LSL to bring bit 31 down to 31-(r-1)+s
9868 i.e. by r - (s + 1). */
9869 value <<= 31 - s;
9870 value >>= r - (s + 1);
9871 }
9872
2cdad34c 9873 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9874 rd = INSTR (4, 0);
2e8cf49e
NC
9875 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
9876}
9877
9878/* 64 bit bitfield move, left and right of affected zeroed
9879 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9880static void
9881ubfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9882{
9883 unsigned rd;
ef0d8ffc 9884 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9885 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9886
9887 if (r <= s)
9888 {
9889 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9890 We want only bits s:xxx:r at the bottom of the word.
9891 So we LSL bit s up to bit 63 i.e. by 63 - s
9892 and then we LSR to bring bit 63 down to bit s - r
9893 i.e. by 63 + r - s. */
9894 value <<= 63 - s;
9895 value >>= 63 + r - s;
9896 }
9897 else
9898 {
9899 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0.
9900 We want only bits s:xxx:0 starting at it 63-(r-1).
9901 So we LSL bit s up to bit 63 i.e. by 63 - s
9902 and then we LSL to bring bit 63 down to 63-(r-1)+s
9903 i.e. by r - (s + 1). */
9904 value <<= 63 - s;
9905 value >>= r - (s + 1);
9906 }
9907
2cdad34c 9908 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9909 rd = INSTR (4, 0);
2e8cf49e
NC
9910 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
9911}
9912
9913/* The signed versions need to insert sign bits
9914 on the left of the inserted bit field. so we do
9915 much the same as the unsigned version except we
9916 use an arithmetic shift right -- this just means
9917 we need to operate on signed values. */
9918
9919/* 32 bit bitfield move, left of affected sign-extended, right zeroed. */
9920/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9921static void
9922sbfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9923{
9924 unsigned rd;
ef0d8ffc 9925 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9926 /* as per ubfm32 but use an ASR instead of an LSR. */
9927 int32_t value = aarch64_get_reg_s32 (cpu, rn, NO_SP);
9928
9929 if (r <= s)
9930 {
9931 value <<= 31 - s;
9932 value >>= 31 + r - s;
9933 }
9934 else
9935 {
9936 value <<= 31 - s;
9937 value >>= r - (s + 1);
9938 }
9939
2cdad34c 9940 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9941 rd = INSTR (4, 0);
2e8cf49e
NC
9942 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
9943}
9944
9945/* 64 bit bitfield move, left of affected sign-extended, right zeroed. */
9946/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9947static void
9948sbfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9949{
9950 unsigned rd;
ef0d8ffc 9951 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9952 /* acpu per ubfm but use an ASR instead of an LSR. */
9953 int64_t value = aarch64_get_reg_s64 (cpu, rn, NO_SP);
9954
9955 if (r <= s)
9956 {
9957 value <<= 63 - s;
9958 value >>= 63 + r - s;
9959 }
9960 else
9961 {
9962 value <<= 63 - s;
9963 value >>= r - (s + 1);
9964 }
9965
2cdad34c 9966 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9967 rd = INSTR (4, 0);
2e8cf49e
NC
9968 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
9969}
9970
9971/* Finally, these versions leave non-affected bits
9972 as is. so we need to generate the bits as per
9973 ubfm and also generate a mask to pick the
9974 bits from the original and computed values. */
9975
9976/* 32 bit bitfield move, non-affected bits left as is.
9977 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9978static void
9979bfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9980{
ef0d8ffc 9981 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9982 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9983 uint32_t mask = -1;
9984 unsigned rd;
9985 uint32_t value2;
9986
9987 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
9988 if (r <= s)
9989 {
9990 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
9991 We want only bits s:xxx:r at the bottom of the word
9992 so we LSL bit s up to bit 31 i.e. by 31 - s
9993 and then we LSR to bring bit 31 down to bit s - r
9994 i.e. by 31 + r - s. */
9995 value <<= 31 - s;
9996 value >>= 31 + r - s;
9997 /* the mask must include the same bits. */
9998 mask <<= 31 - s;
9999 mask >>= 31 + r - s;
10000 }
10001 else
10002 {
10003 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0.
10004 We want only bits s:xxx:0 starting at it 31-(r-1)
10005 so we LSL bit s up to bit 31 i.e. by 31 - s
10006 and then we LSL to bring bit 31 down to 31-(r-1)+s
10007 i.e. by r - (s + 1). */
10008 value <<= 31 - s;
10009 value >>= r - (s + 1);
10010 /* The mask must include the same bits. */
10011 mask <<= 31 - s;
10012 mask >>= r - (s + 1);
10013 }
10014
ef0d8ffc 10015 rd = INSTR (4, 0);
2e8cf49e
NC
10016 value2 = aarch64_get_reg_u32 (cpu, rd, NO_SP);
10017
10018 value2 &= ~mask;
10019 value2 |= value;
10020
2cdad34c 10021 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10022 aarch64_set_reg_u64
10023 (cpu, rd, NO_SP, (aarch64_get_reg_u32 (cpu, rd, NO_SP) & ~mask) | value);
10024}
10025
10026/* 64 bit bitfield move, non-affected bits left as is.
10027 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
10028static void
10029bfm (sim_cpu *cpu, uint32_t r, uint32_t s)
10030{
10031 unsigned rd;
ef0d8ffc 10032 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10033 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
10034 uint64_t mask = 0xffffffffffffffffULL;
10035
10036 if (r <= s)
10037 {
10038 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
10039 We want only bits s:xxx:r at the bottom of the word
10040 so we LSL bit s up to bit 63 i.e. by 63 - s
10041 and then we LSR to bring bit 63 down to bit s - r
10042 i.e. by 63 + r - s. */
10043 value <<= 63 - s;
10044 value >>= 63 + r - s;
10045 /* The mask must include the same bits. */
10046 mask <<= 63 - s;
10047 mask >>= 63 + r - s;
10048 }
10049 else
10050 {
10051 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0
10052 We want only bits s:xxx:0 starting at it 63-(r-1)
10053 so we LSL bit s up to bit 63 i.e. by 63 - s
10054 and then we LSL to bring bit 63 down to 63-(r-1)+s
10055 i.e. by r - (s + 1). */
10056 value <<= 63 - s;
10057 value >>= r - (s + 1);
10058 /* The mask must include the same bits. */
10059 mask <<= 63 - s;
10060 mask >>= r - (s + 1);
10061 }
10062
2cdad34c 10063 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 10064 rd = INSTR (4, 0);
2e8cf49e
NC
10065 aarch64_set_reg_u64
10066 (cpu, rd, NO_SP, (aarch64_get_reg_u64 (cpu, rd, NO_SP) & ~mask) | value);
10067}
10068
10069static void
10070dexBitfieldImmediate (sim_cpu *cpu)
10071{
10072 /* assert instr[28:23] = 100110
10073 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
10074 instr[30,29] = op : 0 ==> SBFM, 1 ==> BFM, 2 ==> UBFM, 3 ==> UNALLOC
10075 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit ow UNALLOC
10076 instr[21,16] = immr : 0xxxxx for 32 bit, xxxxxx for 64 bit
10077 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
10078 instr[9,5] = Rn
10079 instr[4,0] = Rd */
10080
10081 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
10082 uint32_t dispatch;
10083 uint32_t imms;
ef0d8ffc
NC
10084 uint32_t size = INSTR (31, 31);
10085 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
10086 /* 32 bit operations must have immr[5] = 0 and imms[5] = 0. */
10087 /* or else we have an UNALLOC. */
ef0d8ffc 10088 uint32_t immr = INSTR (21, 16);
2e8cf49e
NC
10089
10090 if (~size & N)
10091 HALT_UNALLOC;
10092
10093 if (!size && uimm (immr, 5, 5))
10094 HALT_UNALLOC;
10095
ef0d8ffc 10096 imms = INSTR (15, 10);
2e8cf49e
NC
10097 if (!size && uimm (imms, 5, 5))
10098 HALT_UNALLOC;
10099
10100 /* Switch on combined size and op. */
ef0d8ffc 10101 dispatch = INSTR (31, 29);
2e8cf49e
NC
10102 switch (dispatch)
10103 {
10104 case 0: sbfm32 (cpu, immr, imms); return;
10105 case 1: bfm32 (cpu, immr, imms); return;
10106 case 2: ubfm32 (cpu, immr, imms); return;
10107 case 4: sbfm (cpu, immr, imms); return;
10108 case 5: bfm (cpu, immr, imms); return;
10109 case 6: ubfm (cpu, immr, imms); return;
10110 default: HALT_UNALLOC;
10111 }
10112}
10113
10114static void
10115do_EXTR_32 (sim_cpu *cpu)
10116{
10117 /* instr[31:21] = 00010011100
10118 instr[20,16] = Rm
10119 instr[15,10] = imms : 0xxxxx for 32 bit
10120 instr[9,5] = Rn
10121 instr[4,0] = Rd */
ef0d8ffc
NC
10122 unsigned rm = INSTR (20, 16);
10123 unsigned imms = INSTR (15, 10) & 31;
10124 unsigned rn = INSTR ( 9, 5);
10125 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
10126 uint64_t val1;
10127 uint64_t val2;
10128
10129 val1 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
10130 val1 >>= imms;
10131 val2 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
10132 val2 <<= (32 - imms);
10133
2cdad34c 10134 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10135 aarch64_set_reg_u64 (cpu, rd, NO_SP, val1 | val2);
10136}
10137
10138static void
10139do_EXTR_64 (sim_cpu *cpu)
10140{
10141 /* instr[31:21] = 10010011100
10142 instr[20,16] = Rm
10143 instr[15,10] = imms
10144 instr[9,5] = Rn
10145 instr[4,0] = Rd */
ef0d8ffc
NC
10146 unsigned rm = INSTR (20, 16);
10147 unsigned imms = INSTR (15, 10) & 63;
10148 unsigned rn = INSTR ( 9, 5);
10149 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
10150 uint64_t val;
10151
10152 val = aarch64_get_reg_u64 (cpu, rm, NO_SP);
10153 val >>= imms;
10154 val |= (aarch64_get_reg_u64 (cpu, rn, NO_SP) << (64 - imms));
10155
10156 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
10157}
10158
10159static void
10160dexExtractImmediate (sim_cpu *cpu)
10161{
10162 /* assert instr[28:23] = 100111
10163 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
10164 instr[30,29] = op21 : 0 ==> EXTR, 1,2,3 ==> UNALLOC
10165 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit or UNALLOC
10166 instr[21] = op0 : must be 0 or UNALLOC
10167 instr[20,16] = Rm
10168 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
10169 instr[9,5] = Rn
10170 instr[4,0] = Rd */
10171
10172 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
10173 /* 64 bit operations must have N = 1 or else we have an UNALLOC. */
10174 uint32_t dispatch;
ef0d8ffc
NC
10175 uint32_t size = INSTR (31, 31);
10176 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
10177 /* 32 bit operations must have imms[5] = 0
10178 or else we have an UNALLOC. */
ef0d8ffc 10179 uint32_t imms = INSTR (15, 10);
2e8cf49e
NC
10180
10181 if (size ^ N)
10182 HALT_UNALLOC;
10183
10184 if (!size && uimm (imms, 5, 5))
10185 HALT_UNALLOC;
10186
10187 /* Switch on combined size and op. */
ef0d8ffc 10188 dispatch = INSTR (31, 29);
2e8cf49e
NC
10189
10190 if (dispatch == 0)
10191 do_EXTR_32 (cpu);
10192
10193 else if (dispatch == 4)
10194 do_EXTR_64 (cpu);
10195
10196 else if (dispatch == 1)
10197 HALT_NYI;
10198 else
10199 HALT_UNALLOC;
10200}
10201
10202static void
10203dexDPImm (sim_cpu *cpu)
10204{
10205 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
10206 assert group == GROUP_DPIMM_1000 || grpoup == GROUP_DPIMM_1001
10207 bits [25,23] of a DPImm are the secondary dispatch vector. */
10208 uint32_t group2 = dispatchDPImm (aarch64_get_instr (cpu));
10209
10210 switch (group2)
10211 {
10212 case DPIMM_PCADR_000:
10213 case DPIMM_PCADR_001:
10214 dexPCRelAddressing (cpu);
10215 return;
10216
10217 case DPIMM_ADDSUB_010:
10218 case DPIMM_ADDSUB_011:
10219 dexAddSubtractImmediate (cpu);
10220 return;
10221
10222 case DPIMM_LOG_100:
10223 dexLogicalImmediate (cpu);
10224 return;
10225
10226 case DPIMM_MOV_101:
10227 dexMoveWideImmediate (cpu);
10228 return;
10229
10230 case DPIMM_BITF_110:
10231 dexBitfieldImmediate (cpu);
10232 return;
10233
10234 case DPIMM_EXTR_111:
10235 dexExtractImmediate (cpu);
10236 return;
10237
10238 default:
10239 /* Should never reach here. */
10240 HALT_NYI;
10241 }
10242}
10243
10244static void
10245dexLoadUnscaledImmediate (sim_cpu *cpu)
10246{
10247 /* instr[29,24] == 111_00
10248 instr[21] == 0
10249 instr[11,10] == 00
10250 instr[31,30] = size
10251 instr[26] = V
10252 instr[23,22] = opc
10253 instr[20,12] = simm9
10254 instr[9,5] = rn may be SP. */
ef0d8ffc
NC
10255 /* unsigned rt = INSTR (4, 0); */
10256 uint32_t V = INSTR (26, 26);
7517e550 10257 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
2e8cf49e
NC
10258 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
10259
10260 if (!V)
10261 {
10262 /* GReg operations. */
10263 switch (dispatch)
10264 {
10265 case 0: sturb (cpu, imm); return;
10266 case 1: ldurb32 (cpu, imm); return;
10267 case 2: ldursb64 (cpu, imm); return;
10268 case 3: ldursb32 (cpu, imm); return;
10269 case 4: sturh (cpu, imm); return;
10270 case 5: ldurh32 (cpu, imm); return;
10271 case 6: ldursh64 (cpu, imm); return;
10272 case 7: ldursh32 (cpu, imm); return;
10273 case 8: stur32 (cpu, imm); return;
10274 case 9: ldur32 (cpu, imm); return;
10275 case 10: ldursw (cpu, imm); return;
10276 case 12: stur64 (cpu, imm); return;
10277 case 13: ldur64 (cpu, imm); return;
10278
10279 case 14:
10280 /* PRFUM NYI. */
10281 HALT_NYI;
10282
10283 default:
10284 case 11:
10285 case 15:
10286 HALT_UNALLOC;
10287 }
10288 }
10289
10290 /* FReg operations. */
10291 switch (dispatch)
10292 {
10293 case 2: fsturq (cpu, imm); return;
10294 case 3: fldurq (cpu, imm); return;
10295 case 8: fsturs (cpu, imm); return;
10296 case 9: fldurs (cpu, imm); return;
10297 case 12: fsturd (cpu, imm); return;
10298 case 13: fldurd (cpu, imm); return;
10299
10300 case 0: /* STUR 8 bit FP. */
10301 case 1: /* LDUR 8 bit FP. */
10302 case 4: /* STUR 16 bit FP. */
10303 case 5: /* LDUR 8 bit FP. */
10304 HALT_NYI;
10305
10306 default:
10307 case 6:
10308 case 7:
10309 case 10:
10310 case 11:
10311 case 14:
10312 case 15:
10313 HALT_UNALLOC;
10314 }
10315}
10316
10317/* N.B. A preliminary note regarding all the ldrs<x>32
10318 instructions
10319
10320 The signed value loaded by these instructions is cast to unsigned
10321 before being assigned to aarch64_get_reg_u64 (cpu, N) i.e. to the
10322 64 bit element of the GReg union. this performs a 32 bit sign extension
10323 (as required) but avoids 64 bit sign extension, thus ensuring that the
10324 top half of the register word is zero. this is what the spec demands
10325 when a 32 bit load occurs. */
10326
10327/* 32 bit load sign-extended byte scaled unsigned 12 bit. */
10328static void
10329ldrsb32_abs (sim_cpu *cpu, uint32_t offset)
10330{
ef0d8ffc
NC
10331 unsigned int rn = INSTR (9, 5);
10332 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10333
10334 /* The target register may not be SP but the source may be
10335 there is no scaling required for a byte load. */
10336 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
10337 aarch64_set_reg_u64 (cpu, rt, NO_SP,
10338 (int64_t) aarch64_get_mem_s8 (cpu, address));
10339}
10340
10341/* 32 bit load sign-extended byte scaled or unscaled zero-
10342 or sign-extended 32-bit register offset. */
10343static void
10344ldrsb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10345{
ef0d8ffc
NC
10346 unsigned int rm = INSTR (20, 16);
10347 unsigned int rn = INSTR (9, 5);
10348 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10349
10350 /* rn may reference SP, rm and rt must reference ZR. */
10351
10352 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10353 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10354 extension);
10355
10356 /* There is no scaling required for a byte load. */
10357 aarch64_set_reg_u64
10358 (cpu, rt, NO_SP, (int64_t) aarch64_get_mem_s8 (cpu, address
10359 + displacement));
10360}
10361
10362/* 32 bit load sign-extended byte unscaled signed 9 bit with
10363 pre- or post-writeback. */
10364static void
10365ldrsb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10366{
10367 uint64_t address;
ef0d8ffc
NC
10368 unsigned int rn = INSTR (9, 5);
10369 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10370
10371 if (rn == rt && wb != NoWriteBack)
10372 HALT_UNALLOC;
10373
10374 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10375
10376 if (wb == Pre)
10377 address += offset;
10378
10379 aarch64_set_reg_u64 (cpu, rt, NO_SP,
10380 (int64_t) aarch64_get_mem_s8 (cpu, address));
10381
10382 if (wb == Post)
10383 address += offset;
10384
10385 if (wb != NoWriteBack)
10386 aarch64_set_reg_u64 (cpu, rn, NO_SP, address);
10387}
10388
10389/* 8 bit store scaled. */
10390static void
10391fstrb_abs (sim_cpu *cpu, uint32_t offset)
10392{
ef0d8ffc
NC
10393 unsigned st = INSTR (4, 0);
10394 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10395
10396 aarch64_set_mem_u8 (cpu,
10397 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
10398 aarch64_get_vec_u8 (cpu, st, 0));
10399}
10400
10401/* 8 bit store scaled or unscaled zero- or
10402 sign-extended 8-bit register offset. */
10403static void
10404fstrb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10405{
ef0d8ffc
NC
10406 unsigned rm = INSTR (20, 16);
10407 unsigned rn = INSTR (9, 5);
10408 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10409
10410 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10411 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10412 extension);
7517e550 10413 uint64_t displacement = scaling == Scaled ? extended : 0;
2e8cf49e
NC
10414
10415 aarch64_set_mem_u8
10416 (cpu, address + displacement, aarch64_get_vec_u8 (cpu, st, 0));
10417}
10418
10419/* 16 bit store scaled. */
10420static void
10421fstrh_abs (sim_cpu *cpu, uint32_t offset)
10422{
ef0d8ffc
NC
10423 unsigned st = INSTR (4, 0);
10424 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10425
10426 aarch64_set_mem_u16
10427 (cpu,
10428 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16),
10429 aarch64_get_vec_u16 (cpu, st, 0));
10430}
10431
10432/* 16 bit store scaled or unscaled zero-
10433 or sign-extended 16-bit register offset. */
10434static void
10435fstrh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10436{
ef0d8ffc
NC
10437 unsigned rm = INSTR (20, 16);
10438 unsigned rn = INSTR (9, 5);
10439 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10440
10441 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10442 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10443 extension);
7517e550 10444 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
2e8cf49e
NC
10445
10446 aarch64_set_mem_u16
10447 (cpu, address + displacement, aarch64_get_vec_u16 (cpu, st, 0));
10448}
10449
10450/* 32 bit store scaled unsigned 12 bit. */
10451static void
10452fstrs_abs (sim_cpu *cpu, uint32_t offset)
10453{
ef0d8ffc
NC
10454 unsigned st = INSTR (4, 0);
10455 unsigned rn = INSTR (9, 5);
2e8cf49e 10456
e101a78b 10457 aarch64_set_mem_u32
2e8cf49e
NC
10458 (cpu,
10459 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
e101a78b 10460 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10461}
10462
10463/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
10464static void
10465fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10466{
ef0d8ffc
NC
10467 unsigned rn = INSTR (9, 5);
10468 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10469
10470 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10471
10472 if (wb != Post)
10473 address += offset;
10474
e101a78b 10475 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10476
10477 if (wb == Post)
10478 address += offset;
10479
10480 if (wb != NoWriteBack)
10481 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10482}
10483
10484/* 32 bit store scaled or unscaled zero-
10485 or sign-extended 32-bit register offset. */
10486static void
10487fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10488{
ef0d8ffc
NC
10489 unsigned rm = INSTR (20, 16);
10490 unsigned rn = INSTR (9, 5);
10491 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10492
10493 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10494 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10495 extension);
10496 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
10497
e101a78b
NC
10498 aarch64_set_mem_u32
10499 (cpu, address + displacement, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10500}
10501
10502/* 64 bit store scaled unsigned 12 bit. */
10503static void
10504fstrd_abs (sim_cpu *cpu, uint32_t offset)
10505{
ef0d8ffc
NC
10506 unsigned st = INSTR (4, 0);
10507 unsigned rn = INSTR (9, 5);
2e8cf49e 10508
e101a78b 10509 aarch64_set_mem_u64
2e8cf49e
NC
10510 (cpu,
10511 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
e101a78b 10512 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10513}
10514
10515/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
10516static void
10517fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10518{
ef0d8ffc
NC
10519 unsigned rn = INSTR (9, 5);
10520 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10521
10522 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10523
10524 if (wb != Post)
10525 address += offset;
10526
e101a78b 10527 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10528
10529 if (wb == Post)
10530 address += offset;
10531
10532 if (wb != NoWriteBack)
10533 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10534}
10535
10536/* 64 bit store scaled or unscaled zero-
10537 or sign-extended 32-bit register offset. */
10538static void
10539fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10540{
ef0d8ffc
NC
10541 unsigned rm = INSTR (20, 16);
10542 unsigned rn = INSTR (9, 5);
10543 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10544
10545 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10546 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10547 extension);
10548 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
10549
e101a78b
NC
10550 aarch64_set_mem_u64
10551 (cpu, address + displacement, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10552}
10553
10554/* 128 bit store scaled unsigned 12 bit. */
10555static void
10556fstrq_abs (sim_cpu *cpu, uint32_t offset)
10557{
10558 FRegister a;
ef0d8ffc
NC
10559 unsigned st = INSTR (4, 0);
10560 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10561 uint64_t addr;
10562
10563 aarch64_get_FP_long_double (cpu, st, & a);
10564
10565 addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
10566 aarch64_set_mem_long_double (cpu, addr, a);
10567}
10568
10569/* 128 bit store unscaled signed 9 bit with pre- or post-writeback. */
10570static void
10571fstrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10572{
10573 FRegister a;
ef0d8ffc
NC
10574 unsigned rn = INSTR (9, 5);
10575 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10576 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10577
10578 if (wb != Post)
10579 address += offset;
10580
10581 aarch64_get_FP_long_double (cpu, st, & a);
10582 aarch64_set_mem_long_double (cpu, address, a);
10583
10584 if (wb == Post)
10585 address += offset;
10586
10587 if (wb != NoWriteBack)
10588 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10589}
10590
10591/* 128 bit store scaled or unscaled zero-
10592 or sign-extended 32-bit register offset. */
10593static void
10594fstrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10595{
ef0d8ffc
NC
10596 unsigned rm = INSTR (20, 16);
10597 unsigned rn = INSTR (9, 5);
10598 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10599
10600 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10601 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10602 extension);
10603 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
10604
10605 FRegister a;
10606
10607 aarch64_get_FP_long_double (cpu, st, & a);
10608 aarch64_set_mem_long_double (cpu, address + displacement, a);
10609}
10610
10611static void
10612dexLoadImmediatePrePost (sim_cpu *cpu)
10613{
ef0d8ffc
NC
10614 /* instr[31,30] = size
10615 instr[29,27] = 111
10616 instr[26] = V
10617 instr[25,24] = 00
2e8cf49e 10618 instr[23,22] = opc
ef0d8ffc 10619 instr[21] = 0
2e8cf49e 10620 instr[20,12] = simm9
ef0d8ffc
NC
10621 instr[11] = wb : 0 ==> Post, 1 ==> Pre
10622 instr[10] = 0
10623 instr[9,5] = Rn may be SP.
10624 instr[4,0] = Rt */
10625
10626 uint32_t V = INSTR (26, 26);
10627 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10628 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
10629 WriteBack wb = INSTR (11, 11);
2e8cf49e
NC
10630
10631 if (!V)
10632 {
10633 /* GReg operations. */
10634 switch (dispatch)
10635 {
10636 case 0: strb_wb (cpu, imm, wb); return;
10637 case 1: ldrb32_wb (cpu, imm, wb); return;
10638 case 2: ldrsb_wb (cpu, imm, wb); return;
10639 case 3: ldrsb32_wb (cpu, imm, wb); return;
10640 case 4: strh_wb (cpu, imm, wb); return;
10641 case 5: ldrh32_wb (cpu, imm, wb); return;
10642 case 6: ldrsh64_wb (cpu, imm, wb); return;
10643 case 7: ldrsh32_wb (cpu, imm, wb); return;
10644 case 8: str32_wb (cpu, imm, wb); return;
10645 case 9: ldr32_wb (cpu, imm, wb); return;
10646 case 10: ldrsw_wb (cpu, imm, wb); return;
10647 case 12: str_wb (cpu, imm, wb); return;
10648 case 13: ldr_wb (cpu, imm, wb); return;
10649
10650 default:
10651 case 11:
10652 case 14:
10653 case 15:
10654 HALT_UNALLOC;
10655 }
10656 }
10657
10658 /* FReg operations. */
10659 switch (dispatch)
10660 {
10661 case 2: fstrq_wb (cpu, imm, wb); return;
10662 case 3: fldrq_wb (cpu, imm, wb); return;
10663 case 8: fstrs_wb (cpu, imm, wb); return;
10664 case 9: fldrs_wb (cpu, imm, wb); return;
10665 case 12: fstrd_wb (cpu, imm, wb); return;
10666 case 13: fldrd_wb (cpu, imm, wb); return;
10667
10668 case 0: /* STUR 8 bit FP. */
10669 case 1: /* LDUR 8 bit FP. */
10670 case 4: /* STUR 16 bit FP. */
10671 case 5: /* LDUR 8 bit FP. */
10672 HALT_NYI;
10673
10674 default:
10675 case 6:
10676 case 7:
10677 case 10:
10678 case 11:
10679 case 14:
10680 case 15:
10681 HALT_UNALLOC;
10682 }
10683}
10684
10685static void
10686dexLoadRegisterOffset (sim_cpu *cpu)
10687{
10688 /* instr[31,30] = size
10689 instr[29,27] = 111
10690 instr[26] = V
10691 instr[25,24] = 00
10692 instr[23,22] = opc
10693 instr[21] = 1
10694 instr[20,16] = rm
10695 instr[15,13] = option : 010 ==> UXTW, 011 ==> UXTX/LSL,
10696 110 ==> SXTW, 111 ==> SXTX,
10697 ow ==> RESERVED
10698 instr[12] = scaled
10699 instr[11,10] = 10
10700 instr[9,5] = rn
10701 instr[4,0] = rt. */
10702
ef0d8ffc
NC
10703 uint32_t V = INSTR (26, 26);
10704 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10705 Scaling scale = INSTR (12, 12);
10706 Extension extensionType = INSTR (15, 13);
2e8cf49e
NC
10707
10708 /* Check for illegal extension types. */
10709 if (uimm (extensionType, 1, 1) == 0)
10710 HALT_UNALLOC;
10711
10712 if (extensionType == UXTX || extensionType == SXTX)
10713 extensionType = NoExtension;
10714
10715 if (!V)
10716 {
10717 /* GReg operations. */
10718 switch (dispatch)
10719 {
10720 case 0: strb_scale_ext (cpu, scale, extensionType); return;
10721 case 1: ldrb32_scale_ext (cpu, scale, extensionType); return;
10722 case 2: ldrsb_scale_ext (cpu, scale, extensionType); return;
10723 case 3: ldrsb32_scale_ext (cpu, scale, extensionType); return;
10724 case 4: strh_scale_ext (cpu, scale, extensionType); return;
10725 case 5: ldrh32_scale_ext (cpu, scale, extensionType); return;
10726 case 6: ldrsh_scale_ext (cpu, scale, extensionType); return;
10727 case 7: ldrsh32_scale_ext (cpu, scale, extensionType); return;
10728 case 8: str32_scale_ext (cpu, scale, extensionType); return;
10729 case 9: ldr32_scale_ext (cpu, scale, extensionType); return;
10730 case 10: ldrsw_scale_ext (cpu, scale, extensionType); return;
10731 case 12: str_scale_ext (cpu, scale, extensionType); return;
10732 case 13: ldr_scale_ext (cpu, scale, extensionType); return;
10733 case 14: prfm_scale_ext (cpu, scale, extensionType); return;
10734
10735 default:
10736 case 11:
10737 case 15:
10738 HALT_UNALLOC;
10739 }
10740 }
10741
10742 /* FReg operations. */
10743 switch (dispatch)
10744 {
10745 case 1: /* LDUR 8 bit FP. */
10746 HALT_NYI;
10747 case 3: fldrq_scale_ext (cpu, scale, extensionType); return;
10748 case 5: /* LDUR 8 bit FP. */
10749 HALT_NYI;
10750 case 9: fldrs_scale_ext (cpu, scale, extensionType); return;
10751 case 13: fldrd_scale_ext (cpu, scale, extensionType); return;
10752
10753 case 0: fstrb_scale_ext (cpu, scale, extensionType); return;
10754 case 2: fstrq_scale_ext (cpu, scale, extensionType); return;
10755 case 4: fstrh_scale_ext (cpu, scale, extensionType); return;
10756 case 8: fstrs_scale_ext (cpu, scale, extensionType); return;
10757 case 12: fstrd_scale_ext (cpu, scale, extensionType); return;
10758
10759 default:
10760 case 6:
10761 case 7:
10762 case 10:
10763 case 11:
10764 case 14:
10765 case 15:
10766 HALT_UNALLOC;
10767 }
10768}
10769
10770static void
10771dexLoadUnsignedImmediate (sim_cpu *cpu)
10772{
5ab6d79e 10773 /* instr[29,24] == 111_01
2e8cf49e 10774 instr[31,30] = size
5ab6d79e 10775 instr[26] = V
2e8cf49e
NC
10776 instr[23,22] = opc
10777 instr[21,10] = uimm12 : unsigned immediate offset
5ab6d79e
NC
10778 instr[9,5] = rn may be SP.
10779 instr[4,0] = rt. */
ef0d8ffc
NC
10780
10781 uint32_t V = INSTR (26,26);
7517e550 10782 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
ef0d8ffc 10783 uint32_t imm = INSTR (21, 10);
2e8cf49e
NC
10784
10785 if (!V)
10786 {
10787 /* GReg operations. */
10788 switch (dispatch)
10789 {
10790 case 0: strb_abs (cpu, imm); return;
10791 case 1: ldrb32_abs (cpu, imm); return;
10792 case 2: ldrsb_abs (cpu, imm); return;
10793 case 3: ldrsb32_abs (cpu, imm); return;
10794 case 4: strh_abs (cpu, imm); return;
10795 case 5: ldrh32_abs (cpu, imm); return;
10796 case 6: ldrsh_abs (cpu, imm); return;
10797 case 7: ldrsh32_abs (cpu, imm); return;
10798 case 8: str32_abs (cpu, imm); return;
10799 case 9: ldr32_abs (cpu, imm); return;
10800 case 10: ldrsw_abs (cpu, imm); return;
10801 case 12: str_abs (cpu, imm); return;
10802 case 13: ldr_abs (cpu, imm); return;
10803 case 14: prfm_abs (cpu, imm); return;
10804
10805 default:
10806 case 11:
10807 case 15:
10808 HALT_UNALLOC;
10809 }
10810 }
10811
10812 /* FReg operations. */
10813 switch (dispatch)
10814 {
2e8cf49e 10815 case 0: fstrb_abs (cpu, imm); return;
2e8cf49e
NC
10816 case 4: fstrh_abs (cpu, imm); return;
10817 case 8: fstrs_abs (cpu, imm); return;
10818 case 12: fstrd_abs (cpu, imm); return;
5ab6d79e 10819 case 2: fstrq_abs (cpu, imm); return;
2e8cf49e 10820
5ab6d79e
NC
10821 case 1: fldrb_abs (cpu, imm); return;
10822 case 5: fldrh_abs (cpu, imm); return;
10823 case 9: fldrs_abs (cpu, imm); return;
10824 case 13: fldrd_abs (cpu, imm); return;
10825 case 3: fldrq_abs (cpu, imm); return;
2e8cf49e
NC
10826
10827 default:
10828 case 6:
10829 case 7:
10830 case 10:
10831 case 11:
10832 case 14:
10833 case 15:
10834 HALT_UNALLOC;
10835 }
10836}
10837
10838static void
10839dexLoadExclusive (sim_cpu *cpu)
10840{
10841 /* assert instr[29:24] = 001000;
10842 instr[31,30] = size
10843 instr[23] = 0 if exclusive
10844 instr[22] = L : 1 if load, 0 if store
10845 instr[21] = 1 if pair
10846 instr[20,16] = Rs
10847 instr[15] = o0 : 1 if ordered
10848 instr[14,10] = Rt2
10849 instr[9,5] = Rn
10850 instr[4.0] = Rt. */
10851
ef0d8ffc 10852 switch (INSTR (22, 21))
2e8cf49e
NC
10853 {
10854 case 2: ldxr (cpu); return;
10855 case 0: stxr (cpu); return;
10856 default: HALT_NYI;
10857 }
10858}
10859
10860static void
10861dexLoadOther (sim_cpu *cpu)
10862{
10863 uint32_t dispatch;
10864
10865 /* instr[29,25] = 111_0
10866 instr[24] == 0 ==> dispatch, 1 ==> ldst reg unsigned immediate
10867 instr[21:11,10] is the secondary dispatch. */
ef0d8ffc 10868 if (INSTR (24, 24))
2e8cf49e
NC
10869 {
10870 dexLoadUnsignedImmediate (cpu);
10871 return;
10872 }
10873
7517e550 10874 dispatch = ((INSTR (21, 21) << 2) | INSTR (11, 10));
2e8cf49e
NC
10875 switch (dispatch)
10876 {
10877 case 0: dexLoadUnscaledImmediate (cpu); return;
10878 case 1: dexLoadImmediatePrePost (cpu); return;
10879 case 3: dexLoadImmediatePrePost (cpu); return;
10880 case 6: dexLoadRegisterOffset (cpu); return;
10881
10882 default:
10883 case 2:
10884 case 4:
10885 case 5:
10886 case 7:
10887 HALT_NYI;
10888 }
10889}
10890
10891static void
10892store_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10893{
ef0d8ffc
NC
10894 unsigned rn = INSTR (14, 10);
10895 unsigned rd = INSTR (9, 5);
10896 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10897 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10898
10899 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10900 HALT_UNALLOC; /* ??? */
10901
10902 offset <<= 2;
10903
10904 if (wb != Post)
10905 address += offset;
10906
10907 aarch64_set_mem_u32 (cpu, address,
10908 aarch64_get_reg_u32 (cpu, rm, NO_SP));
10909 aarch64_set_mem_u32 (cpu, address + 4,
10910 aarch64_get_reg_u32 (cpu, rn, NO_SP));
10911
10912 if (wb == Post)
10913 address += offset;
10914
10915 if (wb != NoWriteBack)
10916 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10917}
10918
10919static void
10920store_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10921{
ef0d8ffc
NC
10922 unsigned rn = INSTR (14, 10);
10923 unsigned rd = INSTR (9, 5);
10924 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10925 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10926
10927 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10928 HALT_UNALLOC; /* ??? */
10929
10930 offset <<= 3;
10931
10932 if (wb != Post)
10933 address += offset;
10934
10935 aarch64_set_mem_u64 (cpu, address,
7517e550 10936 aarch64_get_reg_u64 (cpu, rm, NO_SP));
2e8cf49e 10937 aarch64_set_mem_u64 (cpu, address + 8,
7517e550 10938 aarch64_get_reg_u64 (cpu, rn, NO_SP));
2e8cf49e
NC
10939
10940 if (wb == Post)
10941 address += offset;
10942
10943 if (wb != NoWriteBack)
10944 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10945}
10946
10947static void
10948load_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10949{
ef0d8ffc
NC
10950 unsigned rn = INSTR (14, 10);
10951 unsigned rd = INSTR (9, 5);
10952 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10953 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10954
7517e550 10955 /* Treat this as unalloc to make sure we don't do it. */
2e8cf49e
NC
10956 if (rn == rm)
10957 HALT_UNALLOC;
10958
10959 offset <<= 2;
10960
10961 if (wb != Post)
10962 address += offset;
10963
10964 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u32 (cpu, address));
10965 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u32 (cpu, address + 4));
10966
10967 if (wb == Post)
10968 address += offset;
10969
10970 if (wb != NoWriteBack)
10971 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10972}
10973
10974static void
10975load_pair_s32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10976{
ef0d8ffc
NC
10977 unsigned rn = INSTR (14, 10);
10978 unsigned rd = INSTR (9, 5);
10979 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10980 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10981
10982 /* Treat this as unalloc to make sure we don't do it. */
10983 if (rn == rm)
10984 HALT_UNALLOC;
10985
10986 offset <<= 2;
10987
10988 if (wb != Post)
10989 address += offset;
10990
10991 aarch64_set_reg_s64 (cpu, rm, SP_OK, aarch64_get_mem_s32 (cpu, address));
10992 aarch64_set_reg_s64 (cpu, rn, SP_OK, aarch64_get_mem_s32 (cpu, address + 4));
10993
10994 if (wb == Post)
10995 address += offset;
10996
10997 if (wb != NoWriteBack)
10998 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10999}
11000
11001static void
11002load_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
11003{
ef0d8ffc
NC
11004 unsigned rn = INSTR (14, 10);
11005 unsigned rd = INSTR (9, 5);
11006 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11007 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11008
11009 /* Treat this as unalloc to make sure we don't do it. */
11010 if (rn == rm)
11011 HALT_UNALLOC;
11012
11013 offset <<= 3;
11014
11015 if (wb != Post)
11016 address += offset;
11017
11018 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u64 (cpu, address));
11019 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u64 (cpu, address + 8));
11020
11021 if (wb == Post)
11022 address += offset;
11023
11024 if (wb != NoWriteBack)
11025 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11026}
11027
11028static void
11029dex_load_store_pair_gr (sim_cpu *cpu)
11030{
11031 /* instr[31,30] = size (10=> 64-bit, 01=> signed 32-bit, 00=> 32-bit)
11032 instr[29,25] = instruction encoding: 101_0
11033 instr[26] = V : 1 if fp 0 if gp
11034 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
11035 instr[22] = load/store (1=> load)
11036 instr[21,15] = signed, scaled, offset
11037 instr[14,10] = Rn
11038 instr[ 9, 5] = Rd
11039 instr[ 4, 0] = Rm. */
11040
7517e550 11041 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
11042 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
11043
11044 switch (dispatch)
11045 {
11046 case 2: store_pair_u32 (cpu, offset, Post); return;
11047 case 3: load_pair_u32 (cpu, offset, Post); return;
11048 case 4: store_pair_u32 (cpu, offset, NoWriteBack); return;
11049 case 5: load_pair_u32 (cpu, offset, NoWriteBack); return;
11050 case 6: store_pair_u32 (cpu, offset, Pre); return;
11051 case 7: load_pair_u32 (cpu, offset, Pre); return;
11052
11053 case 11: load_pair_s32 (cpu, offset, Post); return;
11054 case 13: load_pair_s32 (cpu, offset, NoWriteBack); return;
11055 case 15: load_pair_s32 (cpu, offset, Pre); return;
11056
11057 case 18: store_pair_u64 (cpu, offset, Post); return;
11058 case 19: load_pair_u64 (cpu, offset, Post); return;
11059 case 20: store_pair_u64 (cpu, offset, NoWriteBack); return;
11060 case 21: load_pair_u64 (cpu, offset, NoWriteBack); return;
11061 case 22: store_pair_u64 (cpu, offset, Pre); return;
11062 case 23: load_pair_u64 (cpu, offset, Pre); return;
11063
11064 default:
11065 HALT_UNALLOC;
11066 }
11067}
11068
11069static void
11070store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
11071{
ef0d8ffc
NC
11072 unsigned rn = INSTR (14, 10);
11073 unsigned rd = INSTR (9, 5);
11074 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11075 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11076
11077 offset <<= 2;
11078
11079 if (wb != Post)
11080 address += offset;
11081
e101a78b
NC
11082 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, rm, 0));
11083 aarch64_set_mem_u32 (cpu, address + 4, aarch64_get_vec_u32 (cpu, rn, 0));
2e8cf49e
NC
11084
11085 if (wb == Post)
11086 address += offset;
11087
11088 if (wb != NoWriteBack)
11089 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11090}
11091
11092static void
11093store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11094{
ef0d8ffc
NC
11095 unsigned rn = INSTR (14, 10);
11096 unsigned rd = INSTR (9, 5);
11097 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11098 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11099
11100 offset <<= 3;
11101
11102 if (wb != Post)
11103 address += offset;
11104
e101a78b
NC
11105 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, rm, 0));
11106 aarch64_set_mem_u64 (cpu, address + 8, aarch64_get_vec_u64 (cpu, rn, 0));
2e8cf49e
NC
11107
11108 if (wb == Post)
11109 address += offset;
11110
11111 if (wb != NoWriteBack)
11112 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11113}
11114
11115static void
11116store_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11117{
11118 FRegister a;
ef0d8ffc
NC
11119 unsigned rn = INSTR (14, 10);
11120 unsigned rd = INSTR (9, 5);
11121 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11122 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11123
11124 offset <<= 4;
11125
11126 if (wb != Post)
11127 address += offset;
11128
11129 aarch64_get_FP_long_double (cpu, rm, & a);
11130 aarch64_set_mem_long_double (cpu, address, a);
11131 aarch64_get_FP_long_double (cpu, rn, & a);
11132 aarch64_set_mem_long_double (cpu, address + 16, a);
11133
11134 if (wb == Post)
11135 address += offset;
11136
11137 if (wb != NoWriteBack)
11138 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11139}
11140
11141static void
11142load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
11143{
ef0d8ffc
NC
11144 unsigned rn = INSTR (14, 10);
11145 unsigned rd = INSTR (9, 5);
11146 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11147 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11148
11149 if (rm == rn)
11150 HALT_UNALLOC;
11151
11152 offset <<= 2;
11153
11154 if (wb != Post)
11155 address += offset;
11156
e101a78b
NC
11157 aarch64_set_vec_u32 (cpu, rm, 0, aarch64_get_mem_u32 (cpu, address));
11158 aarch64_set_vec_u32 (cpu, rn, 0, aarch64_get_mem_u32 (cpu, address + 4));
2e8cf49e
NC
11159
11160 if (wb == Post)
11161 address += offset;
11162
11163 if (wb != NoWriteBack)
11164 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11165}
11166
11167static void
11168load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11169{
ef0d8ffc
NC
11170 unsigned rn = INSTR (14, 10);
11171 unsigned rd = INSTR (9, 5);
11172 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11173 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11174
11175 if (rm == rn)
11176 HALT_UNALLOC;
11177
11178 offset <<= 3;
11179
11180 if (wb != Post)
11181 address += offset;
11182
e101a78b
NC
11183 aarch64_set_vec_u64 (cpu, rm, 0, aarch64_get_mem_u64 (cpu, address));
11184 aarch64_set_vec_u64 (cpu, rn, 0, aarch64_get_mem_u64 (cpu, address + 8));
2e8cf49e
NC
11185
11186 if (wb == Post)
11187 address += offset;
11188
11189 if (wb != NoWriteBack)
11190 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11191}
11192
11193static void
11194load_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11195{
11196 FRegister a;
ef0d8ffc
NC
11197 unsigned rn = INSTR (14, 10);
11198 unsigned rd = INSTR (9, 5);
11199 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11200 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11201
11202 if (rm == rn)
11203 HALT_UNALLOC;
11204
11205 offset <<= 4;
11206
11207 if (wb != Post)
11208 address += offset;
11209
11210 aarch64_get_mem_long_double (cpu, address, & a);
11211 aarch64_set_FP_long_double (cpu, rm, a);
11212 aarch64_get_mem_long_double (cpu, address + 16, & a);
11213 aarch64_set_FP_long_double (cpu, rn, a);
11214
11215 if (wb == Post)
11216 address += offset;
11217
11218 if (wb != NoWriteBack)
11219 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11220}
11221
11222static void
11223dex_load_store_pair_fp (sim_cpu *cpu)
11224{
11225 /* instr[31,30] = size (10=> 128-bit, 01=> 64-bit, 00=> 32-bit)
11226 instr[29,25] = instruction encoding
11227 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
11228 instr[22] = load/store (1=> load)
11229 instr[21,15] = signed, scaled, offset
11230 instr[14,10] = Rn
11231 instr[ 9, 5] = Rd
11232 instr[ 4, 0] = Rm */
11233
7517e550 11234 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
11235 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
11236
11237 switch (dispatch)
11238 {
11239 case 2: store_pair_float (cpu, offset, Post); return;
11240 case 3: load_pair_float (cpu, offset, Post); return;
11241 case 4: store_pair_float (cpu, offset, NoWriteBack); return;
11242 case 5: load_pair_float (cpu, offset, NoWriteBack); return;
11243 case 6: store_pair_float (cpu, offset, Pre); return;
11244 case 7: load_pair_float (cpu, offset, Pre); return;
11245
11246 case 10: store_pair_double (cpu, offset, Post); return;
11247 case 11: load_pair_double (cpu, offset, Post); return;
11248 case 12: store_pair_double (cpu, offset, NoWriteBack); return;
11249 case 13: load_pair_double (cpu, offset, NoWriteBack); return;
11250 case 14: store_pair_double (cpu, offset, Pre); return;
11251 case 15: load_pair_double (cpu, offset, Pre); return;
11252
11253 case 18: store_pair_long_double (cpu, offset, Post); return;
11254 case 19: load_pair_long_double (cpu, offset, Post); return;
11255 case 20: store_pair_long_double (cpu, offset, NoWriteBack); return;
11256 case 21: load_pair_long_double (cpu, offset, NoWriteBack); return;
11257 case 22: store_pair_long_double (cpu, offset, Pre); return;
11258 case 23: load_pair_long_double (cpu, offset, Pre); return;
11259
11260 default:
11261 HALT_UNALLOC;
11262 }
11263}
11264
11265static inline unsigned
11266vec_reg (unsigned v, unsigned o)
11267{
11268 return (v + o) & 0x3F;
11269}
11270
11271/* Load multiple N-element structures to N consecutive registers. */
11272static void
11273vec_load (sim_cpu *cpu, uint64_t address, unsigned N)
11274{
ef0d8ffc
NC
11275 int all = INSTR (30, 30);
11276 unsigned size = INSTR (11, 10);
11277 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11278 unsigned i;
11279
11280 switch (size)
11281 {
11282 case 0: /* 8-bit operations. */
11283 if (all)
11284 for (i = 0; i < (16 * N); i++)
11285 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15,
11286 aarch64_get_mem_u8 (cpu, address + i));
11287 else
11288 for (i = 0; i < (8 * N); i++)
11289 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7,
11290 aarch64_get_mem_u8 (cpu, address + i));
11291 return;
11292
11293 case 1: /* 16-bit operations. */
11294 if (all)
11295 for (i = 0; i < (8 * N); i++)
11296 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7,
11297 aarch64_get_mem_u16 (cpu, address + i * 2));
11298 else
11299 for (i = 0; i < (4 * N); i++)
11300 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3,
11301 aarch64_get_mem_u16 (cpu, address + i * 2));
11302 return;
11303
11304 case 2: /* 32-bit operations. */
11305 if (all)
11306 for (i = 0; i < (4 * N); i++)
11307 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3,
11308 aarch64_get_mem_u32 (cpu, address + i * 4));
11309 else
11310 for (i = 0; i < (2 * N); i++)
11311 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1,
11312 aarch64_get_mem_u32 (cpu, address + i * 4));
11313 return;
11314
11315 case 3: /* 64-bit operations. */
11316 if (all)
11317 for (i = 0; i < (2 * N); i++)
11318 aarch64_set_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1,
11319 aarch64_get_mem_u64 (cpu, address + i * 8));
11320 else
11321 for (i = 0; i < N; i++)
11322 aarch64_set_vec_u64 (cpu, vec_reg (vd, i), 0,
11323 aarch64_get_mem_u64 (cpu, address + i * 8));
11324 return;
2e8cf49e
NC
11325 }
11326}
11327
11328/* LD4: load multiple 4-element to four consecutive registers. */
11329static void
11330LD4 (sim_cpu *cpu, uint64_t address)
11331{
11332 vec_load (cpu, address, 4);
11333}
11334
11335/* LD3: load multiple 3-element structures to three consecutive registers. */
11336static void
11337LD3 (sim_cpu *cpu, uint64_t address)
11338{
11339 vec_load (cpu, address, 3);
11340}
11341
11342/* LD2: load multiple 2-element structures to two consecutive registers. */
11343static void
11344LD2 (sim_cpu *cpu, uint64_t address)
11345{
11346 vec_load (cpu, address, 2);
11347}
11348
11349/* Load multiple 1-element structures into one register. */
11350static void
11351LD1_1 (sim_cpu *cpu, uint64_t address)
11352{
ef0d8ffc
NC
11353 int all = INSTR (30, 30);
11354 unsigned size = INSTR (11, 10);
11355 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11356 unsigned i;
11357
11358 switch (size)
11359 {
11360 case 0:
11361 /* LD1 {Vd.16b}, addr, #16 */
11362 /* LD1 {Vd.8b}, addr, #8 */
11363 for (i = 0; i < (all ? 16 : 8); i++)
11364 aarch64_set_vec_u8 (cpu, vd, i,
11365 aarch64_get_mem_u8 (cpu, address + i));
11366 return;
11367
11368 case 1:
11369 /* LD1 {Vd.8h}, addr, #16 */
11370 /* LD1 {Vd.4h}, addr, #8 */
11371 for (i = 0; i < (all ? 8 : 4); i++)
11372 aarch64_set_vec_u16 (cpu, vd, i,
11373 aarch64_get_mem_u16 (cpu, address + i * 2));
11374 return;
11375
11376 case 2:
11377 /* LD1 {Vd.4s}, addr, #16 */
11378 /* LD1 {Vd.2s}, addr, #8 */
11379 for (i = 0; i < (all ? 4 : 2); i++)
11380 aarch64_set_vec_u32 (cpu, vd, i,
11381 aarch64_get_mem_u32 (cpu, address + i * 4));
11382 return;
11383
11384 case 3:
11385 /* LD1 {Vd.2d}, addr, #16 */
11386 /* LD1 {Vd.1d}, addr, #8 */
11387 for (i = 0; i < (all ? 2 : 1); i++)
11388 aarch64_set_vec_u64 (cpu, vd, i,
11389 aarch64_get_mem_u64 (cpu, address + i * 8));
11390 return;
2e8cf49e
NC
11391 }
11392}
11393
11394/* Load multiple 1-element structures into two registers. */
11395static void
11396LD1_2 (sim_cpu *cpu, uint64_t address)
11397{
11398 /* FIXME: This algorithm is *exactly* the same as the LD2 version.
11399 So why have two different instructions ? There must be something
11400 wrong somewhere. */
11401 vec_load (cpu, address, 2);
11402}
11403
11404/* Load multiple 1-element structures into three registers. */
11405static void
11406LD1_3 (sim_cpu *cpu, uint64_t address)
11407{
11408 /* FIXME: This algorithm is *exactly* the same as the LD3 version.
11409 So why have two different instructions ? There must be something
11410 wrong somewhere. */
11411 vec_load (cpu, address, 3);
11412}
11413
11414/* Load multiple 1-element structures into four registers. */
11415static void
11416LD1_4 (sim_cpu *cpu, uint64_t address)
11417{
11418 /* FIXME: This algorithm is *exactly* the same as the LD4 version.
11419 So why have two different instructions ? There must be something
11420 wrong somewhere. */
11421 vec_load (cpu, address, 4);
11422}
11423
11424/* Store multiple N-element structures to N consecutive registers. */
11425static void
11426vec_store (sim_cpu *cpu, uint64_t address, unsigned N)
11427{
ef0d8ffc
NC
11428 int all = INSTR (30, 30);
11429 unsigned size = INSTR (11, 10);
11430 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11431 unsigned i;
11432
11433 switch (size)
11434 {
11435 case 0: /* 8-bit operations. */
11436 if (all)
11437 for (i = 0; i < (16 * N); i++)
11438 aarch64_set_mem_u8
11439 (cpu, address + i,
11440 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15));
11441 else
11442 for (i = 0; i < (8 * N); i++)
11443 aarch64_set_mem_u8
11444 (cpu, address + i,
11445 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7));
11446 return;
11447
11448 case 1: /* 16-bit operations. */
11449 if (all)
11450 for (i = 0; i < (8 * N); i++)
11451 aarch64_set_mem_u16
11452 (cpu, address + i * 2,
11453 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7));
11454 else
11455 for (i = 0; i < (4 * N); i++)
11456 aarch64_set_mem_u16
11457 (cpu, address + i * 2,
11458 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3));
11459 return;
11460
11461 case 2: /* 32-bit operations. */
11462 if (all)
11463 for (i = 0; i < (4 * N); i++)
11464 aarch64_set_mem_u32
11465 (cpu, address + i * 4,
11466 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3));
11467 else
11468 for (i = 0; i < (2 * N); i++)
11469 aarch64_set_mem_u32
11470 (cpu, address + i * 4,
11471 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1));
11472 return;
11473
11474 case 3: /* 64-bit operations. */
11475 if (all)
11476 for (i = 0; i < (2 * N); i++)
11477 aarch64_set_mem_u64
11478 (cpu, address + i * 8,
11479 aarch64_get_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1));
11480 else
11481 for (i = 0; i < N; i++)
11482 aarch64_set_mem_u64
11483 (cpu, address + i * 8,
11484 aarch64_get_vec_u64 (cpu, vec_reg (vd, i), 0));
11485 return;
2e8cf49e
NC
11486 }
11487}
11488
11489/* Store multiple 4-element structure to four consecutive registers. */
11490static void
11491ST4 (sim_cpu *cpu, uint64_t address)
11492{
11493 vec_store (cpu, address, 4);
11494}
11495
11496/* Store multiple 3-element structures to three consecutive registers. */
11497static void
11498ST3 (sim_cpu *cpu, uint64_t address)
11499{
11500 vec_store (cpu, address, 3);
11501}
11502
11503/* Store multiple 2-element structures to two consecutive registers. */
11504static void
11505ST2 (sim_cpu *cpu, uint64_t address)
11506{
11507 vec_store (cpu, address, 2);
11508}
11509
11510/* Store multiple 1-element structures into one register. */
11511static void
11512ST1_1 (sim_cpu *cpu, uint64_t address)
11513{
ef0d8ffc
NC
11514 int all = INSTR (30, 30);
11515 unsigned size = INSTR (11, 10);
11516 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11517 unsigned i;
11518
11519 switch (size)
11520 {
11521 case 0:
11522 for (i = 0; i < (all ? 16 : 8); i++)
11523 aarch64_set_mem_u8 (cpu, address + i,
11524 aarch64_get_vec_u8 (cpu, vd, i));
11525 return;
11526
11527 case 1:
11528 for (i = 0; i < (all ? 8 : 4); i++)
11529 aarch64_set_mem_u16 (cpu, address + i * 2,
11530 aarch64_get_vec_u16 (cpu, vd, i));
11531 return;
11532
11533 case 2:
11534 for (i = 0; i < (all ? 4 : 2); i++)
11535 aarch64_set_mem_u32 (cpu, address + i * 4,
11536 aarch64_get_vec_u32 (cpu, vd, i));
11537 return;
11538
11539 case 3:
11540 for (i = 0; i < (all ? 2 : 1); i++)
11541 aarch64_set_mem_u64 (cpu, address + i * 8,
11542 aarch64_get_vec_u64 (cpu, vd, i));
11543 return;
2e8cf49e
NC
11544 }
11545}
11546
11547/* Store multiple 1-element structures into two registers. */
11548static void
11549ST1_2 (sim_cpu *cpu, uint64_t address)
11550{
11551 /* FIXME: This algorithm is *exactly* the same as the ST2 version.
11552 So why have two different instructions ? There must be
11553 something wrong somewhere. */
11554 vec_store (cpu, address, 2);
11555}
11556
11557/* Store multiple 1-element structures into three registers. */
11558static void
11559ST1_3 (sim_cpu *cpu, uint64_t address)
11560{
11561 /* FIXME: This algorithm is *exactly* the same as the ST3 version.
11562 So why have two different instructions ? There must be
11563 something wrong somewhere. */
11564 vec_store (cpu, address, 3);
11565}
11566
11567/* Store multiple 1-element structures into four registers. */
11568static void
11569ST1_4 (sim_cpu *cpu, uint64_t address)
11570{
11571 /* FIXME: This algorithm is *exactly* the same as the ST4 version.
11572 So why have two different instructions ? There must be
11573 something wrong somewhere. */
11574 vec_store (cpu, address, 4);
11575}
11576
11577static void
11578do_vec_LDnR (sim_cpu *cpu, uint64_t address)
11579{
11580 /* instr[31] = 0
11581 instr[30] = element selector 0=>half, 1=>all elements
11582 instr[29,24] = 00 1101
11583 instr[23] = 0=>simple, 1=>post
11584 instr[22] = 1
11585 instr[21] = width: LD1R-or-LD3R (0) / LD2R-or-LD4R (1)
11586 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
11587 11111 (immediate post inc)
11588 instr[15,14] = 11
11589 instr[13] = width: LD1R-or-LD2R (0) / LD3R-or-LD4R (1)
11590 instr[12] = 0
11591 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11592 10=> word(s), 11=> double(d)
11593 instr[9,5] = address
11594 instr[4,0] = Vd */
11595
ef0d8ffc
NC
11596 unsigned full = INSTR (30, 30);
11597 unsigned vd = INSTR (4, 0);
11598 unsigned size = INSTR (11, 10);
2e8cf49e
NC
11599 int i;
11600
11601 NYI_assert (29, 24, 0x0D);
11602 NYI_assert (22, 22, 1);
11603 NYI_assert (15, 14, 3);
11604 NYI_assert (12, 12, 0);
11605
7517e550 11606 switch ((INSTR (13, 13) << 1) | INSTR (21, 21))
2e8cf49e
NC
11607 {
11608 case 0: /* LD1R. */
11609 switch (size)
11610 {
11611 case 0:
11612 {
11613 uint8_t val = aarch64_get_mem_u8 (cpu, address);
11614 for (i = 0; i < (full ? 16 : 8); i++)
11615 aarch64_set_vec_u8 (cpu, vd, i, val);
11616 break;
11617 }
11618
11619 case 1:
11620 {
11621 uint16_t val = aarch64_get_mem_u16 (cpu, address);
11622 for (i = 0; i < (full ? 8 : 4); i++)
11623 aarch64_set_vec_u16 (cpu, vd, i, val);
11624 break;
11625 }
11626
11627 case 2:
11628 {
11629 uint32_t val = aarch64_get_mem_u32 (cpu, address);
11630 for (i = 0; i < (full ? 4 : 2); i++)
11631 aarch64_set_vec_u32 (cpu, vd, i, val);
11632 break;
11633 }
11634
11635 case 3:
11636 {
11637 uint64_t val = aarch64_get_mem_u64 (cpu, address);
11638 for (i = 0; i < (full ? 2 : 1); i++)
11639 aarch64_set_vec_u64 (cpu, vd, i, val);
11640 break;
11641 }
11642
11643 default:
11644 HALT_UNALLOC;
11645 }
11646 break;
11647
11648 case 1: /* LD2R. */
11649 switch (size)
11650 {
11651 case 0:
11652 {
11653 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11654 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11655
11656 for (i = 0; i < (full ? 16 : 8); i++)
11657 {
11658 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11659 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11660 }
11661 break;
11662 }
11663
11664 case 1:
11665 {
11666 uint16_t val1 = aarch64_get_mem_u16 (cpu, address);
11667 uint16_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11668
11669 for (i = 0; i < (full ? 8 : 4); i++)
11670 {
11671 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11672 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11673 }
11674 break;
11675 }
11676
11677 case 2:
11678 {
11679 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11680 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11681
11682 for (i = 0; i < (full ? 4 : 2); i++)
11683 {
11684 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11685 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11686 }
11687 break;
11688 }
11689
11690 case 3:
11691 {
11692 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11693 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11694
11695 for (i = 0; i < (full ? 2 : 1); i++)
11696 {
11697 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11698 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11699 }
11700 break;
11701 }
11702
11703 default:
11704 HALT_UNALLOC;
11705 }
11706 break;
11707
11708 case 2: /* LD3R. */
11709 switch (size)
11710 {
11711 case 0:
11712 {
11713 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11714 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11715 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
11716
11717 for (i = 0; i < (full ? 16 : 8); i++)
11718 {
11719 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11720 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11721 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
11722 }
11723 }
11724 break;
11725
11726 case 1:
11727 {
11728 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
11729 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11730 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
11731
11732 for (i = 0; i < (full ? 8 : 4); i++)
11733 {
11734 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11735 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11736 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
11737 }
11738 }
11739 break;
11740
11741 case 2:
11742 {
11743 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11744 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11745 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
11746
11747 for (i = 0; i < (full ? 4 : 2); i++)
11748 {
11749 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11750 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11751 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
11752 }
11753 }
11754 break;
11755
11756 case 3:
11757 {
11758 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11759 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11760 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
11761
11762 for (i = 0; i < (full ? 2 : 1); i++)
11763 {
11764 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11765 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11766 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
11767 }
11768 }
11769 break;
11770
11771 default:
11772 HALT_UNALLOC;
11773 }
11774 break;
11775
11776 case 3: /* LD4R. */
11777 switch (size)
11778 {
11779 case 0:
11780 {
11781 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11782 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11783 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
11784 uint8_t val4 = aarch64_get_mem_u8 (cpu, address + 3);
11785
11786 for (i = 0; i < (full ? 16 : 8); i++)
11787 {
11788 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11789 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11790 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
11791 aarch64_set_vec_u8 (cpu, vd + 3, 0, val4);
11792 }
11793 }
11794 break;
11795
11796 case 1:
11797 {
11798 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
11799 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11800 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
11801 uint32_t val4 = aarch64_get_mem_u16 (cpu, address + 6);
11802
11803 for (i = 0; i < (full ? 8 : 4); i++)
11804 {
11805 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11806 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11807 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
11808 aarch64_set_vec_u16 (cpu, vd + 3, 0, val4);
11809 }
11810 }
11811 break;
11812
11813 case 2:
11814 {
11815 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11816 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11817 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
11818 uint32_t val4 = aarch64_get_mem_u32 (cpu, address + 12);
11819
11820 for (i = 0; i < (full ? 4 : 2); i++)
11821 {
11822 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11823 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11824 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
11825 aarch64_set_vec_u32 (cpu, vd + 3, 0, val4);
11826 }
11827 }
11828 break;
11829
11830 case 3:
11831 {
11832 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11833 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11834 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
11835 uint64_t val4 = aarch64_get_mem_u64 (cpu, address + 24);
11836
11837 for (i = 0; i < (full ? 2 : 1); i++)
11838 {
11839 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11840 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11841 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
11842 aarch64_set_vec_u64 (cpu, vd + 3, 0, val4);
11843 }
11844 }
11845 break;
11846
11847 default:
11848 HALT_UNALLOC;
11849 }
11850 break;
11851
11852 default:
11853 HALT_UNALLOC;
11854 }
11855}
11856
11857static void
11858do_vec_load_store (sim_cpu *cpu)
11859{
11860 /* {LD|ST}<N> {Vd..Vd+N}, vaddr
11861
11862 instr[31] = 0
11863 instr[30] = element selector 0=>half, 1=>all elements
11864 instr[29,25] = 00110
11865 instr[24] = ?
11866 instr[23] = 0=>simple, 1=>post
11867 instr[22] = 0=>store, 1=>load
11868 instr[21] = 0 (LDn) / small(0)-large(1) selector (LDnR)
11869 instr[20,16] = 00000 (simple), Vinc (reg-post-inc, no SP),
11870 11111 (immediate post inc)
11871 instr[15,12] = elements and destinations. eg for load:
11872 0000=>LD4 => load multiple 4-element to
11873 four consecutive registers
11874 0100=>LD3 => load multiple 3-element to
11875 three consecutive registers
11876 1000=>LD2 => load multiple 2-element to
11877 two consecutive registers
11878 0010=>LD1 => load multiple 1-element to
11879 four consecutive registers
11880 0110=>LD1 => load multiple 1-element to
11881 three consecutive registers
11882 1010=>LD1 => load multiple 1-element to
11883 two consecutive registers
11884 0111=>LD1 => load multiple 1-element to
11885 one register
11886 1100=>LDR1,LDR2
11887 1110=>LDR3,LDR4
11888 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11889 10=> word(s), 11=> double(d)
11890 instr[9,5] = Vn, can be SP
11891 instr[4,0] = Vd */
11892
11893 int post;
11894 int load;
11895 unsigned vn;
11896 uint64_t address;
11897 int type;
11898
7517e550 11899 if (INSTR (31, 31) != 0 || INSTR (29, 25) != 0x06)
2e8cf49e
NC
11900 HALT_NYI;
11901
ef0d8ffc
NC
11902 type = INSTR (15, 12);
11903 if (type != 0xE && type != 0xE && INSTR (21, 21) != 0)
2e8cf49e
NC
11904 HALT_NYI;
11905
ef0d8ffc
NC
11906 post = INSTR (23, 23);
11907 load = INSTR (22, 22);
11908 vn = INSTR (9, 5);
2e8cf49e
NC
11909 address = aarch64_get_reg_u64 (cpu, vn, SP_OK);
11910
11911 if (post)
11912 {
ef0d8ffc 11913 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
11914
11915 if (vm == R31)
11916 {
11917 unsigned sizeof_operation;
11918
11919 switch (type)
11920 {
11921 case 0: sizeof_operation = 32; break;
11922 case 4: sizeof_operation = 24; break;
11923 case 8: sizeof_operation = 16; break;
11924
11925 case 0xC:
ef0d8ffc
NC
11926 sizeof_operation = INSTR (21, 21) ? 2 : 1;
11927 sizeof_operation <<= INSTR (11, 10);
2e8cf49e
NC
11928 break;
11929
11930 case 0xE:
ef0d8ffc
NC
11931 sizeof_operation = INSTR (21, 21) ? 8 : 4;
11932 sizeof_operation <<= INSTR (11, 10);
2e8cf49e
NC
11933 break;
11934
2e8cf49e 11935 case 7:
57aa1742
NC
11936 /* One register, immediate offset variant. */
11937 sizeof_operation = 8;
11938 break;
ef0d8ffc 11939
57aa1742
NC
11940 case 10:
11941 /* Two registers, immediate offset variant. */
11942 sizeof_operation = 16;
11943 break;
11944
11945 case 6:
11946 /* Three registers, immediate offset variant. */
11947 sizeof_operation = 24;
11948 break;
11949
11950 case 2:
11951 /* Four registers, immediate offset variant. */
11952 sizeof_operation = 32;
2e8cf49e
NC
11953 break;
11954
11955 default:
11956 HALT_UNALLOC;
11957 }
11958
ef0d8ffc 11959 if (INSTR (30, 30))
2e8cf49e
NC
11960 sizeof_operation *= 2;
11961
11962 aarch64_set_reg_u64 (cpu, vn, SP_OK, address + sizeof_operation);
11963 }
11964 else
11965 aarch64_set_reg_u64 (cpu, vn, SP_OK,
11966 address + aarch64_get_reg_u64 (cpu, vm, NO_SP));
11967 }
11968 else
11969 {
11970 NYI_assert (20, 16, 0);
11971 }
11972
11973 if (load)
11974 {
11975 switch (type)
11976 {
11977 case 0: LD4 (cpu, address); return;
11978 case 4: LD3 (cpu, address); return;
11979 case 8: LD2 (cpu, address); return;
11980 case 2: LD1_4 (cpu, address); return;
11981 case 6: LD1_3 (cpu, address); return;
11982 case 10: LD1_2 (cpu, address); return;
11983 case 7: LD1_1 (cpu, address); return;
11984
11985 case 0xE:
11986 case 0xC: do_vec_LDnR (cpu, address); return;
11987
11988 default:
11989 HALT_NYI;
11990 }
11991 }
11992
11993 /* Stores. */
11994 switch (type)
11995 {
11996 case 0: ST4 (cpu, address); return;
11997 case 4: ST3 (cpu, address); return;
11998 case 8: ST2 (cpu, address); return;
11999 case 2: ST1_4 (cpu, address); return;
12000 case 6: ST1_3 (cpu, address); return;
12001 case 10: ST1_2 (cpu, address); return;
12002 case 7: ST1_1 (cpu, address); return;
12003 default:
12004 HALT_NYI;
12005 }
12006}
12007
12008static void
12009dexLdSt (sim_cpu *cpu)
12010{
12011 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12012 assert group == GROUP_LDST_0100 || group == GROUP_LDST_0110 ||
12013 group == GROUP_LDST_1100 || group == GROUP_LDST_1110
12014 bits [29,28:26] of a LS are the secondary dispatch vector. */
12015 uint32_t group2 = dispatchLS (aarch64_get_instr (cpu));
12016
12017 switch (group2)
12018 {
12019 case LS_EXCL_000:
12020 dexLoadExclusive (cpu); return;
12021
12022 case LS_LIT_010:
12023 case LS_LIT_011:
12024 dexLoadLiteral (cpu); return;
12025
12026 case LS_OTHER_110:
12027 case LS_OTHER_111:
12028 dexLoadOther (cpu); return;
12029
12030 case LS_ADVSIMD_001:
12031 do_vec_load_store (cpu); return;
12032
12033 case LS_PAIR_100:
12034 dex_load_store_pair_gr (cpu); return;
12035
12036 case LS_PAIR_101:
12037 dex_load_store_pair_fp (cpu); return;
12038
12039 default:
12040 /* Should never reach here. */
12041 HALT_NYI;
12042 }
12043}
12044
12045/* Specific decode and execute for group Data Processing Register. */
12046
12047static void
12048dexLogicalShiftedRegister (sim_cpu *cpu)
12049{
ef0d8ffc
NC
12050 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12051 instr[30,29] = op
12052 instr[28:24] = 01010
2e8cf49e 12053 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> ROR
ef0d8ffc
NC
12054 instr[21] = N
12055 instr[20,16] = Rm
2e8cf49e 12056 instr[15,10] = count : must be 0xxxxx for 32 bit
ef0d8ffc
NC
12057 instr[9,5] = Rn
12058 instr[4,0] = Rd */
2e8cf49e 12059
ef0d8ffc
NC
12060 uint32_t size = INSTR (31, 31);
12061 Shift shiftType = INSTR (23, 22);
12062 uint32_t count = INSTR (15, 10);
2e8cf49e 12063
ef0d8ffc
NC
12064 /* 32 bit operations must have count[5] = 0.
12065 or else we have an UNALLOC. */
12066 if (size == 0 && uimm (count, 5, 5))
2e8cf49e
NC
12067 HALT_UNALLOC;
12068
ef0d8ffc
NC
12069 /* Dispatch on size:op:N. */
12070 switch ((INSTR (31, 29) << 1) | INSTR (21, 21))
2e8cf49e
NC
12071 {
12072 case 0: and32_shift (cpu, shiftType, count); return;
12073 case 1: bic32_shift (cpu, shiftType, count); return;
12074 case 2: orr32_shift (cpu, shiftType, count); return;
12075 case 3: orn32_shift (cpu, shiftType, count); return;
12076 case 4: eor32_shift (cpu, shiftType, count); return;
12077 case 5: eon32_shift (cpu, shiftType, count); return;
12078 case 6: ands32_shift (cpu, shiftType, count); return;
12079 case 7: bics32_shift (cpu, shiftType, count); return;
12080 case 8: and64_shift (cpu, shiftType, count); return;
12081 case 9: bic64_shift (cpu, shiftType, count); return;
12082 case 10:orr64_shift (cpu, shiftType, count); return;
12083 case 11:orn64_shift (cpu, shiftType, count); return;
12084 case 12:eor64_shift (cpu, shiftType, count); return;
12085 case 13:eon64_shift (cpu, shiftType, count); return;
12086 case 14:ands64_shift (cpu, shiftType, count); return;
12087 case 15:bics64_shift (cpu, shiftType, count); return;
2e8cf49e
NC
12088 }
12089}
12090
12091/* 32 bit conditional select. */
12092static void
12093csel32 (sim_cpu *cpu, CondCode cc)
12094{
ef0d8ffc
NC
12095 unsigned rm = INSTR (20, 16);
12096 unsigned rn = INSTR (9, 5);
12097 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12098
12099 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12100 testConditionCode (cpu, cc)
12101 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12102 : aarch64_get_reg_u32 (cpu, rm, NO_SP));
12103}
12104
12105/* 64 bit conditional select. */
12106static void
12107csel64 (sim_cpu *cpu, CondCode cc)
12108{
ef0d8ffc
NC
12109 unsigned rm = INSTR (20, 16);
12110 unsigned rn = INSTR (9, 5);
12111 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12112
12113 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12114 testConditionCode (cpu, cc)
12115 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12116 : aarch64_get_reg_u64 (cpu, rm, NO_SP));
12117}
12118
12119/* 32 bit conditional increment. */
12120static void
12121csinc32 (sim_cpu *cpu, CondCode cc)
12122{
ef0d8ffc
NC
12123 unsigned rm = INSTR (20, 16);
12124 unsigned rn = INSTR (9, 5);
12125 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12126
12127 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12128 testConditionCode (cpu, cc)
12129 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12130 : aarch64_get_reg_u32 (cpu, rm, NO_SP) + 1);
12131}
12132
12133/* 64 bit conditional increment. */
12134static void
12135csinc64 (sim_cpu *cpu, CondCode cc)
12136{
ef0d8ffc
NC
12137 unsigned rm = INSTR (20, 16);
12138 unsigned rn = INSTR (9, 5);
12139 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12140
12141 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12142 testConditionCode (cpu, cc)
12143 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12144 : aarch64_get_reg_u64 (cpu, rm, NO_SP) + 1);
12145}
12146
12147/* 32 bit conditional invert. */
12148static void
12149csinv32 (sim_cpu *cpu, CondCode cc)
12150{
ef0d8ffc
NC
12151 unsigned rm = INSTR (20, 16);
12152 unsigned rn = INSTR (9, 5);
12153 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12154
12155 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12156 testConditionCode (cpu, cc)
12157 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12158 : ~ aarch64_get_reg_u32 (cpu, rm, NO_SP));
12159}
12160
12161/* 64 bit conditional invert. */
12162static void
12163csinv64 (sim_cpu *cpu, CondCode cc)
12164{
ef0d8ffc
NC
12165 unsigned rm = INSTR (20, 16);
12166 unsigned rn = INSTR (9, 5);
12167 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12168
12169 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12170 testConditionCode (cpu, cc)
12171 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12172 : ~ aarch64_get_reg_u64 (cpu, rm, NO_SP));
12173}
12174
12175/* 32 bit conditional negate. */
12176static void
12177csneg32 (sim_cpu *cpu, CondCode cc)
12178{
ef0d8ffc
NC
12179 unsigned rm = INSTR (20, 16);
12180 unsigned rn = INSTR (9, 5);
12181 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12182
12183 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12184 testConditionCode (cpu, cc)
12185 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12186 : - aarch64_get_reg_u32 (cpu, rm, NO_SP));
12187}
12188
12189/* 64 bit conditional negate. */
12190static void
12191csneg64 (sim_cpu *cpu, CondCode cc)
12192{
ef0d8ffc
NC
12193 unsigned rm = INSTR (20, 16);
12194 unsigned rn = INSTR (9, 5);
12195 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12196
12197 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12198 testConditionCode (cpu, cc)
12199 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12200 : - aarch64_get_reg_u64 (cpu, rm, NO_SP));
12201}
12202
12203static void
12204dexCondSelect (sim_cpu *cpu)
12205{
ef0d8ffc
NC
12206 /* instr[28,21] = 11011011
12207 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2e8cf49e
NC
12208 instr[30:11,10] = op : 000 ==> CSEL, 001 ==> CSINC,
12209 100 ==> CSINV, 101 ==> CSNEG,
12210 _1_ ==> UNALLOC
12211 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
12212 instr[15,12] = cond
12213 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC */
12214
ef0d8ffc
NC
12215 CondCode cc = INSTR (15, 12);
12216 uint32_t S = INSTR (29, 29);
12217 uint32_t op2 = INSTR (11, 10);
2e8cf49e
NC
12218
12219 if (S == 1)
12220 HALT_UNALLOC;
12221
12222 if (op2 & 0x2)
12223 HALT_UNALLOC;
12224
ef0d8ffc 12225 switch ((INSTR (31, 30) << 1) | op2)
2e8cf49e
NC
12226 {
12227 case 0: csel32 (cpu, cc); return;
12228 case 1: csinc32 (cpu, cc); return;
12229 case 2: csinv32 (cpu, cc); return;
12230 case 3: csneg32 (cpu, cc); return;
12231 case 4: csel64 (cpu, cc); return;
12232 case 5: csinc64 (cpu, cc); return;
12233 case 6: csinv64 (cpu, cc); return;
12234 case 7: csneg64 (cpu, cc); return;
2e8cf49e
NC
12235 }
12236}
12237
12238/* Some helpers for counting leading 1 or 0 bits. */
12239
12240/* Counts the number of leading bits which are the same
12241 in a 32 bit value in the range 1 to 32. */
12242static uint32_t
12243leading32 (uint32_t value)
12244{
12245 int32_t mask= 0xffff0000;
12246 uint32_t count= 16; /* Counts number of bits set in mask. */
12247 uint32_t lo = 1; /* Lower bound for number of sign bits. */
12248 uint32_t hi = 32; /* Upper bound for number of sign bits. */
12249
12250 while (lo + 1 < hi)
12251 {
12252 int32_t test = (value & mask);
12253
12254 if (test == 0 || test == mask)
12255 {
12256 lo = count;
12257 count = (lo + hi) / 2;
12258 mask >>= (count - lo);
12259 }
12260 else
12261 {
12262 hi = count;
12263 count = (lo + hi) / 2;
12264 mask <<= hi - count;
12265 }
12266 }
12267
12268 if (lo != hi)
12269 {
12270 int32_t test;
12271
12272 mask >>= 1;
12273 test = (value & mask);
12274
12275 if (test == 0 || test == mask)
12276 count = hi;
12277 else
12278 count = lo;
12279 }
12280
12281 return count;
12282}
12283
12284/* Counts the number of leading bits which are the same
12285 in a 64 bit value in the range 1 to 64. */
12286static uint64_t
12287leading64 (uint64_t value)
12288{
12289 int64_t mask= 0xffffffff00000000LL;
12290 uint64_t count = 32; /* Counts number of bits set in mask. */
12291 uint64_t lo = 1; /* Lower bound for number of sign bits. */
12292 uint64_t hi = 64; /* Upper bound for number of sign bits. */
12293
12294 while (lo + 1 < hi)
12295 {
12296 int64_t test = (value & mask);
12297
12298 if (test == 0 || test == mask)
12299 {
12300 lo = count;
12301 count = (lo + hi) / 2;
12302 mask >>= (count - lo);
12303 }
12304 else
12305 {
12306 hi = count;
12307 count = (lo + hi) / 2;
12308 mask <<= hi - count;
12309 }
12310 }
12311
12312 if (lo != hi)
12313 {
12314 int64_t test;
12315
12316 mask >>= 1;
12317 test = (value & mask);
12318
12319 if (test == 0 || test == mask)
12320 count = hi;
12321 else
12322 count = lo;
12323 }
12324
12325 return count;
12326}
12327
12328/* Bit operations. */
12329/* N.B register args may not be SP. */
12330
12331/* 32 bit count leading sign bits. */
12332static void
12333cls32 (sim_cpu *cpu)
12334{
ef0d8ffc
NC
12335 unsigned rn = INSTR (9, 5);
12336 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12337
12338 /* N.B. the result needs to exclude the leading bit. */
12339 aarch64_set_reg_u64
12340 (cpu, rd, NO_SP, leading32 (aarch64_get_reg_u32 (cpu, rn, NO_SP)) - 1);
12341}
12342
12343/* 64 bit count leading sign bits. */
12344static void
12345cls64 (sim_cpu *cpu)
12346{
ef0d8ffc
NC
12347 unsigned rn = INSTR (9, 5);
12348 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12349
12350 /* N.B. the result needs to exclude the leading bit. */
12351 aarch64_set_reg_u64
12352 (cpu, rd, NO_SP, leading64 (aarch64_get_reg_u64 (cpu, rn, NO_SP)) - 1);
12353}
12354
12355/* 32 bit count leading zero bits. */
12356static void
12357clz32 (sim_cpu *cpu)
12358{
ef0d8ffc
NC
12359 unsigned rn = INSTR (9, 5);
12360 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12361 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12362
12363 /* if the sign (top) bit is set then the count is 0. */
12364 if (pick32 (value, 31, 31))
12365 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
12366 else
12367 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading32 (value));
12368}
12369
12370/* 64 bit count leading zero bits. */
12371static void
12372clz64 (sim_cpu *cpu)
12373{
ef0d8ffc
NC
12374 unsigned rn = INSTR (9, 5);
12375 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12376 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12377
12378 /* if the sign (top) bit is set then the count is 0. */
12379 if (pick64 (value, 63, 63))
12380 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
12381 else
12382 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading64 (value));
12383}
12384
12385/* 32 bit reverse bits. */
12386static void
12387rbit32 (sim_cpu *cpu)
12388{
ef0d8ffc
NC
12389 unsigned rn = INSTR (9, 5);
12390 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12391 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12392 uint32_t result = 0;
12393 int i;
12394
12395 for (i = 0; i < 32; i++)
12396 {
12397 result <<= 1;
12398 result |= (value & 1);
12399 value >>= 1;
12400 }
12401 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12402}
12403
12404/* 64 bit reverse bits. */
12405static void
12406rbit64 (sim_cpu *cpu)
12407{
ef0d8ffc
NC
12408 unsigned rn = INSTR (9, 5);
12409 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12410 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12411 uint64_t result = 0;
12412 int i;
12413
12414 for (i = 0; i < 64; i++)
12415 {
12416 result <<= 1;
57aa1742 12417 result |= (value & 1UL);
2e8cf49e
NC
12418 value >>= 1;
12419 }
12420 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12421}
12422
12423/* 32 bit reverse bytes. */
12424static void
12425rev32 (sim_cpu *cpu)
12426{
ef0d8ffc
NC
12427 unsigned rn = INSTR (9, 5);
12428 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12429 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12430 uint32_t result = 0;
12431 int i;
12432
12433 for (i = 0; i < 4; i++)
12434 {
12435 result <<= 8;
12436 result |= (value & 0xff);
12437 value >>= 8;
12438 }
12439 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12440}
12441
12442/* 64 bit reverse bytes. */
12443static void
12444rev64 (sim_cpu *cpu)
12445{
ef0d8ffc
NC
12446 unsigned rn = INSTR (9, 5);
12447 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12448 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12449 uint64_t result = 0;
12450 int i;
12451
12452 for (i = 0; i < 8; i++)
12453 {
12454 result <<= 8;
12455 result |= (value & 0xffULL);
12456 value >>= 8;
12457 }
12458 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12459}
12460
12461/* 32 bit reverse shorts. */
12462/* N.B.this reverses the order of the bytes in each half word. */
12463static void
12464revh32 (sim_cpu *cpu)
12465{
ef0d8ffc
NC
12466 unsigned rn = INSTR (9, 5);
12467 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12468 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12469 uint32_t result = 0;
12470 int i;
12471
12472 for (i = 0; i < 2; i++)
12473 {
12474 result <<= 8;
12475 result |= (value & 0x00ff00ff);
12476 value >>= 8;
12477 }
12478 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12479}
12480
12481/* 64 bit reverse shorts. */
12482/* N.B.this reverses the order of the bytes in each half word. */
12483static void
12484revh64 (sim_cpu *cpu)
12485{
ef0d8ffc
NC
12486 unsigned rn = INSTR (9, 5);
12487 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12488 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12489 uint64_t result = 0;
12490 int i;
12491
12492 for (i = 0; i < 2; i++)
12493 {
12494 result <<= 8;
12495 result |= (value & 0x00ff00ff00ff00ffULL);
12496 value >>= 8;
12497 }
12498 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12499}
12500
12501static void
12502dexDataProc1Source (sim_cpu *cpu)
12503{
ef0d8ffc
NC
12504 /* instr[30] = 1
12505 instr[28,21] = 111010110
12506 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12507 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
2e8cf49e
NC
12508 instr[20,16] = opcode2 : 00000 ==> ok, ow ==> UNALLOC
12509 instr[15,10] = opcode : 000000 ==> RBIT, 000001 ==> REV16,
12510 000010 ==> REV, 000011 ==> UNALLOC
12511 000100 ==> CLZ, 000101 ==> CLS
12512 ow ==> UNALLOC
ef0d8ffc
NC
12513 instr[9,5] = rn : may not be SP
12514 instr[4,0] = rd : may not be SP. */
2e8cf49e 12515
ef0d8ffc
NC
12516 uint32_t S = INSTR (29, 29);
12517 uint32_t opcode2 = INSTR (20, 16);
12518 uint32_t opcode = INSTR (15, 10);
12519 uint32_t dispatch = ((INSTR (31, 31) << 3) | opcode);
2e8cf49e
NC
12520
12521 if (S == 1)
12522 HALT_UNALLOC;
12523
12524 if (opcode2 != 0)
12525 HALT_UNALLOC;
12526
12527 if (opcode & 0x38)
12528 HALT_UNALLOC;
12529
12530 switch (dispatch)
12531 {
12532 case 0: rbit32 (cpu); return;
12533 case 1: revh32 (cpu); return;
12534 case 2: rev32 (cpu); return;
12535 case 4: clz32 (cpu); return;
12536 case 5: cls32 (cpu); return;
12537 case 8: rbit64 (cpu); return;
12538 case 9: revh64 (cpu); return;
12539 case 10:rev32 (cpu); return;
12540 case 11:rev64 (cpu); return;
12541 case 12:clz64 (cpu); return;
12542 case 13:cls64 (cpu); return;
12543 default: HALT_UNALLOC;
12544 }
12545}
12546
12547/* Variable shift.
12548 Shifts by count supplied in register.
12549 N.B register args may not be SP.
12550 These all use the shifted auxiliary function for
12551 simplicity and clarity. Writing the actual shift
12552 inline would avoid a branch and so be faster but
12553 would also necessitate getting signs right. */
12554
12555/* 32 bit arithmetic shift right. */
12556static void
12557asrv32 (sim_cpu *cpu)
12558{
ef0d8ffc
NC
12559 unsigned rm = INSTR (20, 16);
12560 unsigned rn = INSTR (9, 5);
12561 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12562
12563 aarch64_set_reg_u64
12564 (cpu, rd, NO_SP,
12565 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ASR,
12566 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12567}
12568
12569/* 64 bit arithmetic shift right. */
12570static void
12571asrv64 (sim_cpu *cpu)
12572{
ef0d8ffc
NC
12573 unsigned rm = INSTR (20, 16);
12574 unsigned rn = INSTR (9, 5);
12575 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12576
12577 aarch64_set_reg_u64
12578 (cpu, rd, NO_SP,
12579 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ASR,
12580 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12581}
12582
12583/* 32 bit logical shift left. */
12584static void
12585lslv32 (sim_cpu *cpu)
12586{
ef0d8ffc
NC
12587 unsigned rm = INSTR (20, 16);
12588 unsigned rn = INSTR (9, 5);
12589 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12590
12591 aarch64_set_reg_u64
12592 (cpu, rd, NO_SP,
12593 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSL,
12594 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12595}
12596
12597/* 64 bit arithmetic shift left. */
12598static void
12599lslv64 (sim_cpu *cpu)
12600{
ef0d8ffc
NC
12601 unsigned rm = INSTR (20, 16);
12602 unsigned rn = INSTR (9, 5);
12603 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12604
12605 aarch64_set_reg_u64
12606 (cpu, rd, NO_SP,
12607 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSL,
12608 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12609}
12610
12611/* 32 bit logical shift right. */
12612static void
12613lsrv32 (sim_cpu *cpu)
12614{
ef0d8ffc
NC
12615 unsigned rm = INSTR (20, 16);
12616 unsigned rn = INSTR (9, 5);
12617 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12618
12619 aarch64_set_reg_u64
12620 (cpu, rd, NO_SP,
12621 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSR,
12622 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12623}
12624
12625/* 64 bit logical shift right. */
12626static void
12627lsrv64 (sim_cpu *cpu)
12628{
ef0d8ffc
NC
12629 unsigned rm = INSTR (20, 16);
12630 unsigned rn = INSTR (9, 5);
12631 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12632
12633 aarch64_set_reg_u64
12634 (cpu, rd, NO_SP,
12635 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSR,
12636 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12637}
12638
12639/* 32 bit rotate right. */
12640static void
12641rorv32 (sim_cpu *cpu)
12642{
ef0d8ffc
NC
12643 unsigned rm = INSTR (20, 16);
12644 unsigned rn = INSTR (9, 5);
12645 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12646
12647 aarch64_set_reg_u64
12648 (cpu, rd, NO_SP,
12649 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ROR,
12650 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12651}
12652
12653/* 64 bit rotate right. */
12654static void
12655rorv64 (sim_cpu *cpu)
12656{
ef0d8ffc
NC
12657 unsigned rm = INSTR (20, 16);
12658 unsigned rn = INSTR (9, 5);
12659 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12660
12661 aarch64_set_reg_u64
12662 (cpu, rd, NO_SP,
12663 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ROR,
12664 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12665}
12666
12667
12668/* divide. */
12669
12670/* 32 bit signed divide. */
12671static void
12672cpuiv32 (sim_cpu *cpu)
12673{
ef0d8ffc
NC
12674 unsigned rm = INSTR (20, 16);
12675 unsigned rn = INSTR (9, 5);
12676 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12677 /* N.B. the pseudo-code does the divide using 64 bit data. */
12678 /* TODO : check that this rounds towards zero as required. */
12679 int64_t dividend = aarch64_get_reg_s32 (cpu, rn, NO_SP);
12680 int64_t divisor = aarch64_get_reg_s32 (cpu, rm, NO_SP);
12681
12682 aarch64_set_reg_s64 (cpu, rd, NO_SP,
12683 divisor ? ((int32_t) (dividend / divisor)) : 0);
12684}
12685
12686/* 64 bit signed divide. */
12687static void
12688cpuiv64 (sim_cpu *cpu)
12689{
ef0d8ffc
NC
12690 unsigned rm = INSTR (20, 16);
12691 unsigned rn = INSTR (9, 5);
12692 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12693
12694 /* TODO : check that this rounds towards zero as required. */
12695 int64_t divisor = aarch64_get_reg_s64 (cpu, rm, NO_SP);
12696
12697 aarch64_set_reg_s64
12698 (cpu, rd, NO_SP,
12699 divisor ? (aarch64_get_reg_s64 (cpu, rn, NO_SP) / divisor) : 0);
12700}
12701
12702/* 32 bit unsigned divide. */
12703static void
12704udiv32 (sim_cpu *cpu)
12705{
ef0d8ffc
NC
12706 unsigned rm = INSTR (20, 16);
12707 unsigned rn = INSTR (9, 5);
12708 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12709
12710 /* N.B. the pseudo-code does the divide using 64 bit data. */
12711 uint64_t dividend = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12712 uint64_t divisor = aarch64_get_reg_u32 (cpu, rm, NO_SP);
12713
12714 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12715 divisor ? (uint32_t) (dividend / divisor) : 0);
12716}
12717
12718/* 64 bit unsigned divide. */
12719static void
12720udiv64 (sim_cpu *cpu)
12721{
ef0d8ffc
NC
12722 unsigned rm = INSTR (20, 16);
12723 unsigned rn = INSTR (9, 5);
12724 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12725
12726 /* TODO : check that this rounds towards zero as required. */
12727 uint64_t divisor = aarch64_get_reg_u64 (cpu, rm, NO_SP);
12728
12729 aarch64_set_reg_u64
12730 (cpu, rd, NO_SP,
12731 divisor ? (aarch64_get_reg_u64 (cpu, rn, NO_SP) / divisor) : 0);
12732}
12733
12734static void
12735dexDataProc2Source (sim_cpu *cpu)
12736{
12737 /* assert instr[30] == 0
12738 instr[28,21] == 11010110
12739 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12740 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
12741 instr[15,10] = opcode : 000010 ==> UDIV, 000011 ==> CPUIV,
12742 001000 ==> LSLV, 001001 ==> LSRV
12743 001010 ==> ASRV, 001011 ==> RORV
12744 ow ==> UNALLOC. */
12745
12746 uint32_t dispatch;
ef0d8ffc
NC
12747 uint32_t S = INSTR (29, 29);
12748 uint32_t opcode = INSTR (15, 10);
2e8cf49e
NC
12749
12750 if (S == 1)
12751 HALT_UNALLOC;
12752
12753 if (opcode & 0x34)
12754 HALT_UNALLOC;
12755
ef0d8ffc 12756 dispatch = ( (INSTR (31, 31) << 3)
2e8cf49e
NC
12757 | (uimm (opcode, 3, 3) << 2)
12758 | uimm (opcode, 1, 0));
12759 switch (dispatch)
12760 {
12761 case 2: udiv32 (cpu); return;
12762 case 3: cpuiv32 (cpu); return;
12763 case 4: lslv32 (cpu); return;
12764 case 5: lsrv32 (cpu); return;
12765 case 6: asrv32 (cpu); return;
12766 case 7: rorv32 (cpu); return;
12767 case 10: udiv64 (cpu); return;
12768 case 11: cpuiv64 (cpu); return;
12769 case 12: lslv64 (cpu); return;
12770 case 13: lsrv64 (cpu); return;
12771 case 14: asrv64 (cpu); return;
12772 case 15: rorv64 (cpu); return;
12773 default: HALT_UNALLOC;
12774 }
12775}
12776
12777
12778/* Multiply. */
12779
12780/* 32 bit multiply and add. */
12781static void
12782madd32 (sim_cpu *cpu)
12783{
ef0d8ffc
NC
12784 unsigned rm = INSTR (20, 16);
12785 unsigned ra = INSTR (14, 10);
12786 unsigned rn = INSTR (9, 5);
12787 unsigned rd = INSTR (4, 0);
2e8cf49e 12788
2cdad34c 12789 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12790 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12791 aarch64_get_reg_u32 (cpu, ra, NO_SP)
12792 + aarch64_get_reg_u32 (cpu, rn, NO_SP)
12793 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
12794}
12795
12796/* 64 bit multiply and add. */
12797static void
12798madd64 (sim_cpu *cpu)
12799{
ef0d8ffc
NC
12800 unsigned rm = INSTR (20, 16);
12801 unsigned ra = INSTR (14, 10);
12802 unsigned rn = INSTR (9, 5);
12803 unsigned rd = INSTR (4, 0);
2e8cf49e 12804
2cdad34c 12805 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12806 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12807 aarch64_get_reg_u64 (cpu, ra, NO_SP)
2cdad34c
NC
12808 + (aarch64_get_reg_u64 (cpu, rn, NO_SP)
12809 * aarch64_get_reg_u64 (cpu, rm, NO_SP)));
2e8cf49e
NC
12810}
12811
12812/* 32 bit multiply and sub. */
12813static void
12814msub32 (sim_cpu *cpu)
12815{
ef0d8ffc
NC
12816 unsigned rm = INSTR (20, 16);
12817 unsigned ra = INSTR (14, 10);
12818 unsigned rn = INSTR (9, 5);
12819 unsigned rd = INSTR (4, 0);
2e8cf49e 12820
2cdad34c 12821 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12822 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12823 aarch64_get_reg_u32 (cpu, ra, NO_SP)
12824 - aarch64_get_reg_u32 (cpu, rn, NO_SP)
12825 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
12826}
12827
12828/* 64 bit multiply and sub. */
12829static void
12830msub64 (sim_cpu *cpu)
12831{
ef0d8ffc
NC
12832 unsigned rm = INSTR (20, 16);
12833 unsigned ra = INSTR (14, 10);
12834 unsigned rn = INSTR (9, 5);
12835 unsigned rd = INSTR (4, 0);
2e8cf49e 12836
2cdad34c 12837 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12838 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12839 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12840 - aarch64_get_reg_u64 (cpu, rn, NO_SP)
12841 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
12842}
12843
12844/* Signed multiply add long -- source, source2 : 32 bit, source3 : 64 bit. */
12845static void
12846smaddl (sim_cpu *cpu)
12847{
ef0d8ffc
NC
12848 unsigned rm = INSTR (20, 16);
12849 unsigned ra = INSTR (14, 10);
12850 unsigned rn = INSTR (9, 5);
12851 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12852
12853 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12854 obtain a 64 bit product. */
12855 aarch64_set_reg_s64
12856 (cpu, rd, NO_SP,
12857 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12858 + ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12859 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12860}
12861
12862/* Signed multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12863static void
12864smsubl (sim_cpu *cpu)
12865{
ef0d8ffc
NC
12866 unsigned rm = INSTR (20, 16);
12867 unsigned ra = INSTR (14, 10);
12868 unsigned rn = INSTR (9, 5);
12869 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12870
12871 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12872 obtain a 64 bit product. */
12873 aarch64_set_reg_s64
12874 (cpu, rd, NO_SP,
12875 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12876 - ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12877 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12878}
12879
12880/* Integer Multiply/Divide. */
12881
12882/* First some macros and a helper function. */
12883/* Macros to test or access elements of 64 bit words. */
12884
12885/* Mask used to access lo 32 bits of 64 bit unsigned int. */
12886#define LOW_WORD_MASK ((1ULL << 32) - 1)
12887/* Return the lo 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12888#define lowWordToU64(_value_u64) ((_value_u64) & LOW_WORD_MASK)
12889/* Return the hi 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12890#define highWordToU64(_value_u64) ((_value_u64) >> 32)
12891
12892/* Offset of sign bit in 64 bit signed integger. */
12893#define SIGN_SHIFT_U64 63
12894/* The sign bit itself -- also identifies the minimum negative int value. */
12895#define SIGN_BIT_U64 (1UL << SIGN_SHIFT_U64)
12896/* Return true if a 64 bit signed int presented as an unsigned int is the
12897 most negative value. */
12898#define isMinimumU64(_value_u64) ((_value_u64) == SIGN_BIT_U64)
12899/* Return true (non-zero) if a 64 bit signed int presented as an unsigned
12900 int has its sign bit set to false. */
12901#define isSignSetU64(_value_u64) ((_value_u64) & SIGN_BIT_U64)
12902/* Return 1L or -1L according to whether a 64 bit signed int presented as
12903 an unsigned int has its sign bit set or not. */
12904#define signOfU64(_value_u64) (1L + (((value_u64) >> SIGN_SHIFT_U64) * -2L)
12905/* Clear the sign bit of a 64 bit signed int presented as an unsigned int. */
12906#define clearSignU64(_value_u64) ((_value_u64) &= ~SIGN_BIT_U64)
12907
12908/* Multiply two 64 bit ints and return.
12909 the hi 64 bits of the 128 bit product. */
12910
12911static uint64_t
12912mul64hi (uint64_t value1, uint64_t value2)
12913{
12914 uint64_t resultmid1;
12915 uint64_t result;
12916 uint64_t value1_lo = lowWordToU64 (value1);
12917 uint64_t value1_hi = highWordToU64 (value1) ;
12918 uint64_t value2_lo = lowWordToU64 (value2);
12919 uint64_t value2_hi = highWordToU64 (value2);
12920
12921 /* Cross-multiply and collect results. */
2e8cf49e
NC
12922 uint64_t xproductlo = value1_lo * value2_lo;
12923 uint64_t xproductmid1 = value1_lo * value2_hi;
12924 uint64_t xproductmid2 = value1_hi * value2_lo;
12925 uint64_t xproducthi = value1_hi * value2_hi;
12926 uint64_t carry = 0;
12927 /* Start accumulating 64 bit results. */
12928 /* Drop bottom half of lowest cross-product. */
12929 uint64_t resultmid = xproductlo >> 32;
12930 /* Add in middle products. */
12931 resultmid = resultmid + xproductmid1;
12932
12933 /* Check for overflow. */
12934 if (resultmid < xproductmid1)
12935 /* Carry over 1 into top cross-product. */
12936 carry++;
12937
12938 resultmid1 = resultmid + xproductmid2;
12939
12940 /* Check for overflow. */
12941 if (resultmid1 < xproductmid2)
12942 /* Carry over 1 into top cross-product. */
12943 carry++;
12944
12945 /* Drop lowest 32 bits of middle cross-product. */
12946 result = resultmid1 >> 32;
12947
12948 /* Add top cross-product plus and any carry. */
12949 result += xproducthi + carry;
12950
12951 return result;
12952}
12953
12954/* Signed multiply high, source, source2 :
12955 64 bit, dest <-- high 64-bit of result. */
12956static void
12957smulh (sim_cpu *cpu)
12958{
12959 uint64_t uresult;
ef0d8ffc
NC
12960 int64_t result;
12961 unsigned rm = INSTR (20, 16);
12962 unsigned rn = INSTR (9, 5);
12963 unsigned rd = INSTR (4, 0);
12964 GReg ra = INSTR (14, 10);
12965 int64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12966 int64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2e8cf49e
NC
12967 uint64_t uvalue1;
12968 uint64_t uvalue2;
ef0d8ffc 12969 int64_t signum = 1;
2e8cf49e
NC
12970
12971 if (ra != R31)
12972 HALT_UNALLOC;
12973
12974 /* Convert to unsigned and use the unsigned mul64hi routine
12975 the fix the sign up afterwards. */
12976 if (value1 < 0)
12977 {
12978 signum *= -1L;
12979 uvalue1 = -value1;
12980 }
12981 else
12982 {
12983 uvalue1 = value1;
12984 }
12985
12986 if (value2 < 0)
12987 {
12988 signum *= -1L;
12989 uvalue2 = -value2;
12990 }
12991 else
12992 {
12993 uvalue2 = value2;
12994 }
12995
2cdad34c 12996 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12997 uresult = mul64hi (uvalue1, uvalue2);
12998 result = uresult;
12999 result *= signum;
13000
13001 aarch64_set_reg_s64 (cpu, rd, NO_SP, result);
13002}
13003
13004/* Unsigned multiply add long -- source, source2 :
13005 32 bit, source3 : 64 bit. */
13006static void
13007umaddl (sim_cpu *cpu)
13008{
ef0d8ffc
NC
13009 unsigned rm = INSTR (20, 16);
13010 unsigned ra = INSTR (14, 10);
13011 unsigned rn = INSTR (9, 5);
13012 unsigned rd = INSTR (4, 0);
2e8cf49e 13013
2cdad34c 13014 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13015 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
13016 obtain a 64 bit product. */
13017 aarch64_set_reg_u64
13018 (cpu, rd, NO_SP,
13019 aarch64_get_reg_u64 (cpu, ra, NO_SP)
13020 + ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
13021 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
13022}
13023
13024/* Unsigned multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
13025static void
13026umsubl (sim_cpu *cpu)
13027{
ef0d8ffc
NC
13028 unsigned rm = INSTR (20, 16);
13029 unsigned ra = INSTR (14, 10);
13030 unsigned rn = INSTR (9, 5);
13031 unsigned rd = INSTR (4, 0);
2e8cf49e 13032
2cdad34c 13033 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13034 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
13035 obtain a 64 bit product. */
13036 aarch64_set_reg_u64
13037 (cpu, rd, NO_SP,
13038 aarch64_get_reg_u64 (cpu, ra, NO_SP)
13039 - ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
13040 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
13041}
13042
13043/* Unsigned multiply high, source, source2 :
13044 64 bit, dest <-- high 64-bit of result. */
13045static void
13046umulh (sim_cpu *cpu)
13047{
ef0d8ffc
NC
13048 unsigned rm = INSTR (20, 16);
13049 unsigned rn = INSTR (9, 5);
13050 unsigned rd = INSTR (4, 0);
13051 GReg ra = INSTR (14, 10);
2e8cf49e
NC
13052
13053 if (ra != R31)
13054 HALT_UNALLOC;
13055
2cdad34c 13056 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13057 aarch64_set_reg_u64 (cpu, rd, NO_SP,
13058 mul64hi (aarch64_get_reg_u64 (cpu, rn, NO_SP),
13059 aarch64_get_reg_u64 (cpu, rm, NO_SP)));
13060}
13061
13062static void
13063dexDataProc3Source (sim_cpu *cpu)
13064{
13065 /* assert instr[28,24] == 11011. */
13066 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit (for rd at least)
13067 instr[30,29] = op54 : 00 ==> ok, ow ==> UNALLOC
13068 instr[23,21] = op31 : 111 ==> UNALLOC, o2 ==> ok
13069 instr[15] = o0 : 0/1 ==> ok
13070 instr[23,21:15] ==> op : 0000 ==> MADD, 0001 ==> MSUB, (32/64 bit)
13071 0010 ==> SMADDL, 0011 ==> SMSUBL, (64 bit only)
13072 0100 ==> SMULH, (64 bit only)
13073 1010 ==> UMADDL, 1011 ==> UNSUBL, (64 bit only)
13074 1100 ==> UMULH (64 bit only)
13075 ow ==> UNALLOC. */
13076
13077 uint32_t dispatch;
ef0d8ffc
NC
13078 uint32_t size = INSTR (31, 31);
13079 uint32_t op54 = INSTR (30, 29);
13080 uint32_t op31 = INSTR (23, 21);
13081 uint32_t o0 = INSTR (15, 15);
2e8cf49e
NC
13082
13083 if (op54 != 0)
13084 HALT_UNALLOC;
13085
13086 if (size == 0)
13087 {
13088 if (op31 != 0)
13089 HALT_UNALLOC;
13090
13091 if (o0 == 0)
13092 madd32 (cpu);
13093 else
13094 msub32 (cpu);
13095 return;
13096 }
13097
13098 dispatch = (op31 << 1) | o0;
13099
13100 switch (dispatch)
13101 {
13102 case 0: madd64 (cpu); return;
13103 case 1: msub64 (cpu); return;
13104 case 2: smaddl (cpu); return;
13105 case 3: smsubl (cpu); return;
13106 case 4: smulh (cpu); return;
13107 case 10: umaddl (cpu); return;
13108 case 11: umsubl (cpu); return;
13109 case 12: umulh (cpu); return;
13110 default: HALT_UNALLOC;
13111 }
13112}
13113
13114static void
13115dexDPReg (sim_cpu *cpu)
13116{
13117 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
13118 assert group == GROUP_DPREG_0101 || group == GROUP_DPREG_1101
13119 bits [28:24:21] of a DPReg are the secondary dispatch vector. */
13120 uint32_t group2 = dispatchDPReg (aarch64_get_instr (cpu));
13121
13122 switch (group2)
13123 {
13124 case DPREG_LOG_000:
13125 case DPREG_LOG_001:
13126 dexLogicalShiftedRegister (cpu); return;
13127
13128 case DPREG_ADDSHF_010:
13129 dexAddSubtractShiftedRegister (cpu); return;
13130
13131 case DPREG_ADDEXT_011:
13132 dexAddSubtractExtendedRegister (cpu); return;
13133
13134 case DPREG_ADDCOND_100:
13135 {
13136 /* This set bundles a variety of different operations. */
13137 /* Check for. */
13138 /* 1) add/sub w carry. */
13139 uint32_t mask1 = 0x1FE00000U;
13140 uint32_t val1 = 0x1A000000U;
13141 /* 2) cond compare register/immediate. */
13142 uint32_t mask2 = 0x1FE00000U;
13143 uint32_t val2 = 0x1A400000U;
13144 /* 3) cond select. */
13145 uint32_t mask3 = 0x1FE00000U;
13146 uint32_t val3 = 0x1A800000U;
13147 /* 4) data proc 1/2 source. */
13148 uint32_t mask4 = 0x1FE00000U;
13149 uint32_t val4 = 0x1AC00000U;
13150
13151 if ((aarch64_get_instr (cpu) & mask1) == val1)
13152 dexAddSubtractWithCarry (cpu);
13153
13154 else if ((aarch64_get_instr (cpu) & mask2) == val2)
13155 CondCompare (cpu);
13156
13157 else if ((aarch64_get_instr (cpu) & mask3) == val3)
13158 dexCondSelect (cpu);
13159
13160 else if ((aarch64_get_instr (cpu) & mask4) == val4)
13161 {
13162 /* Bit 30 is clear for data proc 2 source
13163 and set for data proc 1 source. */
13164 if (aarch64_get_instr (cpu) & (1U << 30))
13165 dexDataProc1Source (cpu);
13166 else
13167 dexDataProc2Source (cpu);
13168 }
13169
13170 else
13171 /* Should not reach here. */
13172 HALT_NYI;
13173
13174 return;
13175 }
13176
13177 case DPREG_3SRC_110:
13178 dexDataProc3Source (cpu); return;
13179
13180 case DPREG_UNALLOC_101:
13181 HALT_UNALLOC;
13182
13183 case DPREG_3SRC_111:
13184 dexDataProc3Source (cpu); return;
13185
13186 default:
13187 /* Should never reach here. */
13188 HALT_NYI;
13189 }
13190}
13191
13192/* Unconditional Branch immediate.
13193 Offset is a PC-relative byte offset in the range +/- 128MiB.
13194 The offset is assumed to be raw from the decode i.e. the
13195 simulator is expected to scale them from word offsets to byte. */
13196
13197/* Unconditional branch. */
13198static void
13199buc (sim_cpu *cpu, int32_t offset)
13200{
13201 aarch64_set_next_PC_by_offset (cpu, offset);
13202}
13203
13204static unsigned stack_depth = 0;
13205
13206/* Unconditional branch and link -- writes return PC to LR. */
13207static void
13208bl (sim_cpu *cpu, int32_t offset)
13209{
2cdad34c 13210 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13211 aarch64_save_LR (cpu);
13212 aarch64_set_next_PC_by_offset (cpu, offset);
13213
13214 if (TRACE_BRANCH_P (cpu))
13215 {
13216 ++ stack_depth;
13217 TRACE_BRANCH (cpu,
13218 " %*scall %" PRIx64 " [%s]"
13219 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
13220 stack_depth, " ", aarch64_get_next_PC (cpu),
5357150c
MF
13221 aarch64_get_func (CPU_STATE (cpu),
13222 aarch64_get_next_PC (cpu)),
2e8cf49e
NC
13223 aarch64_get_reg_u64 (cpu, 0, NO_SP),
13224 aarch64_get_reg_u64 (cpu, 1, NO_SP),
13225 aarch64_get_reg_u64 (cpu, 2, NO_SP)
13226 );
13227 }
13228}
13229
13230/* Unconditional Branch register.
13231 Branch/return address is in source register. */
13232
13233/* Unconditional branch. */
13234static void
13235br (sim_cpu *cpu)
13236{
ef0d8ffc 13237 unsigned rn = INSTR (9, 5);
2cdad34c 13238 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13239 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13240}
13241
13242/* Unconditional branch and link -- writes return PC to LR. */
13243static void
13244blr (sim_cpu *cpu)
13245{
ef0d8ffc 13246 unsigned rn = INSTR (9, 5);
2e8cf49e 13247
2cdad34c 13248 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13249 /* The pseudo code in the spec says we update LR before fetching.
13250 the value from the rn. */
13251 aarch64_save_LR (cpu);
13252 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13253
13254 if (TRACE_BRANCH_P (cpu))
13255 {
13256 ++ stack_depth;
13257 TRACE_BRANCH (cpu,
13258 " %*scall %" PRIx64 " [%s]"
13259 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
13260 stack_depth, " ", aarch64_get_next_PC (cpu),
5357150c
MF
13261 aarch64_get_func (CPU_STATE (cpu),
13262 aarch64_get_next_PC (cpu)),
2e8cf49e
NC
13263 aarch64_get_reg_u64 (cpu, 0, NO_SP),
13264 aarch64_get_reg_u64 (cpu, 1, NO_SP),
13265 aarch64_get_reg_u64 (cpu, 2, NO_SP)
13266 );
13267 }
13268}
13269
13270/* Return -- assembler will default source to LR this is functionally
13271 equivalent to br but, presumably, unlike br it side effects the
13272 branch predictor. */
13273static void
13274ret (sim_cpu *cpu)
13275{
ef0d8ffc 13276 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
13277 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13278
2cdad34c 13279 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13280 if (TRACE_BRANCH_P (cpu))
13281 {
13282 TRACE_BRANCH (cpu,
13283 " %*sreturn [result: %" PRIx64 "]",
13284 stack_depth, " ", aarch64_get_reg_u64 (cpu, 0, NO_SP));
13285 -- stack_depth;
13286 }
13287}
13288
13289/* NOP -- we implement this and call it from the decode in case we
13290 want to intercept it later. */
13291
13292static void
13293nop (sim_cpu *cpu)
13294{
2cdad34c 13295 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13296}
13297
13298/* Data synchronization barrier. */
13299
13300static void
13301dsb (sim_cpu *cpu)
13302{
2cdad34c 13303 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13304}
13305
13306/* Data memory barrier. */
13307
13308static void
13309dmb (sim_cpu *cpu)
13310{
2cdad34c 13311 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13312}
13313
13314/* Instruction synchronization barrier. */
13315
13316static void
13317isb (sim_cpu *cpu)
13318{
2cdad34c 13319 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13320}
13321
13322static void
13323dexBranchImmediate (sim_cpu *cpu)
13324{
13325 /* assert instr[30,26] == 00101
13326 instr[31] ==> 0 == B, 1 == BL
13327 instr[25,0] == imm26 branch offset counted in words. */
13328
ef0d8ffc 13329 uint32_t top = INSTR (31, 31);
2e8cf49e
NC
13330 /* We have a 26 byte signed word offset which we need to pass to the
13331 execute routine as a signed byte offset. */
13332 int32_t offset = simm32 (aarch64_get_instr (cpu), 25, 0) << 2;
13333
13334 if (top)
13335 bl (cpu, offset);
13336 else
13337 buc (cpu, offset);
13338}
13339
13340/* Control Flow. */
13341
13342/* Conditional branch
13343
13344 Offset is a PC-relative byte offset in the range +/- 1MiB pos is
13345 a bit position in the range 0 .. 63
13346
13347 cc is a CondCode enum value as pulled out of the decode
13348
13349 N.B. any offset register (source) can only be Xn or Wn. */
13350
13351static void
13352bcc (sim_cpu *cpu, int32_t offset, CondCode cc)
13353{
2cdad34c
NC
13354 /* The test returns TRUE if CC is met. */
13355 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13356 if (testConditionCode (cpu, cc))
13357 aarch64_set_next_PC_by_offset (cpu, offset);
13358}
13359
13360/* 32 bit branch on register non-zero. */
13361static void
13362cbnz32 (sim_cpu *cpu, int32_t offset)
13363{
ef0d8ffc 13364 unsigned rt = INSTR (4, 0);
2e8cf49e 13365
2cdad34c 13366 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13367 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) != 0)
13368 aarch64_set_next_PC_by_offset (cpu, offset);
13369}
13370
13371/* 64 bit branch on register zero. */
13372static void
13373cbnz (sim_cpu *cpu, int32_t offset)
13374{
ef0d8ffc 13375 unsigned rt = INSTR (4, 0);
2e8cf49e 13376
2cdad34c 13377 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13378 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) != 0)
13379 aarch64_set_next_PC_by_offset (cpu, offset);
13380}
13381
13382/* 32 bit branch on register non-zero. */
13383static void
13384cbz32 (sim_cpu *cpu, int32_t offset)
13385{
ef0d8ffc 13386 unsigned rt = INSTR (4, 0);
2e8cf49e 13387
2cdad34c 13388 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13389 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) == 0)
13390 aarch64_set_next_PC_by_offset (cpu, offset);
13391}
13392
13393/* 64 bit branch on register zero. */
13394static void
13395cbz (sim_cpu *cpu, int32_t offset)
13396{
ef0d8ffc 13397 unsigned rt = INSTR (4, 0);
2e8cf49e 13398
2cdad34c 13399 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13400 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) == 0)
13401 aarch64_set_next_PC_by_offset (cpu, offset);
13402}
13403
13404/* Branch on register bit test non-zero -- one size fits all. */
13405static void
13406tbnz (sim_cpu *cpu, uint32_t pos, int32_t offset)
13407{
ef0d8ffc 13408 unsigned rt = INSTR (4, 0);
2e8cf49e 13409
2cdad34c 13410 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
668650d5 13411 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) & (((uint64_t) 1) << pos))
2e8cf49e
NC
13412 aarch64_set_next_PC_by_offset (cpu, offset);
13413}
13414
2cdad34c 13415/* Branch on register bit test zero -- one size fits all. */
2e8cf49e
NC
13416static void
13417tbz (sim_cpu *cpu, uint32_t pos, int32_t offset)
13418{
ef0d8ffc 13419 unsigned rt = INSTR (4, 0);
2e8cf49e 13420
2cdad34c 13421 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
668650d5 13422 if (!(aarch64_get_reg_u64 (cpu, rt, NO_SP) & (((uint64_t) 1) << pos)))
2e8cf49e
NC
13423 aarch64_set_next_PC_by_offset (cpu, offset);
13424}
13425
13426static void
13427dexCompareBranchImmediate (sim_cpu *cpu)
13428{
13429 /* instr[30,25] = 01 1010
13430 instr[31] = size : 0 ==> 32, 1 ==> 64
13431 instr[24] = op : 0 ==> CBZ, 1 ==> CBNZ
13432 instr[23,5] = simm19 branch offset counted in words
13433 instr[4,0] = rt */
13434
ef0d8ffc
NC
13435 uint32_t size = INSTR (31, 31);
13436 uint32_t op = INSTR (24, 24);
2e8cf49e
NC
13437 int32_t offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
13438
13439 if (size == 0)
13440 {
13441 if (op == 0)
13442 cbz32 (cpu, offset);
13443 else
13444 cbnz32 (cpu, offset);
13445 }
13446 else
13447 {
13448 if (op == 0)
13449 cbz (cpu, offset);
13450 else
13451 cbnz (cpu, offset);
13452 }
13453}
13454
13455static void
13456dexTestBranchImmediate (sim_cpu *cpu)
13457{
13458 /* instr[31] = b5 : bit 5 of test bit idx
13459 instr[30,25] = 01 1011
13460 instr[24] = op : 0 ==> TBZ, 1 == TBNZ
13461 instr[23,19] = b40 : bits 4 to 0 of test bit idx
13462 instr[18,5] = simm14 : signed offset counted in words
13463 instr[4,0] = uimm5 */
13464
668650d5 13465 uint32_t pos = ((INSTR (31, 31) << 5) | INSTR (23, 19));
2e8cf49e
NC
13466 int32_t offset = simm32 (aarch64_get_instr (cpu), 18, 5) << 2;
13467
13468 NYI_assert (30, 25, 0x1b);
13469
ef0d8ffc 13470 if (INSTR (24, 24) == 0)
2e8cf49e
NC
13471 tbz (cpu, pos, offset);
13472 else
13473 tbnz (cpu, pos, offset);
13474}
13475
13476static void
13477dexCondBranchImmediate (sim_cpu *cpu)
13478{
13479 /* instr[31,25] = 010 1010
13480 instr[24] = op1; op => 00 ==> B.cond
13481 instr[23,5] = simm19 : signed offset counted in words
13482 instr[4] = op0
13483 instr[3,0] = cond */
13484
13485 int32_t offset;
ef0d8ffc 13486 uint32_t op = ((INSTR (24, 24) << 1) | INSTR (4, 4));
2e8cf49e
NC
13487
13488 NYI_assert (31, 25, 0x2a);
13489
13490 if (op != 0)
13491 HALT_UNALLOC;
13492
13493 offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
2e8cf49e 13494
ef0d8ffc 13495 bcc (cpu, offset, INSTR (3, 0));
2e8cf49e
NC
13496}
13497
13498static void
13499dexBranchRegister (sim_cpu *cpu)
13500{
13501 /* instr[31,25] = 110 1011
13502 instr[24,21] = op : 0 ==> BR, 1 => BLR, 2 => RET, 3 => ERET, 4 => DRPS
13503 instr[20,16] = op2 : must be 11111
13504 instr[15,10] = op3 : must be 000000
13505 instr[4,0] = op2 : must be 11111. */
13506
ef0d8ffc
NC
13507 uint32_t op = INSTR (24, 21);
13508 uint32_t op2 = INSTR (20, 16);
13509 uint32_t op3 = INSTR (15, 10);
13510 uint32_t op4 = INSTR (4, 0);
2e8cf49e
NC
13511
13512 NYI_assert (31, 25, 0x6b);
13513
13514 if (op2 != 0x1F || op3 != 0 || op4 != 0)
13515 HALT_UNALLOC;
13516
13517 if (op == 0)
13518 br (cpu);
13519
13520 else if (op == 1)
13521 blr (cpu);
13522
13523 else if (op == 2)
13524 ret (cpu);
13525
13526 else
13527 {
ef0d8ffc 13528 /* ERET and DRPS accept 0b11111 for rn = instr [4,0]. */
2e8cf49e 13529 /* anything else is unallocated. */
ef0d8ffc 13530 uint32_t rn = INSTR (4, 0);
2e8cf49e
NC
13531
13532 if (rn != 0x1f)
13533 HALT_UNALLOC;
13534
13535 if (op == 4 || op == 5)
13536 HALT_NYI;
13537
13538 HALT_UNALLOC;
13539 }
13540}
13541
13542/* FIXME: We should get the Angel SWI values from ../../libgloss/aarch64/svc.h
13543 but this may not be available. So instead we define the values we need
13544 here. */
13545#define AngelSVC_Reason_Open 0x01
13546#define AngelSVC_Reason_Close 0x02
13547#define AngelSVC_Reason_Write 0x05
13548#define AngelSVC_Reason_Read 0x06
13549#define AngelSVC_Reason_IsTTY 0x09
13550#define AngelSVC_Reason_Seek 0x0A
13551#define AngelSVC_Reason_FLen 0x0C
13552#define AngelSVC_Reason_Remove 0x0E
13553#define AngelSVC_Reason_Rename 0x0F
13554#define AngelSVC_Reason_Clock 0x10
13555#define AngelSVC_Reason_Time 0x11
13556#define AngelSVC_Reason_System 0x12
13557#define AngelSVC_Reason_Errno 0x13
13558#define AngelSVC_Reason_GetCmdLine 0x15
13559#define AngelSVC_Reason_HeapInfo 0x16
13560#define AngelSVC_Reason_ReportException 0x18
13561#define AngelSVC_Reason_Elapsed 0x30
13562
13563
13564static void
13565handle_halt (sim_cpu *cpu, uint32_t val)
13566{
13567 uint64_t result = 0;
13568
2cdad34c 13569 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13570 if (val != 0xf000)
13571 {
13572 TRACE_SYSCALL (cpu, " HLT [0x%x]", val);
13573 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13574 sim_stopped, SIM_SIGTRAP);
13575 }
13576
13577 /* We have encountered an Angel SVC call. See if we can process it. */
13578 switch (aarch64_get_reg_u32 (cpu, 0, NO_SP))
13579 {
13580 case AngelSVC_Reason_HeapInfo:
13581 {
13582 /* Get the values. */
13583 uint64_t stack_top = aarch64_get_stack_start (cpu);
13584 uint64_t heap_base = aarch64_get_heap_start (cpu);
13585
13586 /* Get the pointer */
13587 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13588 ptr = aarch64_get_mem_u64 (cpu, ptr);
13589
13590 /* Fill in the memory block. */
13591 /* Start addr of heap. */
13592 aarch64_set_mem_u64 (cpu, ptr + 0, heap_base);
13593 /* End addr of heap. */
13594 aarch64_set_mem_u64 (cpu, ptr + 8, stack_top);
13595 /* Lowest stack addr. */
13596 aarch64_set_mem_u64 (cpu, ptr + 16, heap_base);
13597 /* Initial stack addr. */
13598 aarch64_set_mem_u64 (cpu, ptr + 24, stack_top);
13599
13600 TRACE_SYSCALL (cpu, " AngelSVC: Get Heap Info");
13601 }
13602 break;
13603
13604 case AngelSVC_Reason_Open:
13605 {
13606 /* Get the pointer */
13607 /* uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);. */
13608 /* FIXME: For now we just assume that we will only be asked
13609 to open the standard file descriptors. */
13610 static int fd = 0;
13611 result = fd ++;
13612
13613 TRACE_SYSCALL (cpu, " AngelSVC: Open file %d", fd - 1);
13614 }
13615 break;
13616
13617 case AngelSVC_Reason_Close:
13618 {
13619 uint64_t fh = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13620 TRACE_SYSCALL (cpu, " AngelSVC: Close file %d", (int) fh);
13621 result = 0;
13622 }
13623 break;
13624
13625 case AngelSVC_Reason_Errno:
13626 result = 0;
13627 TRACE_SYSCALL (cpu, " AngelSVC: Get Errno");
13628 break;
13629
13630 case AngelSVC_Reason_Clock:
13631 result =
13632#ifdef CLOCKS_PER_SEC
13633 (CLOCKS_PER_SEC >= 100)
13634 ? (clock () / (CLOCKS_PER_SEC / 100))
13635 : ((clock () * 100) / CLOCKS_PER_SEC)
13636#else
13637 /* Presume unix... clock() returns microseconds. */
13638 (clock () / 10000)
13639#endif
13640 ;
13641 TRACE_SYSCALL (cpu, " AngelSVC: Get Clock");
13642 break;
13643
13644 case AngelSVC_Reason_GetCmdLine:
13645 {
13646 /* Get the pointer */
13647 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13648 ptr = aarch64_get_mem_u64 (cpu, ptr);
13649
13650 /* FIXME: No command line for now. */
13651 aarch64_set_mem_u64 (cpu, ptr, 0);
13652 TRACE_SYSCALL (cpu, " AngelSVC: Get Command Line");
13653 }
13654 break;
13655
13656 case AngelSVC_Reason_IsTTY:
13657 result = 1;
13658 TRACE_SYSCALL (cpu, " AngelSVC: IsTTY ?");
13659 break;
13660
13661 case AngelSVC_Reason_Write:
13662 {
13663 /* Get the pointer */
13664 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13665 /* Get the write control block. */
13666 uint64_t fd = aarch64_get_mem_u64 (cpu, ptr);
13667 uint64_t buf = aarch64_get_mem_u64 (cpu, ptr + 8);
13668 uint64_t len = aarch64_get_mem_u64 (cpu, ptr + 16);
13669
13670 TRACE_SYSCALL (cpu, "write of %" PRIx64 " bytes from %"
13671 PRIx64 " on descriptor %" PRIx64,
13672 len, buf, fd);
13673
13674 if (len > 1280)
13675 {
13676 TRACE_SYSCALL (cpu,
13677 " AngelSVC: Write: Suspiciously long write: %ld",
13678 (long) len);
13679 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13680 sim_stopped, SIM_SIGBUS);
13681 }
13682 else if (fd == 1)
13683 {
13684 printf ("%.*s", (int) len, aarch64_get_mem_ptr (cpu, buf));
2e8cf49e
NC
13685 }
13686 else if (fd == 2)
13687 {
13688 TRACE (cpu, 0, "\n");
13689 sim_io_eprintf (CPU_STATE (cpu), "%.*s",
13690 (int) len, aarch64_get_mem_ptr (cpu, buf));
13691 TRACE (cpu, 0, "\n");
13692 }
13693 else
13694 {
13695 TRACE_SYSCALL (cpu,
13696 " AngelSVC: Write: Unexpected file handle: %d",
13697 (int) fd);
13698 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13699 sim_stopped, SIM_SIGABRT);
13700 }
13701 }
13702 break;
13703
13704 case AngelSVC_Reason_ReportException:
13705 {
13706 /* Get the pointer */
13707 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13708 /*ptr = aarch64_get_mem_u64 (cpu, ptr);. */
13709 uint64_t type = aarch64_get_mem_u64 (cpu, ptr);
13710 uint64_t state = aarch64_get_mem_u64 (cpu, ptr + 8);
13711
13712 TRACE_SYSCALL (cpu,
13713 "Angel Exception: type 0x%" PRIx64 " state %" PRIx64,
13714 type, state);
13715
13716 if (type == 0x20026)
13717 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13718 sim_exited, state);
13719 else
13720 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13721 sim_stopped, SIM_SIGINT);
13722 }
13723 break;
13724
13725 case AngelSVC_Reason_Read:
13726 case AngelSVC_Reason_FLen:
13727 case AngelSVC_Reason_Seek:
13728 case AngelSVC_Reason_Remove:
13729 case AngelSVC_Reason_Time:
13730 case AngelSVC_Reason_System:
13731 case AngelSVC_Reason_Rename:
13732 case AngelSVC_Reason_Elapsed:
13733 default:
13734 TRACE_SYSCALL (cpu, " HLT [Unknown angel %x]",
13735 aarch64_get_reg_u32 (cpu, 0, NO_SP));
13736 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13737 sim_stopped, SIM_SIGTRAP);
13738 }
13739
13740 aarch64_set_reg_u64 (cpu, 0, NO_SP, result);
13741}
13742
13743static void
13744dexExcpnGen (sim_cpu *cpu)
13745{
13746 /* instr[31:24] = 11010100
13747 instr[23,21] = opc : 000 ==> GEN EXCPN, 001 ==> BRK
13748 010 ==> HLT, 101 ==> DBG GEN EXCPN
13749 instr[20,5] = imm16
13750 instr[4,2] = opc2 000 ==> OK, ow ==> UNALLOC
13751 instr[1,0] = LL : discriminates opc */
13752
ef0d8ffc
NC
13753 uint32_t opc = INSTR (23, 21);
13754 uint32_t imm16 = INSTR (20, 5);
13755 uint32_t opc2 = INSTR (4, 2);
2e8cf49e
NC
13756 uint32_t LL;
13757
13758 NYI_assert (31, 24, 0xd4);
13759
13760 if (opc2 != 0)
13761 HALT_UNALLOC;
13762
ef0d8ffc 13763 LL = INSTR (1, 0);
2e8cf49e
NC
13764
13765 /* We only implement HLT and BRK for now. */
13766 if (opc == 1 && LL == 0)
13767 {
13768 TRACE_EVENTS (cpu, " BRK [0x%x]", imm16);
13769 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13770 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13771 }
13772
13773 if (opc == 2 && LL == 0)
13774 handle_halt (cpu, imm16);
13775
13776 else if (opc == 0 || opc == 5)
13777 HALT_NYI;
13778
13779 else
13780 HALT_UNALLOC;
13781}
13782
5ab6d79e 13783/* Stub for accessing system registers. */
caa8d700
NC
13784
13785static uint64_t
13786system_get (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
13787 unsigned crm, unsigned op2)
13788{
13789 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 7)
13790 /* DCZID_EL0 - the Data Cache Zero ID register.
13791 We do not support DC ZVA at the moment, so
5ab6d79e
NC
13792 we return a value with the disable bit set.
13793 We implement support for the DCZID register since
13794 it is used by the C library's memset function. */
caa8d700
NC
13795 return ((uint64_t) 1) << 4;
13796
5ab6d79e
NC
13797 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 1)
13798 /* Cache Type Register. */
13799 return 0x80008000UL;
13800
13801 if (crn == 13 && op1 == 3 && crm == 0 && op2 == 2)
13802 /* TPIDR_EL0 - thread pointer id. */
13803 return aarch64_get_thread_id (cpu);
13804
13805 if (op1 == 3 && crm == 4 && op2 == 0)
13806 return aarch64_get_FPCR (cpu);
13807
13808 if (op1 == 3 && crm == 4 && op2 == 1)
13809 return aarch64_get_FPSR (cpu);
13810
13811 else if (op1 == 3 && crm == 2 && op2 == 0)
13812 return aarch64_get_CPSR (cpu);
13813
caa8d700
NC
13814 HALT_NYI;
13815}
13816
5ab6d79e
NC
13817static void
13818system_set (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
13819 unsigned crm, unsigned op2, uint64_t val)
13820{
13821 if (op1 == 3 && crm == 4 && op2 == 0)
13822 aarch64_set_FPCR (cpu, val);
13823
13824 else if (op1 == 3 && crm == 4 && op2 == 1)
13825 aarch64_set_FPSR (cpu, val);
13826
13827 else if (op1 == 3 && crm == 2 && op2 == 0)
13828 aarch64_set_CPSR (cpu, val);
13829
13830 else
13831 HALT_NYI;
13832}
ef0d8ffc 13833
caa8d700
NC
13834static void
13835do_mrs (sim_cpu *cpu)
13836{
5ab6d79e 13837 /* instr[31:20] = 1101 0101 0001 1
caa8d700
NC
13838 instr[19] = op0
13839 instr[18,16] = op1
13840 instr[15,12] = CRn
13841 instr[11,8] = CRm
13842 instr[7,5] = op2
13843 instr[4,0] = Rt */
ef0d8ffc
NC
13844 unsigned sys_op0 = INSTR (19, 19) + 2;
13845 unsigned sys_op1 = INSTR (18, 16);
13846 unsigned sys_crn = INSTR (15, 12);
13847 unsigned sys_crm = INSTR (11, 8);
13848 unsigned sys_op2 = INSTR (7, 5);
13849 unsigned rt = INSTR (4, 0);
caa8d700 13850
2cdad34c 13851 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
caa8d700
NC
13852 aarch64_set_reg_u64 (cpu, rt, NO_SP,
13853 system_get (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2));
13854}
13855
5ab6d79e
NC
13856static void
13857do_MSR_immediate (sim_cpu *cpu)
13858{
13859 /* instr[31:19] = 1101 0101 0000 0
13860 instr[18,16] = op1
13861 instr[15,12] = 0100
13862 instr[11,8] = CRm
13863 instr[7,5] = op2
13864 instr[4,0] = 1 1111 */
13865
ef0d8ffc
NC
13866 unsigned op1 = INSTR (18, 16);
13867 /*unsigned crm = INSTR (11, 8);*/
13868 unsigned op2 = INSTR (7, 5);
5ab6d79e
NC
13869
13870 NYI_assert (31, 19, 0x1AA0);
13871 NYI_assert (15, 12, 0x4);
13872 NYI_assert (4, 0, 0x1F);
13873
13874 if (op1 == 0)
13875 {
13876 if (op2 == 5)
13877 HALT_NYI; /* set SPSel. */
13878 else
13879 HALT_UNALLOC;
13880 }
13881 else if (op1 == 3)
13882 {
13883 if (op2 == 6)
13884 HALT_NYI; /* set DAIFset. */
13885 else if (op2 == 7)
13886 HALT_NYI; /* set DAIFclr. */
13887 else
13888 HALT_UNALLOC;
13889 }
13890 else
13891 HALT_UNALLOC;
13892}
13893
13894static void
13895do_MSR_reg (sim_cpu *cpu)
13896{
13897 /* instr[31:20] = 1101 0101 0001
13898 instr[19] = op0
13899 instr[18,16] = op1
13900 instr[15,12] = CRn
13901 instr[11,8] = CRm
13902 instr[7,5] = op2
13903 instr[4,0] = Rt */
13904
ef0d8ffc
NC
13905 unsigned sys_op0 = INSTR (19, 19) + 2;
13906 unsigned sys_op1 = INSTR (18, 16);
13907 unsigned sys_crn = INSTR (15, 12);
13908 unsigned sys_crm = INSTR (11, 8);
13909 unsigned sys_op2 = INSTR (7, 5);
13910 unsigned rt = INSTR (4, 0);
5ab6d79e
NC
13911
13912 NYI_assert (31, 20, 0xD51);
ef0d8ffc 13913
2cdad34c 13914 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
13915 system_set (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2,
13916 aarch64_get_reg_u64 (cpu, rt, NO_SP));
13917}
13918
13919static void
ef0d8ffc 13920do_SYS (sim_cpu *cpu)
5ab6d79e
NC
13921{
13922 /* instr[31,19] = 1101 0101 0000 1
13923 instr[18,16] = op1
13924 instr[15,12] = CRn
13925 instr[11,8] = CRm
13926 instr[7,5] = op2
13927 instr[4,0] = Rt */
13928 NYI_assert (31, 19, 0x1AA1);
13929
13930 /* FIXME: For now we just silently accept system ops. */
13931}
ef0d8ffc 13932
2e8cf49e
NC
13933static void
13934dexSystem (sim_cpu *cpu)
13935{
13936 /* instr[31:22] = 1101 01010 0
13937 instr[21] = L
13938 instr[20,19] = op0
13939 instr[18,16] = op1
13940 instr[15,12] = CRn
13941 instr[11,8] = CRm
13942 instr[7,5] = op2
13943 instr[4,0] = uimm5 */
13944
13945 /* We are interested in HINT, DSB, DMB and ISB
13946
13947 Hint #0 encodes NOOP (this is the only hint we care about)
13948 L == 0, op0 == 0, op1 = 011, CRn = 0010, Rt = 11111,
13949 CRm op2 != 0000 000 OR CRm op2 == 0000 000 || CRm op > 0000 101
13950
13951 DSB, DMB, ISB are data store barrier, data memory barrier and
13952 instruction store barrier, respectively, where
13953
13954 L == 0, op0 == 0, op1 = 011, CRn = 0011, Rt = 11111,
13955 op2 : DSB ==> 100, DMB ==> 101, ISB ==> 110
13956 CRm<3:2> ==> domain, CRm<1:0> ==> types,
13957 domain : 00 ==> OuterShareable, 01 ==> Nonshareable,
13958 10 ==> InerShareable, 11 ==> FullSystem
13959 types : 01 ==> Reads, 10 ==> Writes,
13960 11 ==> All, 00 ==> All (domain == FullSystem). */
13961
ef0d8ffc 13962 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
13963
13964 NYI_assert (31, 22, 0x354);
13965
5ab6d79e 13966 switch (INSTR (21, 12))
2e8cf49e
NC
13967 {
13968 case 0x032:
13969 if (rt == 0x1F)
13970 {
13971 /* NOP has CRm != 0000 OR. */
13972 /* (CRm == 0000 AND (op2 == 000 OR op2 > 101)). */
ef0d8ffc
NC
13973 uint32_t crm = INSTR (11, 8);
13974 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
13975
13976 if (crm != 0 || (op2 == 0 || op2 > 5))
13977 {
13978 /* Actually call nop method so we can reimplement it later. */
13979 nop (cpu);
13980 return;
13981 }
13982 }
13983 HALT_NYI;
13984
13985 case 0x033:
13986 {
ef0d8ffc 13987 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
13988
13989 switch (op2)
13990 {
caa8d700 13991 case 2: HALT_NYI;
2e8cf49e
NC
13992 case 4: dsb (cpu); return;
13993 case 5: dmb (cpu); return;
13994 case 6: isb (cpu); return;
2e8cf49e
NC
13995 default: HALT_UNALLOC;
13996 }
13997 }
13998
13999 case 0x3B0:
2e8cf49e
NC
14000 case 0x3B4:
14001 case 0x3BD:
caa8d700 14002 do_mrs (cpu);
2e8cf49e
NC
14003 return;
14004
14005 case 0x0B7:
5ab6d79e 14006 do_SYS (cpu); /* DC is an alias of SYS. */
2e8cf49e
NC
14007 return;
14008
14009 default:
ef0d8ffc 14010 if (INSTR (21, 20) == 0x1)
5ab6d79e
NC
14011 do_MSR_reg (cpu);
14012 else if (INSTR (21, 19) == 0 && INSTR (15, 12) == 0x4)
14013 do_MSR_immediate (cpu);
14014 else
14015 HALT_NYI;
caa8d700 14016 return;
2e8cf49e
NC
14017 }
14018}
14019
14020static void
14021dexBr (sim_cpu *cpu)
14022{
14023 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
14024 assert group == GROUP_BREXSYS_1010 || group == GROUP_BREXSYS_1011
14025 bits [31,29] of a BrExSys are the secondary dispatch vector. */
14026 uint32_t group2 = dispatchBrExSys (aarch64_get_instr (cpu));
14027
14028 switch (group2)
14029 {
14030 case BR_IMM_000:
14031 return dexBranchImmediate (cpu);
14032
14033 case BR_IMMCMP_001:
14034 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 14035 if (!INSTR (25, 25))
2e8cf49e
NC
14036 dexCompareBranchImmediate (cpu);
14037 else
14038 dexTestBranchImmediate (cpu);
14039 return;
14040
14041 case BR_IMMCOND_010:
14042 /* This is a conditional branch if bit 25 is clear otherwise
14043 unallocated. */
ef0d8ffc 14044 if (!INSTR (25, 25))
2e8cf49e
NC
14045 dexCondBranchImmediate (cpu);
14046 else
14047 HALT_UNALLOC;
14048 return;
14049
14050 case BR_UNALLOC_011:
14051 HALT_UNALLOC;
14052
14053 case BR_IMM_100:
14054 dexBranchImmediate (cpu);
14055 return;
14056
14057 case BR_IMMCMP_101:
14058 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 14059 if (!INSTR (25, 25))
2e8cf49e
NC
14060 dexCompareBranchImmediate (cpu);
14061 else
14062 dexTestBranchImmediate (cpu);
14063 return;
14064
14065 case BR_REG_110:
14066 /* Unconditional branch reg has bit 25 set. */
ef0d8ffc 14067 if (INSTR (25, 25))
2e8cf49e
NC
14068 dexBranchRegister (cpu);
14069
14070 /* This includes both Excpn Gen, System and unalloc operations.
14071 We need to decode the Excpn Gen operation BRK so we can plant
14072 debugger entry points.
ef0d8ffc 14073 Excpn Gen operations have instr [24] = 0.
2e8cf49e
NC
14074 we need to decode at least one of the System operations NOP
14075 which is an alias for HINT #0.
ef0d8ffc
NC
14076 System operations have instr [24,22] = 100. */
14077 else if (INSTR (24, 24) == 0)
2e8cf49e
NC
14078 dexExcpnGen (cpu);
14079
ef0d8ffc 14080 else if (INSTR (24, 22) == 4)
2e8cf49e
NC
14081 dexSystem (cpu);
14082
14083 else
14084 HALT_UNALLOC;
14085
14086 return;
14087
14088 case BR_UNALLOC_111:
14089 HALT_UNALLOC;
14090
14091 default:
14092 /* Should never reach here. */
14093 HALT_NYI;
14094 }
14095}
14096
14097static void
14098aarch64_decode_and_execute (sim_cpu *cpu, uint64_t pc)
14099{
14100 /* We need to check if gdb wants an in here. */
14101 /* checkBreak (cpu);. */
14102
14103 uint64_t group = dispatchGroup (aarch64_get_instr (cpu));
14104
14105 switch (group)
14106 {
14107 case GROUP_PSEUDO_0000: dexPseudo (cpu); break;
14108 case GROUP_LDST_0100: dexLdSt (cpu); break;
14109 case GROUP_DPREG_0101: dexDPReg (cpu); break;
14110 case GROUP_LDST_0110: dexLdSt (cpu); break;
14111 case GROUP_ADVSIMD_0111: dexAdvSIMD0 (cpu); break;
14112 case GROUP_DPIMM_1000: dexDPImm (cpu); break;
14113 case GROUP_DPIMM_1001: dexDPImm (cpu); break;
14114 case GROUP_BREXSYS_1010: dexBr (cpu); break;
14115 case GROUP_BREXSYS_1011: dexBr (cpu); break;
14116 case GROUP_LDST_1100: dexLdSt (cpu); break;
14117 case GROUP_DPREG_1101: dexDPReg (cpu); break;
14118 case GROUP_LDST_1110: dexLdSt (cpu); break;
14119 case GROUP_ADVSIMD_1111: dexAdvSIMD1 (cpu); break;
14120
14121 case GROUP_UNALLOC_0001:
14122 case GROUP_UNALLOC_0010:
14123 case GROUP_UNALLOC_0011:
14124 HALT_UNALLOC;
14125
14126 default:
14127 /* Should never reach here. */
14128 HALT_NYI;
14129 }
14130}
14131
b14bdb3b 14132static bfd_boolean
2e8cf49e
NC
14133aarch64_step (sim_cpu *cpu)
14134{
14135 uint64_t pc = aarch64_get_PC (cpu);
14136
14137 if (pc == TOP_LEVEL_RETURN_PC)
14138 return FALSE;
14139
14140 aarch64_set_next_PC (cpu, pc + 4);
c7be4414
JW
14141
14142 /* Code is always little-endian. */
14143 sim_core_read_buffer (CPU_STATE (cpu), cpu, read_map,
14144 & aarch64_get_instr (cpu), pc, 4);
14145 aarch64_get_instr (cpu) = endian_le2h_4 (aarch64_get_instr (cpu));
2e8cf49e 14146
57aa1742 14147 TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %08x", pc,
1a846c62
MF
14148 aarch64_get_instr (cpu));
14149 TRACE_DISASM (cpu, pc);
2e8cf49e
NC
14150
14151 aarch64_decode_and_execute (cpu, pc);
14152
14153 return TRUE;
14154}
14155
14156void
14157aarch64_run (SIM_DESC sd)
14158{
14159 sim_cpu *cpu = STATE_CPU (sd, 0);
14160
14161 while (aarch64_step (cpu))
b14bdb3b
NC
14162 {
14163 aarch64_update_PC (cpu);
14164
14165 if (sim_events_tick (sd))
14166 sim_events_process (sd);
14167 }
2e8cf49e 14168
b14bdb3b
NC
14169 sim_engine_halt (sd, cpu, NULL, aarch64_get_PC (cpu),
14170 sim_exited, aarch64_get_reg_s32 (cpu, R0, NO_SP));
2e8cf49e
NC
14171}
14172
14173void
14174aarch64_init (sim_cpu *cpu, uint64_t pc)
14175{
14176 uint64_t sp = aarch64_get_stack_start (cpu);
14177
14178 /* Install SP, FP and PC and set LR to -20
14179 so we can detect a top-level return. */
14180 aarch64_set_reg_u64 (cpu, SP, SP_OK, sp);
14181 aarch64_set_reg_u64 (cpu, FP, SP_OK, sp);
14182 aarch64_set_reg_u64 (cpu, LR, SP_OK, TOP_LEVEL_RETURN_PC);
14183 aarch64_set_next_PC (cpu, pc);
14184 aarch64_update_PC (cpu);
14185 aarch64_init_LIT_table ();
14186}
This page took 0.827177 seconds and 4 git commands to generate.