]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/aarch64/simulator.c
update copyright year range in GDB files
[thirdparty/binutils-gdb.git] / sim / aarch64 / simulator.c
CommitLineData
2e8cf49e
NC
1/* simulator.c -- Interface for the AArch64 simulator.
2
61baf725 3 Copyright (C) 2015-2017 Free Software Foundation, Inc.
2e8cf49e
NC
4
5 Contributed by Red Hat.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22#include "config.h"
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <sys/types.h>
2e8cf49e
NC
27#include <math.h>
28#include <time.h>
29#include <limits.h>
30
2e8cf49e
NC
31#include "simulator.h"
32#include "cpustate.h"
33#include "memory.h"
34
35#define NO_SP 0
36#define SP_OK 1
37
2e8cf49e 38#define TST(_flag) (aarch64_test_CPSR_bit (cpu, _flag))
e101a78b
NC
39#define IS_SET(_X) (TST (( _X )) ? 1 : 0)
40#define IS_CLEAR(_X) (TST (( _X )) ? 0 : 1)
2e8cf49e 41
ef0d8ffc
NC
42/* Space saver macro. */
43#define INSTR(HIGH, LOW) uimm (aarch64_get_instr (cpu), (HIGH), (LOW))
44
2e8cf49e
NC
45#define HALT_UNALLOC \
46 do \
47 { \
1a846c62
MF
48 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
49 TRACE_INSN (cpu, \
50 "Unallocated instruction detected at sim line %d," \
51 " exe addr %" PRIx64, \
52 __LINE__, aarch64_get_PC (cpu)); \
2e8cf49e
NC
53 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
54 sim_stopped, SIM_SIGILL); \
55 } \
56 while (0)
57
58#define HALT_NYI \
59 do \
60 { \
1a846c62
MF
61 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
62 TRACE_INSN (cpu, \
63 "Unimplemented instruction detected at sim line %d," \
64 " exe addr %" PRIx64, \
65 __LINE__, aarch64_get_PC (cpu)); \
5ab6d79e 66 if (! TRACE_ANY_P (cpu)) \
6a277579
NC
67 sim_io_eprintf (CPU_STATE (cpu), "SIM Error: Unimplemented instruction: %#08x\n", \
68 aarch64_get_instr (cpu)); \
2e8cf49e
NC
69 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
70 sim_stopped, SIM_SIGABRT); \
71 } \
72 while (0)
73
74#define NYI_assert(HI, LO, EXPECTED) \
75 do \
76 { \
ef0d8ffc 77 if (INSTR ((HI), (LO)) != (EXPECTED)) \
2e8cf49e
NC
78 HALT_NYI; \
79 } \
80 while (0)
81
2e8cf49e
NC
82/* Helper functions used by expandLogicalImmediate. */
83
84/* for i = 1, ... N result<i-1> = 1 other bits are zero */
85static inline uint64_t
86ones (int N)
87{
88 return (N == 64 ? (uint64_t)-1UL : ((1UL << N) - 1));
89}
90
91/* result<0> to val<N> */
92static inline uint64_t
93pickbit (uint64_t val, int N)
94{
95 return pickbits64 (val, N, N);
96}
97
98static uint64_t
99expand_logical_immediate (uint32_t S, uint32_t R, uint32_t N)
100{
101 uint64_t mask;
102 uint64_t imm;
103 unsigned simd_size;
104
105 /* The immediate value is S+1 bits to 1, left rotated by SIMDsize - R
106 (in other words, right rotated by R), then replicated. */
107 if (N != 0)
108 {
109 simd_size = 64;
110 mask = 0xffffffffffffffffull;
111 }
112 else
113 {
114 switch (S)
115 {
116 case 0x00 ... 0x1f: /* 0xxxxx */ simd_size = 32; break;
117 case 0x20 ... 0x2f: /* 10xxxx */ simd_size = 16; S &= 0xf; break;
118 case 0x30 ... 0x37: /* 110xxx */ simd_size = 8; S &= 0x7; break;
119 case 0x38 ... 0x3b: /* 1110xx */ simd_size = 4; S &= 0x3; break;
120 case 0x3c ... 0x3d: /* 11110x */ simd_size = 2; S &= 0x1; break;
121 default: return 0;
122 }
123 mask = (1ull << simd_size) - 1;
124 /* Top bits are IGNORED. */
125 R &= simd_size - 1;
126 }
127
128 /* NOTE: if S = simd_size - 1 we get 0xf..f which is rejected. */
129 if (S == simd_size - 1)
130 return 0;
131
132 /* S+1 consecutive bits to 1. */
133 /* NOTE: S can't be 63 due to detection above. */
134 imm = (1ull << (S + 1)) - 1;
135
136 /* Rotate to the left by simd_size - R. */
137 if (R != 0)
138 imm = ((imm << (simd_size - R)) & mask) | (imm >> R);
139
140 /* Replicate the value according to SIMD size. */
141 switch (simd_size)
142 {
143 case 2: imm = (imm << 2) | imm;
144 case 4: imm = (imm << 4) | imm;
145 case 8: imm = (imm << 8) | imm;
146 case 16: imm = (imm << 16) | imm;
147 case 32: imm = (imm << 32) | imm;
148 case 64: break;
149 default: return 0;
150 }
151
152 return imm;
153}
154
155/* Instr[22,10] encodes N immr and imms. we want a lookup table
156 for each possible combination i.e. 13 bits worth of int entries. */
157#define LI_TABLE_SIZE (1 << 13)
158static uint64_t LITable[LI_TABLE_SIZE];
159
160void
161aarch64_init_LIT_table (void)
162{
163 unsigned index;
164
165 for (index = 0; index < LI_TABLE_SIZE; index++)
166 {
167 uint32_t N = uimm (index, 12, 12);
168 uint32_t immr = uimm (index, 11, 6);
169 uint32_t imms = uimm (index, 5, 0);
170
171 LITable [index] = expand_logical_immediate (imms, immr, N);
172 }
173}
174
175static void
176dexNotify (sim_cpu *cpu)
177{
178 /* instr[14,0] == type : 0 ==> method entry, 1 ==> method reentry
179 2 ==> exit Java, 3 ==> start next bytecode. */
ef0d8ffc 180 uint32_t type = INSTR (14, 0);
2e8cf49e
NC
181
182 TRACE_EVENTS (cpu, "Notify Insn encountered, type = 0x%x", type);
183
184 switch (type)
185 {
186 case 0:
187 /* aarch64_notifyMethodEntry (aarch64_get_reg_u64 (cpu, R23, 0),
188 aarch64_get_reg_u64 (cpu, R22, 0)); */
189 break;
190 case 1:
191 /* aarch64_notifyMethodReentry (aarch64_get_reg_u64 (cpu, R23, 0),
192 aarch64_get_reg_u64 (cpu, R22, 0)); */
193 break;
194 case 2:
195 /* aarch64_notifyMethodExit (); */
196 break;
197 case 3:
198 /* aarch64_notifyBCStart (aarch64_get_reg_u64 (cpu, R23, 0),
199 aarch64_get_reg_u64 (cpu, R22, 0)); */
200 break;
201 }
202}
203
204/* secondary decode within top level groups */
205
206static void
207dexPseudo (sim_cpu *cpu)
208{
209 /* assert instr[28,27] = 00
210
211 We provide 2 pseudo instructions:
212
213 HALT stops execution of the simulator causing an immediate
214 return to the x86 code which entered it.
215
216 CALLOUT initiates recursive entry into x86 code. A register
217 argument holds the address of the x86 routine. Immediate
218 values in the instruction identify the number of general
219 purpose and floating point register arguments to be passed
220 and the type of any value to be returned. */
221
222 uint32_t PSEUDO_HALT = 0xE0000000U;
223 uint32_t PSEUDO_CALLOUT = 0x00018000U;
224 uint32_t PSEUDO_CALLOUTR = 0x00018001U;
225 uint32_t PSEUDO_NOTIFY = 0x00014000U;
226 uint32_t dispatch;
227
228 if (aarch64_get_instr (cpu) == PSEUDO_HALT)
229 {
230 TRACE_EVENTS (cpu, " Pseudo Halt Instruction");
231 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
232 sim_stopped, SIM_SIGTRAP);
233 }
234
ef0d8ffc 235 dispatch = INSTR (31, 15);
2e8cf49e
NC
236
237 /* We do not handle callouts at the moment. */
238 if (dispatch == PSEUDO_CALLOUT || dispatch == PSEUDO_CALLOUTR)
239 {
240 TRACE_EVENTS (cpu, " Callout");
241 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
242 sim_stopped, SIM_SIGABRT);
243 }
244
245 else if (dispatch == PSEUDO_NOTIFY)
246 dexNotify (cpu);
247
248 else
249 HALT_UNALLOC;
250}
251
252/* Load-store single register (unscaled offset)
253 These instructions employ a base register plus an unscaled signed
254 9 bit offset.
255
256 N.B. the base register (source) can be Xn or SP. all other
257 registers may not be SP. */
258
259/* 32 bit load 32 bit unscaled signed 9 bit. */
260static void
261ldur32 (sim_cpu *cpu, int32_t offset)
262{
ef0d8ffc
NC
263 unsigned rn = INSTR (9, 5);
264 unsigned rt = INSTR (4, 0);
2e8cf49e 265
2cdad34c 266 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
267 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
268 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
269 + offset));
270}
271
272/* 64 bit load 64 bit unscaled signed 9 bit. */
273static void
274ldur64 (sim_cpu *cpu, int32_t offset)
275{
ef0d8ffc
NC
276 unsigned rn = INSTR (9, 5);
277 unsigned rt = INSTR (4, 0);
2e8cf49e 278
2cdad34c 279 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
280 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
281 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
282 + offset));
283}
284
285/* 32 bit load zero-extended byte unscaled signed 9 bit. */
286static void
287ldurb32 (sim_cpu *cpu, int32_t offset)
288{
ef0d8ffc
NC
289 unsigned rn = INSTR (9, 5);
290 unsigned rt = INSTR (4, 0);
2e8cf49e 291
2cdad34c 292 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
293 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8
294 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
295 + offset));
296}
297
298/* 32 bit load sign-extended byte unscaled signed 9 bit. */
299static void
300ldursb32 (sim_cpu *cpu, int32_t offset)
301{
ef0d8ffc
NC
302 unsigned rn = INSTR (9, 5);
303 unsigned rt = INSTR (4, 0);
2e8cf49e 304
2cdad34c 305 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
306 aarch64_set_reg_u64 (cpu, rt, NO_SP, (uint32_t) aarch64_get_mem_s8
307 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
308 + offset));
309}
310
311/* 64 bit load sign-extended byte unscaled signed 9 bit. */
312static void
313ldursb64 (sim_cpu *cpu, int32_t offset)
314{
ef0d8ffc
NC
315 unsigned rn = INSTR (9, 5);
316 unsigned rt = INSTR (4, 0);
2e8cf49e 317
2cdad34c 318 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
319 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s8
320 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
321 + offset));
322}
323
324/* 32 bit load zero-extended short unscaled signed 9 bit */
325static void
326ldurh32 (sim_cpu *cpu, int32_t offset)
327{
ef0d8ffc
NC
328 unsigned rn = INSTR (9, 5);
329 unsigned rd = INSTR (4, 0);
2e8cf49e 330
2cdad34c 331 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
332 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_mem_u16
333 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
334 + offset));
335}
336
337/* 32 bit load sign-extended short unscaled signed 9 bit */
338static void
339ldursh32 (sim_cpu *cpu, int32_t offset)
340{
ef0d8ffc
NC
341 unsigned rn = INSTR (9, 5);
342 unsigned rd = INSTR (4, 0);
2e8cf49e 343
2cdad34c 344 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
345 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s16
346 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
347 + offset));
348}
349
350/* 64 bit load sign-extended short unscaled signed 9 bit */
351static void
352ldursh64 (sim_cpu *cpu, int32_t offset)
353{
ef0d8ffc
NC
354 unsigned rn = INSTR (9, 5);
355 unsigned rt = INSTR (4, 0);
2e8cf49e 356
2cdad34c 357 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
358 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s16
359 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
360 + offset));
361}
362
363/* 64 bit load sign-extended word unscaled signed 9 bit */
364static void
365ldursw (sim_cpu *cpu, int32_t offset)
366{
ef0d8ffc
NC
367 unsigned rn = INSTR (9, 5);
368 unsigned rd = INSTR (4, 0);
2e8cf49e 369
2cdad34c 370 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
371 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s32
372 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
373 + offset));
374}
375
376/* N.B. with stores the value in source is written to the address
377 identified by source2 modified by offset. */
378
379/* 32 bit store 32 bit unscaled signed 9 bit. */
380static void
381stur32 (sim_cpu *cpu, int32_t offset)
382{
ef0d8ffc
NC
383 unsigned rn = INSTR (9, 5);
384 unsigned rd = INSTR (4, 0);
2e8cf49e 385
2cdad34c 386 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
387 aarch64_set_mem_u32 (cpu,
388 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
389 aarch64_get_reg_u32 (cpu, rd, NO_SP));
390}
391
392/* 64 bit store 64 bit unscaled signed 9 bit */
393static void
394stur64 (sim_cpu *cpu, int32_t offset)
395{
ef0d8ffc
NC
396 unsigned rn = INSTR (9, 5);
397 unsigned rd = INSTR (4, 0);
2e8cf49e 398
2cdad34c 399 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
400 aarch64_set_mem_u64 (cpu,
401 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
402 aarch64_get_reg_u64 (cpu, rd, NO_SP));
403}
404
405/* 32 bit store byte unscaled signed 9 bit */
406static void
407sturb (sim_cpu *cpu, int32_t offset)
408{
ef0d8ffc
NC
409 unsigned rn = INSTR (9, 5);
410 unsigned rd = INSTR (4, 0);
2e8cf49e 411
2cdad34c 412 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
413 aarch64_set_mem_u8 (cpu,
414 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
415 aarch64_get_reg_u8 (cpu, rd, NO_SP));
416}
417
418/* 32 bit store short unscaled signed 9 bit */
419static void
420sturh (sim_cpu *cpu, int32_t offset)
421{
ef0d8ffc
NC
422 unsigned rn = INSTR (9, 5);
423 unsigned rd = INSTR (4, 0);
2e8cf49e 424
2cdad34c 425 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
426 aarch64_set_mem_u16 (cpu,
427 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
428 aarch64_get_reg_u16 (cpu, rd, NO_SP));
429}
430
431/* Load single register pc-relative label
432 Offset is a signed 19 bit immediate count in words
433 rt may not be SP. */
434
435/* 32 bit pc-relative load */
436static void
437ldr32_pcrel (sim_cpu *cpu, int32_t offset)
438{
ef0d8ffc 439 unsigned rd = INSTR (4, 0);
2e8cf49e 440
2cdad34c 441 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
442 aarch64_set_reg_u64 (cpu, rd, NO_SP,
443 aarch64_get_mem_u32
444 (cpu, aarch64_get_PC (cpu) + offset * 4));
445}
446
447/* 64 bit pc-relative load */
448static void
449ldr_pcrel (sim_cpu *cpu, int32_t offset)
450{
ef0d8ffc 451 unsigned rd = INSTR (4, 0);
2e8cf49e 452
2cdad34c 453 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
454 aarch64_set_reg_u64 (cpu, rd, NO_SP,
455 aarch64_get_mem_u64
456 (cpu, aarch64_get_PC (cpu) + offset * 4));
457}
458
459/* sign extended 32 bit pc-relative load */
460static void
461ldrsw_pcrel (sim_cpu *cpu, int32_t offset)
462{
ef0d8ffc 463 unsigned rd = INSTR (4, 0);
2e8cf49e 464
2cdad34c 465 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
466 aarch64_set_reg_u64 (cpu, rd, NO_SP,
467 aarch64_get_mem_s32
468 (cpu, aarch64_get_PC (cpu) + offset * 4));
469}
470
471/* float pc-relative load */
472static void
473fldrs_pcrel (sim_cpu *cpu, int32_t offset)
474{
ef0d8ffc 475 unsigned int rd = INSTR (4, 0);
2e8cf49e 476
2cdad34c 477 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
478 aarch64_set_vec_u32 (cpu, rd, 0,
479 aarch64_get_mem_u32
480 (cpu, aarch64_get_PC (cpu) + offset * 4));
2e8cf49e
NC
481}
482
483/* double pc-relative load */
484static void
485fldrd_pcrel (sim_cpu *cpu, int32_t offset)
486{
ef0d8ffc 487 unsigned int st = INSTR (4, 0);
2e8cf49e 488
2cdad34c 489 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
490 aarch64_set_vec_u64 (cpu, st, 0,
491 aarch64_get_mem_u64
492 (cpu, aarch64_get_PC (cpu) + offset * 4));
2e8cf49e
NC
493}
494
495/* long double pc-relative load. */
496static void
497fldrq_pcrel (sim_cpu *cpu, int32_t offset)
498{
ef0d8ffc 499 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
500 uint64_t addr = aarch64_get_PC (cpu) + offset * 4;
501 FRegister a;
502
2cdad34c 503 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
504 aarch64_get_mem_long_double (cpu, addr, & a);
505 aarch64_set_FP_long_double (cpu, st, a);
506}
507
508/* This can be used to scale an offset by applying
509 the requisite shift. the second argument is either
510 16, 32 or 64. */
511
512#define SCALE(_offset, _elementSize) \
513 ((_offset) << ScaleShift ## _elementSize)
514
515/* This can be used to optionally scale a register derived offset
516 by applying the requisite shift as indicated by the Scaling
7517e550 517 argument. The second argument is either Byte, Short, Word
2e8cf49e
NC
518 or Long. The third argument is either Scaled or Unscaled.
519 N.B. when _Scaling is Scaled the shift gets ANDed with
520 all 1s while when it is Unscaled it gets ANDed with 0. */
521
522#define OPT_SCALE(_offset, _elementType, _Scaling) \
523 ((_offset) << (_Scaling ? ScaleShift ## _elementType : 0))
524
525/* This can be used to zero or sign extend a 32 bit register derived
526 value to a 64 bit value. the first argument must be the value as
527 a uint32_t and the second must be either UXTW or SXTW. The result
528 is returned as an int64_t. */
529
530static inline int64_t
531extend (uint32_t value, Extension extension)
532{
533 union
534 {
535 uint32_t u;
536 int32_t n;
537 } x;
538
539 /* A branchless variant of this ought to be possible. */
540 if (extension == UXTW || extension == NoExtension)
541 return value;
542
543 x.u = value;
544 return x.n;
545}
546
547/* Scalar Floating Point
548
549 FP load/store single register (4 addressing modes)
550
551 N.B. the base register (source) can be the stack pointer.
552 The secondary source register (source2) can only be an Xn register. */
553
554/* Load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
555static void
556fldrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
557{
ef0d8ffc
NC
558 unsigned rn = INSTR (9, 5);
559 unsigned st = INSTR (4, 0);
2e8cf49e
NC
560 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
561
562 if (wb != Post)
563 address += offset;
564
2cdad34c 565 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b 566 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32 (cpu, address));
2e8cf49e
NC
567 if (wb == Post)
568 address += offset;
569
570 if (wb != NoWriteBack)
571 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
572}
573
5ab6d79e
NC
574/* Load 8 bit with unsigned 12 bit offset. */
575static void
576fldrb_abs (sim_cpu *cpu, uint32_t offset)
577{
ef0d8ffc
NC
578 unsigned rd = INSTR (4, 0);
579 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
580 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
581
2cdad34c 582 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
583 aarch64_set_vec_u8 (cpu, rd, 0, aarch64_get_mem_u32 (cpu, addr));
584}
585
586/* Load 16 bit scaled unsigned 12 bit. */
587static void
588fldrh_abs (sim_cpu *cpu, uint32_t offset)
589{
ef0d8ffc
NC
590 unsigned rd = INSTR (4, 0);
591 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
592 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16);
593
2cdad34c 594 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
595 aarch64_set_vec_u16 (cpu, rd, 0, aarch64_get_mem_u16 (cpu, addr));
596}
597
2e8cf49e
NC
598/* Load 32 bit scaled unsigned 12 bit. */
599static void
600fldrs_abs (sim_cpu *cpu, uint32_t offset)
601{
ef0d8ffc
NC
602 unsigned rd = INSTR (4, 0);
603 unsigned rn = INSTR (9, 5);
5ab6d79e 604 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32);
2e8cf49e 605
2cdad34c 606 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
607 aarch64_set_vec_u32 (cpu, rd, 0, aarch64_get_mem_u32 (cpu, addr));
608}
609
610/* Load 64 bit scaled unsigned 12 bit. */
611static void
612fldrd_abs (sim_cpu *cpu, uint32_t offset)
613{
ef0d8ffc
NC
614 unsigned rd = INSTR (4, 0);
615 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
616 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64);
617
2cdad34c 618 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
619 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_mem_u64 (cpu, addr));
620}
621
622/* Load 128 bit scaled unsigned 12 bit. */
623static void
624fldrq_abs (sim_cpu *cpu, uint32_t offset)
625{
ef0d8ffc
NC
626 unsigned rd = INSTR (4, 0);
627 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
628 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
629
2cdad34c 630 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
631 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_mem_u64 (cpu, addr));
632 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_mem_u64 (cpu, addr + 8));
2e8cf49e
NC
633}
634
635/* Load 32 bit scaled or unscaled zero- or sign-extended
636 32-bit register offset. */
637static void
638fldrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
639{
ef0d8ffc
NC
640 unsigned rm = INSTR (20, 16);
641 unsigned rn = INSTR (9, 5);
642 unsigned st = INSTR (4, 0);
2e8cf49e
NC
643 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
644 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
645 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
646
2cdad34c 647 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
648 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
649 (cpu, address + displacement));
2e8cf49e
NC
650}
651
652/* Load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
653static void
654fldrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
655{
ef0d8ffc
NC
656 unsigned rn = INSTR (9, 5);
657 unsigned st = INSTR (4, 0);
2e8cf49e
NC
658 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
659
660 if (wb != Post)
661 address += offset;
662
2cdad34c 663 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b 664 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64 (cpu, address));
2e8cf49e
NC
665
666 if (wb == Post)
667 address += offset;
668
669 if (wb != NoWriteBack)
670 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
671}
672
2e8cf49e
NC
673/* Load 64 bit scaled or unscaled zero- or sign-extended 32-bit register offset. */
674static void
675fldrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
676{
ef0d8ffc 677 unsigned rm = INSTR (20, 16);
2e8cf49e
NC
678 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
679 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
680
681 fldrd_wb (cpu, displacement, NoWriteBack);
682}
683
684/* Load 128 bit unscaled signed 9 bit with pre- or post-writeback. */
685static void
686fldrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
687{
688 FRegister a;
ef0d8ffc
NC
689 unsigned rn = INSTR (9, 5);
690 unsigned st = INSTR (4, 0);
2e8cf49e
NC
691 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
692
693 if (wb != Post)
694 address += offset;
695
2cdad34c 696 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
697 aarch64_get_mem_long_double (cpu, address, & a);
698 aarch64_set_FP_long_double (cpu, st, a);
699
700 if (wb == Post)
701 address += offset;
702
703 if (wb != NoWriteBack)
704 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
705}
706
2e8cf49e
NC
707/* Load 128 bit scaled or unscaled zero- or sign-extended 32-bit register offset */
708static void
709fldrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
710{
ef0d8ffc 711 unsigned rm = INSTR (20, 16);
2e8cf49e
NC
712 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
713 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
714
715 fldrq_wb (cpu, displacement, NoWriteBack);
716}
717
718/* Memory Access
719
720 load-store single register
721 There are four addressing modes available here which all employ a
722 64 bit source (base) register.
723
724 N.B. the base register (source) can be the stack pointer.
725 The secondary source register (source2)can only be an Xn register.
726
727 Scaled, 12-bit, unsigned immediate offset, without pre- and
728 post-index options.
729 Unscaled, 9-bit, signed immediate offset with pre- or post-index
730 writeback.
731 scaled or unscaled 64-bit register offset.
732 scaled or unscaled 32-bit extended register offset.
733
734 All offsets are assumed to be raw from the decode i.e. the
735 simulator is expected to adjust scaled offsets based on the
736 accessed data size with register or extended register offset
737 versions the same applies except that in the latter case the
738 operation may also require a sign extend.
739
740 A separate method is provided for each possible addressing mode. */
741
742/* 32 bit load 32 bit scaled unsigned 12 bit */
743static void
744ldr32_abs (sim_cpu *cpu, uint32_t offset)
745{
ef0d8ffc
NC
746 unsigned rn = INSTR (9, 5);
747 unsigned rt = INSTR (4, 0);
2e8cf49e 748
2cdad34c 749 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
750 /* The target register may not be SP but the source may be. */
751 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
752 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
753 + SCALE (offset, 32)));
754}
755
756/* 32 bit load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
757static void
758ldr32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
759{
ef0d8ffc
NC
760 unsigned rn = INSTR (9, 5);
761 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
762 uint64_t address;
763
764 if (rn == rt && wb != NoWriteBack)
765 HALT_UNALLOC;
766
767 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
768
769 if (wb != Post)
770 address += offset;
771
2cdad34c 772 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
773 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
774
775 if (wb == Post)
776 address += offset;
777
778 if (wb != NoWriteBack)
779 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
780}
781
782/* 32 bit load 32 bit scaled or unscaled
783 zero- or sign-extended 32-bit register offset */
784static void
785ldr32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
786{
ef0d8ffc
NC
787 unsigned rm = INSTR (20, 16);
788 unsigned rn = INSTR (9, 5);
789 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
790 /* rn may reference SP, rm and rt must reference ZR */
791
792 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
793 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
794 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
795
2cdad34c 796 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
797 aarch64_set_reg_u64 (cpu, rt, NO_SP,
798 aarch64_get_mem_u32 (cpu, address + displacement));
799}
800
801/* 64 bit load 64 bit scaled unsigned 12 bit */
802static void
803ldr_abs (sim_cpu *cpu, uint32_t offset)
804{
ef0d8ffc
NC
805 unsigned rn = INSTR (9, 5);
806 unsigned rt = INSTR (4, 0);
2e8cf49e 807
2cdad34c 808 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
809 /* The target register may not be SP but the source may be. */
810 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
811 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
812 + SCALE (offset, 64)));
813}
814
815/* 64 bit load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
816static void
817ldr_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
818{
ef0d8ffc
NC
819 unsigned rn = INSTR (9, 5);
820 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
821 uint64_t address;
822
823 if (rn == rt && wb != NoWriteBack)
824 HALT_UNALLOC;
825
826 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
827
828 if (wb != Post)
829 address += offset;
830
2cdad34c 831 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
832 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
833
834 if (wb == Post)
835 address += offset;
836
837 if (wb != NoWriteBack)
838 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
839}
840
841/* 64 bit load 64 bit scaled or unscaled zero-
842 or sign-extended 32-bit register offset. */
843static void
844ldr_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
845{
ef0d8ffc
NC
846 unsigned rm = INSTR (20, 16);
847 unsigned rn = INSTR (9, 5);
848 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
849 /* rn may reference SP, rm and rt must reference ZR */
850
851 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
852 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
853 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
854
2cdad34c 855 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
856 aarch64_set_reg_u64 (cpu, rt, NO_SP,
857 aarch64_get_mem_u64 (cpu, address + displacement));
858}
859
860/* 32 bit load zero-extended byte scaled unsigned 12 bit. */
861static void
862ldrb32_abs (sim_cpu *cpu, uint32_t offset)
863{
ef0d8ffc
NC
864 unsigned rn = INSTR (9, 5);
865 unsigned rt = INSTR (4, 0);
2e8cf49e 866
2cdad34c 867 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
868 /* The target register may not be SP but the source may be
869 there is no scaling required for a byte load. */
870 aarch64_set_reg_u64 (cpu, rt, NO_SP,
871 aarch64_get_mem_u8
872 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
873}
874
875/* 32 bit load zero-extended byte unscaled signed 9 bit with pre- or post-writeback. */
876static void
877ldrb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
878{
ef0d8ffc
NC
879 unsigned rn = INSTR (9, 5);
880 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
881 uint64_t address;
882
883 if (rn == rt && wb != NoWriteBack)
884 HALT_UNALLOC;
885
886 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
887
888 if (wb != Post)
889 address += offset;
890
2cdad34c 891 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
892 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
893
894 if (wb == Post)
895 address += offset;
896
897 if (wb != NoWriteBack)
898 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
899}
900
901/* 32 bit load zero-extended byte scaled or unscaled zero-
902 or sign-extended 32-bit register offset. */
903static void
904ldrb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
905{
ef0d8ffc
NC
906 unsigned rm = INSTR (20, 16);
907 unsigned rn = INSTR (9, 5);
908 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
909 /* rn may reference SP, rm and rt must reference ZR */
910
911 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
912 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
913 extension);
914
2cdad34c 915 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
916 /* There is no scaling required for a byte load. */
917 aarch64_set_reg_u64 (cpu, rt, NO_SP,
918 aarch64_get_mem_u8 (cpu, address + displacement));
919}
920
921/* 64 bit load sign-extended byte unscaled signed 9 bit
922 with pre- or post-writeback. */
923static void
924ldrsb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
925{
ef0d8ffc
NC
926 unsigned rn = INSTR (9, 5);
927 unsigned rt = INSTR (4, 0);
2e8cf49e 928 uint64_t address;
7517e550 929 int64_t val;
2e8cf49e
NC
930
931 if (rn == rt && wb != NoWriteBack)
932 HALT_UNALLOC;
933
934 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
935
936 if (wb != Post)
937 address += offset;
938
2cdad34c 939 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
940 val = aarch64_get_mem_s8 (cpu, address);
941 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
942
943 if (wb == Post)
944 address += offset;
945
946 if (wb != NoWriteBack)
947 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
948}
949
950/* 64 bit load sign-extended byte scaled unsigned 12 bit. */
951static void
952ldrsb_abs (sim_cpu *cpu, uint32_t offset)
953{
954 ldrsb_wb (cpu, offset, NoWriteBack);
955}
956
957/* 64 bit load sign-extended byte scaled or unscaled zero-
958 or sign-extended 32-bit register offset. */
959static void
960ldrsb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
961{
ef0d8ffc
NC
962 unsigned rm = INSTR (20, 16);
963 unsigned rn = INSTR (9, 5);
964 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
965 /* rn may reference SP, rm and rt must reference ZR */
966
967 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
968 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
969 extension);
2cdad34c 970 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 971 /* There is no scaling required for a byte load. */
7517e550 972 aarch64_set_reg_s64 (cpu, rt, NO_SP,
2e8cf49e
NC
973 aarch64_get_mem_s8 (cpu, address + displacement));
974}
975
976/* 32 bit load zero-extended short scaled unsigned 12 bit. */
977static void
978ldrh32_abs (sim_cpu *cpu, uint32_t offset)
979{
ef0d8ffc
NC
980 unsigned rn = INSTR (9, 5);
981 unsigned rt = INSTR (4, 0);
7517e550 982 uint32_t val;
2e8cf49e 983
2cdad34c 984 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 985 /* The target register may not be SP but the source may be. */
7517e550
NC
986 val = aarch64_get_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
987 + SCALE (offset, 16));
988 aarch64_set_reg_u32 (cpu, rt, NO_SP, val);
2e8cf49e
NC
989}
990
991/* 32 bit load zero-extended short unscaled signed 9 bit
992 with pre- or post-writeback. */
993static void
994ldrh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
995{
ef0d8ffc
NC
996 unsigned rn = INSTR (9, 5);
997 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
998 uint64_t address;
999
1000 if (rn == rt && wb != NoWriteBack)
1001 HALT_UNALLOC;
1002
1003 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1004
1005 if (wb != Post)
1006 address += offset;
1007
2cdad34c 1008 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 1009 aarch64_set_reg_u32 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
2e8cf49e
NC
1010
1011 if (wb == Post)
1012 address += offset;
1013
1014 if (wb != NoWriteBack)
1015 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1016}
1017
1018/* 32 bit load zero-extended short scaled or unscaled zero-
1019 or sign-extended 32-bit register offset. */
1020static void
1021ldrh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1022{
ef0d8ffc
NC
1023 unsigned rm = INSTR (20, 16);
1024 unsigned rn = INSTR (9, 5);
1025 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1026 /* rn may reference SP, rm and rt must reference ZR */
1027
1028 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1029 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1030 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1031
2cdad34c 1032 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 1033 aarch64_set_reg_u32 (cpu, rt, NO_SP,
2e8cf49e
NC
1034 aarch64_get_mem_u16 (cpu, address + displacement));
1035}
1036
1037/* 32 bit load sign-extended short scaled unsigned 12 bit. */
1038static void
1039ldrsh32_abs (sim_cpu *cpu, uint32_t offset)
1040{
ef0d8ffc
NC
1041 unsigned rn = INSTR (9, 5);
1042 unsigned rt = INSTR (4, 0);
7517e550 1043 int32_t val;
2e8cf49e 1044
2cdad34c 1045 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 1046 /* The target register may not be SP but the source may be. */
7517e550
NC
1047 val = aarch64_get_mem_s16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1048 + SCALE (offset, 16));
1049 aarch64_set_reg_s32 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1050}
1051
1052/* 32 bit load sign-extended short unscaled signed 9 bit
1053 with pre- or post-writeback. */
1054static void
1055ldrsh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1056{
ef0d8ffc
NC
1057 unsigned rn = INSTR (9, 5);
1058 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1059 uint64_t address;
1060
1061 if (rn == rt && wb != NoWriteBack)
1062 HALT_UNALLOC;
1063
1064 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1065
1066 if (wb != Post)
1067 address += offset;
1068
2cdad34c 1069 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1070 aarch64_set_reg_s32 (cpu, rt, NO_SP,
1071 (int32_t) aarch64_get_mem_s16 (cpu, address));
2e8cf49e
NC
1072
1073 if (wb == Post)
1074 address += offset;
1075
1076 if (wb != NoWriteBack)
1077 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1078}
1079
1080/* 32 bit load sign-extended short scaled or unscaled zero-
1081 or sign-extended 32-bit register offset. */
1082static void
1083ldrsh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1084{
ef0d8ffc
NC
1085 unsigned rm = INSTR (20, 16);
1086 unsigned rn = INSTR (9, 5);
1087 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1088 /* rn may reference SP, rm and rt must reference ZR */
1089
1090 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1091 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1092 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1093
2cdad34c 1094 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1095 aarch64_set_reg_s32 (cpu, rt, NO_SP,
1096 (int32_t) aarch64_get_mem_s16
2e8cf49e
NC
1097 (cpu, address + displacement));
1098}
1099
1100/* 64 bit load sign-extended short scaled unsigned 12 bit. */
1101static void
1102ldrsh_abs (sim_cpu *cpu, uint32_t offset)
1103{
ef0d8ffc
NC
1104 unsigned rn = INSTR (9, 5);
1105 unsigned rt = INSTR (4, 0);
7517e550 1106 int64_t val;
2e8cf49e 1107
2cdad34c 1108 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 1109 /* The target register may not be SP but the source may be. */
7517e550
NC
1110 val = aarch64_get_mem_s16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1111 + SCALE (offset, 16));
1112 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1113}
1114
1115/* 64 bit load sign-extended short unscaled signed 9 bit
1116 with pre- or post-writeback. */
1117static void
1118ldrsh64_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1119{
ef0d8ffc
NC
1120 unsigned rn = INSTR (9, 5);
1121 unsigned rt = INSTR (4, 0);
2e8cf49e 1122 uint64_t address;
7517e550 1123 int64_t val;
2e8cf49e
NC
1124
1125 if (rn == rt && wb != NoWriteBack)
1126 HALT_UNALLOC;
1127
2cdad34c 1128 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1129 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1130
1131 if (wb != Post)
1132 address += offset;
1133
7517e550
NC
1134 val = aarch64_get_mem_s16 (cpu, address);
1135 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1136
1137 if (wb == Post)
1138 address += offset;
1139
1140 if (wb != NoWriteBack)
1141 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1142}
1143
1144/* 64 bit load sign-extended short scaled or unscaled zero-
1145 or sign-extended 32-bit register offset. */
1146static void
1147ldrsh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1148{
ef0d8ffc
NC
1149 unsigned rm = INSTR (20, 16);
1150 unsigned rn = INSTR (9, 5);
1151 unsigned rt = INSTR (4, 0);
7517e550 1152
2e8cf49e
NC
1153 /* rn may reference SP, rm and rt must reference ZR */
1154
1155 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1156 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1157 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
7517e550 1158 int64_t val;
2e8cf49e 1159
2cdad34c 1160 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1161 val = aarch64_get_mem_s16 (cpu, address + displacement);
1162 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1163}
1164
1165/* 64 bit load sign-extended 32 bit scaled unsigned 12 bit. */
1166static void
1167ldrsw_abs (sim_cpu *cpu, uint32_t offset)
1168{
ef0d8ffc
NC
1169 unsigned rn = INSTR (9, 5);
1170 unsigned rt = INSTR (4, 0);
7517e550 1171 int64_t val;
2e8cf49e 1172
2cdad34c 1173 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1174 val = aarch64_get_mem_s32 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1175 + SCALE (offset, 32));
2e8cf49e 1176 /* The target register may not be SP but the source may be. */
7517e550 1177 return aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1178}
1179
1180/* 64 bit load sign-extended 32 bit unscaled signed 9 bit
1181 with pre- or post-writeback. */
1182static void
1183ldrsw_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1184{
ef0d8ffc
NC
1185 unsigned rn = INSTR (9, 5);
1186 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1187 uint64_t address;
1188
1189 if (rn == rt && wb != NoWriteBack)
1190 HALT_UNALLOC;
1191
1192 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1193
1194 if (wb != Post)
1195 address += offset;
1196
2cdad34c 1197 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1198 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32 (cpu, address));
1199
1200 if (wb == Post)
1201 address += offset;
1202
1203 if (wb != NoWriteBack)
1204 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1205}
1206
1207/* 64 bit load sign-extended 32 bit scaled or unscaled zero-
1208 or sign-extended 32-bit register offset. */
1209static void
1210ldrsw_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1211{
ef0d8ffc
NC
1212 unsigned rm = INSTR (20, 16);
1213 unsigned rn = INSTR (9, 5);
1214 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1215 /* rn may reference SP, rm and rt must reference ZR */
1216
1217 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1218 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1219 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1220
2cdad34c 1221 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1222 aarch64_set_reg_s64 (cpu, rt, NO_SP,
1223 aarch64_get_mem_s32 (cpu, address + displacement));
1224}
1225
1226/* N.B. with stores the value in source is written to the
1227 address identified by source2 modified by source3/offset. */
1228
1229/* 32 bit store scaled unsigned 12 bit. */
1230static void
1231str32_abs (sim_cpu *cpu, uint32_t offset)
1232{
ef0d8ffc
NC
1233 unsigned rn = INSTR (9, 5);
1234 unsigned rt = INSTR (4, 0);
2e8cf49e 1235
2cdad34c 1236 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1237 /* The target register may not be SP but the source may be. */
1238 aarch64_set_mem_u32 (cpu, (aarch64_get_reg_u64 (cpu, rn, SP_OK)
1239 + SCALE (offset, 32)),
1240 aarch64_get_reg_u32 (cpu, rt, NO_SP));
1241}
1242
1243/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
1244static void
1245str32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1246{
ef0d8ffc
NC
1247 unsigned rn = INSTR (9, 5);
1248 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1249 uint64_t address;
1250
1251 if (rn == rt && wb != NoWriteBack)
1252 HALT_UNALLOC;
1253
1254 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1255 if (wb != Post)
1256 address += offset;
1257
2cdad34c 1258 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1259 aarch64_set_mem_u32 (cpu, address, aarch64_get_reg_u32 (cpu, rt, NO_SP));
1260
1261 if (wb == Post)
1262 address += offset;
1263
1264 if (wb != NoWriteBack)
1265 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1266}
1267
1268/* 32 bit store scaled or unscaled zero- or
1269 sign-extended 32-bit register offset. */
1270static void
1271str32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1272{
ef0d8ffc
NC
1273 unsigned rm = INSTR (20, 16);
1274 unsigned rn = INSTR (9, 5);
1275 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1276
1277 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1278 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1279 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1280
2cdad34c 1281 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1282 aarch64_set_mem_u32 (cpu, address + displacement,
1283 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1284}
1285
1286/* 64 bit store scaled unsigned 12 bit. */
1287static void
1288str_abs (sim_cpu *cpu, uint32_t offset)
1289{
ef0d8ffc
NC
1290 unsigned rn = INSTR (9, 5);
1291 unsigned rt = INSTR (4, 0);
2e8cf49e 1292
2cdad34c 1293 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1294 aarch64_set_mem_u64 (cpu,
1295 aarch64_get_reg_u64 (cpu, rn, SP_OK)
1296 + SCALE (offset, 64),
1297 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1298}
1299
1300/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
1301static void
1302str_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1303{
ef0d8ffc
NC
1304 unsigned rn = INSTR (9, 5);
1305 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1306 uint64_t address;
1307
1308 if (rn == rt && wb != NoWriteBack)
1309 HALT_UNALLOC;
1310
1311 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1312
1313 if (wb != Post)
1314 address += offset;
1315
2cdad34c 1316 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1317 aarch64_set_mem_u64 (cpu, address, aarch64_get_reg_u64 (cpu, rt, NO_SP));
1318
1319 if (wb == Post)
1320 address += offset;
1321
1322 if (wb != NoWriteBack)
1323 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1324}
1325
1326/* 64 bit store scaled or unscaled zero-
1327 or sign-extended 32-bit register offset. */
1328static void
1329str_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1330{
ef0d8ffc
NC
1331 unsigned rm = INSTR (20, 16);
1332 unsigned rn = INSTR (9, 5);
1333 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1334 /* rn may reference SP, rm and rt must reference ZR */
1335
1336 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1337 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1338 extension);
1339 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1340
2cdad34c 1341 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1342 aarch64_set_mem_u64 (cpu, address + displacement,
1343 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1344}
1345
1346/* 32 bit store byte scaled unsigned 12 bit. */
1347static void
1348strb_abs (sim_cpu *cpu, uint32_t offset)
1349{
ef0d8ffc
NC
1350 unsigned rn = INSTR (9, 5);
1351 unsigned rt = INSTR (4, 0);
2e8cf49e 1352
2cdad34c 1353 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1354 /* The target register may not be SP but the source may be.
1355 There is no scaling required for a byte load. */
1356 aarch64_set_mem_u8 (cpu,
1357 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
1358 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1359}
1360
1361/* 32 bit store byte unscaled signed 9 bit with pre- or post-writeback. */
1362static void
1363strb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1364{
ef0d8ffc
NC
1365 unsigned rn = INSTR (9, 5);
1366 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1367 uint64_t address;
1368
1369 if (rn == rt && wb != NoWriteBack)
1370 HALT_UNALLOC;
1371
1372 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1373
1374 if (wb != Post)
1375 address += offset;
1376
2cdad34c 1377 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1378 aarch64_set_mem_u8 (cpu, address, aarch64_get_reg_u8 (cpu, rt, NO_SP));
1379
1380 if (wb == Post)
1381 address += offset;
1382
1383 if (wb != NoWriteBack)
1384 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1385}
1386
1387/* 32 bit store byte scaled or unscaled zero-
1388 or sign-extended 32-bit register offset. */
1389static void
1390strb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1391{
ef0d8ffc
NC
1392 unsigned rm = INSTR (20, 16);
1393 unsigned rn = INSTR (9, 5);
1394 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1395 /* rn may reference SP, rm and rt must reference ZR */
1396
1397 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1398 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1399 extension);
1400
2cdad34c 1401 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1402 /* There is no scaling required for a byte load. */
1403 aarch64_set_mem_u8 (cpu, address + displacement,
1404 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1405}
1406
1407/* 32 bit store short scaled unsigned 12 bit. */
1408static void
1409strh_abs (sim_cpu *cpu, uint32_t offset)
1410{
ef0d8ffc
NC
1411 unsigned rn = INSTR (9, 5);
1412 unsigned rt = INSTR (4, 0);
2e8cf49e 1413
2cdad34c 1414 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1415 /* The target register may not be SP but the source may be. */
1416 aarch64_set_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1417 + SCALE (offset, 16),
1418 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1419}
1420
1421/* 32 bit store short unscaled signed 9 bit with pre- or post-writeback. */
1422static void
1423strh_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1424{
ef0d8ffc
NC
1425 unsigned rn = INSTR (9, 5);
1426 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1427 uint64_t address;
1428
1429 if (rn == rt && wb != NoWriteBack)
1430 HALT_UNALLOC;
1431
1432 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1433
1434 if (wb != Post)
1435 address += offset;
1436
2cdad34c 1437 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1438 aarch64_set_mem_u16 (cpu, address, aarch64_get_reg_u16 (cpu, rt, NO_SP));
1439
1440 if (wb == Post)
1441 address += offset;
1442
1443 if (wb != NoWriteBack)
1444 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1445}
1446
1447/* 32 bit store short scaled or unscaled zero-
1448 or sign-extended 32-bit register offset. */
1449static void
1450strh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1451{
ef0d8ffc
NC
1452 unsigned rm = INSTR (20, 16);
1453 unsigned rn = INSTR (9, 5);
1454 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1455 /* rn may reference SP, rm and rt must reference ZR */
1456
1457 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1458 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1459 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1460
2cdad34c 1461 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1462 aarch64_set_mem_u16 (cpu, address + displacement,
1463 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1464}
1465
1466/* Prefetch unsigned 12 bit. */
1467static void
1468prfm_abs (sim_cpu *cpu, uint32_t offset)
1469{
1470 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1471 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1472 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1473 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1474 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1475 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1476 ow ==> UNALLOC
ef0d8ffc 1477 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1478 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK)
1479 + SCALE (offset, 64). */
1480
1481 /* TODO : implement prefetch of address. */
1482}
1483
1484/* Prefetch scaled or unscaled zero- or sign-extended 32-bit register offset. */
1485static void
1486prfm_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1487{
1488 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1489 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1490 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1491 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1492 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1493 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1494 ow ==> UNALLOC
1495 rn may reference SP, rm may only reference ZR
ef0d8ffc 1496 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1497 uint64_t base = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1498 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1499 extension);
1500 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1501 uint64_t address = base + displacement. */
1502
1503 /* TODO : implement prefetch of address */
1504}
1505
1506/* 64 bit pc-relative prefetch. */
1507static void
1508prfm_pcrel (sim_cpu *cpu, int32_t offset)
1509{
1510 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1511 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1512 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1513 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1514 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1515 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1516 ow ==> UNALLOC
ef0d8ffc 1517 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1518 uint64_t address = aarch64_get_PC (cpu) + offset. */
1519
1520 /* TODO : implement this */
1521}
1522
1523/* Load-store exclusive. */
1524
1525static void
1526ldxr (sim_cpu *cpu)
1527{
ef0d8ffc
NC
1528 unsigned rn = INSTR (9, 5);
1529 unsigned rt = INSTR (4, 0);
2e8cf49e 1530 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
ef0d8ffc
NC
1531 int size = INSTR (31, 30);
1532 /* int ordered = INSTR (15, 15); */
1533 /* int exclusive = ! INSTR (23, 23); */
2e8cf49e 1534
2cdad34c 1535 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1536 switch (size)
1537 {
1538 case 0:
1539 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
1540 break;
1541 case 1:
1542 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
1543 break;
1544 case 2:
1545 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
1546 break;
1547 case 3:
1548 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
1549 break;
2e8cf49e
NC
1550 }
1551}
1552
1553static void
1554stxr (sim_cpu *cpu)
1555{
ef0d8ffc
NC
1556 unsigned rn = INSTR (9, 5);
1557 unsigned rt = INSTR (4, 0);
1558 unsigned rs = INSTR (20, 16);
2e8cf49e 1559 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
ef0d8ffc 1560 int size = INSTR (31, 30);
2e8cf49e
NC
1561 uint64_t data = aarch64_get_reg_u64 (cpu, rt, NO_SP);
1562
1563 switch (size)
1564 {
1565 case 0: aarch64_set_mem_u8 (cpu, address, data); break;
1566 case 1: aarch64_set_mem_u16 (cpu, address, data); break;
1567 case 2: aarch64_set_mem_u32 (cpu, address, data); break;
1568 case 3: aarch64_set_mem_u64 (cpu, address, data); break;
2e8cf49e
NC
1569 }
1570
2cdad34c 1571 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1572 aarch64_set_reg_u64 (cpu, rs, NO_SP, 0); /* Always exclusive... */
1573}
1574
1575static void
1576dexLoadLiteral (sim_cpu *cpu)
1577{
1578 /* instr[29,27] == 011
1579 instr[25,24] == 00
1580 instr[31,30:26] = opc: 000 ==> LDRW, 001 ==> FLDRS
1581 010 ==> LDRX, 011 ==> FLDRD
1582 100 ==> LDRSW, 101 ==> FLDRQ
1583 110 ==> PRFM, 111 ==> UNALLOC
1584 instr[26] ==> V : 0 ==> GReg, 1 ==> FReg
1585 instr[23, 5] == simm19 */
1586
ef0d8ffc 1587 /* unsigned rt = INSTR (4, 0); */
7517e550 1588 uint32_t dispatch = (INSTR (31, 30) << 1) | INSTR (26, 26);
2e8cf49e
NC
1589 int32_t imm = simm32 (aarch64_get_instr (cpu), 23, 5);
1590
1591 switch (dispatch)
1592 {
1593 case 0: ldr32_pcrel (cpu, imm); break;
1594 case 1: fldrs_pcrel (cpu, imm); break;
1595 case 2: ldr_pcrel (cpu, imm); break;
1596 case 3: fldrd_pcrel (cpu, imm); break;
1597 case 4: ldrsw_pcrel (cpu, imm); break;
1598 case 5: fldrq_pcrel (cpu, imm); break;
1599 case 6: prfm_pcrel (cpu, imm); break;
1600 case 7:
1601 default:
1602 HALT_UNALLOC;
1603 }
1604}
1605
1606/* Immediate arithmetic
1607 The aimm argument is a 12 bit unsigned value or a 12 bit unsigned
1608 value left shifted by 12 bits (done at decode).
1609
1610 N.B. the register args (dest, source) can normally be Xn or SP.
1611 the exception occurs for flag setting instructions which may
1612 only use Xn for the output (dest). */
1613
1614/* 32 bit add immediate. */
1615static void
1616add32 (sim_cpu *cpu, uint32_t aimm)
1617{
ef0d8ffc
NC
1618 unsigned rn = INSTR (9, 5);
1619 unsigned rd = INSTR (4, 0);
2e8cf49e 1620
2cdad34c 1621 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1622 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1623 aarch64_get_reg_u32 (cpu, rn, SP_OK) + aimm);
1624}
1625
1626/* 64 bit add immediate. */
1627static void
1628add64 (sim_cpu *cpu, uint32_t aimm)
1629{
ef0d8ffc
NC
1630 unsigned rn = INSTR (9, 5);
1631 unsigned rd = INSTR (4, 0);
2e8cf49e 1632
2cdad34c 1633 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1634 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1635 aarch64_get_reg_u64 (cpu, rn, SP_OK) + aimm);
1636}
1637
1638static void
1639set_flags_for_add32 (sim_cpu *cpu, int32_t value1, int32_t value2)
1640{
1641 int32_t result = value1 + value2;
1642 int64_t sresult = (int64_t) value1 + (int64_t) value2;
1643 uint64_t uresult = (uint64_t)(uint32_t) value1
1644 + (uint64_t)(uint32_t) value2;
1645 uint32_t flags = 0;
1646
1647 if (result == 0)
1648 flags |= Z;
1649
1650 if (result & (1 << 31))
1651 flags |= N;
1652
1653 if (uresult != result)
1654 flags |= C;
1655
1656 if (sresult != result)
1657 flags |= V;
1658
1659 aarch64_set_CPSR (cpu, flags);
1660}
1661
963201cf
JW
1662#define NEG(a) (((a) & signbit) == signbit)
1663#define POS(a) (((a) & signbit) == 0)
1664
2e8cf49e
NC
1665static void
1666set_flags_for_add64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1667{
963201cf
JW
1668 uint64_t result = value1 + value2;
1669 uint32_t flags = 0;
1670 uint64_t signbit = 1ULL << 63;
2e8cf49e
NC
1671
1672 if (result == 0)
1673 flags |= Z;
1674
963201cf 1675 if (NEG (result))
2e8cf49e
NC
1676 flags |= N;
1677
963201cf
JW
1678 if ( (NEG (value1) && NEG (value2))
1679 || (NEG (value1) && POS (result))
1680 || (NEG (value2) && POS (result)))
1681 flags |= C;
1682
1683 if ( (NEG (value1) && NEG (value2) && POS (result))
1684 || (POS (value1) && POS (value2) && NEG (result)))
1685 flags |= V;
2e8cf49e
NC
1686
1687 aarch64_set_CPSR (cpu, flags);
1688}
1689
2e8cf49e
NC
1690static void
1691set_flags_for_sub32 (sim_cpu *cpu, uint32_t value1, uint32_t value2)
1692{
1693 uint32_t result = value1 - value2;
1694 uint32_t flags = 0;
57aa1742 1695 uint32_t signbit = 1U << 31;
2e8cf49e
NC
1696
1697 if (result == 0)
1698 flags |= Z;
1699
1700 if (NEG (result))
1701 flags |= N;
1702
1703 if ( (NEG (value1) && POS (value2))
1704 || (NEG (value1) && POS (result))
1705 || (POS (value2) && POS (result)))
1706 flags |= C;
1707
1708 if ( (NEG (value1) && POS (value2) && POS (result))
1709 || (POS (value1) && NEG (value2) && NEG (result)))
1710 flags |= V;
1711
1712 aarch64_set_CPSR (cpu, flags);
1713}
1714
1715static void
1716set_flags_for_sub64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1717{
1718 uint64_t result = value1 - value2;
1719 uint32_t flags = 0;
1720 uint64_t signbit = 1ULL << 63;
1721
1722 if (result == 0)
1723 flags |= Z;
1724
1725 if (NEG (result))
1726 flags |= N;
1727
1728 if ( (NEG (value1) && POS (value2))
1729 || (NEG (value1) && POS (result))
1730 || (POS (value2) && POS (result)))
1731 flags |= C;
1732
1733 if ( (NEG (value1) && POS (value2) && POS (result))
1734 || (POS (value1) && NEG (value2) && NEG (result)))
1735 flags |= V;
1736
1737 aarch64_set_CPSR (cpu, flags);
1738}
1739
1740static void
1741set_flags_for_binop32 (sim_cpu *cpu, uint32_t result)
1742{
1743 uint32_t flags = 0;
1744
1745 if (result == 0)
1746 flags |= Z;
1747 else
1748 flags &= ~ Z;
1749
1750 if (result & (1 << 31))
1751 flags |= N;
1752 else
1753 flags &= ~ N;
1754
1755 aarch64_set_CPSR (cpu, flags);
1756}
1757
1758static void
1759set_flags_for_binop64 (sim_cpu *cpu, uint64_t result)
1760{
1761 uint32_t flags = 0;
1762
1763 if (result == 0)
1764 flags |= Z;
1765 else
1766 flags &= ~ Z;
1767
1768 if (result & (1ULL << 63))
1769 flags |= N;
1770 else
1771 flags &= ~ N;
1772
1773 aarch64_set_CPSR (cpu, flags);
1774}
1775
1776/* 32 bit add immediate set flags. */
1777static void
1778adds32 (sim_cpu *cpu, uint32_t aimm)
1779{
ef0d8ffc
NC
1780 unsigned rn = INSTR (9, 5);
1781 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1782 /* TODO : do we need to worry about signs here? */
1783 int32_t value1 = aarch64_get_reg_s32 (cpu, rn, SP_OK);
1784
2cdad34c 1785 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1786 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + aimm);
1787 set_flags_for_add32 (cpu, value1, aimm);
1788}
1789
1790/* 64 bit add immediate set flags. */
1791static void
1792adds64 (sim_cpu *cpu, uint32_t aimm)
1793{
ef0d8ffc
NC
1794 unsigned rn = INSTR (9, 5);
1795 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1796 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1797 uint64_t value2 = aimm;
1798
2cdad34c 1799 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1800 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1801 set_flags_for_add64 (cpu, value1, value2);
1802}
1803
1804/* 32 bit sub immediate. */
1805static void
1806sub32 (sim_cpu *cpu, uint32_t aimm)
1807{
ef0d8ffc
NC
1808 unsigned rn = INSTR (9, 5);
1809 unsigned rd = INSTR (4, 0);
2e8cf49e 1810
2cdad34c 1811 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1812 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1813 aarch64_get_reg_u32 (cpu, rn, SP_OK) - aimm);
1814}
1815
1816/* 64 bit sub immediate. */
1817static void
1818sub64 (sim_cpu *cpu, uint32_t aimm)
1819{
ef0d8ffc
NC
1820 unsigned rn = INSTR (9, 5);
1821 unsigned rd = INSTR (4, 0);
2e8cf49e 1822
2cdad34c 1823 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1824 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1825 aarch64_get_reg_u64 (cpu, rn, SP_OK) - aimm);
1826}
1827
1828/* 32 bit sub immediate set flags. */
1829static void
1830subs32 (sim_cpu *cpu, uint32_t aimm)
1831{
ef0d8ffc
NC
1832 unsigned rn = INSTR (9, 5);
1833 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1834 uint32_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1835 uint32_t value2 = aimm;
1836
2cdad34c 1837 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1838 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1839 set_flags_for_sub32 (cpu, value1, value2);
1840}
1841
1842/* 64 bit sub immediate set flags. */
1843static void
1844subs64 (sim_cpu *cpu, uint32_t aimm)
1845{
ef0d8ffc
NC
1846 unsigned rn = INSTR (9, 5);
1847 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1848 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1849 uint32_t value2 = aimm;
1850
2cdad34c 1851 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1852 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1853 set_flags_for_sub64 (cpu, value1, value2);
1854}
1855
1856/* Data Processing Register. */
1857
1858/* First two helpers to perform the shift operations. */
1859
1860static inline uint32_t
1861shifted32 (uint32_t value, Shift shift, uint32_t count)
1862{
1863 switch (shift)
1864 {
1865 default:
1866 case LSL:
1867 return (value << count);
1868 case LSR:
1869 return (value >> count);
1870 case ASR:
1871 {
1872 int32_t svalue = value;
1873 return (svalue >> count);
1874 }
1875 case ROR:
1876 {
1877 uint32_t top = value >> count;
1878 uint32_t bottom = value << (32 - count);
1879 return (bottom | top);
1880 }
1881 }
1882}
1883
1884static inline uint64_t
1885shifted64 (uint64_t value, Shift shift, uint32_t count)
1886{
1887 switch (shift)
1888 {
1889 default:
1890 case LSL:
1891 return (value << count);
1892 case LSR:
1893 return (value >> count);
1894 case ASR:
1895 {
1896 int64_t svalue = value;
1897 return (svalue >> count);
1898 }
1899 case ROR:
1900 {
1901 uint64_t top = value >> count;
1902 uint64_t bottom = value << (64 - count);
1903 return (bottom | top);
1904 }
1905 }
1906}
1907
1908/* Arithmetic shifted register.
1909 These allow an optional LSL, ASR or LSR to the second source
1910 register with a count up to the register bit count.
1911
1912 N.B register args may not be SP. */
1913
1914/* 32 bit ADD shifted register. */
1915static void
1916add32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1917{
ef0d8ffc
NC
1918 unsigned rm = INSTR (20, 16);
1919 unsigned rn = INSTR (9, 5);
1920 unsigned rd = INSTR (4, 0);
2e8cf49e 1921
2cdad34c 1922 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1923 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1924 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1925 + shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1926 shift, count));
1927}
1928
1929/* 64 bit ADD shifted register. */
1930static void
1931add64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1932{
ef0d8ffc
NC
1933 unsigned rm = INSTR (20, 16);
1934 unsigned rn = INSTR (9, 5);
1935 unsigned rd = INSTR (4, 0);
2e8cf49e 1936
2cdad34c 1937 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1938 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1939 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1940 + shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1941 shift, count));
1942}
1943
1944/* 32 bit ADD shifted register setting flags. */
1945static void
1946adds32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1947{
ef0d8ffc
NC
1948 unsigned rm = INSTR (20, 16);
1949 unsigned rn = INSTR (9, 5);
1950 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1951
1952 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1953 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1954 shift, count);
1955
2cdad34c 1956 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1957 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1958 set_flags_for_add32 (cpu, value1, value2);
1959}
1960
1961/* 64 bit ADD shifted register setting flags. */
1962static void
1963adds64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1964{
ef0d8ffc
NC
1965 unsigned rm = INSTR (20, 16);
1966 unsigned rn = INSTR (9, 5);
1967 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1968
1969 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1970 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1971 shift, count);
1972
2cdad34c 1973 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1974 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1975 set_flags_for_add64 (cpu, value1, value2);
1976}
1977
1978/* 32 bit SUB shifted register. */
1979static void
1980sub32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1981{
ef0d8ffc
NC
1982 unsigned rm = INSTR (20, 16);
1983 unsigned rn = INSTR (9, 5);
1984 unsigned rd = INSTR (4, 0);
2e8cf49e 1985
2cdad34c 1986 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1987 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1988 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1989 - shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1990 shift, count));
1991}
1992
1993/* 64 bit SUB shifted register. */
1994static void
1995sub64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1996{
ef0d8ffc
NC
1997 unsigned rm = INSTR (20, 16);
1998 unsigned rn = INSTR (9, 5);
1999 unsigned rd = INSTR (4, 0);
2e8cf49e 2000
2cdad34c 2001 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2002 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2003 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2004 - shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
2005 shift, count));
2006}
2007
2008/* 32 bit SUB shifted register setting flags. */
2009static void
2010subs32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
2011{
ef0d8ffc
NC
2012 unsigned rm = INSTR (20, 16);
2013 unsigned rn = INSTR (9, 5);
2014 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2015
2016 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2017 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
2018 shift, count);
2019
2cdad34c 2020 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2021 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2022 set_flags_for_sub32 (cpu, value1, value2);
2023}
2024
2025/* 64 bit SUB shifted register setting flags. */
2026static void
2027subs64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
2028{
ef0d8ffc
NC
2029 unsigned rm = INSTR (20, 16);
2030 unsigned rn = INSTR (9, 5);
2031 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2032
2033 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2034 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
2035 shift, count);
2036
2cdad34c 2037 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2038 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2039 set_flags_for_sub64 (cpu, value1, value2);
2040}
2041
2042/* First a couple more helpers to fetch the
2043 relevant source register element either
2044 sign or zero extended as required by the
2045 extension value. */
2046
2047static uint32_t
2048extreg32 (sim_cpu *cpu, unsigned int lo, Extension extension)
2049{
2050 switch (extension)
2051 {
2052 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
2053 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
2054 case UXTW: /* Fall through. */
2055 case UXTX: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
2056 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
2057 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
2058 case SXTW: /* Fall through. */
2059 case SXTX: /* Fall through. */
2060 default: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
2061 }
2062}
2063
2064static uint64_t
2065extreg64 (sim_cpu *cpu, unsigned int lo, Extension extension)
2066{
2067 switch (extension)
2068 {
2069 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
2070 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
2071 case UXTW: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
2072 case UXTX: return aarch64_get_reg_u64 (cpu, lo, NO_SP);
2073 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
2074 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
2075 case SXTW: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
2076 case SXTX:
2077 default: return aarch64_get_reg_s64 (cpu, lo, NO_SP);
2078 }
2079}
2080
2081/* Arithmetic extending register
2082 These allow an optional sign extension of some portion of the
2083 second source register followed by an optional left shift of
2084 between 1 and 4 bits (i.e. a shift of 0-4 bits???)
2085
2086 N.B output (dest) and first input arg (source) may normally be Xn
2087 or SP. However, for flag setting operations dest can only be
2088 Xn. Second input registers are always Xn. */
2089
2090/* 32 bit ADD extending register. */
2091static void
2092add32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2093{
ef0d8ffc
NC
2094 unsigned rm = INSTR (20, 16);
2095 unsigned rn = INSTR (9, 5);
2096 unsigned rd = INSTR (4, 0);
2e8cf49e 2097
2cdad34c 2098 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2099 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2100 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2101 + (extreg32 (cpu, rm, extension) << shift));
2102}
2103
2104/* 64 bit ADD extending register.
2105 N.B. This subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2106static void
2107add64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2108{
ef0d8ffc
NC
2109 unsigned rm = INSTR (20, 16);
2110 unsigned rn = INSTR (9, 5);
2111 unsigned rd = INSTR (4, 0);
2e8cf49e 2112
2cdad34c 2113 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2114 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2115 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2116 + (extreg64 (cpu, rm, extension) << shift));
2117}
2118
2119/* 32 bit ADD extending register setting flags. */
2120static void
2121adds32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2122{
ef0d8ffc
NC
2123 unsigned rm = INSTR (20, 16);
2124 unsigned rn = INSTR (9, 5);
2125 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2126
2127 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2128 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2129
2cdad34c 2130 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2131 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2132 set_flags_for_add32 (cpu, value1, value2);
2133}
2134
2135/* 64 bit ADD extending register setting flags */
2136/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2137static void
2138adds64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2139{
ef0d8ffc
NC
2140 unsigned rm = INSTR (20, 16);
2141 unsigned rn = INSTR (9, 5);
2142 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2143
2144 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2145 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2146
2cdad34c 2147 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2148 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2149 set_flags_for_add64 (cpu, value1, value2);
2150}
2151
2152/* 32 bit SUB extending register. */
2153static void
2154sub32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2155{
ef0d8ffc
NC
2156 unsigned rm = INSTR (20, 16);
2157 unsigned rn = INSTR (9, 5);
2158 unsigned rd = INSTR (4, 0);
2e8cf49e 2159
2cdad34c 2160 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2161 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2162 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2163 - (extreg32 (cpu, rm, extension) << shift));
2164}
2165
2166/* 64 bit SUB extending register. */
2167/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2168static void
2169sub64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2170{
ef0d8ffc
NC
2171 unsigned rm = INSTR (20, 16);
2172 unsigned rn = INSTR (9, 5);
2173 unsigned rd = INSTR (4, 0);
2e8cf49e 2174
2cdad34c 2175 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2176 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2177 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2178 - (extreg64 (cpu, rm, extension) << shift));
2179}
2180
2181/* 32 bit SUB extending register setting flags. */
2182static void
2183subs32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2184{
ef0d8ffc
NC
2185 unsigned rm = INSTR (20, 16);
2186 unsigned rn = INSTR (9, 5);
2187 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2188
2189 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2190 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2191
2cdad34c 2192 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2193 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2194 set_flags_for_sub32 (cpu, value1, value2);
2195}
2196
2197/* 64 bit SUB extending register setting flags */
2198/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2199static void
2200subs64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2201{
ef0d8ffc
NC
2202 unsigned rm = INSTR (20, 16);
2203 unsigned rn = INSTR (9, 5);
2204 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2205
2206 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2207 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2208
2cdad34c 2209 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2210 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2211 set_flags_for_sub64 (cpu, value1, value2);
2212}
2213
2214static void
2215dexAddSubtractImmediate (sim_cpu *cpu)
2216{
2217 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2218 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2219 instr[29] = set : 0 ==> no flags, 1 ==> set flags
2220 instr[28,24] = 10001
2221 instr[23,22] = shift : 00 == LSL#0, 01 = LSL#12 1x = UNALLOC
2222 instr[21,10] = uimm12
2223 instr[9,5] = Rn
2224 instr[4,0] = Rd */
2225
2226 /* N.B. the shift is applied at decode before calling the add/sub routine. */
ef0d8ffc
NC
2227 uint32_t shift = INSTR (23, 22);
2228 uint32_t imm = INSTR (21, 10);
2229 uint32_t dispatch = INSTR (31, 29);
2e8cf49e
NC
2230
2231 NYI_assert (28, 24, 0x11);
2232
2233 if (shift > 1)
2234 HALT_UNALLOC;
2235
2236 if (shift)
2237 imm <<= 12;
2238
2239 switch (dispatch)
2240 {
2241 case 0: add32 (cpu, imm); break;
2242 case 1: adds32 (cpu, imm); break;
2243 case 2: sub32 (cpu, imm); break;
2244 case 3: subs32 (cpu, imm); break;
2245 case 4: add64 (cpu, imm); break;
2246 case 5: adds64 (cpu, imm); break;
2247 case 6: sub64 (cpu, imm); break;
2248 case 7: subs64 (cpu, imm); break;
2e8cf49e
NC
2249 }
2250}
2251
2252static void
2253dexAddSubtractShiftedRegister (sim_cpu *cpu)
2254{
2255 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2256 instr[30,29] = op : 00 ==> ADD, 01 ==> ADDS, 10 ==> SUB, 11 ==> SUBS
2257 instr[28,24] = 01011
2258 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> UNALLOC
2259 instr[21] = 0
2260 instr[20,16] = Rm
2261 instr[15,10] = count : must be 0xxxxx for 32 bit
2262 instr[9,5] = Rn
2263 instr[4,0] = Rd */
2264
ef0d8ffc
NC
2265 uint32_t size = INSTR (31, 31);
2266 uint32_t count = INSTR (15, 10);
2267 Shift shiftType = INSTR (23, 22);
2e8cf49e
NC
2268
2269 NYI_assert (28, 24, 0x0B);
2270 NYI_assert (21, 21, 0);
2271
ef0d8ffc 2272 /* Shift encoded as ROR is unallocated. */
2e8cf49e
NC
2273 if (shiftType == ROR)
2274 HALT_UNALLOC;
2275
ef0d8ffc
NC
2276 /* 32 bit operations must have count[5] = 0
2277 or else we have an UNALLOC. */
2278 if (size == 0 && uimm (count, 5, 5))
2e8cf49e
NC
2279 HALT_UNALLOC;
2280
ef0d8ffc
NC
2281 /* Dispatch on size:op i.e instr [31,29]. */
2282 switch (INSTR (31, 29))
2e8cf49e
NC
2283 {
2284 case 0: add32_shift (cpu, shiftType, count); break;
2285 case 1: adds32_shift (cpu, shiftType, count); break;
2286 case 2: sub32_shift (cpu, shiftType, count); break;
2287 case 3: subs32_shift (cpu, shiftType, count); break;
2288 case 4: add64_shift (cpu, shiftType, count); break;
2289 case 5: adds64_shift (cpu, shiftType, count); break;
2290 case 6: sub64_shift (cpu, shiftType, count); break;
2291 case 7: subs64_shift (cpu, shiftType, count); break;
2e8cf49e
NC
2292 }
2293}
2294
2295static void
2296dexAddSubtractExtendedRegister (sim_cpu *cpu)
2297{
2298 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2299 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2300 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2301 instr[28,24] = 01011
2302 instr[23,22] = opt : 0 ==> ok, 1,2,3 ==> UNALLOC
2303 instr[21] = 1
2304 instr[20,16] = Rm
2305 instr[15,13] = option : 000 ==> UXTB, 001 ==> UXTH,
2306 000 ==> LSL|UXTW, 001 ==> UXTZ,
2307 000 ==> SXTB, 001 ==> SXTH,
2308 000 ==> SXTW, 001 ==> SXTX,
2309 instr[12,10] = shift : 0,1,2,3,4 ==> ok, 5,6,7 ==> UNALLOC
2310 instr[9,5] = Rn
2311 instr[4,0] = Rd */
2312
ef0d8ffc
NC
2313 Extension extensionType = INSTR (15, 13);
2314 uint32_t shift = INSTR (12, 10);
2e8cf49e
NC
2315
2316 NYI_assert (28, 24, 0x0B);
2317 NYI_assert (21, 21, 1);
2318
2319 /* Shift may not exceed 4. */
2320 if (shift > 4)
2321 HALT_UNALLOC;
2322
ef0d8ffc
NC
2323 /* Dispatch on size:op:set?. */
2324 switch (INSTR (31, 29))
2e8cf49e
NC
2325 {
2326 case 0: add32_ext (cpu, extensionType, shift); break;
2327 case 1: adds32_ext (cpu, extensionType, shift); break;
2328 case 2: sub32_ext (cpu, extensionType, shift); break;
2329 case 3: subs32_ext (cpu, extensionType, shift); break;
2330 case 4: add64_ext (cpu, extensionType, shift); break;
2331 case 5: adds64_ext (cpu, extensionType, shift); break;
2332 case 6: sub64_ext (cpu, extensionType, shift); break;
2333 case 7: subs64_ext (cpu, extensionType, shift); break;
2e8cf49e
NC
2334 }
2335}
2336
2337/* Conditional data processing
2338 Condition register is implicit 3rd source. */
2339
2340/* 32 bit add with carry. */
2341/* N.B register args may not be SP. */
2342
2343static void
2344adc32 (sim_cpu *cpu)
2345{
ef0d8ffc
NC
2346 unsigned rm = INSTR (20, 16);
2347 unsigned rn = INSTR (9, 5);
2348 unsigned rd = INSTR (4, 0);
2e8cf49e 2349
2cdad34c 2350 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2351 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2352 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2353 + aarch64_get_reg_u32 (cpu, rm, NO_SP)
2354 + IS_SET (C));
2355}
2356
2357/* 64 bit add with carry */
2358static void
2359adc64 (sim_cpu *cpu)
2360{
ef0d8ffc
NC
2361 unsigned rm = INSTR (20, 16);
2362 unsigned rn = INSTR (9, 5);
2363 unsigned rd = INSTR (4, 0);
2e8cf49e 2364
2cdad34c 2365 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2366 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2367 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2368 + aarch64_get_reg_u64 (cpu, rm, NO_SP)
2369 + IS_SET (C));
2370}
2371
2372/* 32 bit add with carry setting flags. */
2373static void
2374adcs32 (sim_cpu *cpu)
2375{
ef0d8ffc
NC
2376 unsigned rm = INSTR (20, 16);
2377 unsigned rn = INSTR (9, 5);
2378 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2379
2380 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2381 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2382 uint32_t carry = IS_SET (C);
2383
2cdad34c 2384 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2385 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2386 set_flags_for_add32 (cpu, value1, value2 + carry);
2387}
2388
2389/* 64 bit add with carry setting flags. */
2390static void
2391adcs64 (sim_cpu *cpu)
2392{
ef0d8ffc
NC
2393 unsigned rm = INSTR (20, 16);
2394 unsigned rn = INSTR (9, 5);
2395 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2396
2397 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2398 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2399 uint64_t carry = IS_SET (C);
2400
2cdad34c 2401 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2402 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2403 set_flags_for_add64 (cpu, value1, value2 + carry);
2404}
2405
2406/* 32 bit sub with carry. */
2407static void
2408sbc32 (sim_cpu *cpu)
2409{
ef0d8ffc
NC
2410 unsigned rm = INSTR (20, 16);
2411 unsigned rn = INSTR (9, 5); /* ngc iff rn == 31. */
2412 unsigned rd = INSTR (4, 0);
2e8cf49e 2413
2cdad34c 2414 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2415 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2416 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2417 - aarch64_get_reg_u32 (cpu, rm, NO_SP)
2418 - 1 + IS_SET (C));
2419}
2420
2421/* 64 bit sub with carry */
2422static void
2423sbc64 (sim_cpu *cpu)
2424{
ef0d8ffc
NC
2425 unsigned rm = INSTR (20, 16);
2426 unsigned rn = INSTR (9, 5);
2427 unsigned rd = INSTR (4, 0);
2e8cf49e 2428
2cdad34c 2429 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2430 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2431 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2432 - aarch64_get_reg_u64 (cpu, rm, NO_SP)
2433 - 1 + IS_SET (C));
2434}
2435
2436/* 32 bit sub with carry setting flags */
2437static void
2438sbcs32 (sim_cpu *cpu)
2439{
ef0d8ffc
NC
2440 unsigned rm = INSTR (20, 16);
2441 unsigned rn = INSTR (9, 5);
2442 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2443
2444 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2445 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2446 uint32_t carry = IS_SET (C);
2447 uint32_t result = value1 - value2 + 1 - carry;
2448
2cdad34c 2449 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2450 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2451 set_flags_for_sub32 (cpu, value1, value2 + 1 - carry);
2452}
2453
2454/* 64 bit sub with carry setting flags */
2455static void
2456sbcs64 (sim_cpu *cpu)
2457{
ef0d8ffc
NC
2458 unsigned rm = INSTR (20, 16);
2459 unsigned rn = INSTR (9, 5);
2460 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2461
2462 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2463 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2464 uint64_t carry = IS_SET (C);
2465 uint64_t result = value1 - value2 + 1 - carry;
2466
2cdad34c 2467 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2468 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2469 set_flags_for_sub64 (cpu, value1, value2 + 1 - carry);
2470}
2471
2472static void
2473dexAddSubtractWithCarry (sim_cpu *cpu)
2474{
2475 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2476 instr[30] = op : 0 ==> ADC, 1 ==> SBC
2477 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2478 instr[28,21] = 1 1010 000
2479 instr[20,16] = Rm
2480 instr[15,10] = op2 : 00000 ==> ok, ow ==> UNALLOC
2481 instr[9,5] = Rn
2482 instr[4,0] = Rd */
2483
ef0d8ffc 2484 uint32_t op2 = INSTR (15, 10);
2e8cf49e
NC
2485
2486 NYI_assert (28, 21, 0xD0);
2487
2488 if (op2 != 0)
2489 HALT_UNALLOC;
2490
ef0d8ffc
NC
2491 /* Dispatch on size:op:set?. */
2492 switch (INSTR (31, 29))
2e8cf49e
NC
2493 {
2494 case 0: adc32 (cpu); break;
2495 case 1: adcs32 (cpu); break;
2496 case 2: sbc32 (cpu); break;
2497 case 3: sbcs32 (cpu); break;
2498 case 4: adc64 (cpu); break;
2499 case 5: adcs64 (cpu); break;
2500 case 6: sbc64 (cpu); break;
2501 case 7: sbcs64 (cpu); break;
2e8cf49e
NC
2502 }
2503}
2504
2505static uint32_t
2506testConditionCode (sim_cpu *cpu, CondCode cc)
2507{
2508 /* This should be reduceable to branchless logic
2509 by some careful testing of bits in CC followed
2510 by the requisite masking and combining of bits
2511 from the flag register.
2512
2513 For now we do it with a switch. */
2514 int res;
2515
2516 switch (cc)
2517 {
2518 case EQ: res = IS_SET (Z); break;
2519 case NE: res = IS_CLEAR (Z); break;
2520 case CS: res = IS_SET (C); break;
2521 case CC: res = IS_CLEAR (C); break;
2522 case MI: res = IS_SET (N); break;
2523 case PL: res = IS_CLEAR (N); break;
2524 case VS: res = IS_SET (V); break;
2525 case VC: res = IS_CLEAR (V); break;
2526 case HI: res = IS_SET (C) && IS_CLEAR (Z); break;
2527 case LS: res = IS_CLEAR (C) || IS_SET (Z); break;
2528 case GE: res = IS_SET (N) == IS_SET (V); break;
2529 case LT: res = IS_SET (N) != IS_SET (V); break;
2530 case GT: res = IS_CLEAR (Z) && (IS_SET (N) == IS_SET (V)); break;
2531 case LE: res = IS_SET (Z) || (IS_SET (N) != IS_SET (V)); break;
2532 case AL:
2533 case NV:
2534 default:
2535 res = 1;
2536 break;
2537 }
2538 return res;
2539}
2540
2541static void
2542CondCompare (sim_cpu *cpu) /* aka: ccmp and ccmn */
2543{
2544 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
57aa1742 2545 instr[30] = compare with positive (1) or negative value (0)
2e8cf49e
NC
2546 instr[29,21] = 1 1101 0010
2547 instr[20,16] = Rm or const
2548 instr[15,12] = cond
2549 instr[11] = compare reg (0) or const (1)
2550 instr[10] = 0
2551 instr[9,5] = Rn
2552 instr[4] = 0
2553 instr[3,0] = value for CPSR bits if the comparison does not take place. */
2554 signed int negate;
2555 unsigned rm;
2556 unsigned rn;
2557
2558 NYI_assert (29, 21, 0x1d2);
2559 NYI_assert (10, 10, 0);
2560 NYI_assert (4, 4, 0);
2561
2cdad34c 2562 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2563 if (! testConditionCode (cpu, INSTR (15, 12)))
2e8cf49e 2564 {
ef0d8ffc 2565 aarch64_set_CPSR (cpu, INSTR (3, 0));
2e8cf49e
NC
2566 return;
2567 }
2568
ef0d8ffc
NC
2569 negate = INSTR (30, 30) ? 1 : -1;
2570 rm = INSTR (20, 16);
2571 rn = INSTR ( 9, 5);
2e8cf49e 2572
ef0d8ffc 2573 if (INSTR (31, 31))
2e8cf49e 2574 {
ef0d8ffc 2575 if (INSTR (11, 11))
2e8cf49e
NC
2576 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2577 negate * (uint64_t) rm);
2578 else
2579 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2580 negate * aarch64_get_reg_u64 (cpu, rm, SP_OK));
2581 }
2582 else
2583 {
ef0d8ffc 2584 if (INSTR (11, 11))
2e8cf49e
NC
2585 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2586 negate * rm);
2587 else
2588 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2589 negate * aarch64_get_reg_u32 (cpu, rm, SP_OK));
2590 }
2591}
2592
2593static void
2594do_vec_MOV_whole_vector (sim_cpu *cpu)
2595{
2596 /* MOV Vd.T, Vs.T (alias for ORR Vd.T, Vn.T, Vm.T where Vn == Vm)
2597
2598 instr[31] = 0
2599 instr[30] = half(0)/full(1)
2600 instr[29,21] = 001110101
2601 instr[20,16] = Vs
2602 instr[15,10] = 000111
2603 instr[9,5] = Vs
2604 instr[4,0] = Vd */
2605
ef0d8ffc
NC
2606 unsigned vs = INSTR (9, 5);
2607 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2608
2609 NYI_assert (29, 21, 0x075);
2610 NYI_assert (15, 10, 0x07);
2611
ef0d8ffc 2612 if (INSTR (20, 16) != vs)
2e8cf49e
NC
2613 HALT_NYI;
2614
2cdad34c 2615 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2616 if (INSTR (30, 30))
2e8cf49e
NC
2617 aarch64_set_vec_u64 (cpu, vd, 1, aarch64_get_vec_u64 (cpu, vs, 1));
2618
2619 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vs, 0));
2620}
2621
2622static void
2623do_vec_MOV_into_scalar (sim_cpu *cpu)
2624{
2625 /* instr[31] = 0
2626 instr[30] = word(0)/long(1)
2627 instr[29,21] = 00 1110 000
2628 instr[20,18] = element size and index
2629 instr[17,10] = 00 0011 11
2630 instr[9,5] = V source
2631 instr[4,0] = R dest */
2632
ef0d8ffc
NC
2633 unsigned vs = INSTR (9, 5);
2634 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2635
2636 NYI_assert (29, 21, 0x070);
2637 NYI_assert (17, 10, 0x0F);
2638
2cdad34c 2639 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2640 switch (INSTR (20, 18))
2e8cf49e
NC
2641 {
2642 case 0x2:
2643 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 0));
2644 break;
2645
2646 case 0x6:
2647 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 1));
2648 break;
2649
2650 case 0x1:
2651 case 0x3:
2652 case 0x5:
2653 case 0x7:
2654 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u32
ef0d8ffc 2655 (cpu, vs, INSTR (20, 19)));
2e8cf49e
NC
2656 break;
2657
2658 default:
2659 HALT_NYI;
2660 }
2661}
2662
2663static void
2664do_vec_INS (sim_cpu *cpu)
2665{
2666 /* instr[31,21] = 01001110000
2667 instr[20,16] = element size and index
2668 instr[15,10] = 000111
2669 instr[9,5] = W source
2670 instr[4,0] = V dest */
2671
2672 int index;
ef0d8ffc
NC
2673 unsigned rs = INSTR (9, 5);
2674 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2675
2676 NYI_assert (31, 21, 0x270);
2677 NYI_assert (15, 10, 0x07);
2678
2cdad34c 2679 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2680 if (INSTR (16, 16))
2e8cf49e 2681 {
ef0d8ffc 2682 index = INSTR (20, 17);
2e8cf49e
NC
2683 aarch64_set_vec_u8 (cpu, vd, index,
2684 aarch64_get_reg_u8 (cpu, rs, NO_SP));
2685 }
ef0d8ffc 2686 else if (INSTR (17, 17))
2e8cf49e 2687 {
ef0d8ffc 2688 index = INSTR (20, 18);
2e8cf49e
NC
2689 aarch64_set_vec_u16 (cpu, vd, index,
2690 aarch64_get_reg_u16 (cpu, rs, NO_SP));
2691 }
ef0d8ffc 2692 else if (INSTR (18, 18))
2e8cf49e 2693 {
ef0d8ffc 2694 index = INSTR (20, 19);
2e8cf49e
NC
2695 aarch64_set_vec_u32 (cpu, vd, index,
2696 aarch64_get_reg_u32 (cpu, rs, NO_SP));
2697 }
ef0d8ffc 2698 else if (INSTR (19, 19))
2e8cf49e 2699 {
ef0d8ffc 2700 index = INSTR (20, 20);
2e8cf49e
NC
2701 aarch64_set_vec_u64 (cpu, vd, index,
2702 aarch64_get_reg_u64 (cpu, rs, NO_SP));
2703 }
2704 else
2705 HALT_NYI;
2706}
2707
2708static void
2709do_vec_DUP_vector_into_vector (sim_cpu *cpu)
2710{
2711 /* instr[31] = 0
2712 instr[30] = half(0)/full(1)
2713 instr[29,21] = 00 1110 000
2714 instr[20,16] = element size and index
2715 instr[15,10] = 0000 01
2716 instr[9,5] = V source
2717 instr[4,0] = V dest. */
2718
ef0d8ffc
NC
2719 unsigned full = INSTR (30, 30);
2720 unsigned vs = INSTR (9, 5);
2721 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2722 int i, index;
2723
2724 NYI_assert (29, 21, 0x070);
2725 NYI_assert (15, 10, 0x01);
2726
2cdad34c 2727 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2728 if (INSTR (16, 16))
2e8cf49e 2729 {
ef0d8ffc 2730 index = INSTR (20, 17);
2e8cf49e
NC
2731
2732 for (i = 0; i < (full ? 16 : 8); i++)
2733 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, index));
2734 }
ef0d8ffc 2735 else if (INSTR (17, 17))
2e8cf49e 2736 {
ef0d8ffc 2737 index = INSTR (20, 18);
2e8cf49e
NC
2738
2739 for (i = 0; i < (full ? 8 : 4); i++)
2740 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, index));
2741 }
ef0d8ffc 2742 else if (INSTR (18, 18))
2e8cf49e 2743 {
ef0d8ffc 2744 index = INSTR (20, 19);
2e8cf49e
NC
2745
2746 for (i = 0; i < (full ? 4 : 2); i++)
2747 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, index));
2748 }
2749 else
2750 {
ef0d8ffc 2751 if (INSTR (19, 19) == 0)
2e8cf49e
NC
2752 HALT_UNALLOC;
2753
2754 if (! full)
2755 HALT_UNALLOC;
2756
ef0d8ffc 2757 index = INSTR (20, 20);
2e8cf49e
NC
2758
2759 for (i = 0; i < 2; i++)
2760 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, index));
2761 }
2762}
2763
2764static void
2765do_vec_TBL (sim_cpu *cpu)
2766{
2767 /* instr[31] = 0
2768 instr[30] = half(0)/full(1)
2769 instr[29,21] = 00 1110 000
2770 instr[20,16] = Vm
2771 instr[15] = 0
2772 instr[14,13] = vec length
2773 instr[12,10] = 000
2774 instr[9,5] = V start
2775 instr[4,0] = V dest */
2776
ef0d8ffc
NC
2777 int full = INSTR (30, 30);
2778 int len = INSTR (14, 13) + 1;
2779 unsigned vm = INSTR (20, 16);
2780 unsigned vn = INSTR (9, 5);
2781 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2782 unsigned i;
2783
2784 NYI_assert (29, 21, 0x070);
2785 NYI_assert (12, 10, 0);
2786
2cdad34c 2787 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2788 for (i = 0; i < (full ? 16 : 8); i++)
2789 {
2790 unsigned int selector = aarch64_get_vec_u8 (cpu, vm, i);
2791 uint8_t val;
2792
2793 if (selector < 16)
2794 val = aarch64_get_vec_u8 (cpu, vn, selector);
2795 else if (selector < 32)
2796 val = len < 2 ? 0 : aarch64_get_vec_u8 (cpu, vn + 1, selector - 16);
2797 else if (selector < 48)
2798 val = len < 3 ? 0 : aarch64_get_vec_u8 (cpu, vn + 2, selector - 32);
2799 else if (selector < 64)
2800 val = len < 4 ? 0 : aarch64_get_vec_u8 (cpu, vn + 3, selector - 48);
2801 else
2802 val = 0;
2803
2804 aarch64_set_vec_u8 (cpu, vd, i, val);
2805 }
2806}
2807
2808static void
2809do_vec_TRN (sim_cpu *cpu)
2810{
2811 /* instr[31] = 0
2812 instr[30] = half(0)/full(1)
2813 instr[29,24] = 00 1110
2814 instr[23,22] = size
2815 instr[21] = 0
2816 instr[20,16] = Vm
2817 instr[15] = 0
2818 instr[14] = TRN1 (0) / TRN2 (1)
2819 instr[13,10] = 1010
2820 instr[9,5] = V source
2821 instr[4,0] = V dest. */
2822
ef0d8ffc
NC
2823 int full = INSTR (30, 30);
2824 int second = INSTR (14, 14);
2825 unsigned vm = INSTR (20, 16);
2826 unsigned vn = INSTR (9, 5);
2827 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2828 unsigned i;
2829
2830 NYI_assert (29, 24, 0x0E);
2831 NYI_assert (13, 10, 0xA);
2832
2cdad34c 2833 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2834 switch (INSTR (23, 22))
2e8cf49e
NC
2835 {
2836 case 0:
2837 for (i = 0; i < (full ? 8 : 4); i++)
2838 {
2839 aarch64_set_vec_u8
2840 (cpu, vd, i * 2,
2841 aarch64_get_vec_u8 (cpu, second ? vm : vn, i * 2));
2842 aarch64_set_vec_u8
2843 (cpu, vd, 1 * 2 + 1,
2844 aarch64_get_vec_u8 (cpu, second ? vn : vm, i * 2 + 1));
2845 }
2846 break;
2847
2848 case 1:
2849 for (i = 0; i < (full ? 4 : 2); i++)
2850 {
2851 aarch64_set_vec_u16
2852 (cpu, vd, i * 2,
2853 aarch64_get_vec_u16 (cpu, second ? vm : vn, i * 2));
2854 aarch64_set_vec_u16
2855 (cpu, vd, 1 * 2 + 1,
2856 aarch64_get_vec_u16 (cpu, second ? vn : vm, i * 2 + 1));
2857 }
2858 break;
2859
2860 case 2:
2861 aarch64_set_vec_u32
2862 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, second ? vm : vn, 0));
2863 aarch64_set_vec_u32
2864 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, second ? vn : vm, 1));
2865 aarch64_set_vec_u32
2866 (cpu, vd, 2, aarch64_get_vec_u32 (cpu, second ? vm : vn, 2));
2867 aarch64_set_vec_u32
2868 (cpu, vd, 3, aarch64_get_vec_u32 (cpu, second ? vn : vm, 3));
2869 break;
2870
2871 case 3:
2872 if (! full)
2873 HALT_UNALLOC;
2874
2875 aarch64_set_vec_u64 (cpu, vd, 0,
2876 aarch64_get_vec_u64 (cpu, second ? vm : vn, 0));
2877 aarch64_set_vec_u64 (cpu, vd, 1,
2878 aarch64_get_vec_u64 (cpu, second ? vn : vm, 1));
2879 break;
2e8cf49e
NC
2880 }
2881}
2882
2883static void
2884do_vec_DUP_scalar_into_vector (sim_cpu *cpu)
2885{
2886 /* instr[31] = 0
2887 instr[30] = 0=> zero top 64-bits, 1=> duplicate into top 64-bits
2888 [must be 1 for 64-bit xfer]
2889 instr[29,20] = 00 1110 0000
2890 instr[19,16] = element size: 0001=> 8-bits, 0010=> 16-bits,
2891 0100=> 32-bits. 1000=>64-bits
2892 instr[15,10] = 0000 11
2893 instr[9,5] = W source
2894 instr[4,0] = V dest. */
2895
2896 unsigned i;
ef0d8ffc
NC
2897 unsigned Vd = INSTR (4, 0);
2898 unsigned Rs = INSTR (9, 5);
2899 int both = INSTR (30, 30);
2e8cf49e
NC
2900
2901 NYI_assert (29, 20, 0x0E0);
2902 NYI_assert (15, 10, 0x03);
2903
2cdad34c 2904 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2905 switch (INSTR (19, 16))
2e8cf49e
NC
2906 {
2907 case 1:
2908 for (i = 0; i < (both ? 16 : 8); i++)
2909 aarch64_set_vec_u8 (cpu, Vd, i, aarch64_get_reg_u8 (cpu, Rs, NO_SP));
2910 break;
2911
2912 case 2:
2913 for (i = 0; i < (both ? 8 : 4); i++)
2914 aarch64_set_vec_u16 (cpu, Vd, i, aarch64_get_reg_u16 (cpu, Rs, NO_SP));
2915 break;
2916
2917 case 4:
2918 for (i = 0; i < (both ? 4 : 2); i++)
2919 aarch64_set_vec_u32 (cpu, Vd, i, aarch64_get_reg_u32 (cpu, Rs, NO_SP));
2920 break;
2921
2922 case 8:
2923 if (!both)
2924 HALT_NYI;
2925 aarch64_set_vec_u64 (cpu, Vd, 0, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2926 aarch64_set_vec_u64 (cpu, Vd, 1, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2927 break;
2928
2929 default:
2930 HALT_NYI;
2931 }
2932}
2933
2934static void
2935do_vec_UZP (sim_cpu *cpu)
2936{
2937 /* instr[31] = 0
2938 instr[30] = half(0)/full(1)
2939 instr[29,24] = 00 1110
2940 instr[23,22] = size: byte(00), half(01), word (10), long (11)
2941 instr[21] = 0
2942 instr[20,16] = Vm
2943 instr[15] = 0
2944 instr[14] = lower (0) / upper (1)
2945 instr[13,10] = 0110
2946 instr[9,5] = Vn
2947 instr[4,0] = Vd. */
2948
ef0d8ffc
NC
2949 int full = INSTR (30, 30);
2950 int upper = INSTR (14, 14);
2e8cf49e 2951
ef0d8ffc
NC
2952 unsigned vm = INSTR (20, 16);
2953 unsigned vn = INSTR (9, 5);
2954 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2955
2956 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2957 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2958 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2959 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2960
2961 uint64_t val1 = 0;
2962 uint64_t val2 = 0;
2963
2964 uint64_t input1 = upper ? val_n1 : val_m1;
2965 uint64_t input2 = upper ? val_n2 : val_m2;
2966 unsigned i;
2967
2968 NYI_assert (29, 24, 0x0E);
2969 NYI_assert (21, 21, 0);
2970 NYI_assert (15, 15, 0);
2971 NYI_assert (13, 10, 6);
2972
2cdad34c 2973 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2974 switch (INSTR (23, 23))
2e8cf49e
NC
2975 {
2976 case 0:
2977 for (i = 0; i < 8; i++)
2978 {
2979 val1 |= (input1 >> (i * 8)) & (0xFFULL << (i * 8));
2980 val2 |= (input2 >> (i * 8)) & (0xFFULL << (i * 8));
2981 }
2982 break;
2983
2984 case 1:
2985 for (i = 0; i < 4; i++)
2986 {
2987 val1 |= (input1 >> (i * 16)) & (0xFFFFULL << (i * 16));
2988 val2 |= (input2 >> (i * 16)) & (0xFFFFULL << (i * 16));
2989 }
2990 break;
2991
2992 case 2:
2993 val1 = ((input1 & 0xFFFFFFFF) | ((input1 >> 32) & 0xFFFFFFFF00000000ULL));
2994 val2 = ((input2 & 0xFFFFFFFF) | ((input2 >> 32) & 0xFFFFFFFF00000000ULL));
2995
2996 case 3:
2997 val1 = input1;
2998 val2 = input2;
2999 break;
3000 }
3001
3002 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3003 if (full)
3004 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3005}
3006
3007static void
3008do_vec_ZIP (sim_cpu *cpu)
3009{
3010 /* instr[31] = 0
3011 instr[30] = half(0)/full(1)
3012 instr[29,24] = 00 1110
3013 instr[23,22] = size: byte(00), hald(01), word (10), long (11)
3014 instr[21] = 0
3015 instr[20,16] = Vm
3016 instr[15] = 0
3017 instr[14] = lower (0) / upper (1)
3018 instr[13,10] = 1110
3019 instr[9,5] = Vn
3020 instr[4,0] = Vd. */
3021
ef0d8ffc
NC
3022 int full = INSTR (30, 30);
3023 int upper = INSTR (14, 14);
2e8cf49e 3024
ef0d8ffc
NC
3025 unsigned vm = INSTR (20, 16);
3026 unsigned vn = INSTR (9, 5);
3027 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3028
3029 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
3030 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
3031 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
3032 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
3033
3034 uint64_t val1 = 0;
3035 uint64_t val2 = 0;
3036
3037 uint64_t input1 = upper ? val_n1 : val_m1;
3038 uint64_t input2 = upper ? val_n2 : val_m2;
3039
3040 NYI_assert (29, 24, 0x0E);
3041 NYI_assert (21, 21, 0);
3042 NYI_assert (15, 15, 0);
3043 NYI_assert (13, 10, 0xE);
3044
2cdad34c 3045 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3046 switch (INSTR (23, 23))
2e8cf49e
NC
3047 {
3048 case 0:
3049 val1 =
3050 ((input1 << 0) & (0xFF << 0))
3051 | ((input2 << 8) & (0xFF << 8))
3052 | ((input1 << 8) & (0xFF << 16))
3053 | ((input2 << 16) & (0xFF << 24))
3054 | ((input1 << 16) & (0xFFULL << 32))
3055 | ((input2 << 24) & (0xFFULL << 40))
3056 | ((input1 << 24) & (0xFFULL << 48))
3057 | ((input2 << 32) & (0xFFULL << 56));
3058
3059 val2 =
3060 ((input1 >> 32) & (0xFF << 0))
3061 | ((input2 >> 24) & (0xFF << 8))
3062 | ((input1 >> 24) & (0xFF << 16))
3063 | ((input2 >> 16) & (0xFF << 24))
3064 | ((input1 >> 16) & (0xFFULL << 32))
3065 | ((input2 >> 8) & (0xFFULL << 40))
3066 | ((input1 >> 8) & (0xFFULL << 48))
3067 | ((input2 >> 0) & (0xFFULL << 56));
3068 break;
3069
3070 case 1:
3071 val1 =
3072 ((input1 << 0) & (0xFFFF << 0))
3073 | ((input2 << 16) & (0xFFFF << 16))
3074 | ((input1 << 16) & (0xFFFFULL << 32))
3075 | ((input2 << 32) & (0xFFFFULL << 48));
3076
3077 val2 =
3078 ((input1 >> 32) & (0xFFFF << 0))
3079 | ((input2 >> 16) & (0xFFFF << 16))
3080 | ((input1 >> 16) & (0xFFFFULL << 32))
3081 | ((input2 >> 0) & (0xFFFFULL << 48));
3082 break;
3083
3084 case 2:
3085 val1 = (input1 & 0xFFFFFFFFULL) | (input2 << 32);
3086 val2 = (input2 & 0xFFFFFFFFULL) | (input1 << 32);
3087 break;
3088
3089 case 3:
3090 val1 = input1;
3091 val2 = input2;
3092 break;
3093 }
3094
3095 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3096 if (full)
3097 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3098}
3099
3100/* Floating point immediates are encoded in 8 bits.
3101 fpimm[7] = sign bit.
3102 fpimm[6:4] = signed exponent.
3103 fpimm[3:0] = fraction (assuming leading 1).
3104 i.e. F = s * 1.f * 2^(e - b). */
3105
3106static float
3107fp_immediate_for_encoding_32 (uint32_t imm8)
3108{
3109 float u;
3110 uint32_t s, e, f, i;
3111
3112 s = (imm8 >> 7) & 0x1;
3113 e = (imm8 >> 4) & 0x7;
3114 f = imm8 & 0xf;
3115
3116 /* The fp value is s * n/16 * 2r where n is 16+e. */
3117 u = (16.0 + f) / 16.0;
3118
3119 /* N.B. exponent is signed. */
3120 if (e < 4)
3121 {
3122 int epos = e;
3123
3124 for (i = 0; i <= epos; i++)
3125 u *= 2.0;
3126 }
3127 else
3128 {
3129 int eneg = 7 - e;
3130
3131 for (i = 0; i < eneg; i++)
3132 u /= 2.0;
3133 }
3134
3135 if (s)
3136 u = - u;
3137
3138 return u;
3139}
3140
3141static double
3142fp_immediate_for_encoding_64 (uint32_t imm8)
3143{
3144 double u;
3145 uint32_t s, e, f, i;
3146
3147 s = (imm8 >> 7) & 0x1;
3148 e = (imm8 >> 4) & 0x7;
3149 f = imm8 & 0xf;
3150
3151 /* The fp value is s * n/16 * 2r where n is 16+e. */
3152 u = (16.0 + f) / 16.0;
3153
3154 /* N.B. exponent is signed. */
3155 if (e < 4)
3156 {
3157 int epos = e;
3158
3159 for (i = 0; i <= epos; i++)
3160 u *= 2.0;
3161 }
3162 else
3163 {
3164 int eneg = 7 - e;
3165
3166 for (i = 0; i < eneg; i++)
3167 u /= 2.0;
3168 }
3169
3170 if (s)
3171 u = - u;
3172
3173 return u;
3174}
3175
3176static void
3177do_vec_MOV_immediate (sim_cpu *cpu)
3178{
3179 /* instr[31] = 0
3180 instr[30] = full/half selector
3181 instr[29,19] = 00111100000
3182 instr[18,16] = high 3 bits of uimm8
3183 instr[15,12] = size & shift:
3184 0000 => 32-bit
3185 0010 => 32-bit + LSL#8
3186 0100 => 32-bit + LSL#16
3187 0110 => 32-bit + LSL#24
3188 1010 => 16-bit + LSL#8
3189 1000 => 16-bit
3190 1101 => 32-bit + MSL#16
3191 1100 => 32-bit + MSL#8
3192 1110 => 8-bit
3193 1111 => double
3194 instr[11,10] = 01
3195 instr[9,5] = low 5-bits of uimm8
3196 instr[4,0] = Vd. */
3197
ef0d8ffc
NC
3198 int full = INSTR (30, 30);
3199 unsigned vd = INSTR (4, 0);
7517e550 3200 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3201 unsigned i;
3202
3203 NYI_assert (29, 19, 0x1E0);
3204 NYI_assert (11, 10, 1);
3205
2cdad34c 3206 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3207 switch (INSTR (15, 12))
2e8cf49e
NC
3208 {
3209 case 0x0: /* 32-bit, no shift. */
3210 case 0x2: /* 32-bit, shift by 8. */
3211 case 0x4: /* 32-bit, shift by 16. */
3212 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3213 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3214 for (i = 0; i < (full ? 4 : 2); i++)
3215 aarch64_set_vec_u32 (cpu, vd, i, val);
3216 break;
3217
3218 case 0xa: /* 16-bit, shift by 8. */
3219 val <<= 8;
3220 /* Fall through. */
3221 case 0x8: /* 16-bit, no shift. */
3222 for (i = 0; i < (full ? 8 : 4); i++)
3223 aarch64_set_vec_u16 (cpu, vd, i, val);
3224 /* Fall through. */
3225 case 0xd: /* 32-bit, mask shift by 16. */
3226 val <<= 8;
3227 val |= 0xFF;
3228 /* Fall through. */
3229 case 0xc: /* 32-bit, mask shift by 8. */
3230 val <<= 8;
3231 val |= 0xFF;
3232 for (i = 0; i < (full ? 4 : 2); i++)
3233 aarch64_set_vec_u32 (cpu, vd, i, val);
3234 break;
3235
3236 case 0xe: /* 8-bit, no shift. */
3237 for (i = 0; i < (full ? 16 : 8); i++)
3238 aarch64_set_vec_u8 (cpu, vd, i, val);
3239 break;
3240
3241 case 0xf: /* FMOV Vs.{2|4}S, #fpimm. */
3242 {
3243 float u = fp_immediate_for_encoding_32 (val);
3244 for (i = 0; i < (full ? 4 : 2); i++)
3245 aarch64_set_vec_float (cpu, vd, i, u);
3246 break;
3247 }
3248
3249 default:
3250 HALT_NYI;
3251 }
3252}
3253
3254static void
3255do_vec_MVNI (sim_cpu *cpu)
3256{
3257 /* instr[31] = 0
3258 instr[30] = full/half selector
3259 instr[29,19] = 10111100000
3260 instr[18,16] = high 3 bits of uimm8
3261 instr[15,12] = selector
3262 instr[11,10] = 01
3263 instr[9,5] = low 5-bits of uimm8
3264 instr[4,0] = Vd. */
3265
ef0d8ffc
NC
3266 int full = INSTR (30, 30);
3267 unsigned vd = INSTR (4, 0);
7517e550 3268 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3269 unsigned i;
3270
3271 NYI_assert (29, 19, 0x5E0);
3272 NYI_assert (11, 10, 1);
3273
2cdad34c 3274 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3275 switch (INSTR (15, 12))
2e8cf49e
NC
3276 {
3277 case 0x0: /* 32-bit, no shift. */
3278 case 0x2: /* 32-bit, shift by 8. */
3279 case 0x4: /* 32-bit, shift by 16. */
3280 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3281 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3282 val = ~ val;
3283 for (i = 0; i < (full ? 4 : 2); i++)
3284 aarch64_set_vec_u32 (cpu, vd, i, val);
3285 return;
3286
3287 case 0xa: /* 16-bit, 8 bit shift. */
3288 val <<= 8;
3289 case 0x8: /* 16-bit, no shift. */
3290 val = ~ val;
3291 for (i = 0; i < (full ? 8 : 4); i++)
3292 aarch64_set_vec_u16 (cpu, vd, i, val);
3293 return;
3294
3295 case 0xd: /* 32-bit, mask shift by 16. */
3296 val <<= 8;
3297 val |= 0xFF;
3298 case 0xc: /* 32-bit, mask shift by 8. */
3299 val <<= 8;
3300 val |= 0xFF;
3301 val = ~ val;
3302 for (i = 0; i < (full ? 4 : 2); i++)
3303 aarch64_set_vec_u32 (cpu, vd, i, val);
3304 return;
3305
3306 case 0xE: /* MOVI Dn, #mask64 */
3307 {
3308 uint64_t mask = 0;
3309
3310 for (i = 0; i < 8; i++)
3311 if (val & (1 << i))
7517e550 3312 mask |= (0xFFUL << (i * 8));
2e8cf49e 3313 aarch64_set_vec_u64 (cpu, vd, 0, mask);
7517e550 3314 aarch64_set_vec_u64 (cpu, vd, 1, mask);
2e8cf49e
NC
3315 return;
3316 }
3317
3318 case 0xf: /* FMOV Vd.2D, #fpimm. */
3319 {
3320 double u = fp_immediate_for_encoding_64 (val);
3321
3322 if (! full)
3323 HALT_UNALLOC;
3324
3325 aarch64_set_vec_double (cpu, vd, 0, u);
3326 aarch64_set_vec_double (cpu, vd, 1, u);
3327 return;
3328 }
3329
3330 default:
3331 HALT_NYI;
3332 }
3333}
3334
3335#define ABS(A) ((A) < 0 ? - (A) : (A))
3336
3337static void
3338do_vec_ABS (sim_cpu *cpu)
3339{
3340 /* instr[31] = 0
3341 instr[30] = half(0)/full(1)
3342 instr[29,24] = 00 1110
3343 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3344 instr[21,10] = 10 0000 1011 10
3345 instr[9,5] = Vn
3346 instr[4.0] = Vd. */
3347
ef0d8ffc
NC
3348 unsigned vn = INSTR (9, 5);
3349 unsigned vd = INSTR (4, 0);
3350 unsigned full = INSTR (30, 30);
2e8cf49e
NC
3351 unsigned i;
3352
3353 NYI_assert (29, 24, 0x0E);
3354 NYI_assert (21, 10, 0x82E);
3355
2cdad34c 3356 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3357 switch (INSTR (23, 22))
2e8cf49e
NC
3358 {
3359 case 0:
3360 for (i = 0; i < (full ? 16 : 8); i++)
3361 aarch64_set_vec_s8 (cpu, vd, i,
3362 ABS (aarch64_get_vec_s8 (cpu, vn, i)));
3363 break;
3364
3365 case 1:
3366 for (i = 0; i < (full ? 8 : 4); i++)
3367 aarch64_set_vec_s16 (cpu, vd, i,
3368 ABS (aarch64_get_vec_s16 (cpu, vn, i)));
3369 break;
3370
3371 case 2:
3372 for (i = 0; i < (full ? 4 : 2); i++)
3373 aarch64_set_vec_s32 (cpu, vd, i,
3374 ABS (aarch64_get_vec_s32 (cpu, vn, i)));
3375 break;
3376
3377 case 3:
3378 if (! full)
3379 HALT_NYI;
3380 for (i = 0; i < 2; i++)
3381 aarch64_set_vec_s64 (cpu, vd, i,
3382 ABS (aarch64_get_vec_s64 (cpu, vn, i)));
3383 break;
3384 }
3385}
3386
3387static void
3388do_vec_ADDV (sim_cpu *cpu)
3389{
3390 /* instr[31] = 0
3391 instr[30] = full/half selector
3392 instr[29,24] = 00 1110
3393 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3394 instr[21,10] = 11 0001 1011 10
3395 instr[9,5] = Vm
3396 instr[4.0] = Rd. */
3397
ef0d8ffc
NC
3398 unsigned vm = INSTR (9, 5);
3399 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
3400 unsigned i;
3401 uint64_t val = 0;
ef0d8ffc 3402 int full = INSTR (30, 30);
2e8cf49e
NC
3403
3404 NYI_assert (29, 24, 0x0E);
3405 NYI_assert (21, 10, 0xC6E);
3406
2cdad34c 3407 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3408 switch (INSTR (23, 22))
2e8cf49e
NC
3409 {
3410 case 0:
3411 for (i = 0; i < (full ? 16 : 8); i++)
3412 val += aarch64_get_vec_u8 (cpu, vm, i);
3413 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3414 return;
3415
3416 case 1:
3417 for (i = 0; i < (full ? 8 : 4); i++)
3418 val += aarch64_get_vec_u16 (cpu, vm, i);
3419 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3420 return;
3421
3422 case 2:
3423 for (i = 0; i < (full ? 4 : 2); i++)
3424 val += aarch64_get_vec_u32 (cpu, vm, i);
3425 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3426 return;
3427
3428 case 3:
3429 if (! full)
3430 HALT_UNALLOC;
3431 val = aarch64_get_vec_u64 (cpu, vm, 0);
3432 val += aarch64_get_vec_u64 (cpu, vm, 1);
3433 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3434 return;
2e8cf49e
NC
3435 }
3436}
3437
3438static void
3439do_vec_ins_2 (sim_cpu *cpu)
3440{
3441 /* instr[31,21] = 01001110000
3442 instr[20,18] = size & element selector
3443 instr[17,14] = 0000
3444 instr[13] = direction: to vec(0), from vec (1)
3445 instr[12,10] = 111
3446 instr[9,5] = Vm
3447 instr[4,0] = Vd. */
3448
3449 unsigned elem;
ef0d8ffc
NC
3450 unsigned vm = INSTR (9, 5);
3451 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3452
3453 NYI_assert (31, 21, 0x270);
3454 NYI_assert (17, 14, 0);
3455 NYI_assert (12, 10, 7);
3456
2cdad34c 3457 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3458 if (INSTR (13, 13) == 1)
2e8cf49e 3459 {
ef0d8ffc 3460 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3461 {
3462 /* 32-bit moves. */
ef0d8ffc 3463 elem = INSTR (20, 19);
2e8cf49e
NC
3464 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3465 aarch64_get_vec_u32 (cpu, vm, elem));
3466 }
3467 else
3468 {
3469 /* 64-bit moves. */
ef0d8ffc 3470 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3471 HALT_NYI;
3472
ef0d8ffc 3473 elem = INSTR (20, 20);
2e8cf49e
NC
3474 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3475 aarch64_get_vec_u64 (cpu, vm, elem));
3476 }
3477 }
3478 else
3479 {
ef0d8ffc 3480 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3481 {
3482 /* 32-bit moves. */
ef0d8ffc 3483 elem = INSTR (20, 19);
2e8cf49e
NC
3484 aarch64_set_vec_u32 (cpu, vd, elem,
3485 aarch64_get_reg_u32 (cpu, vm, NO_SP));
3486 }
3487 else
3488 {
3489 /* 64-bit moves. */
ef0d8ffc 3490 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3491 HALT_NYI;
3492
ef0d8ffc 3493 elem = INSTR (20, 20);
2e8cf49e
NC
3494 aarch64_set_vec_u64 (cpu, vd, elem,
3495 aarch64_get_reg_u64 (cpu, vm, NO_SP));
3496 }
3497 }
3498}
3499
7517e550
NC
3500#define DO_VEC_WIDENING_MUL(N, DST_TYPE, READ_TYPE, WRITE_TYPE) \
3501 do \
3502 { \
3503 DST_TYPE a[N], b[N]; \
3504 \
3505 for (i = 0; i < (N); i++) \
3506 { \
3507 a[i] = aarch64_get_vec_##READ_TYPE (cpu, vn, i + bias); \
3508 b[i] = aarch64_get_vec_##READ_TYPE (cpu, vm, i + bias); \
3509 } \
3510 for (i = 0; i < (N); i++) \
3511 aarch64_set_vec_##WRITE_TYPE (cpu, vd, i, a[i] * b[i]); \
3512 } \
3513 while (0)
3514
2e8cf49e
NC
3515static void
3516do_vec_mull (sim_cpu *cpu)
3517{
3518 /* instr[31] = 0
3519 instr[30] = lower(0)/upper(1) selector
3520 instr[29] = signed(0)/unsigned(1)
3521 instr[28,24] = 0 1110
3522 instr[23,22] = size: 8-bit (00), 16-bit (01), 32-bit (10)
3523 instr[21] = 1
3524 instr[20,16] = Vm
3525 instr[15,10] = 11 0000
3526 instr[9,5] = Vn
3527 instr[4.0] = Vd. */
3528
ef0d8ffc
NC
3529 int unsign = INSTR (29, 29);
3530 int bias = INSTR (30, 30);
3531 unsigned vm = INSTR (20, 16);
3532 unsigned vn = INSTR ( 9, 5);
3533 unsigned vd = INSTR ( 4, 0);
2e8cf49e
NC
3534 unsigned i;
3535
3536 NYI_assert (28, 24, 0x0E);
3537 NYI_assert (15, 10, 0x30);
3538
2cdad34c 3539 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
3540 /* NB: Read source values before writing results, in case
3541 the source and destination vectors are the same. */
ef0d8ffc 3542 switch (INSTR (23, 22))
2e8cf49e
NC
3543 {
3544 case 0:
3545 if (bias)
3546 bias = 8;
3547 if (unsign)
7517e550 3548 DO_VEC_WIDENING_MUL (8, uint16_t, u8, u16);
2e8cf49e 3549 else
7517e550 3550 DO_VEC_WIDENING_MUL (8, int16_t, s8, s16);
2e8cf49e
NC
3551 return;
3552
3553 case 1:
3554 if (bias)
3555 bias = 4;
3556 if (unsign)
7517e550 3557 DO_VEC_WIDENING_MUL (4, uint32_t, u16, u32);
2e8cf49e 3558 else
7517e550 3559 DO_VEC_WIDENING_MUL (4, int32_t, s16, s32);
2e8cf49e
NC
3560 return;
3561
3562 case 2:
3563 if (bias)
3564 bias = 2;
3565 if (unsign)
7517e550 3566 DO_VEC_WIDENING_MUL (2, uint64_t, u32, u64);
2e8cf49e 3567 else
7517e550 3568 DO_VEC_WIDENING_MUL (2, int64_t, s32, s64);
2e8cf49e
NC
3569 return;
3570
3571 case 3:
2e8cf49e
NC
3572 HALT_NYI;
3573 }
3574}
3575
3576static void
3577do_vec_fadd (sim_cpu *cpu)
3578{
3579 /* instr[31] = 0
3580 instr[30] = half(0)/full(1)
3581 instr[29,24] = 001110
3582 instr[23] = FADD(0)/FSUB(1)
3583 instr[22] = float (0)/double(1)
3584 instr[21] = 1
3585 instr[20,16] = Vm
3586 instr[15,10] = 110101
3587 instr[9,5] = Vn
3588 instr[4.0] = Vd. */
3589
ef0d8ffc
NC
3590 unsigned vm = INSTR (20, 16);
3591 unsigned vn = INSTR (9, 5);
3592 unsigned vd = INSTR (4, 0);
2e8cf49e 3593 unsigned i;
ef0d8ffc 3594 int full = INSTR (30, 30);
2e8cf49e
NC
3595
3596 NYI_assert (29, 24, 0x0E);
3597 NYI_assert (21, 21, 1);
3598 NYI_assert (15, 10, 0x35);
3599
2cdad34c 3600 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3601 if (INSTR (23, 23))
2e8cf49e 3602 {
ef0d8ffc 3603 if (INSTR (22, 22))
2e8cf49e
NC
3604 {
3605 if (! full)
3606 HALT_NYI;
3607
3608 for (i = 0; i < 2; i++)
3609 aarch64_set_vec_double (cpu, vd, i,
3610 aarch64_get_vec_double (cpu, vn, i)
3611 - aarch64_get_vec_double (cpu, vm, i));
3612 }
3613 else
3614 {
3615 for (i = 0; i < (full ? 4 : 2); i++)
3616 aarch64_set_vec_float (cpu, vd, i,
3617 aarch64_get_vec_float (cpu, vn, i)
3618 - aarch64_get_vec_float (cpu, vm, i));
3619 }
3620 }
3621 else
3622 {
ef0d8ffc 3623 if (INSTR (22, 22))
2e8cf49e
NC
3624 {
3625 if (! full)
3626 HALT_NYI;
3627
3628 for (i = 0; i < 2; i++)
3629 aarch64_set_vec_double (cpu, vd, i,
3630 aarch64_get_vec_double (cpu, vm, i)
3631 + aarch64_get_vec_double (cpu, vn, i));
3632 }
3633 else
3634 {
3635 for (i = 0; i < (full ? 4 : 2); i++)
3636 aarch64_set_vec_float (cpu, vd, i,
3637 aarch64_get_vec_float (cpu, vm, i)
3638 + aarch64_get_vec_float (cpu, vn, i));
3639 }
3640 }
3641}
3642
3643static void
3644do_vec_add (sim_cpu *cpu)
3645{
3646 /* instr[31] = 0
3647 instr[30] = full/half selector
3648 instr[29,24] = 001110
3649 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3650 instr[21] = 1
3651 instr[20,16] = Vn
3652 instr[15,10] = 100001
3653 instr[9,5] = Vm
3654 instr[4.0] = Vd. */
3655
ef0d8ffc
NC
3656 unsigned vm = INSTR (20, 16);
3657 unsigned vn = INSTR (9, 5);
3658 unsigned vd = INSTR (4, 0);
2e8cf49e 3659 unsigned i;
ef0d8ffc 3660 int full = INSTR (30, 30);
2e8cf49e
NC
3661
3662 NYI_assert (29, 24, 0x0E);
3663 NYI_assert (21, 21, 1);
3664 NYI_assert (15, 10, 0x21);
3665
2cdad34c 3666 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3667 switch (INSTR (23, 22))
2e8cf49e
NC
3668 {
3669 case 0:
3670 for (i = 0; i < (full ? 16 : 8); i++)
3671 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
3672 + aarch64_get_vec_u8 (cpu, vm, i));
3673 return;
3674
3675 case 1:
3676 for (i = 0; i < (full ? 8 : 4); i++)
3677 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
3678 + aarch64_get_vec_u16 (cpu, vm, i));
3679 return;
3680
3681 case 2:
3682 for (i = 0; i < (full ? 4 : 2); i++)
3683 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
3684 + aarch64_get_vec_u32 (cpu, vm, i));
3685 return;
3686
3687 case 3:
3688 if (! full)
3689 HALT_UNALLOC;
3690 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vn, 0)
3691 + aarch64_get_vec_u64 (cpu, vm, 0));
3692 aarch64_set_vec_u64 (cpu, vd, 1,
3693 aarch64_get_vec_u64 (cpu, vn, 1)
3694 + aarch64_get_vec_u64 (cpu, vm, 1));
3695 return;
2e8cf49e
NC
3696 }
3697}
3698
3699static void
3700do_vec_mul (sim_cpu *cpu)
3701{
3702 /* instr[31] = 0
3703 instr[30] = full/half selector
3704 instr[29,24] = 00 1110
3705 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3706 instr[21] = 1
3707 instr[20,16] = Vn
3708 instr[15,10] = 10 0111
3709 instr[9,5] = Vm
3710 instr[4.0] = Vd. */
3711
ef0d8ffc
NC
3712 unsigned vm = INSTR (20, 16);
3713 unsigned vn = INSTR (9, 5);
3714 unsigned vd = INSTR (4, 0);
2e8cf49e 3715 unsigned i;
ef0d8ffc 3716 int full = INSTR (30, 30);
7517e550 3717 int bias = 0;
2e8cf49e
NC
3718
3719 NYI_assert (29, 24, 0x0E);
3720 NYI_assert (21, 21, 1);
3721 NYI_assert (15, 10, 0x27);
3722
2cdad34c 3723 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3724 switch (INSTR (23, 22))
2e8cf49e
NC
3725 {
3726 case 0:
7517e550 3727 DO_VEC_WIDENING_MUL (full ? 16 : 8, uint16_t, u8, u16);
2e8cf49e
NC
3728 return;
3729
3730 case 1:
7517e550 3731 DO_VEC_WIDENING_MUL (full ? 8 : 4, uint32_t, u16, u32);
2e8cf49e
NC
3732 return;
3733
3734 case 2:
7517e550 3735 DO_VEC_WIDENING_MUL (full ? 4 : 2, uint64_t, u32, u64);
2e8cf49e
NC
3736 return;
3737
2e8cf49e
NC
3738 case 3:
3739 HALT_UNALLOC;
3740 }
3741}
3742
3743static void
3744do_vec_MLA (sim_cpu *cpu)
3745{
3746 /* instr[31] = 0
3747 instr[30] = full/half selector
3748 instr[29,24] = 00 1110
3749 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3750 instr[21] = 1
3751 instr[20,16] = Vn
3752 instr[15,10] = 1001 01
3753 instr[9,5] = Vm
3754 instr[4.0] = Vd. */
3755
ef0d8ffc
NC
3756 unsigned vm = INSTR (20, 16);
3757 unsigned vn = INSTR (9, 5);
3758 unsigned vd = INSTR (4, 0);
2e8cf49e 3759 unsigned i;
ef0d8ffc 3760 int full = INSTR (30, 30);
2e8cf49e
NC
3761
3762 NYI_assert (29, 24, 0x0E);
3763 NYI_assert (21, 21, 1);
3764 NYI_assert (15, 10, 0x25);
3765
2cdad34c 3766 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3767 switch (INSTR (23, 22))
2e8cf49e
NC
3768 {
3769 case 0:
7517e550
NC
3770 {
3771 uint16_t a[16], b[16];
2e8cf49e 3772
7517e550
NC
3773 for (i = 0; i < (full ? 16 : 8); i++)
3774 {
3775 a[i] = aarch64_get_vec_u8 (cpu, vn, i);
3776 b[i] = aarch64_get_vec_u8 (cpu, vm, i);
3777 }
3778
3779 for (i = 0; i < (full ? 16 : 8); i++)
3780 {
3781 uint16_t v = aarch64_get_vec_u8 (cpu, vd, i);
3782
3783 aarch64_set_vec_u16 (cpu, vd, i, v + (a[i] * b[i]));
3784 }
3785 }
2e8cf49e
NC
3786 return;
3787
3788 case 1:
7517e550
NC
3789 {
3790 uint32_t a[8], b[8];
2e8cf49e 3791
7517e550
NC
3792 for (i = 0; i < (full ? 8 : 4); i++)
3793 {
3794 a[i] = aarch64_get_vec_u16 (cpu, vn, i);
3795 b[i] = aarch64_get_vec_u16 (cpu, vm, i);
3796 }
3797
3798 for (i = 0; i < (full ? 8 : 4); i++)
3799 {
3800 uint32_t v = aarch64_get_vec_u16 (cpu, vd, i);
3801
3802 aarch64_set_vec_u32 (cpu, vd, i, v + (a[i] * b[i]));
3803 }
3804 }
2e8cf49e
NC
3805 return;
3806
3807 case 2:
7517e550
NC
3808 {
3809 uint64_t a[4], b[4];
2e8cf49e 3810
7517e550
NC
3811 for (i = 0; i < (full ? 4 : 2); i++)
3812 {
3813 a[i] = aarch64_get_vec_u32 (cpu, vn, i);
3814 b[i] = aarch64_get_vec_u32 (cpu, vm, i);
3815 }
3816
3817 for (i = 0; i < (full ? 4 : 2); i++)
3818 {
3819 uint64_t v = aarch64_get_vec_u32 (cpu, vd, i);
3820
3821 aarch64_set_vec_u64 (cpu, vd, i, v + (a[i] * b[i]));
3822 }
3823 }
2e8cf49e
NC
3824 return;
3825
2e8cf49e
NC
3826 case 3:
3827 HALT_UNALLOC;
3828 }
3829}
3830
3831static float
3832fmaxnm (float a, float b)
3833{
3834 if (fpclassify (a) == FP_NORMAL)
3835 {
3836 if (fpclassify (b) == FP_NORMAL)
3837 return a > b ? a : b;
3838 return a;
3839 }
3840 else if (fpclassify (b) == FP_NORMAL)
3841 return b;
3842 return a;
3843}
3844
3845static float
3846fminnm (float a, float b)
3847{
3848 if (fpclassify (a) == FP_NORMAL)
3849 {
3850 if (fpclassify (b) == FP_NORMAL)
3851 return a < b ? a : b;
3852 return a;
3853 }
3854 else if (fpclassify (b) == FP_NORMAL)
3855 return b;
3856 return a;
3857}
3858
3859static double
3860dmaxnm (double a, double b)
3861{
3862 if (fpclassify (a) == FP_NORMAL)
3863 {
3864 if (fpclassify (b) == FP_NORMAL)
3865 return a > b ? a : b;
3866 return a;
3867 }
3868 else if (fpclassify (b) == FP_NORMAL)
3869 return b;
3870 return a;
3871}
3872
3873static double
3874dminnm (double a, double b)
3875{
3876 if (fpclassify (a) == FP_NORMAL)
3877 {
3878 if (fpclassify (b) == FP_NORMAL)
3879 return a < b ? a : b;
3880 return a;
3881 }
3882 else if (fpclassify (b) == FP_NORMAL)
3883 return b;
3884 return a;
3885}
3886
3887static void
3888do_vec_FminmaxNMP (sim_cpu *cpu)
3889{
ef0d8ffc
NC
3890 /* instr [31] = 0
3891 instr [30] = half (0)/full (1)
3892 instr [29,24] = 10 1110
3893 instr [23] = max(0)/min(1)
3894 instr [22] = float (0)/double (1)
3895 instr [21] = 1
3896 instr [20,16] = Vn
3897 instr [15,10] = 1100 01
3898 instr [9,5] = Vm
3899 instr [4.0] = Vd. */
3900
3901 unsigned vm = INSTR (20, 16);
3902 unsigned vn = INSTR (9, 5);
3903 unsigned vd = INSTR (4, 0);
3904 int full = INSTR (30, 30);
2e8cf49e
NC
3905
3906 NYI_assert (29, 24, 0x2E);
3907 NYI_assert (21, 21, 1);
3908 NYI_assert (15, 10, 0x31);
3909
2cdad34c 3910 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3911 if (INSTR (22, 22))
2e8cf49e 3912 {
ef0d8ffc 3913 double (* fn)(double, double) = INSTR (23, 23)
2e8cf49e
NC
3914 ? dminnm : dmaxnm;
3915
3916 if (! full)
3917 HALT_NYI;
3918 aarch64_set_vec_double (cpu, vd, 0,
3919 fn (aarch64_get_vec_double (cpu, vn, 0),
3920 aarch64_get_vec_double (cpu, vn, 1)));
3921 aarch64_set_vec_double (cpu, vd, 0,
3922 fn (aarch64_get_vec_double (cpu, vm, 0),
3923 aarch64_get_vec_double (cpu, vm, 1)));
3924 }
3925 else
3926 {
ef0d8ffc 3927 float (* fn)(float, float) = INSTR (23, 23)
2e8cf49e
NC
3928 ? fminnm : fmaxnm;
3929
3930 aarch64_set_vec_float (cpu, vd, 0,
3931 fn (aarch64_get_vec_float (cpu, vn, 0),
3932 aarch64_get_vec_float (cpu, vn, 1)));
3933 if (full)
3934 aarch64_set_vec_float (cpu, vd, 1,
3935 fn (aarch64_get_vec_float (cpu, vn, 2),
3936 aarch64_get_vec_float (cpu, vn, 3)));
3937
3938 aarch64_set_vec_float (cpu, vd, (full ? 2 : 1),
3939 fn (aarch64_get_vec_float (cpu, vm, 0),
3940 aarch64_get_vec_float (cpu, vm, 1)));
3941 if (full)
3942 aarch64_set_vec_float (cpu, vd, 3,
3943 fn (aarch64_get_vec_float (cpu, vm, 2),
3944 aarch64_get_vec_float (cpu, vm, 3)));
3945 }
3946}
3947
3948static void
3949do_vec_AND (sim_cpu *cpu)
3950{
3951 /* instr[31] = 0
3952 instr[30] = half (0)/full (1)
3953 instr[29,21] = 001110001
3954 instr[20,16] = Vm
3955 instr[15,10] = 000111
3956 instr[9,5] = Vn
3957 instr[4.0] = Vd. */
3958
ef0d8ffc
NC
3959 unsigned vm = INSTR (20, 16);
3960 unsigned vn = INSTR (9, 5);
3961 unsigned vd = INSTR (4, 0);
2e8cf49e 3962 unsigned i;
ef0d8ffc 3963 int full = INSTR (30, 30);
2e8cf49e
NC
3964
3965 NYI_assert (29, 21, 0x071);
3966 NYI_assert (15, 10, 0x07);
3967
2cdad34c 3968 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
3969 for (i = 0; i < (full ? 4 : 2); i++)
3970 aarch64_set_vec_u32 (cpu, vd, i,
3971 aarch64_get_vec_u32 (cpu, vn, i)
3972 & aarch64_get_vec_u32 (cpu, vm, i));
3973}
3974
3975static void
3976do_vec_BSL (sim_cpu *cpu)
3977{
3978 /* instr[31] = 0
3979 instr[30] = half (0)/full (1)
3980 instr[29,21] = 101110011
3981 instr[20,16] = Vm
3982 instr[15,10] = 000111
3983 instr[9,5] = Vn
3984 instr[4.0] = Vd. */
3985
ef0d8ffc
NC
3986 unsigned vm = INSTR (20, 16);
3987 unsigned vn = INSTR (9, 5);
3988 unsigned vd = INSTR (4, 0);
2e8cf49e 3989 unsigned i;
ef0d8ffc 3990 int full = INSTR (30, 30);
2e8cf49e
NC
3991
3992 NYI_assert (29, 21, 0x173);
3993 NYI_assert (15, 10, 0x07);
3994
2cdad34c 3995 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
3996 for (i = 0; i < (full ? 16 : 8); i++)
3997 aarch64_set_vec_u8 (cpu, vd, i,
3998 ( aarch64_get_vec_u8 (cpu, vd, i)
3999 & aarch64_get_vec_u8 (cpu, vn, i))
4000 | ((~ aarch64_get_vec_u8 (cpu, vd, i))
4001 & aarch64_get_vec_u8 (cpu, vm, i)));
4002}
4003
4004static void
4005do_vec_EOR (sim_cpu *cpu)
4006{
4007 /* instr[31] = 0
4008 instr[30] = half (0)/full (1)
4009 instr[29,21] = 10 1110 001
4010 instr[20,16] = Vm
4011 instr[15,10] = 000111
4012 instr[9,5] = Vn
4013 instr[4.0] = Vd. */
4014
ef0d8ffc
NC
4015 unsigned vm = INSTR (20, 16);
4016 unsigned vn = INSTR (9, 5);
4017 unsigned vd = INSTR (4, 0);
2e8cf49e 4018 unsigned i;
ef0d8ffc 4019 int full = INSTR (30, 30);
2e8cf49e
NC
4020
4021 NYI_assert (29, 21, 0x171);
4022 NYI_assert (15, 10, 0x07);
4023
2cdad34c 4024 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4025 for (i = 0; i < (full ? 4 : 2); i++)
4026 aarch64_set_vec_u32 (cpu, vd, i,
4027 aarch64_get_vec_u32 (cpu, vn, i)
4028 ^ aarch64_get_vec_u32 (cpu, vm, i));
4029}
4030
4031static void
4032do_vec_bit (sim_cpu *cpu)
4033{
4034 /* instr[31] = 0
4035 instr[30] = half (0)/full (1)
4036 instr[29,23] = 10 1110 1
4037 instr[22] = BIT (0) / BIF (1)
4038 instr[21] = 1
4039 instr[20,16] = Vm
4040 instr[15,10] = 0001 11
4041 instr[9,5] = Vn
4042 instr[4.0] = Vd. */
4043
ef0d8ffc
NC
4044 unsigned vm = INSTR (20, 16);
4045 unsigned vn = INSTR (9, 5);
4046 unsigned vd = INSTR (4, 0);
4047 unsigned full = INSTR (30, 30);
4048 unsigned test_false = INSTR (22, 22);
2e8cf49e
NC
4049 unsigned i;
4050
4051 NYI_assert (29, 23, 0x5D);
4052 NYI_assert (21, 21, 1);
4053 NYI_assert (15, 10, 0x07);
4054
2cdad34c 4055 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4056 if (test_false)
4057 {
4058 for (i = 0; i < (full ? 16 : 8); i++)
4059 if (aarch64_get_vec_u32 (cpu, vn, i) == 0)
4060 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
4061 }
4062 else
4063 {
4064 for (i = 0; i < (full ? 16 : 8); i++)
4065 if (aarch64_get_vec_u32 (cpu, vn, i) != 0)
4066 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
4067 }
4068}
4069
4070static void
4071do_vec_ORN (sim_cpu *cpu)
4072{
4073 /* instr[31] = 0
4074 instr[30] = half (0)/full (1)
4075 instr[29,21] = 00 1110 111
4076 instr[20,16] = Vm
4077 instr[15,10] = 00 0111
4078 instr[9,5] = Vn
4079 instr[4.0] = Vd. */
4080
ef0d8ffc
NC
4081 unsigned vm = INSTR (20, 16);
4082 unsigned vn = INSTR (9, 5);
4083 unsigned vd = INSTR (4, 0);
2e8cf49e 4084 unsigned i;
ef0d8ffc 4085 int full = INSTR (30, 30);
2e8cf49e
NC
4086
4087 NYI_assert (29, 21, 0x077);
4088 NYI_assert (15, 10, 0x07);
4089
2cdad34c 4090 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4091 for (i = 0; i < (full ? 16 : 8); i++)
4092 aarch64_set_vec_u8 (cpu, vd, i,
4093 aarch64_get_vec_u8 (cpu, vn, i)
4094 | ~ aarch64_get_vec_u8 (cpu, vm, i));
4095}
4096
4097static void
4098do_vec_ORR (sim_cpu *cpu)
4099{
4100 /* instr[31] = 0
4101 instr[30] = half (0)/full (1)
4102 instr[29,21] = 00 1110 101
4103 instr[20,16] = Vm
4104 instr[15,10] = 0001 11
4105 instr[9,5] = Vn
4106 instr[4.0] = Vd. */
4107
ef0d8ffc
NC
4108 unsigned vm = INSTR (20, 16);
4109 unsigned vn = INSTR (9, 5);
4110 unsigned vd = INSTR (4, 0);
2e8cf49e 4111 unsigned i;
ef0d8ffc 4112 int full = INSTR (30, 30);
2e8cf49e
NC
4113
4114 NYI_assert (29, 21, 0x075);
4115 NYI_assert (15, 10, 0x07);
4116
2cdad34c 4117 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4118 for (i = 0; i < (full ? 16 : 8); i++)
4119 aarch64_set_vec_u8 (cpu, vd, i,
4120 aarch64_get_vec_u8 (cpu, vn, i)
4121 | aarch64_get_vec_u8 (cpu, vm, i));
4122}
4123
4124static void
4125do_vec_BIC (sim_cpu *cpu)
4126{
4127 /* instr[31] = 0
4128 instr[30] = half (0)/full (1)
4129 instr[29,21] = 00 1110 011
4130 instr[20,16] = Vm
4131 instr[15,10] = 00 0111
4132 instr[9,5] = Vn
4133 instr[4.0] = Vd. */
4134
ef0d8ffc
NC
4135 unsigned vm = INSTR (20, 16);
4136 unsigned vn = INSTR (9, 5);
4137 unsigned vd = INSTR (4, 0);
2e8cf49e 4138 unsigned i;
ef0d8ffc 4139 int full = INSTR (30, 30);
2e8cf49e
NC
4140
4141 NYI_assert (29, 21, 0x073);
4142 NYI_assert (15, 10, 0x07);
4143
2cdad34c 4144 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4145 for (i = 0; i < (full ? 16 : 8); i++)
4146 aarch64_set_vec_u8 (cpu, vd, i,
4147 aarch64_get_vec_u8 (cpu, vn, i)
4148 & ~ aarch64_get_vec_u8 (cpu, vm, i));
4149}
4150
4151static void
4152do_vec_XTN (sim_cpu *cpu)
4153{
4154 /* instr[31] = 0
4155 instr[30] = first part (0)/ second part (1)
4156 instr[29,24] = 00 1110
4157 instr[23,22] = size: byte(00), half(01), word (10)
4158 instr[21,10] = 1000 0100 1010
4159 instr[9,5] = Vs
4160 instr[4,0] = Vd. */
4161
ef0d8ffc
NC
4162 unsigned vs = INSTR (9, 5);
4163 unsigned vd = INSTR (4, 0);
4164 unsigned bias = INSTR (30, 30);
2e8cf49e
NC
4165 unsigned i;
4166
4167 NYI_assert (29, 24, 0x0E);
4168 NYI_assert (21, 10, 0x84A);
4169
2cdad34c 4170 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4171 switch (INSTR (23, 22))
2e8cf49e
NC
4172 {
4173 case 0:
4174 if (bias)
4175 for (i = 0; i < 8; i++)
4176 aarch64_set_vec_u8 (cpu, vd, i + 8,
4177 aarch64_get_vec_u16 (cpu, vs, i) >> 8);
4178 else
4179 for (i = 0; i < 8; i++)
4180 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i));
4181 return;
4182
4183 case 1:
4184 if (bias)
4185 for (i = 0; i < 4; i++)
4186 aarch64_set_vec_u16 (cpu, vd, i + 4,
4187 aarch64_get_vec_u32 (cpu, vs, i) >> 16);
4188 else
4189 for (i = 0; i < 4; i++)
4190 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, i));
4191 return;
4192
4193 case 2:
4194 if (bias)
4195 for (i = 0; i < 2; i++)
4196 aarch64_set_vec_u32 (cpu, vd, i + 4,
4197 aarch64_get_vec_u64 (cpu, vs, i) >> 32);
4198 else
4199 for (i = 0; i < 2; i++)
4200 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, i));
4201 return;
2e8cf49e
NC
4202 }
4203}
4204
2e8cf49e
NC
4205static void
4206do_vec_maxv (sim_cpu *cpu)
4207{
4208 /* instr[31] = 0
4209 instr[30] = half(0)/full(1)
4210 instr[29] = signed (0)/unsigned(1)
4211 instr[28,24] = 0 1110
4212 instr[23,22] = size: byte(00), half(01), word (10)
4213 instr[21] = 1
4214 instr[20,17] = 1 000
4215 instr[16] = max(0)/min(1)
4216 instr[15,10] = 1010 10
4217 instr[9,5] = V source
4218 instr[4.0] = R dest. */
4219
ef0d8ffc
NC
4220 unsigned vs = INSTR (9, 5);
4221 unsigned rd = INSTR (4, 0);
4222 unsigned full = INSTR (30, 30);
2e8cf49e
NC
4223 unsigned i;
4224
4225 NYI_assert (28, 24, 0x0E);
4226 NYI_assert (21, 21, 1);
4227 NYI_assert (20, 17, 8);
4228 NYI_assert (15, 10, 0x2A);
4229
2cdad34c 4230 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 4231 switch ((INSTR (29, 29) << 1) | INSTR (16, 16))
2e8cf49e
NC
4232 {
4233 case 0: /* SMAXV. */
4234 {
4235 int64_t smax;
ef0d8ffc 4236 switch (INSTR (23, 22))
2e8cf49e
NC
4237 {
4238 case 0:
4239 smax = aarch64_get_vec_s8 (cpu, vs, 0);
4240 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4241 smax = max (smax, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4242 break;
4243 case 1:
4244 smax = aarch64_get_vec_s16 (cpu, vs, 0);
4245 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4246 smax = max (smax, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4247 break;
4248 case 2:
4249 smax = aarch64_get_vec_s32 (cpu, vs, 0);
4250 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4251 smax = max (smax, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4252 break;
2e8cf49e
NC
4253 case 3:
4254 HALT_UNALLOC;
4255 }
4256 aarch64_set_reg_s64 (cpu, rd, NO_SP, smax);
4257 return;
4258 }
4259
4260 case 1: /* SMINV. */
4261 {
4262 int64_t smin;
ef0d8ffc 4263 switch (INSTR (23, 22))
2e8cf49e
NC
4264 {
4265 case 0:
4266 smin = aarch64_get_vec_s8 (cpu, vs, 0);
4267 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4268 smin = min (smin, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4269 break;
4270 case 1:
4271 smin = aarch64_get_vec_s16 (cpu, vs, 0);
4272 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4273 smin = min (smin, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4274 break;
4275 case 2:
4276 smin = aarch64_get_vec_s32 (cpu, vs, 0);
4277 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4278 smin = min (smin, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4279 break;
5ab6d79e 4280
2e8cf49e
NC
4281 case 3:
4282 HALT_UNALLOC;
4283 }
4284 aarch64_set_reg_s64 (cpu, rd, NO_SP, smin);
4285 return;
4286 }
4287
4288 case 2: /* UMAXV. */
4289 {
4290 uint64_t umax;
ef0d8ffc 4291 switch (INSTR (23, 22))
2e8cf49e
NC
4292 {
4293 case 0:
4294 umax = aarch64_get_vec_u8 (cpu, vs, 0);
4295 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4296 umax = max (umax, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4297 break;
4298 case 1:
4299 umax = aarch64_get_vec_u16 (cpu, vs, 0);
4300 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4301 umax = max (umax, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4302 break;
4303 case 2:
4304 umax = aarch64_get_vec_u32 (cpu, vs, 0);
4305 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4306 umax = max (umax, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4307 break;
5ab6d79e 4308
2e8cf49e
NC
4309 case 3:
4310 HALT_UNALLOC;
4311 }
4312 aarch64_set_reg_u64 (cpu, rd, NO_SP, umax);
4313 return;
4314 }
4315
4316 case 3: /* UMINV. */
4317 {
4318 uint64_t umin;
ef0d8ffc 4319 switch (INSTR (23, 22))
2e8cf49e
NC
4320 {
4321 case 0:
4322 umin = aarch64_get_vec_u8 (cpu, vs, 0);
4323 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4324 umin = min (umin, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4325 break;
4326 case 1:
4327 umin = aarch64_get_vec_u16 (cpu, vs, 0);
4328 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4329 umin = min (umin, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4330 break;
4331 case 2:
4332 umin = aarch64_get_vec_u32 (cpu, vs, 0);
4333 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4334 umin = min (umin, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4335 break;
5ab6d79e 4336
2e8cf49e
NC
4337 case 3:
4338 HALT_UNALLOC;
4339 }
4340 aarch64_set_reg_u64 (cpu, rd, NO_SP, umin);
4341 return;
4342 }
2e8cf49e
NC
4343 }
4344}
4345
4346static void
4347do_vec_fminmaxV (sim_cpu *cpu)
4348{
4349 /* instr[31,24] = 0110 1110
4350 instr[23] = max(0)/min(1)
4351 instr[22,14] = 011 0000 11
4352 instr[13,12] = nm(00)/normal(11)
4353 instr[11,10] = 10
4354 instr[9,5] = V source
4355 instr[4.0] = R dest. */
4356
ef0d8ffc
NC
4357 unsigned vs = INSTR (9, 5);
4358 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
4359 unsigned i;
4360 float res = aarch64_get_vec_float (cpu, vs, 0);
4361
4362 NYI_assert (31, 24, 0x6E);
4363 NYI_assert (22, 14, 0x0C3);
4364 NYI_assert (11, 10, 2);
4365
2cdad34c 4366 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4367 if (INSTR (23, 23))
2e8cf49e 4368 {
ef0d8ffc 4369 switch (INSTR (13, 12))
2e8cf49e
NC
4370 {
4371 case 0: /* FMNINNMV. */
4372 for (i = 1; i < 4; i++)
4373 res = fminnm (res, aarch64_get_vec_float (cpu, vs, i));
4374 break;
4375
4376 case 3: /* FMINV. */
4377 for (i = 1; i < 4; i++)
bc273e17 4378 res = min (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4379 break;
4380
4381 default:
4382 HALT_NYI;
4383 }
4384 }
4385 else
4386 {
ef0d8ffc 4387 switch (INSTR (13, 12))
2e8cf49e
NC
4388 {
4389 case 0: /* FMNAXNMV. */
4390 for (i = 1; i < 4; i++)
4391 res = fmaxnm (res, aarch64_get_vec_float (cpu, vs, i));
4392 break;
4393
4394 case 3: /* FMAXV. */
4395 for (i = 1; i < 4; i++)
bc273e17 4396 res = max (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4397 break;
4398
4399 default:
4400 HALT_NYI;
4401 }
4402 }
4403
4404 aarch64_set_FP_float (cpu, rd, res);
4405}
4406
4407static void
4408do_vec_Fminmax (sim_cpu *cpu)
4409{
4410 /* instr[31] = 0
4411 instr[30] = half(0)/full(1)
4412 instr[29,24] = 00 1110
4413 instr[23] = max(0)/min(1)
4414 instr[22] = float(0)/double(1)
4415 instr[21] = 1
4416 instr[20,16] = Vm
4417 instr[15,14] = 11
4418 instr[13,12] = nm(00)/normal(11)
4419 instr[11,10] = 01
4420 instr[9,5] = Vn
4421 instr[4,0] = Vd. */
4422
ef0d8ffc
NC
4423 unsigned vm = INSTR (20, 16);
4424 unsigned vn = INSTR (9, 5);
4425 unsigned vd = INSTR (4, 0);
4426 unsigned full = INSTR (30, 30);
4427 unsigned min = INSTR (23, 23);
2e8cf49e
NC
4428 unsigned i;
4429
4430 NYI_assert (29, 24, 0x0E);
4431 NYI_assert (21, 21, 1);
4432 NYI_assert (15, 14, 3);
4433 NYI_assert (11, 10, 1);
4434
2cdad34c 4435 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4436 if (INSTR (22, 22))
2e8cf49e
NC
4437 {
4438 double (* func)(double, double);
4439
4440 if (! full)
4441 HALT_NYI;
4442
ef0d8ffc 4443 if (INSTR (13, 12) == 0)
2e8cf49e 4444 func = min ? dminnm : dmaxnm;
ef0d8ffc 4445 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4446 func = min ? fmin : fmax;
4447 else
4448 HALT_NYI;
4449
4450 for (i = 0; i < 2; i++)
4451 aarch64_set_vec_double (cpu, vd, i,
4452 func (aarch64_get_vec_double (cpu, vn, i),
4453 aarch64_get_vec_double (cpu, vm, i)));
4454 }
4455 else
4456 {
4457 float (* func)(float, float);
4458
ef0d8ffc 4459 if (INSTR (13, 12) == 0)
2e8cf49e 4460 func = min ? fminnm : fmaxnm;
ef0d8ffc 4461 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4462 func = min ? fminf : fmaxf;
4463 else
4464 HALT_NYI;
4465
4466 for (i = 0; i < (full ? 4 : 2); i++)
4467 aarch64_set_vec_float (cpu, vd, i,
4468 func (aarch64_get_vec_float (cpu, vn, i),
4469 aarch64_get_vec_float (cpu, vm, i)));
4470 }
4471}
4472
4473static void
4474do_vec_SCVTF (sim_cpu *cpu)
4475{
4476 /* instr[31] = 0
4477 instr[30] = Q
4478 instr[29,23] = 00 1110 0
4479 instr[22] = float(0)/double(1)
4480 instr[21,10] = 10 0001 1101 10
4481 instr[9,5] = Vn
4482 instr[4,0] = Vd. */
4483
ef0d8ffc
NC
4484 unsigned vn = INSTR (9, 5);
4485 unsigned vd = INSTR (4, 0);
4486 unsigned full = INSTR (30, 30);
4487 unsigned size = INSTR (22, 22);
2e8cf49e
NC
4488 unsigned i;
4489
4490 NYI_assert (29, 23, 0x1C);
4491 NYI_assert (21, 10, 0x876);
4492
2cdad34c 4493 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4494 if (size)
4495 {
4496 if (! full)
4497 HALT_UNALLOC;
4498
4499 for (i = 0; i < 2; i++)
4500 {
4501 double val = (double) aarch64_get_vec_u64 (cpu, vn, i);
4502 aarch64_set_vec_double (cpu, vd, i, val);
4503 }
4504 }
4505 else
4506 {
4507 for (i = 0; i < (full ? 4 : 2); i++)
4508 {
4509 float val = (float) aarch64_get_vec_u32 (cpu, vn, i);
4510 aarch64_set_vec_float (cpu, vd, i, val);
4511 }
4512 }
4513}
4514
4515#define VEC_CMP(SOURCE, CMP) \
4516 do \
4517 { \
4518 switch (size) \
4519 { \
4520 case 0: \
4521 for (i = 0; i < (full ? 16 : 8); i++) \
4522 aarch64_set_vec_u8 (cpu, vd, i, \
4523 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4524 CMP \
4525 aarch64_get_vec_##SOURCE##8 (cpu, vm, i) \
4526 ? -1 : 0); \
4527 return; \
4528 case 1: \
4529 for (i = 0; i < (full ? 8 : 4); i++) \
4530 aarch64_set_vec_u16 (cpu, vd, i, \
4531 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4532 CMP \
4533 aarch64_get_vec_##SOURCE##16 (cpu, vm, i) \
4534 ? -1 : 0); \
4535 return; \
4536 case 2: \
4537 for (i = 0; i < (full ? 4 : 2); i++) \
4538 aarch64_set_vec_u32 (cpu, vd, i, \
4539 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4540 CMP \
4541 aarch64_get_vec_##SOURCE##32 (cpu, vm, i) \
4542 ? -1 : 0); \
4543 return; \
4544 case 3: \
4545 if (! full) \
4546 HALT_UNALLOC; \
4547 for (i = 0; i < 2; i++) \
4548 aarch64_set_vec_u64 (cpu, vd, i, \
4549 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4550 CMP \
4551 aarch64_get_vec_##SOURCE##64 (cpu, vm, i) \
4552 ? -1ULL : 0); \
4553 return; \
2e8cf49e
NC
4554 } \
4555 } \
4556 while (0)
4557
4558#define VEC_CMP0(SOURCE, CMP) \
4559 do \
4560 { \
4561 switch (size) \
4562 { \
4563 case 0: \
4564 for (i = 0; i < (full ? 16 : 8); i++) \
4565 aarch64_set_vec_u8 (cpu, vd, i, \
4566 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4567 CMP 0 ? -1 : 0); \
4568 return; \
4569 case 1: \
4570 for (i = 0; i < (full ? 8 : 4); i++) \
4571 aarch64_set_vec_u16 (cpu, vd, i, \
4572 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4573 CMP 0 ? -1 : 0); \
4574 return; \
4575 case 2: \
4576 for (i = 0; i < (full ? 4 : 2); i++) \
4577 aarch64_set_vec_u32 (cpu, vd, i, \
4578 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4579 CMP 0 ? -1 : 0); \
4580 return; \
4581 case 3: \
4582 if (! full) \
4583 HALT_UNALLOC; \
4584 for (i = 0; i < 2; i++) \
4585 aarch64_set_vec_u64 (cpu, vd, i, \
4586 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4587 CMP 0 ? -1ULL : 0); \
4588 return; \
2e8cf49e
NC
4589 } \
4590 } \
4591 while (0)
4592
4593#define VEC_FCMP0(CMP) \
4594 do \
4595 { \
4596 if (vm != 0) \
4597 HALT_NYI; \
2cdad34c 4598 if (INSTR (22, 22)) \
2e8cf49e
NC
4599 { \
4600 if (! full) \
4601 HALT_NYI; \
4602 for (i = 0; i < 2; i++) \
4603 aarch64_set_vec_u64 (cpu, vd, i, \
4604 aarch64_get_vec_double (cpu, vn, i) \
4605 CMP 0.0 ? -1 : 0); \
4606 } \
4607 else \
4608 { \
4609 for (i = 0; i < (full ? 4 : 2); i++) \
4610 aarch64_set_vec_u32 (cpu, vd, i, \
4611 aarch64_get_vec_float (cpu, vn, i) \
4612 CMP 0.0 ? -1 : 0); \
4613 } \
4614 return; \
4615 } \
4616 while (0)
4617
4618#define VEC_FCMP(CMP) \
4619 do \
4620 { \
2cdad34c 4621 if (INSTR (22, 22)) \
2e8cf49e
NC
4622 { \
4623 if (! full) \
4624 HALT_NYI; \
4625 for (i = 0; i < 2; i++) \
4626 aarch64_set_vec_u64 (cpu, vd, i, \
4627 aarch64_get_vec_double (cpu, vn, i) \
4628 CMP \
4629 aarch64_get_vec_double (cpu, vm, i) \
4630 ? -1 : 0); \
4631 } \
4632 else \
4633 { \
4634 for (i = 0; i < (full ? 4 : 2); i++) \
4635 aarch64_set_vec_u32 (cpu, vd, i, \
4636 aarch64_get_vec_float (cpu, vn, i) \
4637 CMP \
4638 aarch64_get_vec_float (cpu, vm, i) \
4639 ? -1 : 0); \
4640 } \
4641 return; \
4642 } \
4643 while (0)
4644
4645static void
4646do_vec_compare (sim_cpu *cpu)
4647{
4648 /* instr[31] = 0
4649 instr[30] = half(0)/full(1)
4650 instr[29] = part-of-comparison-type
4651 instr[28,24] = 0 1110
4652 instr[23,22] = size of integer compares: byte(00), half(01), word (10), long (11)
4653 type of float compares: single (-0) / double (-1)
4654 instr[21] = 1
4655 instr[20,16] = Vm or 00000 (compare vs 0)
4656 instr[15,10] = part-of-comparison-type
4657 instr[9,5] = Vn
4658 instr[4.0] = Vd. */
4659
ef0d8ffc
NC
4660 int full = INSTR (30, 30);
4661 int size = INSTR (23, 22);
4662 unsigned vm = INSTR (20, 16);
4663 unsigned vn = INSTR (9, 5);
4664 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
4665 unsigned i;
4666
4667 NYI_assert (28, 24, 0x0E);
4668 NYI_assert (21, 21, 1);
4669
2cdad34c 4670 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc
NC
4671 if ((INSTR (11, 11)
4672 && INSTR (14, 14))
4673 || ((INSTR (11, 11) == 0
4674 && INSTR (10, 10) == 0)))
2e8cf49e
NC
4675 {
4676 /* A compare vs 0. */
4677 if (vm != 0)
4678 {
ef0d8ffc 4679 if (INSTR (15, 10) == 0x2A)
2e8cf49e 4680 do_vec_maxv (cpu);
ef0d8ffc
NC
4681 else if (INSTR (15, 10) == 0x32
4682 || INSTR (15, 10) == 0x3E)
2e8cf49e 4683 do_vec_fminmaxV (cpu);
ef0d8ffc
NC
4684 else if (INSTR (29, 23) == 0x1C
4685 && INSTR (21, 10) == 0x876)
2e8cf49e
NC
4686 do_vec_SCVTF (cpu);
4687 else
4688 HALT_NYI;
4689 return;
4690 }
4691 }
4692
ef0d8ffc 4693 if (INSTR (14, 14))
2e8cf49e
NC
4694 {
4695 /* A floating point compare. */
7517e550 4696 unsigned decode = (INSTR (29, 29) << 5) | (INSTR (23, 23) << 4)
ef0d8ffc 4697 | INSTR (13, 10);
2e8cf49e
NC
4698
4699 NYI_assert (15, 15, 1);
4700
4701 switch (decode)
4702 {
4703 case /* 0b010010: GT#0 */ 0x12: VEC_FCMP0 (>);
4704 case /* 0b110010: GE#0 */ 0x32: VEC_FCMP0 (>=);
4705 case /* 0b010110: EQ#0 */ 0x16: VEC_FCMP0 (==);
4706 case /* 0b110110: LE#0 */ 0x36: VEC_FCMP0 (<=);
4707 case /* 0b011010: LT#0 */ 0x1A: VEC_FCMP0 (<);
4708 case /* 0b111001: GT */ 0x39: VEC_FCMP (>);
4709 case /* 0b101001: GE */ 0x29: VEC_FCMP (>=);
4710 case /* 0b001001: EQ */ 0x09: VEC_FCMP (==);
4711
4712 default:
4713 HALT_NYI;
4714 }
4715 }
4716 else
4717 {
7517e550 4718 unsigned decode = (INSTR (29, 29) << 6) | INSTR (15, 10);
2e8cf49e
NC
4719
4720 switch (decode)
4721 {
4722 case 0x0D: /* 0001101 GT */ VEC_CMP (s, > );
4723 case 0x0F: /* 0001111 GE */ VEC_CMP (s, >= );
4724 case 0x22: /* 0100010 GT #0 */ VEC_CMP0 (s, > );
4725 case 0x26: /* 0100110 EQ #0 */ VEC_CMP0 (s, == );
4726 case 0x2A: /* 0101010 LT #0 */ VEC_CMP0 (s, < );
4727 case 0x4D: /* 1001101 HI */ VEC_CMP (u, > );
4728 case 0x4F: /* 1001111 HS */ VEC_CMP (u, >= );
4729 case 0x62: /* 1100010 GE #0 */ VEC_CMP0 (s, >= );
4730 case 0x63: /* 1100011 EQ */ VEC_CMP (u, == );
4731 case 0x66: /* 1100110 LE #0 */ VEC_CMP0 (s, <= );
4732 default:
4733 if (vm == 0)
4734 HALT_NYI;
4735 do_vec_maxv (cpu);
4736 }
4737 }
4738}
4739
4740static void
4741do_vec_SSHL (sim_cpu *cpu)
4742{
4743 /* instr[31] = 0
4744 instr[30] = first part (0)/ second part (1)
4745 instr[29,24] = 00 1110
4746 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4747 instr[21] = 1
4748 instr[20,16] = Vm
4749 instr[15,10] = 0100 01
4750 instr[9,5] = Vn
4751 instr[4,0] = Vd. */
4752
ef0d8ffc
NC
4753 unsigned full = INSTR (30, 30);
4754 unsigned vm = INSTR (20, 16);
4755 unsigned vn = INSTR (9, 5);
4756 unsigned vd = INSTR (4, 0);
2e8cf49e 4757 unsigned i;
5ab6d79e 4758 signed int shift;
2e8cf49e
NC
4759
4760 NYI_assert (29, 24, 0x0E);
4761 NYI_assert (21, 21, 1);
4762 NYI_assert (15, 10, 0x11);
4763
4764 /* FIXME: What is a signed shift left in this context ?. */
4765
2cdad34c 4766 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4767 switch (INSTR (23, 22))
2e8cf49e
NC
4768 {
4769 case 0:
4770 for (i = 0; i < (full ? 16 : 8); i++)
5ab6d79e
NC
4771 {
4772 shift = aarch64_get_vec_s8 (cpu, vm, i);
4773 if (shift >= 0)
4774 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4775 << shift);
4776 else
4777 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4778 >> - shift);
4779 }
2e8cf49e
NC
4780 return;
4781
4782 case 1:
4783 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 4784 {
7517e550 4785 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
4786 if (shift >= 0)
4787 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4788 << shift);
4789 else
4790 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4791 >> - shift);
4792 }
2e8cf49e
NC
4793 return;
4794
4795 case 2:
4796 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 4797 {
7517e550 4798 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
4799 if (shift >= 0)
4800 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4801 << shift);
4802 else
4803 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4804 >> - shift);
4805 }
2e8cf49e
NC
4806 return;
4807
4808 case 3:
4809 if (! full)
4810 HALT_UNALLOC;
4811 for (i = 0; i < 2; i++)
5ab6d79e 4812 {
7517e550 4813 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
4814 if (shift >= 0)
4815 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4816 << shift);
4817 else
4818 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4819 >> - shift);
4820 }
2e8cf49e 4821 return;
2e8cf49e
NC
4822 }
4823}
4824
4825static void
4826do_vec_USHL (sim_cpu *cpu)
4827{
4828 /* instr[31] = 0
4829 instr[30] = first part (0)/ second part (1)
4830 instr[29,24] = 10 1110
4831 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4832 instr[21] = 1
4833 instr[20,16] = Vm
4834 instr[15,10] = 0100 01
4835 instr[9,5] = Vn
4836 instr[4,0] = Vd */
4837
ef0d8ffc
NC
4838 unsigned full = INSTR (30, 30);
4839 unsigned vm = INSTR (20, 16);
4840 unsigned vn = INSTR (9, 5);
4841 unsigned vd = INSTR (4, 0);
2e8cf49e 4842 unsigned i;
5ab6d79e 4843 signed int shift;
2e8cf49e
NC
4844
4845 NYI_assert (29, 24, 0x2E);
4846 NYI_assert (15, 10, 0x11);
4847
2cdad34c 4848 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4849 switch (INSTR (23, 22))
2e8cf49e
NC
4850 {
4851 case 0:
5ab6d79e
NC
4852 for (i = 0; i < (full ? 16 : 8); i++)
4853 {
4854 shift = aarch64_get_vec_s8 (cpu, vm, i);
4855 if (shift >= 0)
4856 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4857 << shift);
4858 else
4859 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4860 >> - shift);
4861 }
2e8cf49e
NC
4862 return;
4863
4864 case 1:
4865 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 4866 {
7517e550 4867 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
4868 if (shift >= 0)
4869 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4870 << shift);
4871 else
4872 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4873 >> - shift);
4874 }
2e8cf49e
NC
4875 return;
4876
4877 case 2:
4878 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 4879 {
7517e550 4880 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
4881 if (shift >= 0)
4882 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4883 << shift);
4884 else
4885 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4886 >> - shift);
4887 }
2e8cf49e
NC
4888 return;
4889
4890 case 3:
4891 if (! full)
4892 HALT_UNALLOC;
4893 for (i = 0; i < 2; i++)
5ab6d79e 4894 {
7517e550 4895 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
4896 if (shift >= 0)
4897 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4898 << shift);
4899 else
4900 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4901 >> - shift);
4902 }
2e8cf49e 4903 return;
2e8cf49e
NC
4904 }
4905}
4906
4907static void
4908do_vec_FMLA (sim_cpu *cpu)
4909{
4910 /* instr[31] = 0
4911 instr[30] = full/half selector
4912 instr[29,23] = 0011100
4913 instr[22] = size: 0=>float, 1=>double
4914 instr[21] = 1
4915 instr[20,16] = Vn
4916 instr[15,10] = 1100 11
4917 instr[9,5] = Vm
4918 instr[4.0] = Vd. */
4919
ef0d8ffc
NC
4920 unsigned vm = INSTR (20, 16);
4921 unsigned vn = INSTR (9, 5);
4922 unsigned vd = INSTR (4, 0);
2e8cf49e 4923 unsigned i;
ef0d8ffc 4924 int full = INSTR (30, 30);
2e8cf49e
NC
4925
4926 NYI_assert (29, 23, 0x1C);
4927 NYI_assert (21, 21, 1);
4928 NYI_assert (15, 10, 0x33);
4929
2cdad34c 4930 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4931 if (INSTR (22, 22))
2e8cf49e
NC
4932 {
4933 if (! full)
4934 HALT_UNALLOC;
4935 for (i = 0; i < 2; i++)
4936 aarch64_set_vec_double (cpu, vd, i,
4937 aarch64_get_vec_double (cpu, vn, i) *
4938 aarch64_get_vec_double (cpu, vm, i) +
4939 aarch64_get_vec_double (cpu, vd, i));
4940 }
4941 else
4942 {
4943 for (i = 0; i < (full ? 4 : 2); i++)
4944 aarch64_set_vec_float (cpu, vd, i,
4945 aarch64_get_vec_float (cpu, vn, i) *
4946 aarch64_get_vec_float (cpu, vm, i) +
4947 aarch64_get_vec_float (cpu, vd, i));
4948 }
4949}
4950
4951static void
4952do_vec_max (sim_cpu *cpu)
4953{
4954 /* instr[31] = 0
4955 instr[30] = full/half selector
4956 instr[29] = SMAX (0) / UMAX (1)
4957 instr[28,24] = 0 1110
4958 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4959 instr[21] = 1
4960 instr[20,16] = Vn
4961 instr[15,10] = 0110 01
4962 instr[9,5] = Vm
4963 instr[4.0] = Vd. */
4964
ef0d8ffc
NC
4965 unsigned vm = INSTR (20, 16);
4966 unsigned vn = INSTR (9, 5);
4967 unsigned vd = INSTR (4, 0);
2e8cf49e 4968 unsigned i;
ef0d8ffc 4969 int full = INSTR (30, 30);
2e8cf49e
NC
4970
4971 NYI_assert (28, 24, 0x0E);
4972 NYI_assert (21, 21, 1);
4973 NYI_assert (15, 10, 0x19);
4974
2cdad34c 4975 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4976 if (INSTR (29, 29))
2e8cf49e 4977 {
ef0d8ffc 4978 switch (INSTR (23, 22))
2e8cf49e
NC
4979 {
4980 case 0:
4981 for (i = 0; i < (full ? 16 : 8); i++)
4982 aarch64_set_vec_u8 (cpu, vd, i,
4983 aarch64_get_vec_u8 (cpu, vn, i)
4984 > aarch64_get_vec_u8 (cpu, vm, i)
4985 ? aarch64_get_vec_u8 (cpu, vn, i)
4986 : aarch64_get_vec_u8 (cpu, vm, i));
4987 return;
4988
4989 case 1:
4990 for (i = 0; i < (full ? 8 : 4); i++)
4991 aarch64_set_vec_u16 (cpu, vd, i,
4992 aarch64_get_vec_u16 (cpu, vn, i)
4993 > aarch64_get_vec_u16 (cpu, vm, i)
4994 ? aarch64_get_vec_u16 (cpu, vn, i)
4995 : aarch64_get_vec_u16 (cpu, vm, i));
4996 return;
4997
4998 case 2:
4999 for (i = 0; i < (full ? 4 : 2); i++)
5000 aarch64_set_vec_u32 (cpu, vd, i,
5001 aarch64_get_vec_u32 (cpu, vn, i)
5002 > aarch64_get_vec_u32 (cpu, vm, i)
5003 ? aarch64_get_vec_u32 (cpu, vn, i)
5004 : aarch64_get_vec_u32 (cpu, vm, i));
5005 return;
5006
2e8cf49e
NC
5007 case 3:
5008 HALT_UNALLOC;
5009 }
5010 }
5011 else
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_s8 (cpu, vd, i,
5018 aarch64_get_vec_s8 (cpu, vn, i)
5019 > aarch64_get_vec_s8 (cpu, vm, i)
5020 ? aarch64_get_vec_s8 (cpu, vn, i)
5021 : aarch64_get_vec_s8 (cpu, vm, i));
5022 return;
5023
5024 case 1:
5025 for (i = 0; i < (full ? 8 : 4); i++)
5026 aarch64_set_vec_s16 (cpu, vd, i,
5027 aarch64_get_vec_s16 (cpu, vn, i)
5028 > aarch64_get_vec_s16 (cpu, vm, i)
5029 ? aarch64_get_vec_s16 (cpu, vn, i)
5030 : aarch64_get_vec_s16 (cpu, vm, i));
5031 return;
5032
5033 case 2:
5034 for (i = 0; i < (full ? 4 : 2); i++)
5035 aarch64_set_vec_s32 (cpu, vd, i,
5036 aarch64_get_vec_s32 (cpu, vn, i)
5037 > aarch64_get_vec_s32 (cpu, vm, i)
5038 ? aarch64_get_vec_s32 (cpu, vn, i)
5039 : aarch64_get_vec_s32 (cpu, vm, i));
5040 return;
5041
2e8cf49e
NC
5042 case 3:
5043 HALT_UNALLOC;
5044 }
5045 }
5046}
5047
5048static void
5049do_vec_min (sim_cpu *cpu)
5050{
5051 /* instr[31] = 0
5052 instr[30] = full/half selector
5053 instr[29] = SMIN (0) / UMIN (1)
5054 instr[28,24] = 0 1110
5055 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
5056 instr[21] = 1
5057 instr[20,16] = Vn
5058 instr[15,10] = 0110 11
5059 instr[9,5] = Vm
5060 instr[4.0] = Vd. */
5061
ef0d8ffc
NC
5062 unsigned vm = INSTR (20, 16);
5063 unsigned vn = INSTR (9, 5);
5064 unsigned vd = INSTR (4, 0);
2e8cf49e 5065 unsigned i;
ef0d8ffc 5066 int full = INSTR (30, 30);
2e8cf49e
NC
5067
5068 NYI_assert (28, 24, 0x0E);
5069 NYI_assert (21, 21, 1);
5070 NYI_assert (15, 10, 0x1B);
5071
2cdad34c 5072 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5073 if (INSTR (29, 29))
2e8cf49e 5074 {
ef0d8ffc 5075 switch (INSTR (23, 22))
2e8cf49e
NC
5076 {
5077 case 0:
5078 for (i = 0; i < (full ? 16 : 8); i++)
5079 aarch64_set_vec_u8 (cpu, vd, i,
5080 aarch64_get_vec_u8 (cpu, vn, i)
5081 < aarch64_get_vec_u8 (cpu, vm, i)
5082 ? aarch64_get_vec_u8 (cpu, vn, i)
5083 : aarch64_get_vec_u8 (cpu, vm, i));
5084 return;
5085
5086 case 1:
5087 for (i = 0; i < (full ? 8 : 4); i++)
5088 aarch64_set_vec_u16 (cpu, vd, i,
5089 aarch64_get_vec_u16 (cpu, vn, i)
5090 < aarch64_get_vec_u16 (cpu, vm, i)
5091 ? aarch64_get_vec_u16 (cpu, vn, i)
5092 : aarch64_get_vec_u16 (cpu, vm, i));
5093 return;
5094
5095 case 2:
5096 for (i = 0; i < (full ? 4 : 2); i++)
5097 aarch64_set_vec_u32 (cpu, vd, i,
5098 aarch64_get_vec_u32 (cpu, vn, i)
5099 < aarch64_get_vec_u32 (cpu, vm, i)
5100 ? aarch64_get_vec_u32 (cpu, vn, i)
5101 : aarch64_get_vec_u32 (cpu, vm, i));
5102 return;
5103
2e8cf49e
NC
5104 case 3:
5105 HALT_UNALLOC;
5106 }
5107 }
5108 else
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_s8 (cpu, vd, i,
5115 aarch64_get_vec_s8 (cpu, vn, i)
5116 < aarch64_get_vec_s8 (cpu, vm, i)
5117 ? aarch64_get_vec_s8 (cpu, vn, i)
5118 : aarch64_get_vec_s8 (cpu, vm, i));
5119 return;
5120
5121 case 1:
5122 for (i = 0; i < (full ? 8 : 4); i++)
5123 aarch64_set_vec_s16 (cpu, vd, i,
5124 aarch64_get_vec_s16 (cpu, vn, i)
5125 < aarch64_get_vec_s16 (cpu, vm, i)
5126 ? aarch64_get_vec_s16 (cpu, vn, i)
5127 : aarch64_get_vec_s16 (cpu, vm, i));
5128 return;
5129
5130 case 2:
5131 for (i = 0; i < (full ? 4 : 2); i++)
5132 aarch64_set_vec_s32 (cpu, vd, i,
5133 aarch64_get_vec_s32 (cpu, vn, i)
5134 < aarch64_get_vec_s32 (cpu, vm, i)
5135 ? aarch64_get_vec_s32 (cpu, vn, i)
5136 : aarch64_get_vec_s32 (cpu, vm, i));
5137 return;
5138
2e8cf49e
NC
5139 case 3:
5140 HALT_UNALLOC;
5141 }
5142 }
5143}
5144
5145static void
5146do_vec_sub_long (sim_cpu *cpu)
5147{
5148 /* instr[31] = 0
5149 instr[30] = lower (0) / upper (1)
5150 instr[29] = signed (0) / unsigned (1)
5151 instr[28,24] = 0 1110
5152 instr[23,22] = size: bytes (00), half (01), word (10)
5153 instr[21] = 1
5154 insrt[20,16] = Vm
5155 instr[15,10] = 0010 00
5156 instr[9,5] = Vn
5157 instr[4,0] = V dest. */
5158
ef0d8ffc
NC
5159 unsigned size = INSTR (23, 22);
5160 unsigned vm = INSTR (20, 16);
5161 unsigned vn = INSTR (9, 5);
5162 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5163 unsigned bias = 0;
5164 unsigned i;
5165
5166 NYI_assert (28, 24, 0x0E);
5167 NYI_assert (21, 21, 1);
5168 NYI_assert (15, 10, 0x08);
5169
5170 if (size == 3)
5171 HALT_UNALLOC;
5172
2cdad34c 5173 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5174 switch (INSTR (30, 29))
2e8cf49e
NC
5175 {
5176 case 2: /* SSUBL2. */
5177 bias = 2;
5178 case 0: /* SSUBL. */
5179 switch (size)
5180 {
5181 case 0:
5182 bias *= 3;
5183 for (i = 0; i < 8; i++)
5184 aarch64_set_vec_s16 (cpu, vd, i,
5185 aarch64_get_vec_s8 (cpu, vn, i + bias)
5186 - aarch64_get_vec_s8 (cpu, vm, i + bias));
5187 break;
5188
5189 case 1:
5190 bias *= 2;
5191 for (i = 0; i < 4; i++)
5192 aarch64_set_vec_s32 (cpu, vd, i,
5193 aarch64_get_vec_s16 (cpu, vn, i + bias)
5194 - aarch64_get_vec_s16 (cpu, vm, i + bias));
5195 break;
5196
5197 case 2:
5198 for (i = 0; i < 2; i++)
5199 aarch64_set_vec_s64 (cpu, vd, i,
5200 aarch64_get_vec_s32 (cpu, vn, i + bias)
5201 - aarch64_get_vec_s32 (cpu, vm, i + bias));
5202 break;
5203
5204 default:
5205 HALT_UNALLOC;
5206 }
5207 break;
5208
5209 case 3: /* USUBL2. */
5210 bias = 2;
5211 case 1: /* USUBL. */
5212 switch (size)
5213 {
5214 case 0:
5215 bias *= 3;
5216 for (i = 0; i < 8; i++)
5217 aarch64_set_vec_u16 (cpu, vd, i,
5218 aarch64_get_vec_u8 (cpu, vn, i + bias)
5219 - aarch64_get_vec_u8 (cpu, vm, i + bias));
5220 break;
5221
5222 case 1:
5223 bias *= 2;
5224 for (i = 0; i < 4; i++)
5225 aarch64_set_vec_u32 (cpu, vd, i,
5226 aarch64_get_vec_u16 (cpu, vn, i + bias)
5227 - aarch64_get_vec_u16 (cpu, vm, i + bias));
5228 break;
5229
5230 case 2:
5231 for (i = 0; i < 2; i++)
5232 aarch64_set_vec_u64 (cpu, vd, i,
5233 aarch64_get_vec_u32 (cpu, vn, i + bias)
5234 - aarch64_get_vec_u32 (cpu, vm, i + bias));
5235 break;
5236
5237 default:
5238 HALT_UNALLOC;
5239 }
5240 break;
5241 }
5242}
5243
2e8cf49e
NC
5244static void
5245do_vec_ADDP (sim_cpu *cpu)
5246{
5247 /* instr[31] = 0
5248 instr[30] = half(0)/full(1)
5249 instr[29,24] = 00 1110
5250 instr[23,22] = size: bytes (00), half (01), word (10), long (11)
5251 instr[21] = 1
5252 insrt[20,16] = Vm
5253 instr[15,10] = 1011 11
5254 instr[9,5] = Vn
5255 instr[4,0] = V dest. */
5256
57aa1742
NC
5257 FRegister copy_vn;
5258 FRegister copy_vm;
ef0d8ffc
NC
5259 unsigned full = INSTR (30, 30);
5260 unsigned size = INSTR (23, 22);
5261 unsigned vm = INSTR (20, 16);
5262 unsigned vn = INSTR (9, 5);
5263 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5264 unsigned i, range;
5265
5266 NYI_assert (29, 24, 0x0E);
5267 NYI_assert (21, 21, 1);
5268 NYI_assert (15, 10, 0x2F);
5269
57aa1742
NC
5270 /* Make copies of the source registers in case vd == vn/vm. */
5271 copy_vn = cpu->fr[vn];
5272 copy_vm = cpu->fr[vm];
5273
2cdad34c 5274 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
5275 switch (size)
5276 {
5277 case 0:
5278 range = full ? 8 : 4;
57aa1742
NC
5279 for (i = 0; i < range; i++)
5280 {
5281 aarch64_set_vec_u8 (cpu, vd, i,
5282 copy_vn.b[i * 2] + copy_vn.b[i * 2 + 1]);
5283 aarch64_set_vec_u8 (cpu, vd, i + range,
5284 copy_vm.b[i * 2] + copy_vm.b[i * 2 + 1]);
5285 }
2e8cf49e
NC
5286 return;
5287
5288 case 1:
5289 range = full ? 4 : 2;
57aa1742
NC
5290 for (i = 0; i < range; i++)
5291 {
5292 aarch64_set_vec_u16 (cpu, vd, i,
5293 copy_vn.h[i * 2] + copy_vn.h[i * 2 + 1]);
5294 aarch64_set_vec_u16 (cpu, vd, i + range,
5295 copy_vm.h[i * 2] + copy_vm.h[i * 2 + 1]);
5296 }
2e8cf49e
NC
5297 return;
5298
5299 case 2:
5300 range = full ? 2 : 1;
57aa1742
NC
5301 for (i = 0; i < range; i++)
5302 {
5303 aarch64_set_vec_u32 (cpu, vd, i,
5304 copy_vn.w[i * 2] + copy_vn.w[i * 2 + 1]);
5305 aarch64_set_vec_u32 (cpu, vd, i + range,
5306 copy_vm.w[i * 2] + copy_vm.w[i * 2 + 1]);
5307 }
2e8cf49e
NC
5308 return;
5309
5310 case 3:
5311 if (! full)
5312 HALT_UNALLOC;
57aa1742
NC
5313 aarch64_set_vec_u64 (cpu, vd, 0, copy_vn.v[0] + copy_vn.v[1]);
5314 aarch64_set_vec_u64 (cpu, vd, 1, copy_vm.v[0] + copy_vm.v[1]);
2e8cf49e 5315 return;
2e8cf49e
NC
5316 }
5317}
5318
5319static void
5320do_vec_UMOV (sim_cpu *cpu)
5321{
5322 /* instr[31] = 0
5323 instr[30] = 32-bit(0)/64-bit(1)
5324 instr[29,21] = 00 1110 000
5325 insrt[20,16] = size & index
5326 instr[15,10] = 0011 11
5327 instr[9,5] = V source
5328 instr[4,0] = R dest. */
5329
ef0d8ffc
NC
5330 unsigned vs = INSTR (9, 5);
5331 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
5332 unsigned index;
5333
5334 NYI_assert (29, 21, 0x070);
5335 NYI_assert (15, 10, 0x0F);
5336
2cdad34c 5337 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5338 if (INSTR (16, 16))
2e8cf49e
NC
5339 {
5340 /* Byte transfer. */
ef0d8ffc 5341 index = INSTR (20, 17);
2e8cf49e
NC
5342 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5343 aarch64_get_vec_u8 (cpu, vs, index));
5344 }
ef0d8ffc 5345 else if (INSTR (17, 17))
2e8cf49e 5346 {
ef0d8ffc 5347 index = INSTR (20, 18);
2e8cf49e
NC
5348 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5349 aarch64_get_vec_u16 (cpu, vs, index));
5350 }
ef0d8ffc 5351 else if (INSTR (18, 18))
2e8cf49e 5352 {
ef0d8ffc 5353 index = INSTR (20, 19);
2e8cf49e
NC
5354 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5355 aarch64_get_vec_u32 (cpu, vs, index));
5356 }
5357 else
5358 {
ef0d8ffc 5359 if (INSTR (30, 30) != 1)
2e8cf49e
NC
5360 HALT_UNALLOC;
5361
ef0d8ffc 5362 index = INSTR (20, 20);
2e8cf49e
NC
5363 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5364 aarch64_get_vec_u64 (cpu, vs, index));
5365 }
5366}
5367
5368static void
5369do_vec_FABS (sim_cpu *cpu)
5370{
5371 /* instr[31] = 0
5372 instr[30] = half(0)/full(1)
5373 instr[29,23] = 00 1110 1
5374 instr[22] = float(0)/double(1)
5375 instr[21,16] = 10 0000
5376 instr[15,10] = 1111 10
5377 instr[9,5] = Vn
5378 instr[4,0] = Vd. */
5379
ef0d8ffc
NC
5380 unsigned vn = INSTR (9, 5);
5381 unsigned vd = INSTR (4, 0);
5382 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5383 unsigned i;
5384
5385 NYI_assert (29, 23, 0x1D);
5386 NYI_assert (21, 10, 0x83E);
5387
2cdad34c 5388 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5389 if (INSTR (22, 22))
2e8cf49e
NC
5390 {
5391 if (! full)
5392 HALT_NYI;
5393
5394 for (i = 0; i < 2; i++)
5395 aarch64_set_vec_double (cpu, vd, i,
5396 fabs (aarch64_get_vec_double (cpu, vn, i)));
5397 }
5398 else
5399 {
5400 for (i = 0; i < (full ? 4 : 2); i++)
5401 aarch64_set_vec_float (cpu, vd, i,
5402 fabsf (aarch64_get_vec_float (cpu, vn, i)));
5403 }
5404}
5405
5406static void
5407do_vec_FCVTZS (sim_cpu *cpu)
5408{
5409 /* instr[31] = 0
5410 instr[30] = half (0) / all (1)
5411 instr[29,23] = 00 1110 1
5412 instr[22] = single (0) / double (1)
5413 instr[21,10] = 10 0001 1011 10
5414 instr[9,5] = Rn
5415 instr[4,0] = Rd. */
5416
ef0d8ffc
NC
5417 unsigned rn = INSTR (9, 5);
5418 unsigned rd = INSTR (4, 0);
5419 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5420 unsigned i;
5421
5422 NYI_assert (31, 31, 0);
5423 NYI_assert (29, 23, 0x1D);
5424 NYI_assert (21, 10, 0x86E);
5425
2cdad34c 5426 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5427 if (INSTR (22, 22))
2e8cf49e
NC
5428 {
5429 if (! full)
5430 HALT_UNALLOC;
5431
5432 for (i = 0; i < 2; i++)
5433 aarch64_set_vec_s64 (cpu, rd, i,
5434 (int64_t) aarch64_get_vec_double (cpu, rn, i));
5435 }
5436 else
5437 for (i = 0; i < (full ? 4 : 2); i++)
5438 aarch64_set_vec_s32 (cpu, rd, i,
5439 (int32_t) aarch64_get_vec_float (cpu, rn, i));
5440}
5441
67f101ee
NC
5442static void
5443do_vec_REV64 (sim_cpu *cpu)
5444{
5445 /* instr[31] = 0
5446 instr[30] = full/half
5447 instr[29,24] = 00 1110
5448 instr[23,22] = size
5449 instr[21,10] = 10 0000 0000 10
5450 instr[9,5] = Rn
5451 instr[4,0] = Rd. */
5452
5453 unsigned rn = INSTR (9, 5);
5454 unsigned rd = INSTR (4, 0);
5455 unsigned size = INSTR (23, 22);
5456 unsigned full = INSTR (30, 30);
5457 unsigned i;
5458 FRegister val;
5459
5460 NYI_assert (29, 24, 0x0E);
5461 NYI_assert (21, 10, 0x802);
5462
2cdad34c 5463 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
5464 switch (size)
5465 {
5466 case 0:
5467 for (i = 0; i < (full ? 16 : 8); i++)
5468 val.b[i ^ 0x7] = aarch64_get_vec_u8 (cpu, rn, i);
5469 break;
5470
5471 case 1:
5472 for (i = 0; i < (full ? 8 : 4); i++)
5473 val.h[i ^ 0x3] = aarch64_get_vec_u16 (cpu, rn, i);
5474 break;
5475
5476 case 2:
5477 for (i = 0; i < (full ? 4 : 2); i++)
5478 val.w[i ^ 0x1] = aarch64_get_vec_u32 (cpu, rn, i);
5479 break;
5480
5481 case 3:
5482 HALT_UNALLOC;
5483 }
5484
5485 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5486 if (full)
5487 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5488}
5489
5490static void
5491do_vec_REV16 (sim_cpu *cpu)
5492{
5493 /* instr[31] = 0
5494 instr[30] = full/half
5495 instr[29,24] = 00 1110
5496 instr[23,22] = size
5497 instr[21,10] = 10 0000 0001 10
5498 instr[9,5] = Rn
5499 instr[4,0] = Rd. */
5500
5501 unsigned rn = INSTR (9, 5);
5502 unsigned rd = INSTR (4, 0);
5503 unsigned size = INSTR (23, 22);
5504 unsigned full = INSTR (30, 30);
5505 unsigned i;
5506 FRegister val;
5507
5508 NYI_assert (29, 24, 0x0E);
5509 NYI_assert (21, 10, 0x806);
5510
2cdad34c 5511 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
5512 switch (size)
5513 {
5514 case 0:
5515 for (i = 0; i < (full ? 16 : 8); i++)
5516 val.b[i ^ 0x1] = aarch64_get_vec_u8 (cpu, rn, i);
5517 break;
5518
5519 default:
5520 HALT_UNALLOC;
5521 }
5522
5523 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5524 if (full)
5525 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5526}
5527
2e8cf49e
NC
5528static void
5529do_vec_op1 (sim_cpu *cpu)
5530{
5531 /* instr[31] = 0
5532 instr[30] = half/full
5533 instr[29,24] = 00 1110
5534 instr[23,21] = ???
5535 instr[20,16] = Vm
5536 instr[15,10] = sub-opcode
5537 instr[9,5] = Vn
5538 instr[4,0] = Vd */
5539 NYI_assert (29, 24, 0x0E);
5540
ef0d8ffc 5541 if (INSTR (21, 21) == 0)
2e8cf49e 5542 {
ef0d8ffc 5543 if (INSTR (23, 22) == 0)
2e8cf49e 5544 {
ef0d8ffc
NC
5545 if (INSTR (30, 30) == 1
5546 && INSTR (17, 14) == 0
5547 && INSTR (12, 10) == 7)
2e8cf49e
NC
5548 return do_vec_ins_2 (cpu);
5549
ef0d8ffc 5550 switch (INSTR (15, 10))
2e8cf49e
NC
5551 {
5552 case 0x01: do_vec_DUP_vector_into_vector (cpu); return;
5553 case 0x03: do_vec_DUP_scalar_into_vector (cpu); return;
5554 case 0x07: do_vec_INS (cpu); return;
5555 case 0x0A: do_vec_TRN (cpu); return;
5556
5557 case 0x0F:
ef0d8ffc 5558 if (INSTR (17, 16) == 0)
2e8cf49e
NC
5559 {
5560 do_vec_MOV_into_scalar (cpu);
5561 return;
5562 }
5563 break;
5564
5565 case 0x00:
5566 case 0x08:
5567 case 0x10:
5568 case 0x18:
5569 do_vec_TBL (cpu); return;
5570
5571 case 0x06:
5572 case 0x16:
5573 do_vec_UZP (cpu); return;
5574
5575 case 0x0E:
5576 case 0x1E:
5577 do_vec_ZIP (cpu); return;
5578
5579 default:
5580 HALT_NYI;
5581 }
5582 }
5583
ef0d8ffc 5584 switch (INSTR (13, 10))
2e8cf49e
NC
5585 {
5586 case 0x6: do_vec_UZP (cpu); return;
5587 case 0xE: do_vec_ZIP (cpu); return;
5588 case 0xA: do_vec_TRN (cpu); return;
5589 case 0xF: do_vec_UMOV (cpu); return;
5590 default: HALT_NYI;
5591 }
5592 }
5593
ef0d8ffc 5594 switch (INSTR (15, 10))
2e8cf49e 5595 {
67f101ee
NC
5596 case 0x02: do_vec_REV64 (cpu); return;
5597 case 0x06: do_vec_REV16 (cpu); return;
5598
2e8cf49e 5599 case 0x07:
ef0d8ffc 5600 switch (INSTR (23, 21))
2e8cf49e
NC
5601 {
5602 case 1: do_vec_AND (cpu); return;
5603 case 3: do_vec_BIC (cpu); return;
5604 case 5: do_vec_ORR (cpu); return;
5605 case 7: do_vec_ORN (cpu); return;
5606 default: HALT_NYI;
5607 }
5608
5609 case 0x08: do_vec_sub_long (cpu); return;
5610 case 0x0a: do_vec_XTN (cpu); return;
5611 case 0x11: do_vec_SSHL (cpu); return;
5612 case 0x19: do_vec_max (cpu); return;
5613 case 0x1B: do_vec_min (cpu); return;
5614 case 0x21: do_vec_add (cpu); return;
5615 case 0x25: do_vec_MLA (cpu); return;
5616 case 0x27: do_vec_mul (cpu); return;
5617 case 0x2F: do_vec_ADDP (cpu); return;
5618 case 0x30: do_vec_mull (cpu); return;
5619 case 0x33: do_vec_FMLA (cpu); return;
5620 case 0x35: do_vec_fadd (cpu); return;
5621
5622 case 0x2E:
ef0d8ffc 5623 switch (INSTR (20, 16))
2e8cf49e
NC
5624 {
5625 case 0x00: do_vec_ABS (cpu); return;
5626 case 0x01: do_vec_FCVTZS (cpu); return;
5627 case 0x11: do_vec_ADDV (cpu); return;
5628 default: HALT_NYI;
5629 }
5630
5631 case 0x31:
5632 case 0x3B:
5633 do_vec_Fminmax (cpu); return;
5634
5635 case 0x0D:
5636 case 0x0F:
5637 case 0x22:
5638 case 0x23:
5639 case 0x26:
5640 case 0x2A:
5641 case 0x32:
5642 case 0x36:
5643 case 0x39:
5644 case 0x3A:
5645 do_vec_compare (cpu); return;
5646
5647 case 0x3E:
5648 do_vec_FABS (cpu); return;
5649
5650 default:
5651 HALT_NYI;
5652 }
5653}
5654
5655static void
5656do_vec_xtl (sim_cpu *cpu)
5657{
5658 /* instr[31] = 0
5659 instr[30,29] = SXTL (00), UXTL (01), SXTL2 (10), UXTL2 (11)
5660 instr[28,22] = 0 1111 00
5661 instr[21,16] = size & shift (USHLL, SSHLL, USHLL2, SSHLL2)
5662 instr[15,10] = 1010 01
5663 instr[9,5] = V source
5664 instr[4,0] = V dest. */
5665
ef0d8ffc
NC
5666 unsigned vs = INSTR (9, 5);
5667 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5668 unsigned i, shift, bias = 0;
5669
5670 NYI_assert (28, 22, 0x3C);
5671 NYI_assert (15, 10, 0x29);
5672
2cdad34c 5673 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5674 switch (INSTR (30, 29))
2e8cf49e
NC
5675 {
5676 case 2: /* SXTL2, SSHLL2. */
5677 bias = 2;
5678 case 0: /* SXTL, SSHLL. */
ef0d8ffc 5679 if (INSTR (21, 21))
2e8cf49e 5680 {
7517e550
NC
5681 int64_t val1, val2;
5682
ef0d8ffc 5683 shift = INSTR (20, 16);
7517e550
NC
5684 /* Get the source values before setting the destination values
5685 in case the source and destination are the same. */
5686 val1 = aarch64_get_vec_s32 (cpu, vs, bias) << shift;
5687 val2 = aarch64_get_vec_s32 (cpu, vs, bias + 1) << shift;
5688 aarch64_set_vec_s64 (cpu, vd, 0, val1);
5689 aarch64_set_vec_s64 (cpu, vd, 1, val2);
2e8cf49e 5690 }
ef0d8ffc 5691 else if (INSTR (20, 20))
2e8cf49e 5692 {
7517e550
NC
5693 int32_t v[4];
5694 int32_t v1,v2,v3,v4;
5695
ef0d8ffc 5696 shift = INSTR (19, 16);
2e8cf49e
NC
5697 bias *= 2;
5698 for (i = 0; i < 4; i++)
7517e550
NC
5699 v[i] = aarch64_get_vec_s16 (cpu, vs, bias + i) << shift;
5700 for (i = 0; i < 4; i++)
5701 aarch64_set_vec_s32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5702 }
5703 else
5704 {
7517e550 5705 int16_t v[8];
2e8cf49e
NC
5706 NYI_assert (19, 19, 1);
5707
ef0d8ffc 5708 shift = INSTR (18, 16);
2e8cf49e
NC
5709 bias *= 3;
5710 for (i = 0; i < 8; i++)
7517e550
NC
5711 v[i] = aarch64_get_vec_s8 (cpu, vs, i + bias) << shift;
5712 for (i = 0; i < 8; i++)
5713 aarch64_set_vec_s16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5714 }
5715 return;
5716
5717 case 3: /* UXTL2, USHLL2. */
5718 bias = 2;
5719 case 1: /* UXTL, USHLL. */
ef0d8ffc 5720 if (INSTR (21, 21))
2e8cf49e 5721 {
7517e550 5722 uint64_t v1, v2;
ef0d8ffc 5723 shift = INSTR (20, 16);
7517e550
NC
5724 v1 = aarch64_get_vec_u32 (cpu, vs, bias) << shift;
5725 v2 = aarch64_get_vec_u32 (cpu, vs, bias + 1) << shift;
5726 aarch64_set_vec_u64 (cpu, vd, 0, v1);
5727 aarch64_set_vec_u64 (cpu, vd, 1, v2);
2e8cf49e 5728 }
ef0d8ffc 5729 else if (INSTR (20, 20))
2e8cf49e 5730 {
7517e550 5731 uint32_t v[4];
ef0d8ffc 5732 shift = INSTR (19, 16);
2e8cf49e
NC
5733 bias *= 2;
5734 for (i = 0; i < 4; i++)
7517e550
NC
5735 v[i] = aarch64_get_vec_u16 (cpu, vs, i + bias) << shift;
5736 for (i = 0; i < 4; i++)
5737 aarch64_set_vec_u32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5738 }
5739 else
5740 {
7517e550 5741 uint16_t v[8];
2e8cf49e
NC
5742 NYI_assert (19, 19, 1);
5743
ef0d8ffc 5744 shift = INSTR (18, 16);
2e8cf49e
NC
5745 bias *= 3;
5746 for (i = 0; i < 8; i++)
7517e550
NC
5747 v[i] = aarch64_get_vec_u8 (cpu, vs, i + bias) << shift;
5748 for (i = 0; i < 8; i++)
5749 aarch64_set_vec_u16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5750 }
5751 return;
2e8cf49e
NC
5752 }
5753}
5754
5755static void
5756do_vec_SHL (sim_cpu *cpu)
5757{
5758 /* instr [31] = 0
5759 instr [30] = half(0)/full(1)
5760 instr [29,23] = 001 1110
5761 instr [22,16] = size and shift amount
5762 instr [15,10] = 01 0101
5763 instr [9, 5] = Vs
5764 instr [4, 0] = Vd. */
5765
5766 int shift;
ef0d8ffc
NC
5767 int full = INSTR (30, 30);
5768 unsigned vs = INSTR (9, 5);
5769 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5770 unsigned i;
5771
5772 NYI_assert (29, 23, 0x1E);
5773 NYI_assert (15, 10, 0x15);
5774
2cdad34c 5775 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5776 if (INSTR (22, 22))
2e8cf49e 5777 {
ef0d8ffc 5778 shift = INSTR (21, 16);
2e8cf49e
NC
5779
5780 if (full == 0)
5781 HALT_UNALLOC;
5782
5783 for (i = 0; i < 2; i++)
5784 {
5785 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5786 aarch64_set_vec_u64 (cpu, vd, i, val << shift);
5787 }
5788
5789 return;
5790 }
5791
ef0d8ffc 5792 if (INSTR (21, 21))
2e8cf49e 5793 {
ef0d8ffc 5794 shift = INSTR (20, 16);
2e8cf49e
NC
5795
5796 for (i = 0; i < (full ? 4 : 2); i++)
5797 {
5798 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5799 aarch64_set_vec_u32 (cpu, vd, i, val << shift);
5800 }
5801
5802 return;
5803 }
5804
ef0d8ffc 5805 if (INSTR (20, 20))
2e8cf49e 5806 {
ef0d8ffc 5807 shift = INSTR (19, 16);
2e8cf49e
NC
5808
5809 for (i = 0; i < (full ? 8 : 4); i++)
5810 {
5811 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5812 aarch64_set_vec_u16 (cpu, vd, i, val << shift);
5813 }
5814
5815 return;
5816 }
5817
ef0d8ffc 5818 if (INSTR (19, 19) == 0)
2e8cf49e
NC
5819 HALT_UNALLOC;
5820
ef0d8ffc 5821 shift = INSTR (18, 16);
2e8cf49e
NC
5822
5823 for (i = 0; i < (full ? 16 : 8); i++)
5824 {
5825 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5826 aarch64_set_vec_u8 (cpu, vd, i, val << shift);
5827 }
5828}
5829
5830static void
5831do_vec_SSHR_USHR (sim_cpu *cpu)
5832{
5833 /* instr [31] = 0
5834 instr [30] = half(0)/full(1)
5835 instr [29] = signed(0)/unsigned(1)
5ab6d79e 5836 instr [28,23] = 0 1111 0
2e8cf49e
NC
5837 instr [22,16] = size and shift amount
5838 instr [15,10] = 0000 01
5839 instr [9, 5] = Vs
5840 instr [4, 0] = Vd. */
5841
5ab6d79e
NC
5842 int full = INSTR (30, 30);
5843 int sign = ! INSTR (29, 29);
5844 unsigned shift = INSTR (22, 16);
5845 unsigned vs = INSTR (9, 5);
5846 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5847 unsigned i;
5848
5849 NYI_assert (28, 23, 0x1E);
5850 NYI_assert (15, 10, 0x01);
5851
2cdad34c 5852 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5853 if (INSTR (22, 22))
2e8cf49e 5854 {
5ab6d79e 5855 shift = 128 - shift;
2e8cf49e
NC
5856
5857 if (full == 0)
5858 HALT_UNALLOC;
5859
5860 if (sign)
5861 for (i = 0; i < 2; i++)
5862 {
5863 int64_t val = aarch64_get_vec_s64 (cpu, vs, i);
5864 aarch64_set_vec_s64 (cpu, vd, i, val >> shift);
5865 }
5866 else
5867 for (i = 0; i < 2; i++)
5868 {
5869 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5870 aarch64_set_vec_u64 (cpu, vd, i, val >> shift);
5871 }
5872
5873 return;
5874 }
5875
ef0d8ffc 5876 if (INSTR (21, 21))
2e8cf49e 5877 {
5ab6d79e 5878 shift = 64 - shift;
2e8cf49e
NC
5879
5880 if (sign)
5881 for (i = 0; i < (full ? 4 : 2); i++)
5882 {
5883 int32_t val = aarch64_get_vec_s32 (cpu, vs, i);
5884 aarch64_set_vec_s32 (cpu, vd, i, val >> shift);
5885 }
5886 else
5887 for (i = 0; i < (full ? 4 : 2); i++)
5888 {
5889 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5890 aarch64_set_vec_u32 (cpu, vd, i, val >> shift);
5891 }
5892
5893 return;
5894 }
5895
ef0d8ffc 5896 if (INSTR (20, 20))
2e8cf49e 5897 {
5ab6d79e 5898 shift = 32 - shift;
2e8cf49e
NC
5899
5900 if (sign)
5901 for (i = 0; i < (full ? 8 : 4); i++)
5902 {
5903 int16_t val = aarch64_get_vec_s16 (cpu, vs, i);
5904 aarch64_set_vec_s16 (cpu, vd, i, val >> shift);
5905 }
5906 else
5907 for (i = 0; i < (full ? 8 : 4); i++)
5908 {
5909 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5910 aarch64_set_vec_u16 (cpu, vd, i, val >> shift);
5911 }
5912
5913 return;
5914 }
5915
ef0d8ffc 5916 if (INSTR (19, 19) == 0)
2e8cf49e
NC
5917 HALT_UNALLOC;
5918
5ab6d79e 5919 shift = 16 - shift;
2e8cf49e
NC
5920
5921 if (sign)
5922 for (i = 0; i < (full ? 16 : 8); i++)
5923 {
5924 int8_t val = aarch64_get_vec_s8 (cpu, vs, i);
5925 aarch64_set_vec_s8 (cpu, vd, i, val >> shift);
5926 }
5927 else
5928 for (i = 0; i < (full ? 16 : 8); i++)
5929 {
5930 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5931 aarch64_set_vec_u8 (cpu, vd, i, val >> shift);
5932 }
5933}
5934
e101a78b
NC
5935static void
5936do_vec_MUL_by_element (sim_cpu *cpu)
5937{
5938 /* instr[31] = 0
5939 instr[30] = half/full
5940 instr[29,24] = 00 1111
5941 instr[23,22] = size
5942 instr[21] = L
5943 instr[20] = M
5944 instr[19,16] = m
5945 instr[15,12] = 1000
5946 instr[11] = H
5947 instr[10] = 0
5948 instr[9,5] = Vn
5949 instr[4,0] = Vd */
5950
ef0d8ffc
NC
5951 unsigned full = INSTR (30, 30);
5952 unsigned L = INSTR (21, 21);
5953 unsigned H = INSTR (11, 11);
5954 unsigned vn = INSTR (9, 5);
5955 unsigned vd = INSTR (4, 0);
5956 unsigned size = INSTR (23, 22);
e101a78b
NC
5957 unsigned index;
5958 unsigned vm;
5959 unsigned e;
5960
5961 NYI_assert (29, 24, 0x0F);
5962 NYI_assert (15, 12, 0x8);
5963 NYI_assert (10, 10, 0);
5964
2cdad34c 5965 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
5966 switch (size)
5967 {
5968 case 1:
5969 {
5970 /* 16 bit products. */
5971 uint16_t product;
5972 uint16_t element1;
5973 uint16_t element2;
5974
ef0d8ffc
NC
5975 index = (H << 2) | (L << 1) | INSTR (20, 20);
5976 vm = INSTR (19, 16);
e101a78b
NC
5977 element2 = aarch64_get_vec_u16 (cpu, vm, index);
5978
5979 for (e = 0; e < (full ? 8 : 4); e ++)
5980 {
5981 element1 = aarch64_get_vec_u16 (cpu, vn, e);
5982 product = element1 * element2;
5983 aarch64_set_vec_u16 (cpu, vd, e, product);
5984 }
5985 }
5986 break;
5987
5988 case 2:
5989 {
5990 /* 32 bit products. */
5991 uint32_t product;
5992 uint32_t element1;
5993 uint32_t element2;
5994
5995 index = (H << 1) | L;
ef0d8ffc 5996 vm = INSTR (20, 16);
e101a78b
NC
5997 element2 = aarch64_get_vec_u32 (cpu, vm, index);
5998
5999 for (e = 0; e < (full ? 4 : 2); e ++)
6000 {
6001 element1 = aarch64_get_vec_u32 (cpu, vn, e);
6002 product = element1 * element2;
6003 aarch64_set_vec_u32 (cpu, vd, e, product);
6004 }
6005 }
6006 break;
6007
6008 default:
6009 HALT_UNALLOC;
6010 }
6011}
6012
fd7ed446
NC
6013static void
6014do_FMLA_by_element (sim_cpu *cpu)
6015{
6016 /* instr[31] = 0
6017 instr[30] = half/full
6018 instr[29,23] = 00 1111 1
6019 instr[22] = size
6020 instr[21] = L
6021 instr[20,16] = m
6022 instr[15,12] = 0001
6023 instr[11] = H
6024 instr[10] = 0
6025 instr[9,5] = Vn
6026 instr[4,0] = Vd */
6027
6028 unsigned full = INSTR (30, 30);
6029 unsigned size = INSTR (22, 22);
6030 unsigned L = INSTR (21, 21);
6031 unsigned vm = INSTR (20, 16);
6032 unsigned H = INSTR (11, 11);
6033 unsigned vn = INSTR (9, 5);
6034 unsigned vd = INSTR (4, 0);
6035 unsigned e;
6036
6037 NYI_assert (29, 23, 0x1F);
6038 NYI_assert (15, 12, 0x1);
6039 NYI_assert (10, 10, 0);
6040
6041 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
6042 if (size)
6043 {
6044 double element1, element2;
6045
6046 if (! full || L)
6047 HALT_UNALLOC;
6048
6049 element2 = aarch64_get_vec_double (cpu, vm, H);
6050
6051 for (e = 0; e < 2; e++)
6052 {
6053 element1 = aarch64_get_vec_double (cpu, vn, e);
6054 element1 *= element2;
6055 element1 += aarch64_get_vec_double (cpu, vd, e);
6056 aarch64_set_vec_double (cpu, vd, e, element1);
6057 }
6058 }
6059 else
6060 {
6061 float element1;
6062 float element2 = aarch64_get_vec_float (cpu, vm, (H << 1) | L);
6063
6064 for (e = 0; e < (full ? 4 : 2); e++)
6065 {
6066 element1 = aarch64_get_vec_float (cpu, vn, e);
6067 element1 *= element2;
6068 element1 += aarch64_get_vec_float (cpu, vd, e);
6069 aarch64_set_vec_float (cpu, vd, e, element1);
6070 }
6071 }
6072}
6073
2e8cf49e
NC
6074static void
6075do_vec_op2 (sim_cpu *cpu)
6076{
6077 /* instr[31] = 0
6078 instr[30] = half/full
6079 instr[29,24] = 00 1111
6080 instr[23] = ?
6081 instr[22,16] = element size & index
6082 instr[15,10] = sub-opcode
6083 instr[9,5] = Vm
e101a78b 6084 instr[4,0] = Vd */
2e8cf49e
NC
6085
6086 NYI_assert (29, 24, 0x0F);
6087
ef0d8ffc 6088 if (INSTR (23, 23) != 0)
2e8cf49e 6089 {
ef0d8ffc 6090 switch (INSTR (15, 10))
e101a78b 6091 {
fd7ed446
NC
6092 case 0x04:
6093 case 0x06:
6094 do_FMLA_by_element (cpu);
6095 return;
6096
e101a78b 6097 case 0x20:
fd7ed446
NC
6098 case 0x22:
6099 do_vec_MUL_by_element (cpu);
6100 return;
6101
6102 default:
6103 HALT_NYI;
e101a78b
NC
6104 }
6105 }
6106 else
6107 {
ef0d8ffc 6108 switch (INSTR (15, 10))
e101a78b
NC
6109 {
6110 case 0x01: do_vec_SSHR_USHR (cpu); return;
6111 case 0x15: do_vec_SHL (cpu); return;
6112 case 0x20:
6113 case 0x22: do_vec_MUL_by_element (cpu); return;
6114 case 0x29: do_vec_xtl (cpu); return;
6115 default: HALT_NYI;
6116 }
2e8cf49e
NC
6117 }
6118}
6119
6120static void
6121do_vec_neg (sim_cpu *cpu)
6122{
6123 /* instr[31] = 0
6124 instr[30] = full(1)/half(0)
6125 instr[29,24] = 10 1110
6126 instr[23,22] = size: byte(00), half (01), word (10), long (11)
6127 instr[21,10] = 1000 0010 1110
6128 instr[9,5] = Vs
6129 instr[4,0] = Vd */
6130
ef0d8ffc
NC
6131 int full = INSTR (30, 30);
6132 unsigned vs = INSTR (9, 5);
6133 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6134 unsigned i;
6135
6136 NYI_assert (29, 24, 0x2E);
6137 NYI_assert (21, 10, 0x82E);
6138
2cdad34c 6139 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6140 switch (INSTR (23, 22))
2e8cf49e
NC
6141 {
6142 case 0:
6143 for (i = 0; i < (full ? 16 : 8); i++)
6144 aarch64_set_vec_s8 (cpu, vd, i, - aarch64_get_vec_s8 (cpu, vs, i));
6145 return;
6146
6147 case 1:
6148 for (i = 0; i < (full ? 8 : 4); i++)
6149 aarch64_set_vec_s16 (cpu, vd, i, - aarch64_get_vec_s16 (cpu, vs, i));
6150 return;
6151
6152 case 2:
6153 for (i = 0; i < (full ? 4 : 2); i++)
6154 aarch64_set_vec_s32 (cpu, vd, i, - aarch64_get_vec_s32 (cpu, vs, i));
6155 return;
6156
6157 case 3:
6158 if (! full)
6159 HALT_NYI;
6160 for (i = 0; i < 2; i++)
6161 aarch64_set_vec_s64 (cpu, vd, i, - aarch64_get_vec_s64 (cpu, vs, i));
6162 return;
2e8cf49e
NC
6163 }
6164}
6165
6166static void
6167do_vec_sqrt (sim_cpu *cpu)
6168{
6169 /* instr[31] = 0
6170 instr[30] = full(1)/half(0)
6171 instr[29,23] = 101 1101
6172 instr[22] = single(0)/double(1)
6173 instr[21,10] = 1000 0111 1110
6174 instr[9,5] = Vs
6175 instr[4,0] = Vd. */
6176
ef0d8ffc
NC
6177 int full = INSTR (30, 30);
6178 unsigned vs = INSTR (9, 5);
6179 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6180 unsigned i;
6181
6182 NYI_assert (29, 23, 0x5B);
6183 NYI_assert (21, 10, 0x87E);
6184
2cdad34c 6185 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6186 if (INSTR (22, 22) == 0)
2e8cf49e
NC
6187 for (i = 0; i < (full ? 4 : 2); i++)
6188 aarch64_set_vec_float (cpu, vd, i,
6189 sqrtf (aarch64_get_vec_float (cpu, vs, i)));
6190 else
6191 for (i = 0; i < 2; i++)
6192 aarch64_set_vec_double (cpu, vd, i,
6193 sqrt (aarch64_get_vec_double (cpu, vs, i)));
6194}
6195
6196static void
6197do_vec_mls_indexed (sim_cpu *cpu)
6198{
6199 /* instr[31] = 0
6200 instr[30] = half(0)/full(1)
6201 instr[29,24] = 10 1111
6202 instr[23,22] = 16-bit(01)/32-bit(10)
6203 instr[21,20+11] = index (if 16-bit)
6204 instr[21+11] = index (if 32-bit)
6205 instr[20,16] = Vm
6206 instr[15,12] = 0100
6207 instr[11] = part of index
6208 instr[10] = 0
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);
6215 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
6216 unsigned i;
6217
6218 NYI_assert (15, 12, 4);
6219 NYI_assert (10, 10, 0);
6220
2cdad34c 6221 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6222 switch (INSTR (23, 22))
2e8cf49e
NC
6223 {
6224 case 1:
6225 {
6226 unsigned elem;
6227 uint32_t val;
6228
6229 if (vm > 15)
6230 HALT_NYI;
6231
7517e550 6232 elem = (INSTR (21, 20) << 1) | INSTR (11, 11);
2e8cf49e
NC
6233 val = aarch64_get_vec_u16 (cpu, vm, elem);
6234
6235 for (i = 0; i < (full ? 8 : 4); i++)
6236 aarch64_set_vec_u32 (cpu, vd, i,
6237 aarch64_get_vec_u32 (cpu, vd, i) -
6238 (aarch64_get_vec_u32 (cpu, vs, i) * val));
6239 return;
6240 }
6241
6242 case 2:
6243 {
7517e550 6244 unsigned elem = (INSTR (21, 21) << 1) | INSTR (11, 11);
2e8cf49e
NC
6245 uint64_t val = aarch64_get_vec_u32 (cpu, vm, elem);
6246
6247 for (i = 0; i < (full ? 4 : 2); i++)
6248 aarch64_set_vec_u64 (cpu, vd, i,
6249 aarch64_get_vec_u64 (cpu, vd, i) -
6250 (aarch64_get_vec_u64 (cpu, vs, i) * val));
6251 return;
6252 }
6253
6254 case 0:
6255 case 3:
6256 default:
6257 HALT_NYI;
6258 }
6259}
6260
6261static void
6262do_vec_SUB (sim_cpu *cpu)
6263{
6264 /* instr [31] = 0
6265 instr [30] = half(0)/full(1)
6266 instr [29,24] = 10 1110
6267 instr [23,22] = size: byte(00, half(01), word (10), long (11)
6268 instr [21] = 1
6269 instr [20,16] = Vm
6270 instr [15,10] = 10 0001
6271 instr [9, 5] = Vn
6272 instr [4, 0] = Vd. */
6273
ef0d8ffc
NC
6274 unsigned full = INSTR (30, 30);
6275 unsigned vm = INSTR (20, 16);
6276 unsigned vn = INSTR (9, 5);
6277 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6278 unsigned i;
6279
6280 NYI_assert (29, 24, 0x2E);
6281 NYI_assert (21, 21, 1);
6282 NYI_assert (15, 10, 0x21);
6283
2cdad34c 6284 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6285 switch (INSTR (23, 22))
2e8cf49e
NC
6286 {
6287 case 0:
6288 for (i = 0; i < (full ? 16 : 8); i++)
6289 aarch64_set_vec_s8 (cpu, vd, i,
6290 aarch64_get_vec_s8 (cpu, vn, i)
6291 - aarch64_get_vec_s8 (cpu, vm, i));
6292 return;
6293
6294 case 1:
6295 for (i = 0; i < (full ? 8 : 4); i++)
6296 aarch64_set_vec_s16 (cpu, vd, i,
6297 aarch64_get_vec_s16 (cpu, vn, i)
6298 - aarch64_get_vec_s16 (cpu, vm, i));
6299 return;
6300
6301 case 2:
6302 for (i = 0; i < (full ? 4 : 2); i++)
6303 aarch64_set_vec_s32 (cpu, vd, i,
6304 aarch64_get_vec_s32 (cpu, vn, i)
6305 - aarch64_get_vec_s32 (cpu, vm, i));
6306 return;
6307
6308 case 3:
6309 if (full == 0)
6310 HALT_UNALLOC;
6311
6312 for (i = 0; i < 2; i++)
6313 aarch64_set_vec_s64 (cpu, vd, i,
6314 aarch64_get_vec_s64 (cpu, vn, i)
6315 - aarch64_get_vec_s64 (cpu, vm, i));
6316 return;
2e8cf49e
NC
6317 }
6318}
6319
6320static void
6321do_vec_MLS (sim_cpu *cpu)
6322{
6323 /* instr [31] = 0
6324 instr [30] = half(0)/full(1)
6325 instr [29,24] = 10 1110
6326 instr [23,22] = size: byte(00, half(01), word (10)
6327 instr [21] = 1
6328 instr [20,16] = Vm
6329 instr [15,10] = 10 0101
6330 instr [9, 5] = Vn
6331 instr [4, 0] = Vd. */
6332
ef0d8ffc
NC
6333 unsigned full = INSTR (30, 30);
6334 unsigned vm = INSTR (20, 16);
6335 unsigned vn = INSTR (9, 5);
6336 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6337 unsigned i;
6338
6339 NYI_assert (29, 24, 0x2E);
6340 NYI_assert (21, 21, 1);
6341 NYI_assert (15, 10, 0x25);
6342
2cdad34c 6343 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6344 switch (INSTR (23, 22))
2e8cf49e
NC
6345 {
6346 case 0:
6347 for (i = 0; i < (full ? 16 : 8); i++)
6348 aarch64_set_vec_u8 (cpu, vd, i,
6349 (aarch64_get_vec_u8 (cpu, vn, i)
6350 * aarch64_get_vec_u8 (cpu, vm, i))
6351 - aarch64_get_vec_u8 (cpu, vd, i));
6352 return;
6353
6354 case 1:
6355 for (i = 0; i < (full ? 8 : 4); i++)
6356 aarch64_set_vec_u16 (cpu, vd, i,
6357 (aarch64_get_vec_u16 (cpu, vn, i)
6358 * aarch64_get_vec_u16 (cpu, vm, i))
6359 - aarch64_get_vec_u16 (cpu, vd, i));
6360 return;
6361
6362 case 2:
6363 for (i = 0; i < (full ? 4 : 2); i++)
6364 aarch64_set_vec_u32 (cpu, vd, i,
6365 (aarch64_get_vec_u32 (cpu, vn, i)
6366 * aarch64_get_vec_u32 (cpu, vm, i))
6367 - aarch64_get_vec_u32 (cpu, vd, i));
6368 return;
6369
6370 default:
6371 HALT_UNALLOC;
6372 }
6373}
6374
6375static void
6376do_vec_FDIV (sim_cpu *cpu)
6377{
6378 /* instr [31] = 0
6379 instr [30] = half(0)/full(1)
6380 instr [29,23] = 10 1110 0
6381 instr [22] = float()/double(1)
6382 instr [21] = 1
6383 instr [20,16] = Vm
6384 instr [15,10] = 1111 11
6385 instr [9, 5] = Vn
6386 instr [4, 0] = Vd. */
6387
ef0d8ffc
NC
6388 unsigned full = INSTR (30, 30);
6389 unsigned vm = INSTR (20, 16);
6390 unsigned vn = INSTR (9, 5);
6391 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6392 unsigned i;
6393
6394 NYI_assert (29, 23, 0x5C);
6395 NYI_assert (21, 21, 1);
6396 NYI_assert (15, 10, 0x3F);
6397
2cdad34c 6398 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6399 if (INSTR (22, 22))
2e8cf49e
NC
6400 {
6401 if (! full)
6402 HALT_UNALLOC;
6403
6404 for (i = 0; i < 2; i++)
6405 aarch64_set_vec_double (cpu, vd, i,
6406 aarch64_get_vec_double (cpu, vn, i)
6407 / aarch64_get_vec_double (cpu, vm, i));
6408 }
6409 else
6410 for (i = 0; i < (full ? 4 : 2); i++)
6411 aarch64_set_vec_float (cpu, vd, i,
6412 aarch64_get_vec_float (cpu, vn, i)
6413 / aarch64_get_vec_float (cpu, vm, i));
6414}
6415
6416static void
6417do_vec_FMUL (sim_cpu *cpu)
6418{
6419 /* instr [31] = 0
6420 instr [30] = half(0)/full(1)
6421 instr [29,23] = 10 1110 0
6422 instr [22] = float(0)/double(1)
6423 instr [21] = 1
6424 instr [20,16] = Vm
6425 instr [15,10] = 1101 11
6426 instr [9, 5] = Vn
6427 instr [4, 0] = Vd. */
6428
ef0d8ffc
NC
6429 unsigned full = INSTR (30, 30);
6430 unsigned vm = INSTR (20, 16);
6431 unsigned vn = INSTR (9, 5);
6432 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6433 unsigned i;
6434
6435 NYI_assert (29, 23, 0x5C);
6436 NYI_assert (21, 21, 1);
6437 NYI_assert (15, 10, 0x37);
6438
2cdad34c 6439 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6440 if (INSTR (22, 22))
2e8cf49e
NC
6441 {
6442 if (! full)
6443 HALT_UNALLOC;
6444
6445 for (i = 0; i < 2; i++)
6446 aarch64_set_vec_double (cpu, vd, i,
6447 aarch64_get_vec_double (cpu, vn, i)
6448 * aarch64_get_vec_double (cpu, vm, i));
6449 }
6450 else
6451 for (i = 0; i < (full ? 4 : 2); i++)
6452 aarch64_set_vec_float (cpu, vd, i,
6453 aarch64_get_vec_float (cpu, vn, i)
6454 * aarch64_get_vec_float (cpu, vm, i));
6455}
6456
6457static void
6458do_vec_FADDP (sim_cpu *cpu)
6459{
6460 /* instr [31] = 0
6461 instr [30] = half(0)/full(1)
6462 instr [29,23] = 10 1110 0
6463 instr [22] = float(0)/double(1)
6464 instr [21] = 1
6465 instr [20,16] = Vm
6466 instr [15,10] = 1101 01
6467 instr [9, 5] = Vn
6468 instr [4, 0] = Vd. */
6469
ef0d8ffc
NC
6470 unsigned full = INSTR (30, 30);
6471 unsigned vm = INSTR (20, 16);
6472 unsigned vn = INSTR (9, 5);
6473 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6474
6475 NYI_assert (29, 23, 0x5C);
6476 NYI_assert (21, 21, 1);
6477 NYI_assert (15, 10, 0x35);
6478
2cdad34c 6479 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6480 if (INSTR (22, 22))
2e8cf49e 6481 {
57aa1742
NC
6482 /* Extract values before adding them incase vd == vn/vm. */
6483 double tmp1 = aarch64_get_vec_double (cpu, vn, 0);
6484 double tmp2 = aarch64_get_vec_double (cpu, vn, 1);
6485 double tmp3 = aarch64_get_vec_double (cpu, vm, 0);
6486 double tmp4 = aarch64_get_vec_double (cpu, vm, 1);
6487
2e8cf49e
NC
6488 if (! full)
6489 HALT_UNALLOC;
6490
57aa1742
NC
6491 aarch64_set_vec_double (cpu, vd, 0, tmp1 + tmp2);
6492 aarch64_set_vec_double (cpu, vd, 1, tmp3 + tmp4);
2e8cf49e
NC
6493 }
6494 else
6495 {
57aa1742
NC
6496 /* Extract values before adding them incase vd == vn/vm. */
6497 float tmp1 = aarch64_get_vec_float (cpu, vn, 0);
6498 float tmp2 = aarch64_get_vec_float (cpu, vn, 1);
6499 float tmp5 = aarch64_get_vec_float (cpu, vm, 0);
6500 float tmp6 = aarch64_get_vec_float (cpu, vm, 1);
6501
2e8cf49e 6502 if (full)
57aa1742
NC
6503 {
6504 float tmp3 = aarch64_get_vec_float (cpu, vn, 2);
6505 float tmp4 = aarch64_get_vec_float (cpu, vn, 3);
6506 float tmp7 = aarch64_get_vec_float (cpu, vm, 2);
6507 float tmp8 = aarch64_get_vec_float (cpu, vm, 3);
6508
6509 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6510 aarch64_set_vec_float (cpu, vd, 1, tmp3 + tmp4);
6511 aarch64_set_vec_float (cpu, vd, 2, tmp5 + tmp6);
6512 aarch64_set_vec_float (cpu, vd, 3, tmp7 + tmp8);
6513 }
6514 else
6515 {
6516 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6517 aarch64_set_vec_float (cpu, vd, 1, tmp5 + tmp6);
6518 }
2e8cf49e
NC
6519 }
6520}
6521
6522static void
6523do_vec_FSQRT (sim_cpu *cpu)
6524{
6525 /* instr[31] = 0
6526 instr[30] = half(0)/full(1)
6527 instr[29,23] = 10 1110 1
6528 instr[22] = single(0)/double(1)
6529 instr[21,10] = 10 0001 1111 10
6530 instr[9,5] = Vsrc
6531 instr[4,0] = Vdest. */
6532
ef0d8ffc
NC
6533 unsigned vn = INSTR (9, 5);
6534 unsigned vd = INSTR (4, 0);
6535 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6536 int i;
6537
6538 NYI_assert (29, 23, 0x5D);
6539 NYI_assert (21, 10, 0x87E);
6540
2cdad34c 6541 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6542 if (INSTR (22, 22))
2e8cf49e
NC
6543 {
6544 if (! full)
6545 HALT_UNALLOC;
6546
6547 for (i = 0; i < 2; i++)
6548 aarch64_set_vec_double (cpu, vd, i,
6549 sqrt (aarch64_get_vec_double (cpu, vn, i)));
6550 }
6551 else
6552 {
6553 for (i = 0; i < (full ? 4 : 2); i++)
6554 aarch64_set_vec_float (cpu, vd, i,
6555 sqrtf (aarch64_get_vec_float (cpu, vn, i)));
6556 }
6557}
6558
6559static void
6560do_vec_FNEG (sim_cpu *cpu)
6561{
6562 /* instr[31] = 0
6563 instr[30] = half (0)/full (1)
6564 instr[29,23] = 10 1110 1
6565 instr[22] = single (0)/double (1)
6566 instr[21,10] = 10 0000 1111 10
6567 instr[9,5] = Vsrc
6568 instr[4,0] = Vdest. */
6569
ef0d8ffc
NC
6570 unsigned vn = INSTR (9, 5);
6571 unsigned vd = INSTR (4, 0);
6572 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6573 int i;
6574
6575 NYI_assert (29, 23, 0x5D);
6576 NYI_assert (21, 10, 0x83E);
6577
2cdad34c 6578 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6579 if (INSTR (22, 22))
2e8cf49e
NC
6580 {
6581 if (! full)
6582 HALT_UNALLOC;
6583
6584 for (i = 0; i < 2; i++)
6585 aarch64_set_vec_double (cpu, vd, i,
6586 - aarch64_get_vec_double (cpu, vn, i));
6587 }
6588 else
6589 {
6590 for (i = 0; i < (full ? 4 : 2); i++)
6591 aarch64_set_vec_float (cpu, vd, i,
6592 - aarch64_get_vec_float (cpu, vn, i));
6593 }
6594}
6595
6596static void
6597do_vec_NOT (sim_cpu *cpu)
6598{
6599 /* instr[31] = 0
6600 instr[30] = half (0)/full (1)
5ab6d79e 6601 instr[29,10] = 10 1110 0010 0000 0101 10
2e8cf49e
NC
6602 instr[9,5] = Vn
6603 instr[4.0] = Vd. */
6604
ef0d8ffc
NC
6605 unsigned vn = INSTR (9, 5);
6606 unsigned vd = INSTR (4, 0);
2e8cf49e 6607 unsigned i;
ef0d8ffc 6608 int full = INSTR (30, 30);
2e8cf49e
NC
6609
6610 NYI_assert (29, 10, 0xB8816);
6611
2cdad34c 6612 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
6613 for (i = 0; i < (full ? 16 : 8); i++)
6614 aarch64_set_vec_u8 (cpu, vd, i, ~ aarch64_get_vec_u8 (cpu, vn, i));
6615}
6616
5ab6d79e
NC
6617static unsigned int
6618clz (uint64_t val, unsigned size)
6619{
6620 uint64_t mask = 1;
6621 int count;
6622
6623 mask <<= (size - 1);
6624 count = 0;
6625 do
6626 {
6627 if (val & mask)
6628 break;
6629 mask >>= 1;
6630 count ++;
6631 }
6632 while (mask);
6633
6634 return count;
6635}
6636
6637static void
6638do_vec_CLZ (sim_cpu *cpu)
6639{
6640 /* instr[31] = 0
6641 instr[30] = half (0)/full (1)
6642 instr[29,24] = 10 1110
6643 instr[23,22] = size
6644 instr[21,10] = 10 0000 0100 10
6645 instr[9,5] = Vn
6646 instr[4.0] = Vd. */
6647
6648 unsigned vn = INSTR (9, 5);
6649 unsigned vd = INSTR (4, 0);
6650 unsigned i;
6651 int full = INSTR (30,30);
6652
6653 NYI_assert (29, 24, 0x2E);
6654 NYI_assert (21, 10, 0x812);
6655
2cdad34c 6656 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
6657 switch (INSTR (23, 22))
6658 {
6659 case 0:
6660 for (i = 0; i < (full ? 16 : 8); i++)
6661 aarch64_set_vec_u8 (cpu, vd, i, clz (aarch64_get_vec_u8 (cpu, vn, i), 8));
6662 break;
6663 case 1:
6664 for (i = 0; i < (full ? 8 : 4); i++)
6665 aarch64_set_vec_u16 (cpu, vd, i, clz (aarch64_get_vec_u16 (cpu, vn, i), 16));
6666 break;
6667 case 2:
6668 for (i = 0; i < (full ? 4 : 2); i++)
6669 aarch64_set_vec_u32 (cpu, vd, i, clz (aarch64_get_vec_u32 (cpu, vn, i), 32));
6670 break;
6671 case 3:
6672 if (! full)
6673 HALT_UNALLOC;
6674 aarch64_set_vec_u64 (cpu, vd, 0, clz (aarch64_get_vec_u64 (cpu, vn, 0), 64));
6675 aarch64_set_vec_u64 (cpu, vd, 1, clz (aarch64_get_vec_u64 (cpu, vn, 1), 64));
6676 break;
6677 }
6678}
6679
2e8cf49e
NC
6680static void
6681do_vec_MOV_element (sim_cpu *cpu)
6682{
6683 /* instr[31,21] = 0110 1110 000
6684 instr[20,16] = size & dest index
6685 instr[15] = 0
6686 instr[14,11] = source index
6687 instr[10] = 1
6688 instr[9,5] = Vs
6689 instr[4.0] = Vd. */
6690
ef0d8ffc
NC
6691 unsigned vs = INSTR (9, 5);
6692 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6693 unsigned src_index;
6694 unsigned dst_index;
6695
6696 NYI_assert (31, 21, 0x370);
6697 NYI_assert (15, 15, 0);
6698 NYI_assert (10, 10, 1);
6699
2cdad34c 6700 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6701 if (INSTR (16, 16))
2e8cf49e
NC
6702 {
6703 /* Move a byte. */
ef0d8ffc
NC
6704 src_index = INSTR (14, 11);
6705 dst_index = INSTR (20, 17);
2e8cf49e
NC
6706 aarch64_set_vec_u8 (cpu, vd, dst_index,
6707 aarch64_get_vec_u8 (cpu, vs, src_index));
6708 }
ef0d8ffc 6709 else if (INSTR (17, 17))
2e8cf49e
NC
6710 {
6711 /* Move 16-bits. */
6712 NYI_assert (11, 11, 0);
ef0d8ffc
NC
6713 src_index = INSTR (14, 12);
6714 dst_index = INSTR (20, 18);
2e8cf49e
NC
6715 aarch64_set_vec_u16 (cpu, vd, dst_index,
6716 aarch64_get_vec_u16 (cpu, vs, src_index));
6717 }
ef0d8ffc 6718 else if (INSTR (18, 18))
2e8cf49e
NC
6719 {
6720 /* Move 32-bits. */
6721 NYI_assert (12, 11, 0);
ef0d8ffc
NC
6722 src_index = INSTR (14, 13);
6723 dst_index = INSTR (20, 19);
2e8cf49e
NC
6724 aarch64_set_vec_u32 (cpu, vd, dst_index,
6725 aarch64_get_vec_u32 (cpu, vs, src_index));
6726 }
6727 else
6728 {
6729 NYI_assert (19, 19, 1);
6730 NYI_assert (13, 11, 0);
ef0d8ffc
NC
6731 src_index = INSTR (14, 14);
6732 dst_index = INSTR (20, 20);
2e8cf49e
NC
6733 aarch64_set_vec_u64 (cpu, vd, dst_index,
6734 aarch64_get_vec_u64 (cpu, vs, src_index));
6735 }
6736}
6737
67f101ee
NC
6738static void
6739do_vec_REV32 (sim_cpu *cpu)
6740{
6741 /* instr[31] = 0
6742 instr[30] = full/half
6743 instr[29,24] = 10 1110
6744 instr[23,22] = size
6745 instr[21,10] = 10 0000 0000 10
6746 instr[9,5] = Rn
6747 instr[4,0] = Rd. */
6748
6749 unsigned rn = INSTR (9, 5);
6750 unsigned rd = INSTR (4, 0);
6751 unsigned size = INSTR (23, 22);
6752 unsigned full = INSTR (30, 30);
6753 unsigned i;
6754 FRegister val;
6755
6756 NYI_assert (29, 24, 0x2E);
6757 NYI_assert (21, 10, 0x802);
6758
2cdad34c 6759 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
6760 switch (size)
6761 {
6762 case 0:
6763 for (i = 0; i < (full ? 16 : 8); i++)
6764 val.b[i ^ 0x3] = aarch64_get_vec_u8 (cpu, rn, i);
6765 break;
6766
6767 case 1:
6768 for (i = 0; i < (full ? 8 : 4); i++)
6769 val.h[i ^ 0x1] = aarch64_get_vec_u16 (cpu, rn, i);
6770 break;
6771
6772 default:
6773 HALT_UNALLOC;
6774 }
6775
6776 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
6777 if (full)
6778 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
6779}
6780
6781static void
6782do_vec_EXT (sim_cpu *cpu)
6783{
6784 /* instr[31] = 0
6785 instr[30] = full/half
6786 instr[29,21] = 10 1110 000
6787 instr[20,16] = Vm
6788 instr[15] = 0
6789 instr[14,11] = source index
6790 instr[10] = 0
6791 instr[9,5] = Vn
6792 instr[4.0] = Vd. */
6793
6794 unsigned vm = INSTR (20, 16);
6795 unsigned vn = INSTR (9, 5);
6796 unsigned vd = INSTR (4, 0);
6797 unsigned src_index = INSTR (14, 11);
6798 unsigned full = INSTR (30, 30);
6799 unsigned i;
6800 unsigned j;
6801 FRegister val;
6802
6803 NYI_assert (31, 21, 0x370);
6804 NYI_assert (15, 15, 0);
6805 NYI_assert (10, 10, 0);
6806
6807 if (!full && (src_index & 0x8))
6808 HALT_UNALLOC;
6809
6810 j = 0;
6811
2cdad34c 6812 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
6813 for (i = src_index; i < (full ? 16 : 8); i++)
6814 val.b[j ++] = aarch64_get_vec_u8 (cpu, vn, i);
6815 for (i = 0; i < src_index; i++)
6816 val.b[j ++] = aarch64_get_vec_u8 (cpu, vm, i);
6817
6818 aarch64_set_vec_u64 (cpu, vd, 0, val.v[0]);
6819 if (full)
6820 aarch64_set_vec_u64 (cpu, vd, 1, val.v[1]);
6821}
6822
2e8cf49e
NC
6823static void
6824dexAdvSIMD0 (sim_cpu *cpu)
6825{
6826 /* instr [28,25] = 0 111. */
ef0d8ffc
NC
6827 if ( INSTR (15, 10) == 0x07
6828 && (INSTR (9, 5) ==
6829 INSTR (20, 16)))
2e8cf49e 6830 {
ef0d8ffc
NC
6831 if (INSTR (31, 21) == 0x075
6832 || INSTR (31, 21) == 0x275)
2e8cf49e
NC
6833 {
6834 do_vec_MOV_whole_vector (cpu);
6835 return;
6836 }
6837 }
6838
ef0d8ffc 6839 if (INSTR (29, 19) == 0x1E0)
2e8cf49e
NC
6840 {
6841 do_vec_MOV_immediate (cpu);
6842 return;
6843 }
6844
ef0d8ffc 6845 if (INSTR (29, 19) == 0x5E0)
2e8cf49e
NC
6846 {
6847 do_vec_MVNI (cpu);
6848 return;
6849 }
6850
ef0d8ffc
NC
6851 if (INSTR (29, 19) == 0x1C0
6852 || INSTR (29, 19) == 0x1C1)
2e8cf49e 6853 {
ef0d8ffc 6854 if (INSTR (15, 10) == 0x03)
2e8cf49e
NC
6855 {
6856 do_vec_DUP_scalar_into_vector (cpu);
6857 return;
6858 }
6859 }
6860
ef0d8ffc 6861 switch (INSTR (29, 24))
2e8cf49e
NC
6862 {
6863 case 0x0E: do_vec_op1 (cpu); return;
6864 case 0x0F: do_vec_op2 (cpu); return;
6865
2e8cf49e 6866 case 0x2E:
ef0d8ffc 6867 if (INSTR (21, 21) == 1)
2e8cf49e 6868 {
ef0d8ffc 6869 switch (INSTR (15, 10))
2e8cf49e 6870 {
67f101ee
NC
6871 case 0x02:
6872 do_vec_REV32 (cpu);
6873 return;
6874
2e8cf49e 6875 case 0x07:
ef0d8ffc 6876 switch (INSTR (23, 22))
2e8cf49e
NC
6877 {
6878 case 0: do_vec_EOR (cpu); return;
6879 case 1: do_vec_BSL (cpu); return;
6880 case 2:
6881 case 3: do_vec_bit (cpu); return;
6882 }
6883 break;
6884
6885 case 0x08: do_vec_sub_long (cpu); return;
6886 case 0x11: do_vec_USHL (cpu); return;
5ab6d79e 6887 case 0x12: do_vec_CLZ (cpu); return;
2e8cf49e
NC
6888 case 0x16: do_vec_NOT (cpu); return;
6889 case 0x19: do_vec_max (cpu); return;
6890 case 0x1B: do_vec_min (cpu); return;
6891 case 0x21: do_vec_SUB (cpu); return;
6892 case 0x25: do_vec_MLS (cpu); return;
6893 case 0x31: do_vec_FminmaxNMP (cpu); return;
6894 case 0x35: do_vec_FADDP (cpu); return;
6895 case 0x37: do_vec_FMUL (cpu); return;
6896 case 0x3F: do_vec_FDIV (cpu); return;
6897
6898 case 0x3E:
ef0d8ffc 6899 switch (INSTR (20, 16))
2e8cf49e
NC
6900 {
6901 case 0x00: do_vec_FNEG (cpu); return;
6902 case 0x01: do_vec_FSQRT (cpu); return;
6903 default: HALT_NYI;
6904 }
6905
6906 case 0x0D:
6907 case 0x0F:
6908 case 0x22:
6909 case 0x23:
6910 case 0x26:
6911 case 0x2A:
6912 case 0x32:
6913 case 0x36:
6914 case 0x39:
6915 case 0x3A:
6916 do_vec_compare (cpu); return;
6917
5ab6d79e
NC
6918 default:
6919 break;
2e8cf49e
NC
6920 }
6921 }
6922
ef0d8ffc 6923 if (INSTR (31, 21) == 0x370)
2e8cf49e 6924 {
67f101ee
NC
6925 if (INSTR (10, 10))
6926 do_vec_MOV_element (cpu);
6927 else
6928 do_vec_EXT (cpu);
2e8cf49e
NC
6929 return;
6930 }
6931
ef0d8ffc 6932 switch (INSTR (21, 10))
2e8cf49e
NC
6933 {
6934 case 0x82E: do_vec_neg (cpu); return;
6935 case 0x87E: do_vec_sqrt (cpu); return;
6936 default:
ef0d8ffc 6937 if (INSTR (15, 10) == 0x30)
2e8cf49e
NC
6938 {
6939 do_vec_mull (cpu);
6940 return;
6941 }
6942 break;
6943 }
6944 break;
6945
67f101ee
NC
6946 case 0x2f:
6947 switch (INSTR (15, 10))
6948 {
6949 case 0x01: do_vec_SSHR_USHR (cpu); return;
6950 case 0x10:
6951 case 0x12: do_vec_mls_indexed (cpu); return;
6952 case 0x29: do_vec_xtl (cpu); return;
6953 default:
6954 HALT_NYI;
6955 }
6956
2e8cf49e
NC
6957 default:
6958 break;
6959 }
6960
6961 HALT_NYI;
6962}
6963
6964/* 3 sources. */
6965
6966/* Float multiply add. */
6967static void
6968fmadds (sim_cpu *cpu)
6969{
ef0d8ffc
NC
6970 unsigned sa = INSTR (14, 10);
6971 unsigned sm = INSTR (20, 16);
6972 unsigned sn = INSTR ( 9, 5);
6973 unsigned sd = INSTR ( 4, 0);
2e8cf49e 6974
2cdad34c 6975 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
6976 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6977 + aarch64_get_FP_float (cpu, sn)
6978 * aarch64_get_FP_float (cpu, sm));
6979}
6980
6981/* Double multiply add. */
6982static void
6983fmaddd (sim_cpu *cpu)
6984{
ef0d8ffc
NC
6985 unsigned sa = INSTR (14, 10);
6986 unsigned sm = INSTR (20, 16);
6987 unsigned sn = INSTR ( 9, 5);
6988 unsigned sd = INSTR ( 4, 0);
2e8cf49e 6989
2cdad34c 6990 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
6991 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6992 + aarch64_get_FP_double (cpu, sn)
6993 * aarch64_get_FP_double (cpu, sm));
6994}
6995
6996/* Float multiply subtract. */
6997static void
6998fmsubs (sim_cpu *cpu)
6999{
ef0d8ffc
NC
7000 unsigned sa = INSTR (14, 10);
7001 unsigned sm = INSTR (20, 16);
7002 unsigned sn = INSTR ( 9, 5);
7003 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7004
2cdad34c 7005 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7006 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
7007 - aarch64_get_FP_float (cpu, sn)
7008 * aarch64_get_FP_float (cpu, sm));
7009}
7010
7011/* Double multiply subtract. */
7012static void
7013fmsubd (sim_cpu *cpu)
7014{
ef0d8ffc
NC
7015 unsigned sa = INSTR (14, 10);
7016 unsigned sm = INSTR (20, 16);
7017 unsigned sn = INSTR ( 9, 5);
7018 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7019
2cdad34c 7020 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7021 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
7022 - aarch64_get_FP_double (cpu, sn)
7023 * aarch64_get_FP_double (cpu, sm));
7024}
7025
7026/* Float negative multiply add. */
7027static void
7028fnmadds (sim_cpu *cpu)
7029{
ef0d8ffc
NC
7030 unsigned sa = INSTR (14, 10);
7031 unsigned sm = INSTR (20, 16);
7032 unsigned sn = INSTR ( 9, 5);
7033 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7034
2cdad34c 7035 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7036 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
7037 + (- aarch64_get_FP_float (cpu, sn))
7038 * aarch64_get_FP_float (cpu, sm));
7039}
7040
7041/* Double negative multiply add. */
7042static void
7043fnmaddd (sim_cpu *cpu)
7044{
ef0d8ffc
NC
7045 unsigned sa = INSTR (14, 10);
7046 unsigned sm = INSTR (20, 16);
7047 unsigned sn = INSTR ( 9, 5);
7048 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7049
2cdad34c 7050 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7051 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
7052 + (- aarch64_get_FP_double (cpu, sn))
7053 * aarch64_get_FP_double (cpu, sm));
7054}
7055
7056/* Float negative multiply subtract. */
7057static void
7058fnmsubs (sim_cpu *cpu)
7059{
ef0d8ffc
NC
7060 unsigned sa = INSTR (14, 10);
7061 unsigned sm = INSTR (20, 16);
7062 unsigned sn = INSTR ( 9, 5);
7063 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7064
2cdad34c 7065 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7066 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
7067 + aarch64_get_FP_float (cpu, sn)
7068 * aarch64_get_FP_float (cpu, sm));
7069}
7070
7071/* Double negative multiply subtract. */
7072static void
7073fnmsubd (sim_cpu *cpu)
7074{
ef0d8ffc
NC
7075 unsigned sa = INSTR (14, 10);
7076 unsigned sm = INSTR (20, 16);
7077 unsigned sn = INSTR ( 9, 5);
7078 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7079
2cdad34c 7080 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7081 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
7082 + aarch64_get_FP_double (cpu, sn)
7083 * aarch64_get_FP_double (cpu, sm));
7084}
7085
7086static void
7087dexSimpleFPDataProc3Source (sim_cpu *cpu)
7088{
7089 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7090 instr[30] = 0
7091 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7092 instr[28,25] = 1111
7093 instr[24] = 1
7094 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7095 instr[21] ==> o1 : 0 ==> unnegated, 1 ==> negated
7096 instr[15] ==> o2 : 0 ==> ADD, 1 ==> SUB */
7097
7517e550 7098 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
2e8cf49e 7099 /* dispatch on combined type:o1:o2. */
7517e550 7100 uint32_t dispatch = (INSTR (23, 21) << 1) | INSTR (15, 15);
2e8cf49e
NC
7101
7102 if (M_S != 0)
7103 HALT_UNALLOC;
7104
7105 switch (dispatch)
7106 {
7107 case 0: fmadds (cpu); return;
7108 case 1: fmsubs (cpu); return;
7109 case 2: fnmadds (cpu); return;
7110 case 3: fnmsubs (cpu); return;
7111 case 4: fmaddd (cpu); return;
7112 case 5: fmsubd (cpu); return;
7113 case 6: fnmaddd (cpu); return;
7114 case 7: fnmsubd (cpu); return;
7115 default:
7116 /* type > 1 is currently unallocated. */
7117 HALT_UNALLOC;
7118 }
7119}
7120
7121static void
7122dexSimpleFPFixedConvert (sim_cpu *cpu)
7123{
7124 HALT_NYI;
7125}
7126
7127static void
7128dexSimpleFPCondCompare (sim_cpu *cpu)
7129{
5ab6d79e
NC
7130 /* instr [31,23] = 0001 1110 0
7131 instr [22] = type
7132 instr [21] = 1
7133 instr [20,16] = Rm
7134 instr [15,12] = condition
7135 instr [11,10] = 01
7136 instr [9,5] = Rn
7137 instr [4] = 0
7138 instr [3,0] = nzcv */
7139
7140 unsigned rm = INSTR (20, 16);
7141 unsigned rn = INSTR (9, 5);
7142
7143 NYI_assert (31, 23, 0x3C);
7144 NYI_assert (11, 10, 0x1);
7145 NYI_assert (4, 4, 0);
7146
2cdad34c 7147 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7148 if (! testConditionCode (cpu, INSTR (15, 12)))
7149 {
7150 aarch64_set_CPSR (cpu, INSTR (3, 0));
7151 return;
7152 }
7153
7154 if (INSTR (22, 22))
7155 {
7156 /* Double precision. */
7157 double val1 = aarch64_get_vec_double (cpu, rn, 0);
7158 double val2 = aarch64_get_vec_double (cpu, rm, 0);
7159
7160 /* FIXME: Check for NaNs. */
7161 if (val1 == val2)
7162 aarch64_set_CPSR (cpu, (Z | C));
7163 else if (val1 < val2)
7164 aarch64_set_CPSR (cpu, N);
7165 else /* val1 > val2 */
7166 aarch64_set_CPSR (cpu, C);
7167 }
7168 else
7169 {
7170 /* Single precision. */
7171 float val1 = aarch64_get_vec_float (cpu, rn, 0);
7172 float val2 = aarch64_get_vec_float (cpu, rm, 0);
ef0d8ffc 7173
5ab6d79e
NC
7174 /* FIXME: Check for NaNs. */
7175 if (val1 == val2)
7176 aarch64_set_CPSR (cpu, (Z | C));
7177 else if (val1 < val2)
7178 aarch64_set_CPSR (cpu, N);
7179 else /* val1 > val2 */
7180 aarch64_set_CPSR (cpu, C);
7181 }
2e8cf49e
NC
7182}
7183
7184/* 2 sources. */
7185
7186/* Float add. */
7187static void
7188fadds (sim_cpu *cpu)
7189{
ef0d8ffc
NC
7190 unsigned sm = INSTR (20, 16);
7191 unsigned sn = INSTR ( 9, 5);
7192 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7193
2cdad34c 7194 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7195 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7196 + aarch64_get_FP_float (cpu, sm));
7197}
7198
7199/* Double add. */
7200static void
7201faddd (sim_cpu *cpu)
7202{
ef0d8ffc
NC
7203 unsigned sm = INSTR (20, 16);
7204 unsigned sn = INSTR ( 9, 5);
7205 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7206
2cdad34c 7207 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7208 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7209 + aarch64_get_FP_double (cpu, sm));
7210}
7211
7212/* Float divide. */
7213static void
7214fdivs (sim_cpu *cpu)
7215{
ef0d8ffc
NC
7216 unsigned sm = INSTR (20, 16);
7217 unsigned sn = INSTR ( 9, 5);
7218 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7219
2cdad34c 7220 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7221 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7222 / aarch64_get_FP_float (cpu, sm));
7223}
7224
7225/* Double divide. */
7226static void
7227fdivd (sim_cpu *cpu)
7228{
ef0d8ffc
NC
7229 unsigned sm = INSTR (20, 16);
7230 unsigned sn = INSTR ( 9, 5);
7231 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7232
2cdad34c 7233 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7234 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7235 / aarch64_get_FP_double (cpu, sm));
7236}
7237
7238/* Float multiply. */
7239static void
7240fmuls (sim_cpu *cpu)
7241{
ef0d8ffc
NC
7242 unsigned sm = INSTR (20, 16);
7243 unsigned sn = INSTR ( 9, 5);
7244 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7245
2cdad34c 7246 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7247 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7248 * aarch64_get_FP_float (cpu, sm));
7249}
7250
7251/* Double multiply. */
7252static void
7253fmuld (sim_cpu *cpu)
7254{
ef0d8ffc
NC
7255 unsigned sm = INSTR (20, 16);
7256 unsigned sn = INSTR ( 9, 5);
7257 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7258
2cdad34c 7259 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7260 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7261 * aarch64_get_FP_double (cpu, sm));
7262}
7263
7264/* Float negate and multiply. */
7265static void
7266fnmuls (sim_cpu *cpu)
7267{
ef0d8ffc
NC
7268 unsigned sm = INSTR (20, 16);
7269 unsigned sn = INSTR ( 9, 5);
7270 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7271
2cdad34c 7272 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7273 aarch64_set_FP_float (cpu, sd, - (aarch64_get_FP_float (cpu, sn)
7274 * aarch64_get_FP_float (cpu, sm)));
7275}
7276
7277/* Double negate and multiply. */
7278static void
7279fnmuld (sim_cpu *cpu)
7280{
ef0d8ffc
NC
7281 unsigned sm = INSTR (20, 16);
7282 unsigned sn = INSTR ( 9, 5);
7283 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7284
2cdad34c 7285 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7286 aarch64_set_FP_double (cpu, sd, - (aarch64_get_FP_double (cpu, sn)
7287 * aarch64_get_FP_double (cpu, sm)));
7288}
7289
7290/* Float subtract. */
7291static void
7292fsubs (sim_cpu *cpu)
7293{
ef0d8ffc
NC
7294 unsigned sm = INSTR (20, 16);
7295 unsigned sn = INSTR ( 9, 5);
7296 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7297
2cdad34c 7298 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7299 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7300 - aarch64_get_FP_float (cpu, sm));
7301}
7302
7303/* Double subtract. */
7304static void
7305fsubd (sim_cpu *cpu)
7306{
ef0d8ffc
NC
7307 unsigned sm = INSTR (20, 16);
7308 unsigned sn = INSTR ( 9, 5);
7309 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7310
2cdad34c 7311 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7312 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7313 - aarch64_get_FP_double (cpu, sm));
7314}
7315
7316static void
7317do_FMINNM (sim_cpu *cpu)
7318{
7319 /* instr[31,23] = 0 0011 1100
7320 instr[22] = float(0)/double(1)
7321 instr[21] = 1
7322 instr[20,16] = Sm
7323 instr[15,10] = 01 1110
7324 instr[9,5] = Sn
7325 instr[4,0] = Cpu */
7326
ef0d8ffc
NC
7327 unsigned sm = INSTR (20, 16);
7328 unsigned sn = INSTR ( 9, 5);
7329 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7330
7331 NYI_assert (31, 23, 0x03C);
7332 NYI_assert (15, 10, 0x1E);
7333
2cdad34c 7334 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7335 if (INSTR (22, 22))
2e8cf49e
NC
7336 aarch64_set_FP_double (cpu, sd,
7337 dminnm (aarch64_get_FP_double (cpu, sn),
7338 aarch64_get_FP_double (cpu, sm)));
7339 else
7340 aarch64_set_FP_float (cpu, sd,
7341 fminnm (aarch64_get_FP_float (cpu, sn),
7342 aarch64_get_FP_float (cpu, sm)));
7343}
7344
7345static void
7346do_FMAXNM (sim_cpu *cpu)
7347{
7348 /* instr[31,23] = 0 0011 1100
7349 instr[22] = float(0)/double(1)
7350 instr[21] = 1
7351 instr[20,16] = Sm
7352 instr[15,10] = 01 1010
7353 instr[9,5] = Sn
7354 instr[4,0] = Cpu */
7355
ef0d8ffc
NC
7356 unsigned sm = INSTR (20, 16);
7357 unsigned sn = INSTR ( 9, 5);
7358 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7359
7360 NYI_assert (31, 23, 0x03C);
7361 NYI_assert (15, 10, 0x1A);
7362
2cdad34c 7363 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7364 if (INSTR (22, 22))
2e8cf49e
NC
7365 aarch64_set_FP_double (cpu, sd,
7366 dmaxnm (aarch64_get_FP_double (cpu, sn),
7367 aarch64_get_FP_double (cpu, sm)));
7368 else
7369 aarch64_set_FP_float (cpu, sd,
7370 fmaxnm (aarch64_get_FP_float (cpu, sn),
7371 aarch64_get_FP_float (cpu, sm)));
7372}
7373
7374static void
7375dexSimpleFPDataProc2Source (sim_cpu *cpu)
7376{
7377 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7378 instr[30] = 0
7379 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7380 instr[28,25] = 1111
7381 instr[24] = 0
7382 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7383 instr[21] = 1
7384 instr[20,16] = Vm
7385 instr[15,12] ==> opcode : 0000 ==> FMUL, 0001 ==> FDIV
7386 0010 ==> FADD, 0011 ==> FSUB,
7387 0100 ==> FMAX, 0101 ==> FMIN
7388 0110 ==> FMAXNM, 0111 ==> FMINNM
7389 1000 ==> FNMUL, ow ==> UNALLOC
7390 instr[11,10] = 10
7391 instr[9,5] = Vn
7392 instr[4,0] = Vd */
7393
7517e550 7394 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc 7395 uint32_t type = INSTR (23, 22);
2e8cf49e 7396 /* Dispatch on opcode. */
ef0d8ffc 7397 uint32_t dispatch = INSTR (15, 12);
2e8cf49e
NC
7398
7399 if (type > 1)
7400 HALT_UNALLOC;
7401
7402 if (M_S != 0)
7403 HALT_UNALLOC;
7404
7405 if (type)
7406 switch (dispatch)
7407 {
7408 case 0: fmuld (cpu); return;
7409 case 1: fdivd (cpu); return;
7410 case 2: faddd (cpu); return;
7411 case 3: fsubd (cpu); return;
7412 case 6: do_FMAXNM (cpu); return;
7413 case 7: do_FMINNM (cpu); return;
7414 case 8: fnmuld (cpu); return;
7415
7416 /* Have not yet implemented fmax and fmin. */
7417 case 4:
7418 case 5:
7419 HALT_NYI;
7420
7421 default:
7422 HALT_UNALLOC;
7423 }
7424 else /* type == 0 => floats. */
7425 switch (dispatch)
7426 {
7427 case 0: fmuls (cpu); return;
7428 case 1: fdivs (cpu); return;
7429 case 2: fadds (cpu); return;
7430 case 3: fsubs (cpu); return;
7431 case 6: do_FMAXNM (cpu); return;
7432 case 7: do_FMINNM (cpu); return;
7433 case 8: fnmuls (cpu); return;
7434
7435 case 4:
7436 case 5:
7437 HALT_NYI;
7438
7439 default:
7440 HALT_UNALLOC;
7441 }
7442}
7443
7444static void
7445dexSimpleFPCondSelect (sim_cpu *cpu)
7446{
7447 /* FCSEL
7448 instr[31,23] = 0 0011 1100
7449 instr[22] = 0=>single 1=>double
7450 instr[21] = 1
7451 instr[20,16] = Sm
7452 instr[15,12] = cond
7453 instr[11,10] = 11
7454 instr[9,5] = Sn
7455 instr[4,0] = Cpu */
ef0d8ffc
NC
7456 unsigned sm = INSTR (20, 16);
7457 unsigned sn = INSTR ( 9, 5);
7458 unsigned sd = INSTR ( 4, 0);
7459 uint32_t set = testConditionCode (cpu, INSTR (15, 12));
2e8cf49e
NC
7460
7461 NYI_assert (31, 23, 0x03C);
7462 NYI_assert (11, 10, 0x3);
7463
2cdad34c 7464 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7465 if (INSTR (22, 22))
2e8cf49e
NC
7466 aarch64_set_FP_double (cpu, sd, set ? sn : sm);
7467 else
7468 aarch64_set_FP_float (cpu, sd, set ? sn : sm);
7469}
7470
7471/* Store 32 bit unscaled signed 9 bit. */
7472static void
7473fsturs (sim_cpu *cpu, int32_t offset)
7474{
ef0d8ffc
NC
7475 unsigned int rn = INSTR (9, 5);
7476 unsigned int st = INSTR (4, 0);
2e8cf49e 7477
2cdad34c 7478 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1
JW
7479 aarch64_set_mem_u32 (cpu, aarch64_get_reg_u64 (cpu, rn, 1) + offset,
7480 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
7481}
7482
7483/* Store 64 bit unscaled signed 9 bit. */
7484static void
7485fsturd (sim_cpu *cpu, int32_t offset)
7486{
ef0d8ffc
NC
7487 unsigned int rn = INSTR (9, 5);
7488 unsigned int st = INSTR (4, 0);
2e8cf49e 7489
2cdad34c 7490 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1
JW
7491 aarch64_set_mem_u64 (cpu, aarch64_get_reg_u64 (cpu, rn, 1) + offset,
7492 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
7493}
7494
7495/* Store 128 bit unscaled signed 9 bit. */
7496static void
7497fsturq (sim_cpu *cpu, int32_t offset)
7498{
ef0d8ffc
NC
7499 unsigned int rn = INSTR (9, 5);
7500 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7501 FRegister a;
7502
2cdad34c 7503 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1 7504 aarch64_get_FP_long_double (cpu, st, & a);
2e8cf49e 7505 aarch64_set_mem_long_double (cpu,
88ddd4a1 7506 aarch64_get_reg_u64 (cpu, rn, 1)
2e8cf49e
NC
7507 + offset, a);
7508}
7509
7510/* TODO FP move register. */
7511
7512/* 32 bit fp to fp move register. */
7513static void
7514ffmovs (sim_cpu *cpu)
7515{
ef0d8ffc
NC
7516 unsigned int rn = INSTR (9, 5);
7517 unsigned int st = INSTR (4, 0);
2e8cf49e 7518
2cdad34c 7519 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7520 aarch64_set_FP_float (cpu, st, aarch64_get_FP_float (cpu, rn));
7521}
7522
7523/* 64 bit fp to fp move register. */
7524static void
7525ffmovd (sim_cpu *cpu)
7526{
ef0d8ffc
NC
7527 unsigned int rn = INSTR (9, 5);
7528 unsigned int st = INSTR (4, 0);
2e8cf49e 7529
2cdad34c 7530 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7531 aarch64_set_FP_double (cpu, st, aarch64_get_FP_double (cpu, rn));
7532}
7533
7534/* 32 bit GReg to Vec move register. */
7535static void
7536fgmovs (sim_cpu *cpu)
7537{
ef0d8ffc
NC
7538 unsigned int rn = INSTR (9, 5);
7539 unsigned int st = INSTR (4, 0);
2e8cf49e 7540
2cdad34c 7541 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7542 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_reg_u32 (cpu, rn, NO_SP));
7543}
7544
7545/* 64 bit g to fp move register. */
7546static void
7547fgmovd (sim_cpu *cpu)
7548{
ef0d8ffc
NC
7549 unsigned int rn = INSTR (9, 5);
7550 unsigned int st = INSTR (4, 0);
2e8cf49e 7551
2cdad34c 7552 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7553 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_reg_u64 (cpu, rn, NO_SP));
7554}
7555
7556/* 32 bit fp to g move register. */
7557static void
7558gfmovs (sim_cpu *cpu)
7559{
ef0d8ffc
NC
7560 unsigned int rn = INSTR (9, 5);
7561 unsigned int st = INSTR (4, 0);
2e8cf49e 7562
2cdad34c 7563 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7564 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u32 (cpu, rn, 0));
7565}
7566
7567/* 64 bit fp to g move register. */
7568static void
7569gfmovd (sim_cpu *cpu)
7570{
ef0d8ffc
NC
7571 unsigned int rn = INSTR (9, 5);
7572 unsigned int st = INSTR (4, 0);
2e8cf49e 7573
2cdad34c 7574 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7575 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u64 (cpu, rn, 0));
7576}
7577
7578/* FP move immediate
7579
7580 These install an immediate 8 bit value in the target register
7581 where the 8 bits comprise 1 sign bit, 4 bits of fraction and a 3
7582 bit exponent. */
7583
7584static void
7585fmovs (sim_cpu *cpu)
7586{
ef0d8ffc
NC
7587 unsigned int sd = INSTR (4, 0);
7588 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7589 float f = fp_immediate_for_encoding_32 (imm);
7590
2cdad34c 7591 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7592 aarch64_set_FP_float (cpu, sd, f);
7593}
7594
7595static void
7596fmovd (sim_cpu *cpu)
7597{
ef0d8ffc
NC
7598 unsigned int sd = INSTR (4, 0);
7599 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7600 double d = fp_immediate_for_encoding_64 (imm);
7601
2cdad34c 7602 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7603 aarch64_set_FP_double (cpu, sd, d);
7604}
7605
7606static void
7607dexSimpleFPImmediate (sim_cpu *cpu)
7608{
7609 /* instr[31,23] == 00111100
7610 instr[22] == type : single(0)/double(1)
7611 instr[21] == 1
7612 instr[20,13] == imm8
7613 instr[12,10] == 100
7614 instr[9,5] == imm5 : 00000 ==> PK, ow ==> UNALLOC
7615 instr[4,0] == Rd */
ef0d8ffc 7616 uint32_t imm5 = INSTR (9, 5);
2e8cf49e
NC
7617
7618 NYI_assert (31, 23, 0x3C);
7619
7620 if (imm5 != 0)
7621 HALT_UNALLOC;
7622
ef0d8ffc 7623 if (INSTR (22, 22))
2e8cf49e
NC
7624 fmovd (cpu);
7625 else
7626 fmovs (cpu);
7627}
7628
7629/* TODO specific decode and execute for group Load Store. */
7630
7631/* TODO FP load/store single register (unscaled offset). */
7632
7633/* TODO load 8 bit unscaled signed 9 bit. */
7634/* TODO load 16 bit unscaled signed 9 bit. */
7635
7636/* Load 32 bit unscaled signed 9 bit. */
7637static void
7638fldurs (sim_cpu *cpu, int32_t offset)
7639{
ef0d8ffc
NC
7640 unsigned int rn = INSTR (9, 5);
7641 unsigned int st = INSTR (4, 0);
2e8cf49e 7642
2cdad34c 7643 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
7644 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
7645 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7646}
7647
7648/* Load 64 bit unscaled signed 9 bit. */
7649static void
7650fldurd (sim_cpu *cpu, int32_t offset)
7651{
ef0d8ffc
NC
7652 unsigned int rn = INSTR (9, 5);
7653 unsigned int st = INSTR (4, 0);
2e8cf49e 7654
2cdad34c 7655 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
7656 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64
7657 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7658}
7659
7660/* Load 128 bit unscaled signed 9 bit. */
7661static void
7662fldurq (sim_cpu *cpu, int32_t offset)
7663{
ef0d8ffc
NC
7664 unsigned int rn = INSTR (9, 5);
7665 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7666 FRegister a;
7667 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
7668
2cdad34c 7669 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7670 aarch64_get_mem_long_double (cpu, addr, & a);
7671 aarch64_set_FP_long_double (cpu, st, a);
7672}
7673
7674/* TODO store 8 bit unscaled signed 9 bit. */
7675/* TODO store 16 bit unscaled signed 9 bit. */
7676
7677
7678/* 1 source. */
7679
7680/* Float absolute value. */
7681static void
7682fabss (sim_cpu *cpu)
7683{
ef0d8ffc
NC
7684 unsigned sn = INSTR (9, 5);
7685 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7686 float value = aarch64_get_FP_float (cpu, sn);
7687
2cdad34c 7688 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7689 aarch64_set_FP_float (cpu, sd, fabsf (value));
7690}
7691
7692/* Double absolute value. */
7693static void
7694fabcpu (sim_cpu *cpu)
7695{
ef0d8ffc
NC
7696 unsigned sn = INSTR (9, 5);
7697 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7698 double value = aarch64_get_FP_double (cpu, sn);
7699
2cdad34c 7700 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7701 aarch64_set_FP_double (cpu, sd, fabs (value));
7702}
7703
7704/* Float negative value. */
7705static void
7706fnegs (sim_cpu *cpu)
7707{
ef0d8ffc
NC
7708 unsigned sn = INSTR (9, 5);
7709 unsigned sd = INSTR (4, 0);
2e8cf49e 7710
2cdad34c 7711 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7712 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sn));
7713}
7714
7715/* Double negative value. */
7716static void
7717fnegd (sim_cpu *cpu)
7718{
ef0d8ffc
NC
7719 unsigned sn = INSTR (9, 5);
7720 unsigned sd = INSTR (4, 0);
2e8cf49e 7721
2cdad34c 7722 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7723 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sn));
7724}
7725
7726/* Float square root. */
7727static void
7728fsqrts (sim_cpu *cpu)
7729{
ef0d8ffc
NC
7730 unsigned sn = INSTR (9, 5);
7731 unsigned sd = INSTR (4, 0);
2e8cf49e 7732
2cdad34c 7733 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
0f118bc7 7734 aarch64_set_FP_float (cpu, sd, sqrtf (aarch64_get_FP_float (cpu, sn)));
2e8cf49e
NC
7735}
7736
7737/* Double square root. */
7738static void
7739fsqrtd (sim_cpu *cpu)
7740{
ef0d8ffc
NC
7741 unsigned sn = INSTR (9, 5);
7742 unsigned sd = INSTR (4, 0);
2e8cf49e 7743
2cdad34c 7744 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7745 aarch64_set_FP_double (cpu, sd,
7746 sqrt (aarch64_get_FP_double (cpu, sn)));
7747}
7748
7749/* Convert double to float. */
7750static void
7751fcvtds (sim_cpu *cpu)
7752{
ef0d8ffc
NC
7753 unsigned sn = INSTR (9, 5);
7754 unsigned sd = INSTR (4, 0);
2e8cf49e 7755
2cdad34c 7756 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7757 aarch64_set_FP_float (cpu, sd, (float) aarch64_get_FP_double (cpu, sn));
7758}
7759
7760/* Convert float to double. */
7761static void
7762fcvtcpu (sim_cpu *cpu)
7763{
ef0d8ffc
NC
7764 unsigned sn = INSTR (9, 5);
7765 unsigned sd = INSTR (4, 0);
2e8cf49e 7766
2cdad34c 7767 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7768 aarch64_set_FP_double (cpu, sd, (double) aarch64_get_FP_float (cpu, sn));
7769}
7770
7771static void
7772do_FRINT (sim_cpu *cpu)
7773{
7774 /* instr[31,23] = 0001 1110 0
7775 instr[22] = single(0)/double(1)
7776 instr[21,18] = 1001
7777 instr[17,15] = rounding mode
7778 instr[14,10] = 10000
7779 instr[9,5] = source
7780 instr[4,0] = dest */
7781
7782 float val;
ef0d8ffc
NC
7783 unsigned rs = INSTR (9, 5);
7784 unsigned rd = INSTR (4, 0);
7785 unsigned int rmode = INSTR (17, 15);
2e8cf49e
NC
7786
7787 NYI_assert (31, 23, 0x03C);
7788 NYI_assert (21, 18, 0x9);
7789 NYI_assert (14, 10, 0x10);
7790
7791 if (rmode == 6 || rmode == 7)
7792 /* FIXME: Add support for rmode == 6 exactness check. */
7793 rmode = uimm (aarch64_get_FPSR (cpu), 23, 22);
7794
2cdad34c 7795 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7796 if (INSTR (22, 22))
2e8cf49e
NC
7797 {
7798 double val = aarch64_get_FP_double (cpu, rs);
7799
7800 switch (rmode)
7801 {
7802 case 0: /* mode N: nearest or even. */
7803 {
7804 double rval = round (val);
7805
7806 if (val - rval == 0.5)
7807 {
7808 if (((rval / 2.0) * 2.0) != rval)
7809 rval += 1.0;
7810 }
7811
7812 aarch64_set_FP_double (cpu, rd, round (val));
7813 return;
7814 }
7815
7816 case 1: /* mode P: towards +inf. */
7817 if (val < 0.0)
7818 aarch64_set_FP_double (cpu, rd, trunc (val));
7819 else
7820 aarch64_set_FP_double (cpu, rd, round (val));
7821 return;
7822
7823 case 2: /* mode M: towards -inf. */
7824 if (val < 0.0)
7825 aarch64_set_FP_double (cpu, rd, round (val));
7826 else
7827 aarch64_set_FP_double (cpu, rd, trunc (val));
7828 return;
7829
7830 case 3: /* mode Z: towards 0. */
7831 aarch64_set_FP_double (cpu, rd, trunc (val));
7832 return;
7833
7834 case 4: /* mode A: away from 0. */
7835 aarch64_set_FP_double (cpu, rd, round (val));
7836 return;
7837
7838 case 6: /* mode X: use FPCR with exactness check. */
7839 case 7: /* mode I: use FPCR mode. */
7840 HALT_NYI;
7841
7842 default:
7843 HALT_UNALLOC;
7844 }
7845 }
7846
7847 val = aarch64_get_FP_float (cpu, rs);
7848
7849 switch (rmode)
7850 {
7851 case 0: /* mode N: nearest or even. */
7852 {
7853 float rval = roundf (val);
7854
7855 if (val - rval == 0.5)
7856 {
7857 if (((rval / 2.0) * 2.0) != rval)
7858 rval += 1.0;
7859 }
7860
7861 aarch64_set_FP_float (cpu, rd, rval);
7862 return;
7863 }
7864
7865 case 1: /* mode P: towards +inf. */
7866 if (val < 0.0)
7867 aarch64_set_FP_float (cpu, rd, truncf (val));
7868 else
7869 aarch64_set_FP_float (cpu, rd, roundf (val));
7870 return;
7871
7872 case 2: /* mode M: towards -inf. */
7873 if (val < 0.0)
7874 aarch64_set_FP_float (cpu, rd, truncf (val));
7875 else
7876 aarch64_set_FP_float (cpu, rd, roundf (val));
7877 return;
7878
7879 case 3: /* mode Z: towards 0. */
7880 aarch64_set_FP_float (cpu, rd, truncf (val));
7881 return;
7882
7883 case 4: /* mode A: away from 0. */
7884 aarch64_set_FP_float (cpu, rd, roundf (val));
7885 return;
7886
7887 case 6: /* mode X: use FPCR with exactness check. */
7888 case 7: /* mode I: use FPCR mode. */
7889 HALT_NYI;
7890
7891 default:
7892 HALT_UNALLOC;
7893 }
7894}
7895
5ab6d79e
NC
7896/* Convert half to float. */
7897static void
ef0d8ffc 7898do_FCVT_half_to_single (sim_cpu *cpu)
5ab6d79e
NC
7899{
7900 unsigned rn = INSTR (9, 5);
7901 unsigned rd = INSTR (4, 0);
7902
7903 NYI_assert (31, 10, 0x7B890);
7904
2cdad34c 7905 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7906 aarch64_set_FP_float (cpu, rd, (float) aarch64_get_FP_half (cpu, rn));
7907}
7908
7517e550 7909/* Convert half to double. */
5ab6d79e 7910static void
ef0d8ffc 7911do_FCVT_half_to_double (sim_cpu *cpu)
5ab6d79e
NC
7912{
7913 unsigned rn = INSTR (9, 5);
7914 unsigned rd = INSTR (4, 0);
7915
7916 NYI_assert (31, 10, 0x7B8B0);
ef0d8ffc 7917
2cdad34c 7918 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7919 aarch64_set_FP_double (cpu, rd, (double) aarch64_get_FP_half (cpu, rn));
7920}
7921
7922static void
ef0d8ffc 7923do_FCVT_single_to_half (sim_cpu *cpu)
5ab6d79e
NC
7924{
7925 unsigned rn = INSTR (9, 5);
7926 unsigned rd = INSTR (4, 0);
7927
7928 NYI_assert (31, 10, 0x788F0);
7929
2cdad34c 7930 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7931 aarch64_set_FP_half (cpu, rd, aarch64_get_FP_float (cpu, rn));
7932}
7933
7517e550 7934/* Convert double to half. */
5ab6d79e 7935static void
ef0d8ffc 7936do_FCVT_double_to_half (sim_cpu *cpu)
5ab6d79e
NC
7937{
7938 unsigned rn = INSTR (9, 5);
7939 unsigned rd = INSTR (4, 0);
7940
7941 NYI_assert (31, 10, 0x798F0);
ef0d8ffc 7942
2cdad34c 7943 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7944 aarch64_set_FP_half (cpu, rd, (float) aarch64_get_FP_double (cpu, rn));
7945}
7946
2e8cf49e
NC
7947static void
7948dexSimpleFPDataProc1Source (sim_cpu *cpu)
7949{
7950 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7951 instr[30] = 0
7952 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7953 instr[28,25] = 1111
7954 instr[24] = 0
7955 instr[23,22] ==> type : 00 ==> source is single,
7956 01 ==> source is double
7957 10 ==> UNALLOC
7958 11 ==> UNALLOC or source is half
7959 instr[21] = 1
7960 instr[20,15] ==> opcode : with type 00 or 01
7961 000000 ==> FMOV, 000001 ==> FABS,
7962 000010 ==> FNEG, 000011 ==> FSQRT,
7963 000100 ==> UNALLOC, 000101 ==> FCVT,(to single/double)
7964 000110 ==> UNALLOC, 000111 ==> FCVT (to half)
7965 001000 ==> FRINTN, 001001 ==> FRINTP,
7966 001010 ==> FRINTM, 001011 ==> FRINTZ,
7967 001100 ==> FRINTA, 001101 ==> UNALLOC
7968 001110 ==> FRINTX, 001111 ==> FRINTI
7969 with type 11
7970 000100 ==> FCVT (half-to-single)
7971 000101 ==> FCVT (half-to-double)
7972 instr[14,10] = 10000. */
7973
7517e550 7974 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
7975 uint32_t type = INSTR (23, 22);
7976 uint32_t opcode = INSTR (20, 15);
2e8cf49e
NC
7977
7978 if (M_S != 0)
7979 HALT_UNALLOC;
7980
7981 if (type == 3)
7982 {
5ab6d79e
NC
7983 if (opcode == 4)
7984 do_FCVT_half_to_single (cpu);
7985 else if (opcode == 5)
7986 do_FCVT_half_to_double (cpu);
2e8cf49e
NC
7987 else
7988 HALT_UNALLOC;
5ab6d79e 7989 return;
2e8cf49e
NC
7990 }
7991
7992 if (type == 2)
7993 HALT_UNALLOC;
7994
7995 switch (opcode)
7996 {
7997 case 0:
7998 if (type)
7999 ffmovd (cpu);
8000 else
8001 ffmovs (cpu);
8002 return;
8003
8004 case 1:
8005 if (type)
8006 fabcpu (cpu);
8007 else
8008 fabss (cpu);
8009 return;
8010
8011 case 2:
8012 if (type)
8013 fnegd (cpu);
8014 else
8015 fnegs (cpu);
8016 return;
8017
8018 case 3:
8019 if (type)
8020 fsqrtd (cpu);
8021 else
8022 fsqrts (cpu);
8023 return;
8024
8025 case 4:
8026 if (type)
8027 fcvtds (cpu);
8028 else
8029 HALT_UNALLOC;
8030 return;
8031
8032 case 5:
8033 if (type)
8034 HALT_UNALLOC;
8035 fcvtcpu (cpu);
8036 return;
8037
8038 case 8: /* FRINTN etc. */
8039 case 9:
8040 case 10:
8041 case 11:
8042 case 12:
8043 case 14:
8044 case 15:
8045 do_FRINT (cpu);
8046 return;
8047
5ab6d79e
NC
8048 case 7:
8049 if (INSTR (22, 22))
8050 do_FCVT_double_to_half (cpu);
8051 else
8052 do_FCVT_single_to_half (cpu);
8053 return;
8054
2e8cf49e
NC
8055 case 13:
8056 HALT_NYI;
8057
8058 default:
8059 HALT_UNALLOC;
8060 }
8061}
8062
8063/* 32 bit signed int to float. */
8064static void
8065scvtf32 (sim_cpu *cpu)
8066{
ef0d8ffc
NC
8067 unsigned rn = INSTR (9, 5);
8068 unsigned sd = INSTR (4, 0);
2e8cf49e 8069
2cdad34c 8070 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8071 aarch64_set_FP_float
8072 (cpu, sd, (float) aarch64_get_reg_s32 (cpu, rn, NO_SP));
8073}
8074
8075/* signed int to float. */
8076static void
8077scvtf (sim_cpu *cpu)
8078{
ef0d8ffc
NC
8079 unsigned rn = INSTR (9, 5);
8080 unsigned sd = INSTR (4, 0);
2e8cf49e 8081
2cdad34c 8082 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8083 aarch64_set_FP_float
8084 (cpu, sd, (float) aarch64_get_reg_s64 (cpu, rn, NO_SP));
8085}
8086
8087/* 32 bit signed int to double. */
8088static void
8089scvtd32 (sim_cpu *cpu)
8090{
ef0d8ffc
NC
8091 unsigned rn = INSTR (9, 5);
8092 unsigned sd = INSTR (4, 0);
2e8cf49e 8093
2cdad34c 8094 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8095 aarch64_set_FP_double
8096 (cpu, sd, (double) aarch64_get_reg_s32 (cpu, rn, NO_SP));
8097}
8098
8099/* signed int to double. */
8100static void
8101scvtd (sim_cpu *cpu)
8102{
ef0d8ffc
NC
8103 unsigned rn = INSTR (9, 5);
8104 unsigned sd = INSTR (4, 0);
2e8cf49e 8105
2cdad34c 8106 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8107 aarch64_set_FP_double
8108 (cpu, sd, (double) aarch64_get_reg_s64 (cpu, rn, NO_SP));
8109}
8110
8111static const float FLOAT_INT_MAX = (float) INT_MAX;
8112static const float FLOAT_INT_MIN = (float) INT_MIN;
8113static const double DOUBLE_INT_MAX = (double) INT_MAX;
8114static const double DOUBLE_INT_MIN = (double) INT_MIN;
8115static const float FLOAT_LONG_MAX = (float) LONG_MAX;
8116static const float FLOAT_LONG_MIN = (float) LONG_MIN;
8117static const double DOUBLE_LONG_MAX = (double) LONG_MAX;
8118static const double DOUBLE_LONG_MIN = (double) LONG_MIN;
8119
8120/* Check for FP exception conditions:
8121 NaN raises IO
8122 Infinity raises IO
8123 Out of Range raises IO and IX and saturates value
8124 Denormal raises ID and IX and sets to zero. */
8125#define RAISE_EXCEPTIONS(F, VALUE, FTYPE, ITYPE) \
8126 do \
8127 { \
8128 switch (fpclassify (F)) \
8129 { \
8130 case FP_INFINITE: \
8131 case FP_NAN: \
8132 aarch64_set_FPSR (cpu, IO); \
8133 if (signbit (F)) \
8134 VALUE = ITYPE##_MAX; \
8135 else \
8136 VALUE = ITYPE##_MIN; \
8137 break; \
8138 \
8139 case FP_NORMAL: \
8140 if (F >= FTYPE##_##ITYPE##_MAX) \
8141 { \
8142 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
8143 VALUE = ITYPE##_MAX; \
8144 } \
8145 else if (F <= FTYPE##_##ITYPE##_MIN) \
8146 { \
8147 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
8148 VALUE = ITYPE##_MIN; \
8149 } \
8150 break; \
8151 \
8152 case FP_SUBNORMAL: \
8153 aarch64_set_FPSR_bits (cpu, IO | IX | ID, IX | ID); \
8154 VALUE = 0; \
8155 break; \
8156 \
8157 default: \
8158 case FP_ZERO: \
8159 VALUE = 0; \
8160 break; \
8161 } \
8162 } \
8163 while (0)
8164
8165/* 32 bit convert float to signed int truncate towards zero. */
8166static void
8167fcvtszs32 (sim_cpu *cpu)
8168{
ef0d8ffc
NC
8169 unsigned sn = INSTR (9, 5);
8170 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8171 /* TODO : check that this rounds toward zero. */
8172 float f = aarch64_get_FP_float (cpu, sn);
8173 int32_t value = (int32_t) f;
8174
8175 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
8176
2cdad34c 8177 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8178 /* Avoid sign extension to 64 bit. */
8179 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8180}
8181
8182/* 64 bit convert float to signed int truncate towards zero. */
8183static void
8184fcvtszs (sim_cpu *cpu)
8185{
ef0d8ffc
NC
8186 unsigned sn = INSTR (9, 5);
8187 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8188 float f = aarch64_get_FP_float (cpu, sn);
8189 int64_t value = (int64_t) f;
8190
8191 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
8192
2cdad34c 8193 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8194 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8195}
8196
8197/* 32 bit convert double to signed int truncate towards zero. */
8198static void
8199fcvtszd32 (sim_cpu *cpu)
8200{
ef0d8ffc
NC
8201 unsigned sn = INSTR (9, 5);
8202 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8203 /* TODO : check that this rounds toward zero. */
8204 double d = aarch64_get_FP_double (cpu, sn);
8205 int32_t value = (int32_t) d;
8206
8207 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
8208
2cdad34c 8209 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8210 /* Avoid sign extension to 64 bit. */
8211 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8212}
8213
8214/* 64 bit convert double to signed int truncate towards zero. */
8215static void
8216fcvtszd (sim_cpu *cpu)
8217{
ef0d8ffc
NC
8218 unsigned sn = INSTR (9, 5);
8219 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8220 /* TODO : check that this rounds toward zero. */
8221 double d = aarch64_get_FP_double (cpu, sn);
8222 int64_t value;
8223
8224 value = (int64_t) d;
8225
8226 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
8227
2cdad34c 8228 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8229 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8230}
8231
8232static void
8233do_fcvtzu (sim_cpu *cpu)
8234{
8235 /* instr[31] = size: 32-bit (0), 64-bit (1)
8236 instr[30,23] = 00111100
8237 instr[22] = type: single (0)/ double (1)
8238 instr[21] = enable (0)/disable(1) precision
8239 instr[20,16] = 11001
8240 instr[15,10] = precision
8241 instr[9,5] = Rs
8242 instr[4,0] = Rd. */
8243
ef0d8ffc
NC
8244 unsigned rs = INSTR (9, 5);
8245 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8246
8247 NYI_assert (30, 23, 0x3C);
8248 NYI_assert (20, 16, 0x19);
8249
ef0d8ffc 8250 if (INSTR (21, 21) != 1)
2e8cf49e
NC
8251 /* Convert to fixed point. */
8252 HALT_NYI;
8253
2cdad34c 8254 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8255 if (INSTR (31, 31))
2e8cf49e
NC
8256 {
8257 /* Convert to unsigned 64-bit integer. */
ef0d8ffc 8258 if (INSTR (22, 22))
2e8cf49e
NC
8259 {
8260 double d = aarch64_get_FP_double (cpu, rs);
8261 uint64_t value = (uint64_t) d;
8262
8263 /* Do not raise an exception if we have reached ULONG_MAX. */
8264 if (value != (1UL << 63))
8265 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
8266
8267 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8268 }
8269 else
8270 {
8271 float f = aarch64_get_FP_float (cpu, rs);
8272 uint64_t value = (uint64_t) f;
8273
8274 /* Do not raise an exception if we have reached ULONG_MAX. */
8275 if (value != (1UL << 63))
8276 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
8277
8278 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8279 }
8280 }
8281 else
8282 {
8283 uint32_t value;
8284
8285 /* Convert to unsigned 32-bit integer. */
ef0d8ffc 8286 if (INSTR (22, 22))
2e8cf49e
NC
8287 {
8288 double d = aarch64_get_FP_double (cpu, rs);
8289
8290 value = (uint32_t) d;
8291 /* Do not raise an exception if we have reached UINT_MAX. */
8292 if (value != (1UL << 31))
8293 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
8294 }
8295 else
8296 {
8297 float f = aarch64_get_FP_float (cpu, rs);
8298
8299 value = (uint32_t) f;
8300 /* Do not raise an exception if we have reached UINT_MAX. */
8301 if (value != (1UL << 31))
8302 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
8303 }
8304
8305 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8306 }
8307}
8308
8309static void
8310do_UCVTF (sim_cpu *cpu)
8311{
8312 /* instr[31] = size: 32-bit (0), 64-bit (1)
8313 instr[30,23] = 001 1110 0
8314 instr[22] = type: single (0)/ double (1)
8315 instr[21] = enable (0)/disable(1) precision
8316 instr[20,16] = 0 0011
8317 instr[15,10] = precision
8318 instr[9,5] = Rs
8319 instr[4,0] = Rd. */
8320
ef0d8ffc
NC
8321 unsigned rs = INSTR (9, 5);
8322 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8323
8324 NYI_assert (30, 23, 0x3C);
8325 NYI_assert (20, 16, 0x03);
8326
ef0d8ffc 8327 if (INSTR (21, 21) != 1)
2e8cf49e
NC
8328 HALT_NYI;
8329
8330 /* FIXME: Add exception raising. */
2cdad34c 8331 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8332 if (INSTR (31, 31))
2e8cf49e
NC
8333 {
8334 uint64_t value = aarch64_get_reg_u64 (cpu, rs, NO_SP);
8335
ef0d8ffc 8336 if (INSTR (22, 22))
2e8cf49e
NC
8337 aarch64_set_FP_double (cpu, rd, (double) value);
8338 else
8339 aarch64_set_FP_float (cpu, rd, (float) value);
8340 }
8341 else
8342 {
8343 uint32_t value = aarch64_get_reg_u32 (cpu, rs, NO_SP);
8344
ef0d8ffc 8345 if (INSTR (22, 22))
2e8cf49e
NC
8346 aarch64_set_FP_double (cpu, rd, (double) value);
8347 else
8348 aarch64_set_FP_float (cpu, rd, (float) value);
8349 }
8350}
8351
8352static void
8353float_vector_move (sim_cpu *cpu)
8354{
8355 /* instr[31,17] == 100 1111 0101 0111
8356 instr[16] ==> direction 0=> to GR, 1=> from GR
8357 instr[15,10] => ???
8358 instr[9,5] ==> source
8359 instr[4,0] ==> dest. */
8360
ef0d8ffc
NC
8361 unsigned rn = INSTR (9, 5);
8362 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8363
8364 NYI_assert (31, 17, 0x4F57);
8365
ef0d8ffc 8366 if (INSTR (15, 10) != 0)
2e8cf49e
NC
8367 HALT_UNALLOC;
8368
2cdad34c 8369 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8370 if (INSTR (16, 16))
2e8cf49e
NC
8371 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_reg_u64 (cpu, rn, NO_SP));
8372 else
8373 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, rn, 1));
8374}
8375
8376static void
8377dexSimpleFPIntegerConvert (sim_cpu *cpu)
8378{
8379 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8380 instr[30 = 0
8381 instr[29] = S : 0 ==> OK, 1 ==> UNALLOC
8382 instr[28,25] = 1111
8383 instr[24] = 0
8384 instr[23,22] = type : 00 ==> single, 01 ==> double, 1x ==> UNALLOC
8385 instr[21] = 1
8386 instr[20,19] = rmode
8387 instr[18,16] = opcode
8388 instr[15,10] = 10 0000 */
8389
8390 uint32_t rmode_opcode;
8391 uint32_t size_type;
8392 uint32_t type;
8393 uint32_t size;
8394 uint32_t S;
8395
ef0d8ffc 8396 if (INSTR (31, 17) == 0x4F57)
2e8cf49e
NC
8397 {
8398 float_vector_move (cpu);
8399 return;
8400 }
8401
ef0d8ffc
NC
8402 size = INSTR (31, 31);
8403 S = INSTR (29, 29);
2e8cf49e
NC
8404 if (S != 0)
8405 HALT_UNALLOC;
8406
ef0d8ffc 8407 type = INSTR (23, 22);
2e8cf49e
NC
8408 if (type > 1)
8409 HALT_UNALLOC;
8410
ef0d8ffc 8411 rmode_opcode = INSTR (20, 16);
2e8cf49e
NC
8412 size_type = (size << 1) | type; /* 0==32f, 1==32d, 2==64f, 3==64d. */
8413
8414 switch (rmode_opcode)
8415 {
8416 case 2: /* SCVTF. */
8417 switch (size_type)
8418 {
8419 case 0: scvtf32 (cpu); return;
8420 case 1: scvtd32 (cpu); return;
8421 case 2: scvtf (cpu); return;
8422 case 3: scvtd (cpu); return;
2e8cf49e
NC
8423 }
8424
8425 case 6: /* FMOV GR, Vec. */
8426 switch (size_type)
8427 {
8428 case 0: gfmovs (cpu); return;
8429 case 3: gfmovd (cpu); return;
8430 default: HALT_UNALLOC;
8431 }
8432
8433 case 7: /* FMOV vec, GR. */
8434 switch (size_type)
8435 {
8436 case 0: fgmovs (cpu); return;
8437 case 3: fgmovd (cpu); return;
8438 default: HALT_UNALLOC;
8439 }
8440
8441 case 24: /* FCVTZS. */
8442 switch (size_type)
8443 {
8444 case 0: fcvtszs32 (cpu); return;
8445 case 1: fcvtszd32 (cpu); return;
8446 case 2: fcvtszs (cpu); return;
8447 case 3: fcvtszd (cpu); return;
2e8cf49e
NC
8448 }
8449
8450 case 25: do_fcvtzu (cpu); return;
8451 case 3: do_UCVTF (cpu); return;
8452
8453 case 0: /* FCVTNS. */
8454 case 1: /* FCVTNU. */
8455 case 4: /* FCVTAS. */
8456 case 5: /* FCVTAU. */
8457 case 8: /* FCVPTS. */
8458 case 9: /* FCVTPU. */
8459 case 16: /* FCVTMS. */
8460 case 17: /* FCVTMU. */
8461 default:
8462 HALT_NYI;
8463 }
8464}
8465
8466static void
8467set_flags_for_float_compare (sim_cpu *cpu, float fvalue1, float fvalue2)
8468{
8469 uint32_t flags;
8470
87903eaf 8471 /* FIXME: Add exception raising. */
2e8cf49e
NC
8472 if (isnan (fvalue1) || isnan (fvalue2))
8473 flags = C|V;
87903eaf
JW
8474 else if (isinf (fvalue1) && isinf (fvalue2))
8475 {
8476 /* Subtracting two infinities may give a NaN. We only need to compare
8477 the signs, which we can get from isinf. */
8478 int result = isinf (fvalue1) - isinf (fvalue2);
8479
8480 if (result == 0)
8481 flags = Z|C;
8482 else if (result < 0)
8483 flags = N;
8484 else /* (result > 0). */
8485 flags = C;
8486 }
2e8cf49e
NC
8487 else
8488 {
8489 float result = fvalue1 - fvalue2;
8490
8491 if (result == 0.0)
8492 flags = Z|C;
8493 else if (result < 0)
8494 flags = N;
8495 else /* (result > 0). */
8496 flags = C;
8497 }
8498
8499 aarch64_set_CPSR (cpu, flags);
8500}
8501
8502static void
8503fcmps (sim_cpu *cpu)
8504{
ef0d8ffc
NC
8505 unsigned sm = INSTR (20, 16);
8506 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8507
8508 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8509 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8510
2cdad34c 8511 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8512 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8513}
8514
8515/* Float compare to zero -- Invalid Operation exception
8516 only on signaling NaNs. */
8517static void
8518fcmpzs (sim_cpu *cpu)
8519{
ef0d8ffc 8520 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8521 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8522
2cdad34c 8523 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8524 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8525}
8526
8527/* Float compare -- Invalid Operation exception on all NaNs. */
8528static void
8529fcmpes (sim_cpu *cpu)
8530{
ef0d8ffc
NC
8531 unsigned sm = INSTR (20, 16);
8532 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8533
8534 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8535 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8536
2cdad34c 8537 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8538 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8539}
8540
8541/* Float compare to zero -- Invalid Operation exception on all NaNs. */
8542static void
8543fcmpzes (sim_cpu *cpu)
8544{
ef0d8ffc 8545 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8546 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8547
2cdad34c 8548 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8549 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8550}
8551
8552static void
8553set_flags_for_double_compare (sim_cpu *cpu, double dval1, double dval2)
8554{
8555 uint32_t flags;
8556
87903eaf 8557 /* FIXME: Add exception raising. */
2e8cf49e
NC
8558 if (isnan (dval1) || isnan (dval2))
8559 flags = C|V;
87903eaf
JW
8560 else if (isinf (dval1) && isinf (dval2))
8561 {
8562 /* Subtracting two infinities may give a NaN. We only need to compare
8563 the signs, which we can get from isinf. */
8564 int result = isinf (dval1) - isinf (dval2);
8565
8566 if (result == 0)
8567 flags = Z|C;
8568 else if (result < 0)
8569 flags = N;
8570 else /* (result > 0). */
8571 flags = C;
8572 }
2e8cf49e
NC
8573 else
8574 {
8575 double result = dval1 - dval2;
8576
8577 if (result == 0.0)
8578 flags = Z|C;
8579 else if (result < 0)
8580 flags = N;
8581 else /* (result > 0). */
8582 flags = C;
8583 }
8584
8585 aarch64_set_CPSR (cpu, flags);
8586}
8587
8588/* Double compare -- Invalid Operation exception only on signaling NaNs. */
8589static void
8590fcmpd (sim_cpu *cpu)
8591{
ef0d8ffc
NC
8592 unsigned sm = INSTR (20, 16);
8593 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8594
8595 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8596 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8597
2cdad34c 8598 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8599 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8600}
8601
8602/* Double compare to zero -- Invalid Operation exception
8603 only on signaling NaNs. */
8604static void
8605fcmpzd (sim_cpu *cpu)
8606{
ef0d8ffc 8607 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8608 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8609
2cdad34c 8610 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8611 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8612}
8613
8614/* Double compare -- Invalid Operation exception on all NaNs. */
8615static void
8616fcmped (sim_cpu *cpu)
8617{
ef0d8ffc
NC
8618 unsigned sm = INSTR (20, 16);
8619 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8620
8621 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8622 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8623
2cdad34c 8624 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8625 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8626}
8627
8628/* Double compare to zero -- Invalid Operation exception on all NaNs. */
8629static void
8630fcmpzed (sim_cpu *cpu)
8631{
ef0d8ffc 8632 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8633 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8634
2cdad34c 8635 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8636 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8637}
8638
8639static void
8640dexSimpleFPCompare (sim_cpu *cpu)
8641{
8642 /* assert instr[28,25] == 1111
8643 instr[30:24:21:13,10] = 0011000
8644 instr[31] = M : 0 ==> OK, 1 ==> UNALLOC
8645 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
8646 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
8647 instr[15,14] ==> op : 00 ==> OK, ow ==> UNALLOC
8648 instr[4,0] ==> opcode2 : 00000 ==> FCMP, 10000 ==> FCMPE,
8649 01000 ==> FCMPZ, 11000 ==> FCMPEZ,
8650 ow ==> UNALLOC */
8651 uint32_t dispatch;
7517e550 8652 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
8653 uint32_t type = INSTR (23, 22);
8654 uint32_t op = INSTR (15, 14);
8655 uint32_t op2_2_0 = INSTR (2, 0);
2e8cf49e
NC
8656
8657 if (op2_2_0 != 0)
8658 HALT_UNALLOC;
8659
8660 if (M_S != 0)
8661 HALT_UNALLOC;
8662
8663 if (type > 1)
8664 HALT_UNALLOC;
8665
8666 if (op != 0)
8667 HALT_UNALLOC;
8668
8669 /* dispatch on type and top 2 bits of opcode. */
ef0d8ffc 8670 dispatch = (type << 2) | INSTR (4, 3);
2e8cf49e
NC
8671
8672 switch (dispatch)
8673 {
8674 case 0: fcmps (cpu); return;
8675 case 1: fcmpzs (cpu); return;
8676 case 2: fcmpes (cpu); return;
8677 case 3: fcmpzes (cpu); return;
8678 case 4: fcmpd (cpu); return;
8679 case 5: fcmpzd (cpu); return;
8680 case 6: fcmped (cpu); return;
8681 case 7: fcmpzed (cpu); return;
2e8cf49e
NC
8682 }
8683}
8684
8685static void
8686do_scalar_FADDP (sim_cpu *cpu)
8687{
7517e550 8688 /* instr [31,23] = 0111 1110 0
2e8cf49e 8689 instr [22] = single(0)/double(1)
7517e550 8690 instr [21,10] = 11 0000 1101 10
2e8cf49e
NC
8691 instr [9,5] = Fn
8692 instr [4,0] = Fd. */
8693
ef0d8ffc
NC
8694 unsigned Fn = INSTR (9, 5);
8695 unsigned Fd = INSTR (4, 0);
2e8cf49e
NC
8696
8697 NYI_assert (31, 23, 0x0FC);
8698 NYI_assert (21, 10, 0xC36);
8699
2cdad34c 8700 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8701 if (INSTR (22, 22))
2e8cf49e
NC
8702 {
8703 double val1 = aarch64_get_vec_double (cpu, Fn, 0);
8704 double val2 = aarch64_get_vec_double (cpu, Fn, 1);
8705
8706 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8707 }
8708 else
8709 {
8710 float val1 = aarch64_get_vec_float (cpu, Fn, 0);
8711 float val2 = aarch64_get_vec_float (cpu, Fn, 1);
8712
8713 aarch64_set_FP_float (cpu, Fd, val1 + val2);
8714 }
8715}
8716
8717/* Floating point absolute difference. */
8718
8719static void
8720do_scalar_FABD (sim_cpu *cpu)
8721{
8722 /* instr [31,23] = 0111 1110 1
8723 instr [22] = float(0)/double(1)
8724 instr [21] = 1
8725 instr [20,16] = Rm
8726 instr [15,10] = 1101 01
8727 instr [9, 5] = Rn
8728 instr [4, 0] = Rd. */
8729
ef0d8ffc
NC
8730 unsigned rm = INSTR (20, 16);
8731 unsigned rn = INSTR (9, 5);
8732 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8733
8734 NYI_assert (31, 23, 0x0FD);
8735 NYI_assert (21, 21, 1);
8736 NYI_assert (15, 10, 0x35);
8737
2cdad34c 8738 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8739 if (INSTR (22, 22))
2e8cf49e
NC
8740 aarch64_set_FP_double (cpu, rd,
8741 fabs (aarch64_get_FP_double (cpu, rn)
8742 - aarch64_get_FP_double (cpu, rm)));
8743 else
8744 aarch64_set_FP_float (cpu, rd,
8745 fabsf (aarch64_get_FP_float (cpu, rn)
8746 - aarch64_get_FP_float (cpu, rm)));
8747}
8748
8749static void
8750do_scalar_CMGT (sim_cpu *cpu)
8751{
8752 /* instr [31,21] = 0101 1110 111
8753 instr [20,16] = Rm
8754 instr [15,10] = 00 1101
8755 instr [9, 5] = Rn
8756 instr [4, 0] = Rd. */
8757
ef0d8ffc
NC
8758 unsigned rm = INSTR (20, 16);
8759 unsigned rn = INSTR (9, 5);
8760 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8761
8762 NYI_assert (31, 21, 0x2F7);
8763 NYI_assert (15, 10, 0x0D);
8764
2cdad34c 8765 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8766 aarch64_set_vec_u64 (cpu, rd, 0,
8767 aarch64_get_vec_u64 (cpu, rn, 0) >
8768 aarch64_get_vec_u64 (cpu, rm, 0) ? -1L : 0L);
8769}
8770
8771static void
8772do_scalar_USHR (sim_cpu *cpu)
8773{
8774 /* instr [31,23] = 0111 1111 0
8775 instr [22,16] = shift amount
8776 instr [15,10] = 0000 01
8777 instr [9, 5] = Rn
8778 instr [4, 0] = Rd. */
8779
5ab6d79e
NC
8780 unsigned amount = 128 - INSTR (22, 16);
8781 unsigned rn = INSTR (9, 5);
8782 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8783
8784 NYI_assert (31, 23, 0x0FE);
8785 NYI_assert (15, 10, 0x01);
8786
2cdad34c 8787 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8788 aarch64_set_vec_u64 (cpu, rd, 0,
8789 aarch64_get_vec_u64 (cpu, rn, 0) >> amount);
8790}
8791
8792static void
5ab6d79e
NC
8793do_scalar_SSHL (sim_cpu *cpu)
8794{
8795 /* instr [31,21] = 0101 1110 111
8796 instr [20,16] = Rm
8797 instr [15,10] = 0100 01
8798 instr [9, 5] = Rn
8799 instr [4, 0] = Rd. */
8800
8801 unsigned rm = INSTR (20, 16);
8802 unsigned rn = INSTR (9, 5);
8803 unsigned rd = INSTR (4, 0);
8804 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
8805
8806 NYI_assert (31, 21, 0x2F7);
8807 NYI_assert (15, 10, 0x11);
8808
2cdad34c 8809 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8810 if (shift >= 0)
8811 aarch64_set_vec_s64 (cpu, rd, 0,
8812 aarch64_get_vec_s64 (cpu, rn, 0) << shift);
8813 else
8814 aarch64_set_vec_s64 (cpu, rd, 0,
ef0d8ffc 8815 aarch64_get_vec_s64 (cpu, rn, 0) >> - shift);
5ab6d79e
NC
8816}
8817
8818static void
8819do_scalar_shift (sim_cpu *cpu)
2e8cf49e 8820{
5ab6d79e 8821 /* instr [31,23] = 0101 1111 0
2e8cf49e 8822 instr [22,16] = shift amount
5ab6d79e
NC
8823 instr [15,10] = 0101 01 [SHL]
8824 instr [15,10] = 0000 01 [SSHR]
2e8cf49e
NC
8825 instr [9, 5] = Rn
8826 instr [4, 0] = Rd. */
8827
5ab6d79e
NC
8828 unsigned rn = INSTR (9, 5);
8829 unsigned rd = INSTR (4, 0);
8830 unsigned amount;
2e8cf49e
NC
8831
8832 NYI_assert (31, 23, 0x0BE);
2e8cf49e 8833
5ab6d79e 8834 if (INSTR (22, 22) == 0)
2e8cf49e
NC
8835 HALT_UNALLOC;
8836
2cdad34c 8837 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8838 switch (INSTR (15, 10))
8839 {
8840 case 0x01: /* SSHR */
8841 amount = 128 - INSTR (22, 16);
8842 aarch64_set_vec_s64 (cpu, rd, 0,
8843 aarch64_get_vec_s64 (cpu, rn, 0) >> amount);
8844 return;
8845 case 0x15: /* SHL */
8846 amount = INSTR (22, 16) - 64;
8847 aarch64_set_vec_u64 (cpu, rd, 0,
8848 aarch64_get_vec_u64 (cpu, rn, 0) << amount);
8849 return;
8850 default:
8851 HALT_NYI;
8852 }
2e8cf49e
NC
8853}
8854
8855/* FCMEQ FCMGT FCMGE. */
8856static void
8857do_scalar_FCM (sim_cpu *cpu)
8858{
8859 /* instr [31,30] = 01
8860 instr [29] = U
8861 instr [28,24] = 1 1110
8862 instr [23] = E
8863 instr [22] = size
8864 instr [21] = 1
8865 instr [20,16] = Rm
8866 instr [15,12] = 1110
8867 instr [11] = AC
8868 instr [10] = 1
8869 instr [9, 5] = Rn
8870 instr [4, 0] = Rd. */
8871
ef0d8ffc
NC
8872 unsigned rm = INSTR (20, 16);
8873 unsigned rn = INSTR (9, 5);
8874 unsigned rd = INSTR (4, 0);
7517e550 8875 unsigned EUac = (INSTR (23, 23) << 2) | (INSTR (29, 29) << 1) | INSTR (11, 11);
2e8cf49e
NC
8876 unsigned result;
8877 float val1;
8878 float val2;
8879
8880 NYI_assert (31, 30, 1);
8881 NYI_assert (28, 24, 0x1E);
8882 NYI_assert (21, 21, 1);
8883 NYI_assert (15, 12, 0xE);
8884 NYI_assert (10, 10, 1);
8885
2cdad34c 8886 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8887 if (INSTR (22, 22))
2e8cf49e
NC
8888 {
8889 double val1 = aarch64_get_FP_double (cpu, rn);
8890 double val2 = aarch64_get_FP_double (cpu, rm);
8891
8892 switch (EUac)
8893 {
8894 case 0: /* 000 */
8895 result = val1 == val2;
8896 break;
8897
8898 case 3: /* 011 */
8899 val1 = fabs (val1);
8900 val2 = fabs (val2);
8901 /* Fall through. */
8902 case 2: /* 010 */
8903 result = val1 >= val2;
8904 break;
8905
8906 case 7: /* 111 */
8907 val1 = fabs (val1);
8908 val2 = fabs (val2);
8909 /* Fall through. */
8910 case 6: /* 110 */
8911 result = val1 > val2;
8912 break;
8913
8914 default:
8915 HALT_UNALLOC;
8916 }
8917
8918 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8919 return;
8920 }
8921
8922 val1 = aarch64_get_FP_float (cpu, rn);
8923 val2 = aarch64_get_FP_float (cpu, rm);
8924
8925 switch (EUac)
8926 {
8927 case 0: /* 000 */
8928 result = val1 == val2;
8929 break;
8930
8931 case 3: /* 011 */
8932 val1 = fabsf (val1);
8933 val2 = fabsf (val2);
8934 /* Fall through. */
8935 case 2: /* 010 */
8936 result = val1 >= val2;
8937 break;
8938
8939 case 7: /* 111 */
8940 val1 = fabsf (val1);
8941 val2 = fabsf (val2);
8942 /* Fall through. */
8943 case 6: /* 110 */
8944 result = val1 > val2;
8945 break;
8946
8947 default:
8948 HALT_UNALLOC;
8949 }
8950
8951 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8952}
8953
8954/* An alias of DUP. */
8955static void
8956do_scalar_MOV (sim_cpu *cpu)
8957{
8958 /* instr [31,21] = 0101 1110 000
8959 instr [20,16] = imm5
8960 instr [15,10] = 0000 01
8961 instr [9, 5] = Rn
8962 instr [4, 0] = Rd. */
8963
ef0d8ffc
NC
8964 unsigned rn = INSTR (9, 5);
8965 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8966 unsigned index;
8967
8968 NYI_assert (31, 21, 0x2F0);
8969 NYI_assert (15, 10, 0x01);
8970
2cdad34c 8971 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8972 if (INSTR (16, 16))
2e8cf49e
NC
8973 {
8974 /* 8-bit. */
ef0d8ffc 8975 index = INSTR (20, 17);
2e8cf49e
NC
8976 aarch64_set_vec_u8
8977 (cpu, rd, 0, aarch64_get_vec_u8 (cpu, rn, index));
8978 }
ef0d8ffc 8979 else if (INSTR (17, 17))
2e8cf49e
NC
8980 {
8981 /* 16-bit. */
ef0d8ffc 8982 index = INSTR (20, 18);
2e8cf49e
NC
8983 aarch64_set_vec_u16
8984 (cpu, rd, 0, aarch64_get_vec_u16 (cpu, rn, index));
8985 }
ef0d8ffc 8986 else if (INSTR (18, 18))
2e8cf49e
NC
8987 {
8988 /* 32-bit. */
ef0d8ffc 8989 index = INSTR (20, 19);
2e8cf49e
NC
8990 aarch64_set_vec_u32
8991 (cpu, rd, 0, aarch64_get_vec_u32 (cpu, rn, index));
8992 }
ef0d8ffc 8993 else if (INSTR (19, 19))
2e8cf49e
NC
8994 {
8995 /* 64-bit. */
ef0d8ffc 8996 index = INSTR (20, 20);
2e8cf49e
NC
8997 aarch64_set_vec_u64
8998 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, index));
8999 }
9000 else
9001 HALT_UNALLOC;
9002}
9003
e101a78b
NC
9004static void
9005do_scalar_NEG (sim_cpu *cpu)
9006{
5ab6d79e 9007 /* instr [31,10] = 0111 1110 1110 0000 1011 10
e101a78b
NC
9008 instr [9, 5] = Rn
9009 instr [4, 0] = Rd. */
9010
ef0d8ffc
NC
9011 unsigned rn = INSTR (9, 5);
9012 unsigned rd = INSTR (4, 0);
e101a78b 9013
5ab6d79e 9014 NYI_assert (31, 10, 0x1FB82E);
e101a78b 9015
2cdad34c 9016 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
9017 aarch64_set_vec_u64 (cpu, rd, 0, - aarch64_get_vec_u64 (cpu, rn, 0));
9018}
9019
5ab6d79e
NC
9020static void
9021do_scalar_USHL (sim_cpu *cpu)
9022{
9023 /* instr [31,21] = 0111 1110 111
9024 instr [20,16] = Rm
9025 instr [15,10] = 0100 01
9026 instr [9, 5] = Rn
9027 instr [4, 0] = Rd. */
9028
9029 unsigned rm = INSTR (20, 16);
9030 unsigned rn = INSTR (9, 5);
9031 unsigned rd = INSTR (4, 0);
9032 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
9033
9034 NYI_assert (31, 21, 0x3F7);
9035 NYI_assert (15, 10, 0x11);
9036
2cdad34c 9037 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
9038 if (shift >= 0)
9039 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) << shift);
9040 else
9041 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) >> - shift);
9042}
9043
2e8cf49e
NC
9044static void
9045do_double_add (sim_cpu *cpu)
9046{
5ab6d79e
NC
9047 /* instr [31,21] = 0101 1110 111
9048 instr [20,16] = Fn
9049 instr [15,10] = 1000 01
9050 instr [9,5] = Fm
9051 instr [4,0] = Fd. */
2e8cf49e
NC
9052 unsigned Fd;
9053 unsigned Fm;
9054 unsigned Fn;
9055 double val1;
9056 double val2;
9057
5ab6d79e
NC
9058 NYI_assert (31, 21, 0x2F7);
9059 NYI_assert (15, 10, 0x21);
9060
9061 Fd = INSTR (4, 0);
9062 Fm = INSTR (9, 5);
9063 Fn = INSTR (20, 16);
9064
2cdad34c 9065 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
9066 val1 = aarch64_get_FP_double (cpu, Fm);
9067 val2 = aarch64_get_FP_double (cpu, Fn);
9068
9069 aarch64_set_FP_double (cpu, Fd, val1 + val2);
9070}
9071
7517e550
NC
9072static void
9073do_scalar_UCVTF (sim_cpu *cpu)
9074{
9075 /* instr [31,23] = 0111 1110 0
9076 instr [22] = single(0)/double(1)
9077 instr [21,10] = 10 0001 1101 10
9078 instr [9,5] = rn
9079 instr [4,0] = rd. */
9080
9081 unsigned rn = INSTR (9, 5);
9082 unsigned rd = INSTR (4, 0);
9083
9084 NYI_assert (31, 23, 0x0FC);
9085 NYI_assert (21, 10, 0x876);
9086
2cdad34c 9087 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
9088 if (INSTR (22, 22))
9089 {
9090 uint64_t val = aarch64_get_vec_u64 (cpu, rn, 0);
9091
9092 aarch64_set_vec_double (cpu, rd, 0, (double) val);
9093 }
9094 else
9095 {
9096 uint32_t val = aarch64_get_vec_u32 (cpu, rn, 0);
9097
9098 aarch64_set_vec_float (cpu, rd, 0, (float) val);
9099 }
9100}
9101
5ab6d79e
NC
9102static void
9103do_scalar_vec (sim_cpu *cpu)
9104{
9105 /* instr [30] = 1. */
9106 /* instr [28,25] = 1111. */
ef0d8ffc 9107 switch (INSTR (31, 23))
2e8cf49e
NC
9108 {
9109 case 0xBC:
ef0d8ffc 9110 switch (INSTR (15, 10))
2e8cf49e
NC
9111 {
9112 case 0x01: do_scalar_MOV (cpu); return;
9113 case 0x39: do_scalar_FCM (cpu); return;
9114 case 0x3B: do_scalar_FCM (cpu); return;
9115 }
9116 break;
9117
5ab6d79e 9118 case 0xBE: do_scalar_shift (cpu); return;
2e8cf49e
NC
9119
9120 case 0xFC:
ef0d8ffc 9121 switch (INSTR (15, 10))
2e8cf49e 9122 {
7517e550
NC
9123 case 0x36:
9124 switch (INSTR (21, 16))
9125 {
9126 case 0x30: do_scalar_FADDP (cpu); return;
9127 case 0x21: do_scalar_UCVTF (cpu); return;
9128 }
9129 HALT_NYI;
2e8cf49e
NC
9130 case 0x39: do_scalar_FCM (cpu); return;
9131 case 0x3B: do_scalar_FCM (cpu); return;
9132 }
9133 break;
9134
9135 case 0xFD:
ef0d8ffc 9136 switch (INSTR (15, 10))
2e8cf49e
NC
9137 {
9138 case 0x0D: do_scalar_CMGT (cpu); return;
5ab6d79e
NC
9139 case 0x11: do_scalar_USHL (cpu); return;
9140 case 0x2E: do_scalar_NEG (cpu); return;
2e8cf49e
NC
9141 case 0x35: do_scalar_FABD (cpu); return;
9142 case 0x39: do_scalar_FCM (cpu); return;
9143 case 0x3B: do_scalar_FCM (cpu); return;
9144 default:
9145 HALT_NYI;
9146 }
9147
9148 case 0xFE: do_scalar_USHR (cpu); return;
5ab6d79e
NC
9149
9150 case 0xBD:
9151 switch (INSTR (15, 10))
9152 {
9153 case 0x21: do_double_add (cpu); return;
9154 case 0x11: do_scalar_SSHL (cpu); return;
9155 default:
9156 HALT_NYI;
9157 }
ef0d8ffc 9158
2e8cf49e 9159 default:
5ab6d79e 9160 HALT_NYI;
2e8cf49e 9161 }
2e8cf49e
NC
9162}
9163
9164static void
9165dexAdvSIMD1 (sim_cpu *cpu)
9166{
9167 /* instr [28,25] = 1 111. */
9168
5ab6d79e 9169 /* We are currently only interested in the basic
2e8cf49e 9170 scalar fp routines which all have bit 30 = 0. */
ef0d8ffc 9171 if (INSTR (30, 30))
5ab6d79e 9172 do_scalar_vec (cpu);
2e8cf49e
NC
9173
9174 /* instr[24] is set for FP data processing 3-source and clear for
9175 all other basic scalar fp instruction groups. */
ef0d8ffc 9176 else if (INSTR (24, 24))
2e8cf49e
NC
9177 dexSimpleFPDataProc3Source (cpu);
9178
9179 /* instr[21] is clear for floating <-> fixed conversions and set for
9180 all other basic scalar fp instruction groups. */
ef0d8ffc 9181 else if (!INSTR (21, 21))
2e8cf49e
NC
9182 dexSimpleFPFixedConvert (cpu);
9183
9184 /* instr[11,10] : 01 ==> cond compare, 10 ==> Data Proc 2 Source
9185 11 ==> cond select, 00 ==> other. */
9186 else
ef0d8ffc 9187 switch (INSTR (11, 10))
2e8cf49e
NC
9188 {
9189 case 1: dexSimpleFPCondCompare (cpu); return;
9190 case 2: dexSimpleFPDataProc2Source (cpu); return;
9191 case 3: dexSimpleFPCondSelect (cpu); return;
9192
9193 default:
9194 /* Now an ordered cascade of tests.
ef0d8ffc
NC
9195 FP immediate has instr [12] == 1.
9196 FP compare has instr [13] == 1.
9197 FP Data Proc 1 Source has instr [14] == 1.
9198 FP floating <--> integer conversions has instr [15] == 0. */
9199 if (INSTR (12, 12))
2e8cf49e
NC
9200 dexSimpleFPImmediate (cpu);
9201
ef0d8ffc 9202 else if (INSTR (13, 13))
2e8cf49e
NC
9203 dexSimpleFPCompare (cpu);
9204
ef0d8ffc 9205 else if (INSTR (14, 14))
2e8cf49e
NC
9206 dexSimpleFPDataProc1Source (cpu);
9207
ef0d8ffc 9208 else if (!INSTR (15, 15))
2e8cf49e
NC
9209 dexSimpleFPIntegerConvert (cpu);
9210
9211 else
9212 /* If we get here then instr[15] == 1 which means UNALLOC. */
9213 HALT_UNALLOC;
9214 }
9215}
9216
9217/* PC relative addressing. */
9218
9219static void
9220pcadr (sim_cpu *cpu)
9221{
9222 /* instr[31] = op : 0 ==> ADR, 1 ==> ADRP
9223 instr[30,29] = immlo
9224 instr[23,5] = immhi. */
9225 uint64_t address;
ef0d8ffc
NC
9226 unsigned rd = INSTR (4, 0);
9227 uint32_t isPage = INSTR (31, 31);
2e8cf49e
NC
9228 union { int64_t u64; uint64_t s64; } imm;
9229 uint64_t offset;
9230
9231 imm.s64 = simm64 (aarch64_get_instr (cpu), 23, 5);
9232 offset = imm.u64;
ef0d8ffc 9233 offset = (offset << 2) | INSTR (30, 29);
2e8cf49e
NC
9234
9235 address = aarch64_get_PC (cpu);
9236
9237 if (isPage)
9238 {
9239 offset <<= 12;
9240 address &= ~0xfff;
9241 }
9242
2cdad34c 9243 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9244 aarch64_set_reg_u64 (cpu, rd, NO_SP, address + offset);
9245}
9246
9247/* Specific decode and execute for group Data Processing Immediate. */
9248
9249static void
9250dexPCRelAddressing (sim_cpu *cpu)
9251{
9252 /* assert instr[28,24] = 10000. */
9253 pcadr (cpu);
9254}
9255
9256/* Immediate logical.
9257 The bimm32/64 argument is constructed by replicating a 2, 4, 8,
9258 16, 32 or 64 bit sequence pulled out at decode and possibly
9259 inverting it..
9260
9261 N.B. the output register (dest) can normally be Xn or SP
9262 the exception occurs for flag setting instructions which may
9263 only use Xn for the output (dest). The input register can
9264 never be SP. */
9265
9266/* 32 bit and immediate. */
9267static void
9268and32 (sim_cpu *cpu, uint32_t bimm)
9269{
ef0d8ffc
NC
9270 unsigned rn = INSTR (9, 5);
9271 unsigned rd = INSTR (4, 0);
2e8cf49e 9272
2cdad34c 9273 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9274 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9275 aarch64_get_reg_u32 (cpu, rn, NO_SP) & bimm);
9276}
9277
9278/* 64 bit and immediate. */
9279static void
9280and64 (sim_cpu *cpu, uint64_t bimm)
9281{
ef0d8ffc
NC
9282 unsigned rn = INSTR (9, 5);
9283 unsigned rd = INSTR (4, 0);
2e8cf49e 9284
2cdad34c 9285 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9286 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9287 aarch64_get_reg_u64 (cpu, rn, NO_SP) & bimm);
9288}
9289
9290/* 32 bit and immediate set flags. */
9291static void
9292ands32 (sim_cpu *cpu, uint32_t bimm)
9293{
ef0d8ffc
NC
9294 unsigned rn = INSTR (9, 5);
9295 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9296
9297 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9298 uint32_t value2 = bimm;
9299
2cdad34c 9300 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9301 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9302 set_flags_for_binop32 (cpu, value1 & value2);
9303}
9304
9305/* 64 bit and immediate set flags. */
9306static void
9307ands64 (sim_cpu *cpu, uint64_t bimm)
9308{
ef0d8ffc
NC
9309 unsigned rn = INSTR (9, 5);
9310 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9311
9312 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9313 uint64_t value2 = bimm;
9314
2cdad34c 9315 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9316 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9317 set_flags_for_binop64 (cpu, value1 & value2);
9318}
9319
9320/* 32 bit exclusive or immediate. */
9321static void
9322eor32 (sim_cpu *cpu, uint32_t bimm)
9323{
ef0d8ffc
NC
9324 unsigned rn = INSTR (9, 5);
9325 unsigned rd = INSTR (4, 0);
2e8cf49e 9326
2cdad34c 9327 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9328 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9329 aarch64_get_reg_u32 (cpu, rn, NO_SP) ^ bimm);
9330}
9331
9332/* 64 bit exclusive or immediate. */
9333static void
9334eor64 (sim_cpu *cpu, uint64_t bimm)
9335{
ef0d8ffc
NC
9336 unsigned rn = INSTR (9, 5);
9337 unsigned rd = INSTR (4, 0);
2e8cf49e 9338
2cdad34c 9339 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9340 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9341 aarch64_get_reg_u64 (cpu, rn, NO_SP) ^ bimm);
9342}
9343
9344/* 32 bit or immediate. */
9345static void
9346orr32 (sim_cpu *cpu, uint32_t bimm)
9347{
ef0d8ffc
NC
9348 unsigned rn = INSTR (9, 5);
9349 unsigned rd = INSTR (4, 0);
2e8cf49e 9350
2cdad34c 9351 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9352 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9353 aarch64_get_reg_u32 (cpu, rn, NO_SP) | bimm);
9354}
9355
9356/* 64 bit or immediate. */
9357static void
9358orr64 (sim_cpu *cpu, uint64_t bimm)
9359{
ef0d8ffc
NC
9360 unsigned rn = INSTR (9, 5);
9361 unsigned rd = INSTR (4, 0);
2e8cf49e 9362
2cdad34c 9363 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9364 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9365 aarch64_get_reg_u64 (cpu, rn, NO_SP) | bimm);
9366}
9367
9368/* Logical shifted register.
9369 These allow an optional LSL, ASR, LSR or ROR to the second source
9370 register with a count up to the register bit count.
9371 N.B register args may not be SP. */
9372
9373/* 32 bit AND shifted register. */
9374static void
9375and32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9376{
ef0d8ffc
NC
9377 unsigned rm = INSTR (20, 16);
9378 unsigned rn = INSTR (9, 5);
9379 unsigned rd = INSTR (4, 0);
2e8cf49e 9380
2cdad34c 9381 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9382 aarch64_set_reg_u64
9383 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9384 & shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9385}
9386
9387/* 64 bit AND shifted register. */
9388static void
9389and64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9390{
ef0d8ffc
NC
9391 unsigned rm = INSTR (20, 16);
9392 unsigned rn = INSTR (9, 5);
9393 unsigned rd = INSTR (4, 0);
2e8cf49e 9394
2cdad34c 9395 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9396 aarch64_set_reg_u64
9397 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9398 & shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9399}
9400
9401/* 32 bit AND shifted register setting flags. */
9402static void
9403ands32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9404{
ef0d8ffc
NC
9405 unsigned rm = INSTR (20, 16);
9406 unsigned rn = INSTR (9, 5);
9407 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9408
9409 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9410 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9411 shift, count);
9412
2cdad34c 9413 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9414 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9415 set_flags_for_binop32 (cpu, value1 & value2);
9416}
9417
9418/* 64 bit AND shifted register setting flags. */
9419static void
9420ands64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9421{
ef0d8ffc
NC
9422 unsigned rm = INSTR (20, 16);
9423 unsigned rn = INSTR (9, 5);
9424 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9425
9426 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9427 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9428 shift, count);
9429
2cdad34c 9430 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9431 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9432 set_flags_for_binop64 (cpu, value1 & value2);
9433}
9434
9435/* 32 bit BIC shifted register. */
9436static void
9437bic32_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_u32 (cpu, rn, NO_SP)
9446 & ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9447}
9448
9449/* 64 bit BIC shifted register. */
9450static void
9451bic64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9452{
ef0d8ffc
NC
9453 unsigned rm = INSTR (20, 16);
9454 unsigned rn = INSTR (9, 5);
9455 unsigned rd = INSTR (4, 0);
2e8cf49e 9456
2cdad34c 9457 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9458 aarch64_set_reg_u64
9459 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9460 & ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9461}
9462
9463/* 32 bit BIC shifted register setting flags. */
9464static void
9465bics32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9466{
ef0d8ffc
NC
9467 unsigned rm = INSTR (20, 16);
9468 unsigned rn = INSTR (9, 5);
9469 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9470
9471 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9472 uint32_t value2 = ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9473 shift, count);
9474
2cdad34c 9475 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9476 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9477 set_flags_for_binop32 (cpu, value1 & value2);
9478}
9479
9480/* 64 bit BIC shifted register setting flags. */
9481static void
9482bics64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9483{
ef0d8ffc
NC
9484 unsigned rm = INSTR (20, 16);
9485 unsigned rn = INSTR (9, 5);
9486 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9487
9488 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9489 uint64_t value2 = ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9490 shift, count);
9491
2cdad34c 9492 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9493 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9494 set_flags_for_binop64 (cpu, value1 & value2);
9495}
9496
9497/* 32 bit EON shifted register. */
9498static void
9499eon32_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_u32 (cpu, rn, NO_SP)
9508 ^ ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9509}
9510
9511/* 64 bit EON shifted register. */
9512static void
9513eon64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9514{
ef0d8ffc
NC
9515 unsigned rm = INSTR (20, 16);
9516 unsigned rn = INSTR (9, 5);
9517 unsigned rd = INSTR (4, 0);
2e8cf49e 9518
2cdad34c 9519 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9520 aarch64_set_reg_u64
9521 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9522 ^ ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9523}
9524
9525/* 32 bit EOR shifted register. */
9526static void
9527eor32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9528{
ef0d8ffc
NC
9529 unsigned rm = INSTR (20, 16);
9530 unsigned rn = INSTR (9, 5);
9531 unsigned rd = INSTR (4, 0);
2e8cf49e 9532
2cdad34c 9533 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9534 aarch64_set_reg_u64
9535 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9536 ^ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9537}
9538
9539/* 64 bit EOR shifted register. */
9540static void
9541eor64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9542{
ef0d8ffc
NC
9543 unsigned rm = INSTR (20, 16);
9544 unsigned rn = INSTR (9, 5);
9545 unsigned rd = INSTR (4, 0);
2e8cf49e 9546
2cdad34c 9547 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9548 aarch64_set_reg_u64
9549 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9550 ^ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9551}
9552
9553/* 32 bit ORR shifted register. */
9554static void
9555orr32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9556{
ef0d8ffc
NC
9557 unsigned rm = INSTR (20, 16);
9558 unsigned rn = INSTR (9, 5);
9559 unsigned rd = INSTR (4, 0);
2e8cf49e 9560
2cdad34c 9561 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9562 aarch64_set_reg_u64
9563 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9564 | shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9565}
9566
9567/* 64 bit ORR shifted register. */
9568static void
9569orr64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9570{
ef0d8ffc
NC
9571 unsigned rm = INSTR (20, 16);
9572 unsigned rn = INSTR (9, 5);
9573 unsigned rd = INSTR (4, 0);
2e8cf49e 9574
2cdad34c 9575 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9576 aarch64_set_reg_u64
9577 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9578 | shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9579}
9580
9581/* 32 bit ORN shifted register. */
9582static void
9583orn32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9584{
ef0d8ffc
NC
9585 unsigned rm = INSTR (20, 16);
9586 unsigned rn = INSTR (9, 5);
9587 unsigned rd = INSTR (4, 0);
2e8cf49e 9588
2cdad34c 9589 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9590 aarch64_set_reg_u64
9591 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9592 | ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9593}
9594
9595/* 64 bit ORN shifted register. */
9596static void
9597orn64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9598{
ef0d8ffc
NC
9599 unsigned rm = INSTR (20, 16);
9600 unsigned rn = INSTR (9, 5);
9601 unsigned rd = INSTR (4, 0);
2e8cf49e 9602
2cdad34c 9603 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9604 aarch64_set_reg_u64
9605 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9606 | ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9607}
9608
9609static void
9610dexLogicalImmediate (sim_cpu *cpu)
9611{
9612 /* assert instr[28,23] = 1001000
9613 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9614 instr[30,29] = op : 0 ==> AND, 1 ==> ORR, 2 ==> EOR, 3 ==> ANDS
9615 instr[22] = N : used to construct immediate mask
9616 instr[21,16] = immr
9617 instr[15,10] = imms
9618 instr[9,5] = Rn
9619 instr[4,0] = Rd */
9620
9621 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
ef0d8ffc
NC
9622 uint32_t size = INSTR (31, 31);
9623 uint32_t N = INSTR (22, 22);
9624 /* uint32_t immr = INSTR (21, 16);. */
9625 /* uint32_t imms = INSTR (15, 10);. */
9626 uint32_t index = INSTR (22, 10);
2e8cf49e 9627 uint64_t bimm64 = LITable [index];
ef0d8ffc 9628 uint32_t dispatch = INSTR (30, 29);
2e8cf49e
NC
9629
9630 if (~size & N)
9631 HALT_UNALLOC;
9632
9633 if (!bimm64)
9634 HALT_UNALLOC;
9635
9636 if (size == 0)
9637 {
9638 uint32_t bimm = (uint32_t) bimm64;
9639
9640 switch (dispatch)
9641 {
9642 case 0: and32 (cpu, bimm); return;
9643 case 1: orr32 (cpu, bimm); return;
9644 case 2: eor32 (cpu, bimm); return;
9645 case 3: ands32 (cpu, bimm); return;
9646 }
9647 }
9648 else
9649 {
9650 switch (dispatch)
9651 {
9652 case 0: and64 (cpu, bimm64); return;
9653 case 1: orr64 (cpu, bimm64); return;
9654 case 2: eor64 (cpu, bimm64); return;
9655 case 3: ands64 (cpu, bimm64); return;
9656 }
9657 }
9658 HALT_UNALLOC;
9659}
9660
9661/* Immediate move.
9662 The uimm argument is a 16 bit value to be inserted into the
9663 target register the pos argument locates the 16 bit word in the
9664 dest register i.e. it is in {0, 1} for 32 bit and {0, 1, 2,
9665 3} for 64 bit.
9666 N.B register arg may not be SP so it should be.
9667 accessed using the setGZRegisterXXX accessors. */
9668
9669/* 32 bit move 16 bit immediate zero remaining shorts. */
9670static void
9671movz32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9672{
ef0d8ffc 9673 unsigned rd = INSTR (4, 0);
2e8cf49e 9674
2cdad34c 9675 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9676 aarch64_set_reg_u64 (cpu, rd, NO_SP, val << (pos * 16));
9677}
9678
9679/* 64 bit move 16 bit immediate zero remaining shorts. */
9680static void
9681movz64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9682{
ef0d8ffc 9683 unsigned rd = INSTR (4, 0);
2e8cf49e 9684
2cdad34c 9685 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9686 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((uint64_t) val) << (pos * 16));
9687}
9688
9689/* 32 bit move 16 bit immediate negated. */
9690static void
9691movn32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9692{
ef0d8ffc 9693 unsigned rd = INSTR (4, 0);
2e8cf49e 9694
2cdad34c 9695 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9696 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((val << (pos * 16)) ^ 0xffffffffU));
9697}
9698
9699/* 64 bit move 16 bit immediate negated. */
9700static void
9701movn64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9702{
ef0d8ffc 9703 unsigned rd = INSTR (4, 0);
2e8cf49e 9704
2cdad34c 9705 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9706 aarch64_set_reg_u64
9707 (cpu, rd, NO_SP, ((((uint64_t) val) << (pos * 16))
9708 ^ 0xffffffffffffffffULL));
9709}
9710
9711/* 32 bit move 16 bit immediate keep remaining shorts. */
9712static void
9713movk32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9714{
ef0d8ffc 9715 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9716 uint32_t current = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9717 uint32_t value = val << (pos * 16);
9718 uint32_t mask = ~(0xffffU << (pos * 16));
9719
2cdad34c 9720 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9721 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
9722}
9723
9724/* 64 bit move 16 it immediate keep remaining shorts. */
9725static void
9726movk64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9727{
ef0d8ffc 9728 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9729 uint64_t current = aarch64_get_reg_u64 (cpu, rd, NO_SP);
9730 uint64_t value = (uint64_t) val << (pos * 16);
9731 uint64_t mask = ~(0xffffULL << (pos * 16));
9732
2cdad34c 9733 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9734 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
9735}
9736
9737static void
9738dexMoveWideImmediate (sim_cpu *cpu)
9739{
9740 /* assert instr[28:23] = 100101
9741 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9742 instr[30,29] = op : 0 ==> MOVN, 1 ==> UNALLOC, 2 ==> MOVZ, 3 ==> MOVK
9743 instr[22,21] = shift : 00 == LSL#0, 01 = LSL#16, 10 = LSL#32, 11 = LSL#48
9744 instr[20,5] = uimm16
9745 instr[4,0] = Rd */
9746
9747 /* N.B. the (multiple of 16) shift is applied by the called routine,
9748 we just pass the multiplier. */
9749
9750 uint32_t imm;
ef0d8ffc
NC
9751 uint32_t size = INSTR (31, 31);
9752 uint32_t op = INSTR (30, 29);
9753 uint32_t shift = INSTR (22, 21);
2e8cf49e
NC
9754
9755 /* 32 bit can only shift 0 or 1 lot of 16.
9756 anything else is an unallocated instruction. */
9757 if (size == 0 && (shift > 1))
9758 HALT_UNALLOC;
9759
9760 if (op == 1)
9761 HALT_UNALLOC;
9762
ef0d8ffc 9763 imm = INSTR (20, 5);
2e8cf49e
NC
9764
9765 if (size == 0)
9766 {
9767 if (op == 0)
9768 movn32 (cpu, imm, shift);
9769 else if (op == 2)
9770 movz32 (cpu, imm, shift);
9771 else
9772 movk32 (cpu, imm, shift);
9773 }
9774 else
9775 {
9776 if (op == 0)
9777 movn64 (cpu, imm, shift);
9778 else if (op == 2)
9779 movz64 (cpu, imm, shift);
9780 else
9781 movk64 (cpu, imm, shift);
9782 }
9783}
9784
9785/* Bitfield operations.
9786 These take a pair of bit positions r and s which are in {0..31}
9787 or {0..63} depending on the instruction word size.
9788 N.B register args may not be SP. */
9789
9790/* OK, we start with ubfm which just needs to pick
9791 some bits out of source zero the rest and write
9792 the result to dest. Just need two logical shifts. */
9793
9794/* 32 bit bitfield move, left and right of affected zeroed
9795 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9796static void
9797ubfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9798{
9799 unsigned rd;
ef0d8ffc 9800 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9801 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9802
9803 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
9804 if (r <= s)
9805 {
9806 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
9807 We want only bits s:xxx:r at the bottom of the word
9808 so we LSL bit s up to bit 31 i.e. by 31 - s
9809 and then we LSR to bring bit 31 down to bit s - r
9810 i.e. by 31 + r - s. */
9811 value <<= 31 - s;
9812 value >>= 31 + r - s;
9813 }
9814 else
9815 {
9816 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0
9817 We want only bits s:xxx:0 starting at it 31-(r-1)
9818 so we LSL bit s up to bit 31 i.e. by 31 - s
9819 and then we LSL to bring bit 31 down to 31-(r-1)+s
9820 i.e. by r - (s + 1). */
9821 value <<= 31 - s;
9822 value >>= r - (s + 1);
9823 }
9824
2cdad34c 9825 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9826 rd = INSTR (4, 0);
2e8cf49e
NC
9827 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
9828}
9829
9830/* 64 bit bitfield move, left and right of affected zeroed
9831 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9832static void
9833ubfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9834{
9835 unsigned rd;
ef0d8ffc 9836 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9837 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9838
9839 if (r <= s)
9840 {
9841 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9842 We want only bits s:xxx:r at the bottom of the word.
9843 So we LSL bit s up to bit 63 i.e. by 63 - s
9844 and then we LSR to bring bit 63 down to bit s - r
9845 i.e. by 63 + r - s. */
9846 value <<= 63 - s;
9847 value >>= 63 + r - s;
9848 }
9849 else
9850 {
9851 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0.
9852 We want only bits s:xxx:0 starting at it 63-(r-1).
9853 So we LSL bit s up to bit 63 i.e. by 63 - s
9854 and then we LSL to bring bit 63 down to 63-(r-1)+s
9855 i.e. by r - (s + 1). */
9856 value <<= 63 - s;
9857 value >>= r - (s + 1);
9858 }
9859
2cdad34c 9860 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9861 rd = INSTR (4, 0);
2e8cf49e
NC
9862 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
9863}
9864
9865/* The signed versions need to insert sign bits
9866 on the left of the inserted bit field. so we do
9867 much the same as the unsigned version except we
9868 use an arithmetic shift right -- this just means
9869 we need to operate on signed values. */
9870
9871/* 32 bit bitfield move, left of affected sign-extended, right zeroed. */
9872/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9873static void
9874sbfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9875{
9876 unsigned rd;
ef0d8ffc 9877 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9878 /* as per ubfm32 but use an ASR instead of an LSR. */
9879 int32_t value = aarch64_get_reg_s32 (cpu, rn, NO_SP);
9880
9881 if (r <= s)
9882 {
9883 value <<= 31 - s;
9884 value >>= 31 + r - s;
9885 }
9886 else
9887 {
9888 value <<= 31 - s;
9889 value >>= r - (s + 1);
9890 }
9891
2cdad34c 9892 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9893 rd = INSTR (4, 0);
2e8cf49e
NC
9894 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
9895}
9896
9897/* 64 bit bitfield move, left of affected sign-extended, right zeroed. */
9898/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9899static void
9900sbfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9901{
9902 unsigned rd;
ef0d8ffc 9903 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9904 /* acpu per ubfm but use an ASR instead of an LSR. */
9905 int64_t value = aarch64_get_reg_s64 (cpu, rn, NO_SP);
9906
9907 if (r <= s)
9908 {
9909 value <<= 63 - s;
9910 value >>= 63 + r - s;
9911 }
9912 else
9913 {
9914 value <<= 63 - s;
9915 value >>= r - (s + 1);
9916 }
9917
2cdad34c 9918 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9919 rd = INSTR (4, 0);
2e8cf49e
NC
9920 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
9921}
9922
9923/* Finally, these versions leave non-affected bits
9924 as is. so we need to generate the bits as per
9925 ubfm and also generate a mask to pick the
9926 bits from the original and computed values. */
9927
9928/* 32 bit bitfield move, non-affected bits left as is.
9929 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9930static void
9931bfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9932{
ef0d8ffc 9933 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9934 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9935 uint32_t mask = -1;
9936 unsigned rd;
9937 uint32_t value2;
9938
9939 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
9940 if (r <= s)
9941 {
9942 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
9943 We want only bits s:xxx:r at the bottom of the word
9944 so we LSL bit s up to bit 31 i.e. by 31 - s
9945 and then we LSR to bring bit 31 down to bit s - r
9946 i.e. by 31 + r - s. */
9947 value <<= 31 - s;
9948 value >>= 31 + r - s;
9949 /* the mask must include the same bits. */
9950 mask <<= 31 - s;
9951 mask >>= 31 + r - s;
9952 }
9953 else
9954 {
9955 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0.
9956 We want only bits s:xxx:0 starting at it 31-(r-1)
9957 so we LSL bit s up to bit 31 i.e. by 31 - s
9958 and then we LSL to bring bit 31 down to 31-(r-1)+s
9959 i.e. by r - (s + 1). */
9960 value <<= 31 - s;
9961 value >>= r - (s + 1);
9962 /* The mask must include the same bits. */
9963 mask <<= 31 - s;
9964 mask >>= r - (s + 1);
9965 }
9966
ef0d8ffc 9967 rd = INSTR (4, 0);
2e8cf49e
NC
9968 value2 = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9969
9970 value2 &= ~mask;
9971 value2 |= value;
9972
2cdad34c 9973 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9974 aarch64_set_reg_u64
9975 (cpu, rd, NO_SP, (aarch64_get_reg_u32 (cpu, rd, NO_SP) & ~mask) | value);
9976}
9977
9978/* 64 bit bitfield move, non-affected bits left as is.
9979 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9980static void
9981bfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9982{
9983 unsigned rd;
ef0d8ffc 9984 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9985 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9986 uint64_t mask = 0xffffffffffffffffULL;
9987
9988 if (r <= s)
9989 {
9990 /* 63:...:s:xxx:r:...:0 ==> 63:...: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 63 i.e. by 63 - s
9993 and then we LSR to bring bit 63 down to bit s - r
9994 i.e. by 63 + r - s. */
9995 value <<= 63 - s;
9996 value >>= 63 + r - s;
9997 /* The mask must include the same bits. */
9998 mask <<= 63 - s;
9999 mask >>= 63 + r - s;
10000 }
10001 else
10002 {
10003 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0
10004 We want only bits s:xxx:0 starting at it 63-(r-1)
10005 so we LSL bit s up to bit 63 i.e. by 63 - s
10006 and then we LSL to bring bit 63 down to 63-(r-1)+s
10007 i.e. by r - (s + 1). */
10008 value <<= 63 - s;
10009 value >>= r - (s + 1);
10010 /* The mask must include the same bits. */
10011 mask <<= 63 - s;
10012 mask >>= r - (s + 1);
10013 }
10014
2cdad34c 10015 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 10016 rd = INSTR (4, 0);
2e8cf49e
NC
10017 aarch64_set_reg_u64
10018 (cpu, rd, NO_SP, (aarch64_get_reg_u64 (cpu, rd, NO_SP) & ~mask) | value);
10019}
10020
10021static void
10022dexBitfieldImmediate (sim_cpu *cpu)
10023{
10024 /* assert instr[28:23] = 100110
10025 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
10026 instr[30,29] = op : 0 ==> SBFM, 1 ==> BFM, 2 ==> UBFM, 3 ==> UNALLOC
10027 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit ow UNALLOC
10028 instr[21,16] = immr : 0xxxxx for 32 bit, xxxxxx for 64 bit
10029 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
10030 instr[9,5] = Rn
10031 instr[4,0] = Rd */
10032
10033 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
10034 uint32_t dispatch;
10035 uint32_t imms;
ef0d8ffc
NC
10036 uint32_t size = INSTR (31, 31);
10037 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
10038 /* 32 bit operations must have immr[5] = 0 and imms[5] = 0. */
10039 /* or else we have an UNALLOC. */
ef0d8ffc 10040 uint32_t immr = INSTR (21, 16);
2e8cf49e
NC
10041
10042 if (~size & N)
10043 HALT_UNALLOC;
10044
10045 if (!size && uimm (immr, 5, 5))
10046 HALT_UNALLOC;
10047
ef0d8ffc 10048 imms = INSTR (15, 10);
2e8cf49e
NC
10049 if (!size && uimm (imms, 5, 5))
10050 HALT_UNALLOC;
10051
10052 /* Switch on combined size and op. */
ef0d8ffc 10053 dispatch = INSTR (31, 29);
2e8cf49e
NC
10054 switch (dispatch)
10055 {
10056 case 0: sbfm32 (cpu, immr, imms); return;
10057 case 1: bfm32 (cpu, immr, imms); return;
10058 case 2: ubfm32 (cpu, immr, imms); return;
10059 case 4: sbfm (cpu, immr, imms); return;
10060 case 5: bfm (cpu, immr, imms); return;
10061 case 6: ubfm (cpu, immr, imms); return;
10062 default: HALT_UNALLOC;
10063 }
10064}
10065
10066static void
10067do_EXTR_32 (sim_cpu *cpu)
10068{
10069 /* instr[31:21] = 00010011100
10070 instr[20,16] = Rm
10071 instr[15,10] = imms : 0xxxxx for 32 bit
10072 instr[9,5] = Rn
10073 instr[4,0] = Rd */
ef0d8ffc
NC
10074 unsigned rm = INSTR (20, 16);
10075 unsigned imms = INSTR (15, 10) & 31;
10076 unsigned rn = INSTR ( 9, 5);
10077 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
10078 uint64_t val1;
10079 uint64_t val2;
10080
10081 val1 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
10082 val1 >>= imms;
10083 val2 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
10084 val2 <<= (32 - imms);
10085
2cdad34c 10086 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10087 aarch64_set_reg_u64 (cpu, rd, NO_SP, val1 | val2);
10088}
10089
10090static void
10091do_EXTR_64 (sim_cpu *cpu)
10092{
10093 /* instr[31:21] = 10010011100
10094 instr[20,16] = Rm
10095 instr[15,10] = imms
10096 instr[9,5] = Rn
10097 instr[4,0] = Rd */
ef0d8ffc
NC
10098 unsigned rm = INSTR (20, 16);
10099 unsigned imms = INSTR (15, 10) & 63;
10100 unsigned rn = INSTR ( 9, 5);
10101 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
10102 uint64_t val;
10103
10104 val = aarch64_get_reg_u64 (cpu, rm, NO_SP);
10105 val >>= imms;
10106 val |= (aarch64_get_reg_u64 (cpu, rn, NO_SP) << (64 - imms));
10107
10108 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
10109}
10110
10111static void
10112dexExtractImmediate (sim_cpu *cpu)
10113{
10114 /* assert instr[28:23] = 100111
10115 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
10116 instr[30,29] = op21 : 0 ==> EXTR, 1,2,3 ==> UNALLOC
10117 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit or UNALLOC
10118 instr[21] = op0 : must be 0 or UNALLOC
10119 instr[20,16] = Rm
10120 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
10121 instr[9,5] = Rn
10122 instr[4,0] = Rd */
10123
10124 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
10125 /* 64 bit operations must have N = 1 or else we have an UNALLOC. */
10126 uint32_t dispatch;
ef0d8ffc
NC
10127 uint32_t size = INSTR (31, 31);
10128 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
10129 /* 32 bit operations must have imms[5] = 0
10130 or else we have an UNALLOC. */
ef0d8ffc 10131 uint32_t imms = INSTR (15, 10);
2e8cf49e
NC
10132
10133 if (size ^ N)
10134 HALT_UNALLOC;
10135
10136 if (!size && uimm (imms, 5, 5))
10137 HALT_UNALLOC;
10138
10139 /* Switch on combined size and op. */
ef0d8ffc 10140 dispatch = INSTR (31, 29);
2e8cf49e
NC
10141
10142 if (dispatch == 0)
10143 do_EXTR_32 (cpu);
10144
10145 else if (dispatch == 4)
10146 do_EXTR_64 (cpu);
10147
10148 else if (dispatch == 1)
10149 HALT_NYI;
10150 else
10151 HALT_UNALLOC;
10152}
10153
10154static void
10155dexDPImm (sim_cpu *cpu)
10156{
10157 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
10158 assert group == GROUP_DPIMM_1000 || grpoup == GROUP_DPIMM_1001
10159 bits [25,23] of a DPImm are the secondary dispatch vector. */
10160 uint32_t group2 = dispatchDPImm (aarch64_get_instr (cpu));
10161
10162 switch (group2)
10163 {
10164 case DPIMM_PCADR_000:
10165 case DPIMM_PCADR_001:
10166 dexPCRelAddressing (cpu);
10167 return;
10168
10169 case DPIMM_ADDSUB_010:
10170 case DPIMM_ADDSUB_011:
10171 dexAddSubtractImmediate (cpu);
10172 return;
10173
10174 case DPIMM_LOG_100:
10175 dexLogicalImmediate (cpu);
10176 return;
10177
10178 case DPIMM_MOV_101:
10179 dexMoveWideImmediate (cpu);
10180 return;
10181
10182 case DPIMM_BITF_110:
10183 dexBitfieldImmediate (cpu);
10184 return;
10185
10186 case DPIMM_EXTR_111:
10187 dexExtractImmediate (cpu);
10188 return;
10189
10190 default:
10191 /* Should never reach here. */
10192 HALT_NYI;
10193 }
10194}
10195
10196static void
10197dexLoadUnscaledImmediate (sim_cpu *cpu)
10198{
10199 /* instr[29,24] == 111_00
10200 instr[21] == 0
10201 instr[11,10] == 00
10202 instr[31,30] = size
10203 instr[26] = V
10204 instr[23,22] = opc
10205 instr[20,12] = simm9
10206 instr[9,5] = rn may be SP. */
ef0d8ffc
NC
10207 /* unsigned rt = INSTR (4, 0); */
10208 uint32_t V = INSTR (26, 26);
7517e550 10209 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
2e8cf49e
NC
10210 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
10211
10212 if (!V)
10213 {
10214 /* GReg operations. */
10215 switch (dispatch)
10216 {
10217 case 0: sturb (cpu, imm); return;
10218 case 1: ldurb32 (cpu, imm); return;
10219 case 2: ldursb64 (cpu, imm); return;
10220 case 3: ldursb32 (cpu, imm); return;
10221 case 4: sturh (cpu, imm); return;
10222 case 5: ldurh32 (cpu, imm); return;
10223 case 6: ldursh64 (cpu, imm); return;
10224 case 7: ldursh32 (cpu, imm); return;
10225 case 8: stur32 (cpu, imm); return;
10226 case 9: ldur32 (cpu, imm); return;
10227 case 10: ldursw (cpu, imm); return;
10228 case 12: stur64 (cpu, imm); return;
10229 case 13: ldur64 (cpu, imm); return;
10230
10231 case 14:
10232 /* PRFUM NYI. */
10233 HALT_NYI;
10234
10235 default:
10236 case 11:
10237 case 15:
10238 HALT_UNALLOC;
10239 }
10240 }
10241
10242 /* FReg operations. */
10243 switch (dispatch)
10244 {
10245 case 2: fsturq (cpu, imm); return;
10246 case 3: fldurq (cpu, imm); return;
10247 case 8: fsturs (cpu, imm); return;
10248 case 9: fldurs (cpu, imm); return;
10249 case 12: fsturd (cpu, imm); return;
10250 case 13: fldurd (cpu, imm); return;
10251
10252 case 0: /* STUR 8 bit FP. */
10253 case 1: /* LDUR 8 bit FP. */
10254 case 4: /* STUR 16 bit FP. */
10255 case 5: /* LDUR 8 bit FP. */
10256 HALT_NYI;
10257
10258 default:
10259 case 6:
10260 case 7:
10261 case 10:
10262 case 11:
10263 case 14:
10264 case 15:
10265 HALT_UNALLOC;
10266 }
10267}
10268
10269/* N.B. A preliminary note regarding all the ldrs<x>32
10270 instructions
10271
10272 The signed value loaded by these instructions is cast to unsigned
10273 before being assigned to aarch64_get_reg_u64 (cpu, N) i.e. to the
10274 64 bit element of the GReg union. this performs a 32 bit sign extension
10275 (as required) but avoids 64 bit sign extension, thus ensuring that the
10276 top half of the register word is zero. this is what the spec demands
10277 when a 32 bit load occurs. */
10278
10279/* 32 bit load sign-extended byte scaled unsigned 12 bit. */
10280static void
10281ldrsb32_abs (sim_cpu *cpu, uint32_t offset)
10282{
ef0d8ffc
NC
10283 unsigned int rn = INSTR (9, 5);
10284 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10285
10286 /* The target register may not be SP but the source may be
10287 there is no scaling required for a byte load. */
10288 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
10289 aarch64_set_reg_u64 (cpu, rt, NO_SP,
10290 (int64_t) aarch64_get_mem_s8 (cpu, address));
10291}
10292
10293/* 32 bit load sign-extended byte scaled or unscaled zero-
10294 or sign-extended 32-bit register offset. */
10295static void
10296ldrsb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10297{
ef0d8ffc
NC
10298 unsigned int rm = INSTR (20, 16);
10299 unsigned int rn = INSTR (9, 5);
10300 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10301
10302 /* rn may reference SP, rm and rt must reference ZR. */
10303
10304 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10305 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10306 extension);
10307
10308 /* There is no scaling required for a byte load. */
10309 aarch64_set_reg_u64
10310 (cpu, rt, NO_SP, (int64_t) aarch64_get_mem_s8 (cpu, address
10311 + displacement));
10312}
10313
10314/* 32 bit load sign-extended byte unscaled signed 9 bit with
10315 pre- or post-writeback. */
10316static void
10317ldrsb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10318{
10319 uint64_t address;
ef0d8ffc
NC
10320 unsigned int rn = INSTR (9, 5);
10321 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10322
10323 if (rn == rt && wb != NoWriteBack)
10324 HALT_UNALLOC;
10325
10326 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10327
10328 if (wb == Pre)
10329 address += offset;
10330
10331 aarch64_set_reg_u64 (cpu, rt, NO_SP,
10332 (int64_t) aarch64_get_mem_s8 (cpu, address));
10333
10334 if (wb == Post)
10335 address += offset;
10336
10337 if (wb != NoWriteBack)
10338 aarch64_set_reg_u64 (cpu, rn, NO_SP, address);
10339}
10340
10341/* 8 bit store scaled. */
10342static void
10343fstrb_abs (sim_cpu *cpu, uint32_t offset)
10344{
ef0d8ffc
NC
10345 unsigned st = INSTR (4, 0);
10346 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10347
10348 aarch64_set_mem_u8 (cpu,
10349 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
10350 aarch64_get_vec_u8 (cpu, st, 0));
10351}
10352
10353/* 8 bit store scaled or unscaled zero- or
10354 sign-extended 8-bit register offset. */
10355static void
10356fstrb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10357{
ef0d8ffc
NC
10358 unsigned rm = INSTR (20, 16);
10359 unsigned rn = INSTR (9, 5);
10360 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10361
10362 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10363 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10364 extension);
7517e550 10365 uint64_t displacement = scaling == Scaled ? extended : 0;
2e8cf49e
NC
10366
10367 aarch64_set_mem_u8
10368 (cpu, address + displacement, aarch64_get_vec_u8 (cpu, st, 0));
10369}
10370
10371/* 16 bit store scaled. */
10372static void
10373fstrh_abs (sim_cpu *cpu, uint32_t offset)
10374{
ef0d8ffc
NC
10375 unsigned st = INSTR (4, 0);
10376 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10377
10378 aarch64_set_mem_u16
10379 (cpu,
10380 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16),
10381 aarch64_get_vec_u16 (cpu, st, 0));
10382}
10383
10384/* 16 bit store scaled or unscaled zero-
10385 or sign-extended 16-bit register offset. */
10386static void
10387fstrh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10388{
ef0d8ffc
NC
10389 unsigned rm = INSTR (20, 16);
10390 unsigned rn = INSTR (9, 5);
10391 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10392
10393 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10394 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10395 extension);
7517e550 10396 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
2e8cf49e
NC
10397
10398 aarch64_set_mem_u16
10399 (cpu, address + displacement, aarch64_get_vec_u16 (cpu, st, 0));
10400}
10401
10402/* 32 bit store scaled unsigned 12 bit. */
10403static void
10404fstrs_abs (sim_cpu *cpu, uint32_t offset)
10405{
ef0d8ffc
NC
10406 unsigned st = INSTR (4, 0);
10407 unsigned rn = INSTR (9, 5);
2e8cf49e 10408
e101a78b 10409 aarch64_set_mem_u32
2e8cf49e
NC
10410 (cpu,
10411 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
e101a78b 10412 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10413}
10414
10415/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
10416static void
10417fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10418{
ef0d8ffc
NC
10419 unsigned rn = INSTR (9, 5);
10420 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10421
10422 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10423
10424 if (wb != Post)
10425 address += offset;
10426
e101a78b 10427 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10428
10429 if (wb == Post)
10430 address += offset;
10431
10432 if (wb != NoWriteBack)
10433 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10434}
10435
10436/* 32 bit store scaled or unscaled zero-
10437 or sign-extended 32-bit register offset. */
10438static void
10439fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10440{
ef0d8ffc
NC
10441 unsigned rm = INSTR (20, 16);
10442 unsigned rn = INSTR (9, 5);
10443 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10444
10445 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10446 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10447 extension);
10448 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
10449
e101a78b
NC
10450 aarch64_set_mem_u32
10451 (cpu, address + displacement, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10452}
10453
10454/* 64 bit store scaled unsigned 12 bit. */
10455static void
10456fstrd_abs (sim_cpu *cpu, uint32_t offset)
10457{
ef0d8ffc
NC
10458 unsigned st = INSTR (4, 0);
10459 unsigned rn = INSTR (9, 5);
2e8cf49e 10460
e101a78b 10461 aarch64_set_mem_u64
2e8cf49e
NC
10462 (cpu,
10463 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
e101a78b 10464 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10465}
10466
10467/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
10468static void
10469fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10470{
ef0d8ffc
NC
10471 unsigned rn = INSTR (9, 5);
10472 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10473
10474 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10475
10476 if (wb != Post)
10477 address += offset;
10478
e101a78b 10479 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10480
10481 if (wb == Post)
10482 address += offset;
10483
10484 if (wb != NoWriteBack)
10485 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10486}
10487
10488/* 64 bit store scaled or unscaled zero-
10489 or sign-extended 32-bit register offset. */
10490static void
10491fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10492{
ef0d8ffc
NC
10493 unsigned rm = INSTR (20, 16);
10494 unsigned rn = INSTR (9, 5);
10495 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10496
10497 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10498 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10499 extension);
10500 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
10501
e101a78b
NC
10502 aarch64_set_mem_u64
10503 (cpu, address + displacement, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10504}
10505
10506/* 128 bit store scaled unsigned 12 bit. */
10507static void
10508fstrq_abs (sim_cpu *cpu, uint32_t offset)
10509{
10510 FRegister a;
ef0d8ffc
NC
10511 unsigned st = INSTR (4, 0);
10512 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10513 uint64_t addr;
10514
10515 aarch64_get_FP_long_double (cpu, st, & a);
10516
10517 addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
10518 aarch64_set_mem_long_double (cpu, addr, a);
10519}
10520
10521/* 128 bit store unscaled signed 9 bit with pre- or post-writeback. */
10522static void
10523fstrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10524{
10525 FRegister a;
ef0d8ffc
NC
10526 unsigned rn = INSTR (9, 5);
10527 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10528 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10529
10530 if (wb != Post)
10531 address += offset;
10532
10533 aarch64_get_FP_long_double (cpu, st, & a);
10534 aarch64_set_mem_long_double (cpu, address, a);
10535
10536 if (wb == Post)
10537 address += offset;
10538
10539 if (wb != NoWriteBack)
10540 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10541}
10542
10543/* 128 bit store scaled or unscaled zero-
10544 or sign-extended 32-bit register offset. */
10545static void
10546fstrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10547{
ef0d8ffc
NC
10548 unsigned rm = INSTR (20, 16);
10549 unsigned rn = INSTR (9, 5);
10550 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10551
10552 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10553 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10554 extension);
10555 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
10556
10557 FRegister a;
10558
10559 aarch64_get_FP_long_double (cpu, st, & a);
10560 aarch64_set_mem_long_double (cpu, address + displacement, a);
10561}
10562
10563static void
10564dexLoadImmediatePrePost (sim_cpu *cpu)
10565{
ef0d8ffc
NC
10566 /* instr[31,30] = size
10567 instr[29,27] = 111
10568 instr[26] = V
10569 instr[25,24] = 00
2e8cf49e 10570 instr[23,22] = opc
ef0d8ffc 10571 instr[21] = 0
2e8cf49e 10572 instr[20,12] = simm9
ef0d8ffc
NC
10573 instr[11] = wb : 0 ==> Post, 1 ==> Pre
10574 instr[10] = 0
10575 instr[9,5] = Rn may be SP.
10576 instr[4,0] = Rt */
10577
10578 uint32_t V = INSTR (26, 26);
10579 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10580 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
10581 WriteBack wb = INSTR (11, 11);
2e8cf49e
NC
10582
10583 if (!V)
10584 {
10585 /* GReg operations. */
10586 switch (dispatch)
10587 {
10588 case 0: strb_wb (cpu, imm, wb); return;
10589 case 1: ldrb32_wb (cpu, imm, wb); return;
10590 case 2: ldrsb_wb (cpu, imm, wb); return;
10591 case 3: ldrsb32_wb (cpu, imm, wb); return;
10592 case 4: strh_wb (cpu, imm, wb); return;
10593 case 5: ldrh32_wb (cpu, imm, wb); return;
10594 case 6: ldrsh64_wb (cpu, imm, wb); return;
10595 case 7: ldrsh32_wb (cpu, imm, wb); return;
10596 case 8: str32_wb (cpu, imm, wb); return;
10597 case 9: ldr32_wb (cpu, imm, wb); return;
10598 case 10: ldrsw_wb (cpu, imm, wb); return;
10599 case 12: str_wb (cpu, imm, wb); return;
10600 case 13: ldr_wb (cpu, imm, wb); return;
10601
10602 default:
10603 case 11:
10604 case 14:
10605 case 15:
10606 HALT_UNALLOC;
10607 }
10608 }
10609
10610 /* FReg operations. */
10611 switch (dispatch)
10612 {
10613 case 2: fstrq_wb (cpu, imm, wb); return;
10614 case 3: fldrq_wb (cpu, imm, wb); return;
10615 case 8: fstrs_wb (cpu, imm, wb); return;
10616 case 9: fldrs_wb (cpu, imm, wb); return;
10617 case 12: fstrd_wb (cpu, imm, wb); return;
10618 case 13: fldrd_wb (cpu, imm, wb); return;
10619
10620 case 0: /* STUR 8 bit FP. */
10621 case 1: /* LDUR 8 bit FP. */
10622 case 4: /* STUR 16 bit FP. */
10623 case 5: /* LDUR 8 bit FP. */
10624 HALT_NYI;
10625
10626 default:
10627 case 6:
10628 case 7:
10629 case 10:
10630 case 11:
10631 case 14:
10632 case 15:
10633 HALT_UNALLOC;
10634 }
10635}
10636
10637static void
10638dexLoadRegisterOffset (sim_cpu *cpu)
10639{
10640 /* instr[31,30] = size
10641 instr[29,27] = 111
10642 instr[26] = V
10643 instr[25,24] = 00
10644 instr[23,22] = opc
10645 instr[21] = 1
10646 instr[20,16] = rm
10647 instr[15,13] = option : 010 ==> UXTW, 011 ==> UXTX/LSL,
10648 110 ==> SXTW, 111 ==> SXTX,
10649 ow ==> RESERVED
10650 instr[12] = scaled
10651 instr[11,10] = 10
10652 instr[9,5] = rn
10653 instr[4,0] = rt. */
10654
ef0d8ffc
NC
10655 uint32_t V = INSTR (26, 26);
10656 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10657 Scaling scale = INSTR (12, 12);
10658 Extension extensionType = INSTR (15, 13);
2e8cf49e
NC
10659
10660 /* Check for illegal extension types. */
10661 if (uimm (extensionType, 1, 1) == 0)
10662 HALT_UNALLOC;
10663
10664 if (extensionType == UXTX || extensionType == SXTX)
10665 extensionType = NoExtension;
10666
10667 if (!V)
10668 {
10669 /* GReg operations. */
10670 switch (dispatch)
10671 {
10672 case 0: strb_scale_ext (cpu, scale, extensionType); return;
10673 case 1: ldrb32_scale_ext (cpu, scale, extensionType); return;
10674 case 2: ldrsb_scale_ext (cpu, scale, extensionType); return;
10675 case 3: ldrsb32_scale_ext (cpu, scale, extensionType); return;
10676 case 4: strh_scale_ext (cpu, scale, extensionType); return;
10677 case 5: ldrh32_scale_ext (cpu, scale, extensionType); return;
10678 case 6: ldrsh_scale_ext (cpu, scale, extensionType); return;
10679 case 7: ldrsh32_scale_ext (cpu, scale, extensionType); return;
10680 case 8: str32_scale_ext (cpu, scale, extensionType); return;
10681 case 9: ldr32_scale_ext (cpu, scale, extensionType); return;
10682 case 10: ldrsw_scale_ext (cpu, scale, extensionType); return;
10683 case 12: str_scale_ext (cpu, scale, extensionType); return;
10684 case 13: ldr_scale_ext (cpu, scale, extensionType); return;
10685 case 14: prfm_scale_ext (cpu, scale, extensionType); return;
10686
10687 default:
10688 case 11:
10689 case 15:
10690 HALT_UNALLOC;
10691 }
10692 }
10693
10694 /* FReg operations. */
10695 switch (dispatch)
10696 {
10697 case 1: /* LDUR 8 bit FP. */
10698 HALT_NYI;
10699 case 3: fldrq_scale_ext (cpu, scale, extensionType); return;
10700 case 5: /* LDUR 8 bit FP. */
10701 HALT_NYI;
10702 case 9: fldrs_scale_ext (cpu, scale, extensionType); return;
10703 case 13: fldrd_scale_ext (cpu, scale, extensionType); return;
10704
10705 case 0: fstrb_scale_ext (cpu, scale, extensionType); return;
10706 case 2: fstrq_scale_ext (cpu, scale, extensionType); return;
10707 case 4: fstrh_scale_ext (cpu, scale, extensionType); return;
10708 case 8: fstrs_scale_ext (cpu, scale, extensionType); return;
10709 case 12: fstrd_scale_ext (cpu, scale, extensionType); return;
10710
10711 default:
10712 case 6:
10713 case 7:
10714 case 10:
10715 case 11:
10716 case 14:
10717 case 15:
10718 HALT_UNALLOC;
10719 }
10720}
10721
10722static void
10723dexLoadUnsignedImmediate (sim_cpu *cpu)
10724{
5ab6d79e 10725 /* instr[29,24] == 111_01
2e8cf49e 10726 instr[31,30] = size
5ab6d79e 10727 instr[26] = V
2e8cf49e
NC
10728 instr[23,22] = opc
10729 instr[21,10] = uimm12 : unsigned immediate offset
5ab6d79e
NC
10730 instr[9,5] = rn may be SP.
10731 instr[4,0] = rt. */
ef0d8ffc
NC
10732
10733 uint32_t V = INSTR (26,26);
7517e550 10734 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
ef0d8ffc 10735 uint32_t imm = INSTR (21, 10);
2e8cf49e
NC
10736
10737 if (!V)
10738 {
10739 /* GReg operations. */
10740 switch (dispatch)
10741 {
10742 case 0: strb_abs (cpu, imm); return;
10743 case 1: ldrb32_abs (cpu, imm); return;
10744 case 2: ldrsb_abs (cpu, imm); return;
10745 case 3: ldrsb32_abs (cpu, imm); return;
10746 case 4: strh_abs (cpu, imm); return;
10747 case 5: ldrh32_abs (cpu, imm); return;
10748 case 6: ldrsh_abs (cpu, imm); return;
10749 case 7: ldrsh32_abs (cpu, imm); return;
10750 case 8: str32_abs (cpu, imm); return;
10751 case 9: ldr32_abs (cpu, imm); return;
10752 case 10: ldrsw_abs (cpu, imm); return;
10753 case 12: str_abs (cpu, imm); return;
10754 case 13: ldr_abs (cpu, imm); return;
10755 case 14: prfm_abs (cpu, imm); return;
10756
10757 default:
10758 case 11:
10759 case 15:
10760 HALT_UNALLOC;
10761 }
10762 }
10763
10764 /* FReg operations. */
10765 switch (dispatch)
10766 {
2e8cf49e 10767 case 0: fstrb_abs (cpu, imm); return;
2e8cf49e
NC
10768 case 4: fstrh_abs (cpu, imm); return;
10769 case 8: fstrs_abs (cpu, imm); return;
10770 case 12: fstrd_abs (cpu, imm); return;
5ab6d79e 10771 case 2: fstrq_abs (cpu, imm); return;
2e8cf49e 10772
5ab6d79e
NC
10773 case 1: fldrb_abs (cpu, imm); return;
10774 case 5: fldrh_abs (cpu, imm); return;
10775 case 9: fldrs_abs (cpu, imm); return;
10776 case 13: fldrd_abs (cpu, imm); return;
10777 case 3: fldrq_abs (cpu, imm); return;
2e8cf49e
NC
10778
10779 default:
10780 case 6:
10781 case 7:
10782 case 10:
10783 case 11:
10784 case 14:
10785 case 15:
10786 HALT_UNALLOC;
10787 }
10788}
10789
10790static void
10791dexLoadExclusive (sim_cpu *cpu)
10792{
10793 /* assert instr[29:24] = 001000;
10794 instr[31,30] = size
10795 instr[23] = 0 if exclusive
10796 instr[22] = L : 1 if load, 0 if store
10797 instr[21] = 1 if pair
10798 instr[20,16] = Rs
10799 instr[15] = o0 : 1 if ordered
10800 instr[14,10] = Rt2
10801 instr[9,5] = Rn
10802 instr[4.0] = Rt. */
10803
ef0d8ffc 10804 switch (INSTR (22, 21))
2e8cf49e
NC
10805 {
10806 case 2: ldxr (cpu); return;
10807 case 0: stxr (cpu); return;
10808 default: HALT_NYI;
10809 }
10810}
10811
10812static void
10813dexLoadOther (sim_cpu *cpu)
10814{
10815 uint32_t dispatch;
10816
10817 /* instr[29,25] = 111_0
10818 instr[24] == 0 ==> dispatch, 1 ==> ldst reg unsigned immediate
10819 instr[21:11,10] is the secondary dispatch. */
ef0d8ffc 10820 if (INSTR (24, 24))
2e8cf49e
NC
10821 {
10822 dexLoadUnsignedImmediate (cpu);
10823 return;
10824 }
10825
7517e550 10826 dispatch = ((INSTR (21, 21) << 2) | INSTR (11, 10));
2e8cf49e
NC
10827 switch (dispatch)
10828 {
10829 case 0: dexLoadUnscaledImmediate (cpu); return;
10830 case 1: dexLoadImmediatePrePost (cpu); return;
10831 case 3: dexLoadImmediatePrePost (cpu); return;
10832 case 6: dexLoadRegisterOffset (cpu); return;
10833
10834 default:
10835 case 2:
10836 case 4:
10837 case 5:
10838 case 7:
10839 HALT_NYI;
10840 }
10841}
10842
10843static void
10844store_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10845{
ef0d8ffc
NC
10846 unsigned rn = INSTR (14, 10);
10847 unsigned rd = INSTR (9, 5);
10848 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10849 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10850
10851 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10852 HALT_UNALLOC; /* ??? */
10853
10854 offset <<= 2;
10855
10856 if (wb != Post)
10857 address += offset;
10858
10859 aarch64_set_mem_u32 (cpu, address,
10860 aarch64_get_reg_u32 (cpu, rm, NO_SP));
10861 aarch64_set_mem_u32 (cpu, address + 4,
10862 aarch64_get_reg_u32 (cpu, rn, NO_SP));
10863
10864 if (wb == Post)
10865 address += offset;
10866
10867 if (wb != NoWriteBack)
10868 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10869}
10870
10871static void
10872store_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10873{
ef0d8ffc
NC
10874 unsigned rn = INSTR (14, 10);
10875 unsigned rd = INSTR (9, 5);
10876 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10877 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10878
10879 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10880 HALT_UNALLOC; /* ??? */
10881
10882 offset <<= 3;
10883
10884 if (wb != Post)
10885 address += offset;
10886
10887 aarch64_set_mem_u64 (cpu, address,
7517e550 10888 aarch64_get_reg_u64 (cpu, rm, NO_SP));
2e8cf49e 10889 aarch64_set_mem_u64 (cpu, address + 8,
7517e550 10890 aarch64_get_reg_u64 (cpu, rn, NO_SP));
2e8cf49e
NC
10891
10892 if (wb == Post)
10893 address += offset;
10894
10895 if (wb != NoWriteBack)
10896 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10897}
10898
10899static void
10900load_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10901{
ef0d8ffc
NC
10902 unsigned rn = INSTR (14, 10);
10903 unsigned rd = INSTR (9, 5);
10904 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10905 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10906
7517e550 10907 /* Treat this as unalloc to make sure we don't do it. */
2e8cf49e
NC
10908 if (rn == rm)
10909 HALT_UNALLOC;
10910
10911 offset <<= 2;
10912
10913 if (wb != Post)
10914 address += offset;
10915
10916 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u32 (cpu, address));
10917 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u32 (cpu, address + 4));
10918
10919 if (wb == Post)
10920 address += offset;
10921
10922 if (wb != NoWriteBack)
10923 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10924}
10925
10926static void
10927load_pair_s32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10928{
ef0d8ffc
NC
10929 unsigned rn = INSTR (14, 10);
10930 unsigned rd = INSTR (9, 5);
10931 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10932 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10933
10934 /* Treat this as unalloc to make sure we don't do it. */
10935 if (rn == rm)
10936 HALT_UNALLOC;
10937
10938 offset <<= 2;
10939
10940 if (wb != Post)
10941 address += offset;
10942
10943 aarch64_set_reg_s64 (cpu, rm, SP_OK, aarch64_get_mem_s32 (cpu, address));
10944 aarch64_set_reg_s64 (cpu, rn, SP_OK, aarch64_get_mem_s32 (cpu, address + 4));
10945
10946 if (wb == Post)
10947 address += offset;
10948
10949 if (wb != NoWriteBack)
10950 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10951}
10952
10953static void
10954load_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10955{
ef0d8ffc
NC
10956 unsigned rn = INSTR (14, 10);
10957 unsigned rd = INSTR (9, 5);
10958 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10959 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10960
10961 /* Treat this as unalloc to make sure we don't do it. */
10962 if (rn == rm)
10963 HALT_UNALLOC;
10964
10965 offset <<= 3;
10966
10967 if (wb != Post)
10968 address += offset;
10969
10970 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u64 (cpu, address));
10971 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u64 (cpu, address + 8));
10972
10973 if (wb == Post)
10974 address += offset;
10975
10976 if (wb != NoWriteBack)
10977 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10978}
10979
10980static void
10981dex_load_store_pair_gr (sim_cpu *cpu)
10982{
10983 /* instr[31,30] = size (10=> 64-bit, 01=> signed 32-bit, 00=> 32-bit)
10984 instr[29,25] = instruction encoding: 101_0
10985 instr[26] = V : 1 if fp 0 if gp
10986 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10987 instr[22] = load/store (1=> load)
10988 instr[21,15] = signed, scaled, offset
10989 instr[14,10] = Rn
10990 instr[ 9, 5] = Rd
10991 instr[ 4, 0] = Rm. */
10992
7517e550 10993 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
10994 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10995
10996 switch (dispatch)
10997 {
10998 case 2: store_pair_u32 (cpu, offset, Post); return;
10999 case 3: load_pair_u32 (cpu, offset, Post); return;
11000 case 4: store_pair_u32 (cpu, offset, NoWriteBack); return;
11001 case 5: load_pair_u32 (cpu, offset, NoWriteBack); return;
11002 case 6: store_pair_u32 (cpu, offset, Pre); return;
11003 case 7: load_pair_u32 (cpu, offset, Pre); return;
11004
11005 case 11: load_pair_s32 (cpu, offset, Post); return;
11006 case 13: load_pair_s32 (cpu, offset, NoWriteBack); return;
11007 case 15: load_pair_s32 (cpu, offset, Pre); return;
11008
11009 case 18: store_pair_u64 (cpu, offset, Post); return;
11010 case 19: load_pair_u64 (cpu, offset, Post); return;
11011 case 20: store_pair_u64 (cpu, offset, NoWriteBack); return;
11012 case 21: load_pair_u64 (cpu, offset, NoWriteBack); return;
11013 case 22: store_pair_u64 (cpu, offset, Pre); return;
11014 case 23: load_pair_u64 (cpu, offset, Pre); return;
11015
11016 default:
11017 HALT_UNALLOC;
11018 }
11019}
11020
11021static void
11022store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
11023{
ef0d8ffc
NC
11024 unsigned rn = INSTR (14, 10);
11025 unsigned rd = INSTR (9, 5);
11026 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11027 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11028
11029 offset <<= 2;
11030
11031 if (wb != Post)
11032 address += offset;
11033
e101a78b
NC
11034 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, rm, 0));
11035 aarch64_set_mem_u32 (cpu, address + 4, aarch64_get_vec_u32 (cpu, rn, 0));
2e8cf49e
NC
11036
11037 if (wb == Post)
11038 address += offset;
11039
11040 if (wb != NoWriteBack)
11041 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11042}
11043
11044static void
11045store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11046{
ef0d8ffc
NC
11047 unsigned rn = INSTR (14, 10);
11048 unsigned rd = INSTR (9, 5);
11049 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11050 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11051
11052 offset <<= 3;
11053
11054 if (wb != Post)
11055 address += offset;
11056
e101a78b
NC
11057 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, rm, 0));
11058 aarch64_set_mem_u64 (cpu, address + 8, aarch64_get_vec_u64 (cpu, rn, 0));
2e8cf49e
NC
11059
11060 if (wb == Post)
11061 address += offset;
11062
11063 if (wb != NoWriteBack)
11064 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11065}
11066
11067static void
11068store_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11069{
11070 FRegister a;
ef0d8ffc
NC
11071 unsigned rn = INSTR (14, 10);
11072 unsigned rd = INSTR (9, 5);
11073 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11074 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11075
11076 offset <<= 4;
11077
11078 if (wb != Post)
11079 address += offset;
11080
11081 aarch64_get_FP_long_double (cpu, rm, & a);
11082 aarch64_set_mem_long_double (cpu, address, a);
11083 aarch64_get_FP_long_double (cpu, rn, & a);
11084 aarch64_set_mem_long_double (cpu, address + 16, a);
11085
11086 if (wb == Post)
11087 address += offset;
11088
11089 if (wb != NoWriteBack)
11090 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11091}
11092
11093static void
11094load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
11095{
ef0d8ffc
NC
11096 unsigned rn = INSTR (14, 10);
11097 unsigned rd = INSTR (9, 5);
11098 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11099 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11100
11101 if (rm == rn)
11102 HALT_UNALLOC;
11103
11104 offset <<= 2;
11105
11106 if (wb != Post)
11107 address += offset;
11108
e101a78b
NC
11109 aarch64_set_vec_u32 (cpu, rm, 0, aarch64_get_mem_u32 (cpu, address));
11110 aarch64_set_vec_u32 (cpu, rn, 0, aarch64_get_mem_u32 (cpu, address + 4));
2e8cf49e
NC
11111
11112 if (wb == Post)
11113 address += offset;
11114
11115 if (wb != NoWriteBack)
11116 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11117}
11118
11119static void
11120load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11121{
ef0d8ffc
NC
11122 unsigned rn = INSTR (14, 10);
11123 unsigned rd = INSTR (9, 5);
11124 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11125 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11126
11127 if (rm == rn)
11128 HALT_UNALLOC;
11129
11130 offset <<= 3;
11131
11132 if (wb != Post)
11133 address += offset;
11134
e101a78b
NC
11135 aarch64_set_vec_u64 (cpu, rm, 0, aarch64_get_mem_u64 (cpu, address));
11136 aarch64_set_vec_u64 (cpu, rn, 0, aarch64_get_mem_u64 (cpu, address + 8));
2e8cf49e
NC
11137
11138 if (wb == Post)
11139 address += offset;
11140
11141 if (wb != NoWriteBack)
11142 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11143}
11144
11145static void
11146load_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11147{
11148 FRegister a;
ef0d8ffc
NC
11149 unsigned rn = INSTR (14, 10);
11150 unsigned rd = INSTR (9, 5);
11151 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11152 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11153
11154 if (rm == rn)
11155 HALT_UNALLOC;
11156
11157 offset <<= 4;
11158
11159 if (wb != Post)
11160 address += offset;
11161
11162 aarch64_get_mem_long_double (cpu, address, & a);
11163 aarch64_set_FP_long_double (cpu, rm, a);
11164 aarch64_get_mem_long_double (cpu, address + 16, & a);
11165 aarch64_set_FP_long_double (cpu, rn, a);
11166
11167 if (wb == Post)
11168 address += offset;
11169
11170 if (wb != NoWriteBack)
11171 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11172}
11173
11174static void
11175dex_load_store_pair_fp (sim_cpu *cpu)
11176{
11177 /* instr[31,30] = size (10=> 128-bit, 01=> 64-bit, 00=> 32-bit)
11178 instr[29,25] = instruction encoding
11179 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
11180 instr[22] = load/store (1=> load)
11181 instr[21,15] = signed, scaled, offset
11182 instr[14,10] = Rn
11183 instr[ 9, 5] = Rd
11184 instr[ 4, 0] = Rm */
11185
7517e550 11186 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
11187 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
11188
11189 switch (dispatch)
11190 {
11191 case 2: store_pair_float (cpu, offset, Post); return;
11192 case 3: load_pair_float (cpu, offset, Post); return;
11193 case 4: store_pair_float (cpu, offset, NoWriteBack); return;
11194 case 5: load_pair_float (cpu, offset, NoWriteBack); return;
11195 case 6: store_pair_float (cpu, offset, Pre); return;
11196 case 7: load_pair_float (cpu, offset, Pre); return;
11197
11198 case 10: store_pair_double (cpu, offset, Post); return;
11199 case 11: load_pair_double (cpu, offset, Post); return;
11200 case 12: store_pair_double (cpu, offset, NoWriteBack); return;
11201 case 13: load_pair_double (cpu, offset, NoWriteBack); return;
11202 case 14: store_pair_double (cpu, offset, Pre); return;
11203 case 15: load_pair_double (cpu, offset, Pre); return;
11204
11205 case 18: store_pair_long_double (cpu, offset, Post); return;
11206 case 19: load_pair_long_double (cpu, offset, Post); return;
11207 case 20: store_pair_long_double (cpu, offset, NoWriteBack); return;
11208 case 21: load_pair_long_double (cpu, offset, NoWriteBack); return;
11209 case 22: store_pair_long_double (cpu, offset, Pre); return;
11210 case 23: load_pair_long_double (cpu, offset, Pre); return;
11211
11212 default:
11213 HALT_UNALLOC;
11214 }
11215}
11216
11217static inline unsigned
11218vec_reg (unsigned v, unsigned o)
11219{
11220 return (v + o) & 0x3F;
11221}
11222
11223/* Load multiple N-element structures to N consecutive registers. */
11224static void
11225vec_load (sim_cpu *cpu, uint64_t address, unsigned N)
11226{
ef0d8ffc
NC
11227 int all = INSTR (30, 30);
11228 unsigned size = INSTR (11, 10);
11229 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11230 unsigned i;
11231
11232 switch (size)
11233 {
11234 case 0: /* 8-bit operations. */
11235 if (all)
11236 for (i = 0; i < (16 * N); i++)
11237 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15,
11238 aarch64_get_mem_u8 (cpu, address + i));
11239 else
11240 for (i = 0; i < (8 * N); i++)
11241 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7,
11242 aarch64_get_mem_u8 (cpu, address + i));
11243 return;
11244
11245 case 1: /* 16-bit operations. */
11246 if (all)
11247 for (i = 0; i < (8 * N); i++)
11248 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7,
11249 aarch64_get_mem_u16 (cpu, address + i * 2));
11250 else
11251 for (i = 0; i < (4 * N); i++)
11252 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3,
11253 aarch64_get_mem_u16 (cpu, address + i * 2));
11254 return;
11255
11256 case 2: /* 32-bit operations. */
11257 if (all)
11258 for (i = 0; i < (4 * N); i++)
11259 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3,
11260 aarch64_get_mem_u32 (cpu, address + i * 4));
11261 else
11262 for (i = 0; i < (2 * N); i++)
11263 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1,
11264 aarch64_get_mem_u32 (cpu, address + i * 4));
11265 return;
11266
11267 case 3: /* 64-bit operations. */
11268 if (all)
11269 for (i = 0; i < (2 * N); i++)
11270 aarch64_set_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1,
11271 aarch64_get_mem_u64 (cpu, address + i * 8));
11272 else
11273 for (i = 0; i < N; i++)
11274 aarch64_set_vec_u64 (cpu, vec_reg (vd, i), 0,
11275 aarch64_get_mem_u64 (cpu, address + i * 8));
11276 return;
2e8cf49e
NC
11277 }
11278}
11279
11280/* LD4: load multiple 4-element to four consecutive registers. */
11281static void
11282LD4 (sim_cpu *cpu, uint64_t address)
11283{
11284 vec_load (cpu, address, 4);
11285}
11286
11287/* LD3: load multiple 3-element structures to three consecutive registers. */
11288static void
11289LD3 (sim_cpu *cpu, uint64_t address)
11290{
11291 vec_load (cpu, address, 3);
11292}
11293
11294/* LD2: load multiple 2-element structures to two consecutive registers. */
11295static void
11296LD2 (sim_cpu *cpu, uint64_t address)
11297{
11298 vec_load (cpu, address, 2);
11299}
11300
11301/* Load multiple 1-element structures into one register. */
11302static void
11303LD1_1 (sim_cpu *cpu, uint64_t address)
11304{
ef0d8ffc
NC
11305 int all = INSTR (30, 30);
11306 unsigned size = INSTR (11, 10);
11307 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11308 unsigned i;
11309
11310 switch (size)
11311 {
11312 case 0:
11313 /* LD1 {Vd.16b}, addr, #16 */
11314 /* LD1 {Vd.8b}, addr, #8 */
11315 for (i = 0; i < (all ? 16 : 8); i++)
11316 aarch64_set_vec_u8 (cpu, vd, i,
11317 aarch64_get_mem_u8 (cpu, address + i));
11318 return;
11319
11320 case 1:
11321 /* LD1 {Vd.8h}, addr, #16 */
11322 /* LD1 {Vd.4h}, addr, #8 */
11323 for (i = 0; i < (all ? 8 : 4); i++)
11324 aarch64_set_vec_u16 (cpu, vd, i,
11325 aarch64_get_mem_u16 (cpu, address + i * 2));
11326 return;
11327
11328 case 2:
11329 /* LD1 {Vd.4s}, addr, #16 */
11330 /* LD1 {Vd.2s}, addr, #8 */
11331 for (i = 0; i < (all ? 4 : 2); i++)
11332 aarch64_set_vec_u32 (cpu, vd, i,
11333 aarch64_get_mem_u32 (cpu, address + i * 4));
11334 return;
11335
11336 case 3:
11337 /* LD1 {Vd.2d}, addr, #16 */
11338 /* LD1 {Vd.1d}, addr, #8 */
11339 for (i = 0; i < (all ? 2 : 1); i++)
11340 aarch64_set_vec_u64 (cpu, vd, i,
11341 aarch64_get_mem_u64 (cpu, address + i * 8));
11342 return;
2e8cf49e
NC
11343 }
11344}
11345
11346/* Load multiple 1-element structures into two registers. */
11347static void
11348LD1_2 (sim_cpu *cpu, uint64_t address)
11349{
11350 /* FIXME: This algorithm is *exactly* the same as the LD2 version.
11351 So why have two different instructions ? There must be something
11352 wrong somewhere. */
11353 vec_load (cpu, address, 2);
11354}
11355
11356/* Load multiple 1-element structures into three registers. */
11357static void
11358LD1_3 (sim_cpu *cpu, uint64_t address)
11359{
11360 /* FIXME: This algorithm is *exactly* the same as the LD3 version.
11361 So why have two different instructions ? There must be something
11362 wrong somewhere. */
11363 vec_load (cpu, address, 3);
11364}
11365
11366/* Load multiple 1-element structures into four registers. */
11367static void
11368LD1_4 (sim_cpu *cpu, uint64_t address)
11369{
11370 /* FIXME: This algorithm is *exactly* the same as the LD4 version.
11371 So why have two different instructions ? There must be something
11372 wrong somewhere. */
11373 vec_load (cpu, address, 4);
11374}
11375
11376/* Store multiple N-element structures to N consecutive registers. */
11377static void
11378vec_store (sim_cpu *cpu, uint64_t address, unsigned N)
11379{
ef0d8ffc
NC
11380 int all = INSTR (30, 30);
11381 unsigned size = INSTR (11, 10);
11382 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11383 unsigned i;
11384
11385 switch (size)
11386 {
11387 case 0: /* 8-bit operations. */
11388 if (all)
11389 for (i = 0; i < (16 * N); i++)
11390 aarch64_set_mem_u8
11391 (cpu, address + i,
11392 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15));
11393 else
11394 for (i = 0; i < (8 * N); i++)
11395 aarch64_set_mem_u8
11396 (cpu, address + i,
11397 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7));
11398 return;
11399
11400 case 1: /* 16-bit operations. */
11401 if (all)
11402 for (i = 0; i < (8 * N); i++)
11403 aarch64_set_mem_u16
11404 (cpu, address + i * 2,
11405 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7));
11406 else
11407 for (i = 0; i < (4 * N); i++)
11408 aarch64_set_mem_u16
11409 (cpu, address + i * 2,
11410 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3));
11411 return;
11412
11413 case 2: /* 32-bit operations. */
11414 if (all)
11415 for (i = 0; i < (4 * N); i++)
11416 aarch64_set_mem_u32
11417 (cpu, address + i * 4,
11418 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3));
11419 else
11420 for (i = 0; i < (2 * N); i++)
11421 aarch64_set_mem_u32
11422 (cpu, address + i * 4,
11423 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1));
11424 return;
11425
11426 case 3: /* 64-bit operations. */
11427 if (all)
11428 for (i = 0; i < (2 * N); i++)
11429 aarch64_set_mem_u64
11430 (cpu, address + i * 8,
11431 aarch64_get_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1));
11432 else
11433 for (i = 0; i < N; i++)
11434 aarch64_set_mem_u64
11435 (cpu, address + i * 8,
11436 aarch64_get_vec_u64 (cpu, vec_reg (vd, i), 0));
11437 return;
2e8cf49e
NC
11438 }
11439}
11440
11441/* Store multiple 4-element structure to four consecutive registers. */
11442static void
11443ST4 (sim_cpu *cpu, uint64_t address)
11444{
11445 vec_store (cpu, address, 4);
11446}
11447
11448/* Store multiple 3-element structures to three consecutive registers. */
11449static void
11450ST3 (sim_cpu *cpu, uint64_t address)
11451{
11452 vec_store (cpu, address, 3);
11453}
11454
11455/* Store multiple 2-element structures to two consecutive registers. */
11456static void
11457ST2 (sim_cpu *cpu, uint64_t address)
11458{
11459 vec_store (cpu, address, 2);
11460}
11461
11462/* Store multiple 1-element structures into one register. */
11463static void
11464ST1_1 (sim_cpu *cpu, uint64_t address)
11465{
ef0d8ffc
NC
11466 int all = INSTR (30, 30);
11467 unsigned size = INSTR (11, 10);
11468 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11469 unsigned i;
11470
11471 switch (size)
11472 {
11473 case 0:
11474 for (i = 0; i < (all ? 16 : 8); i++)
11475 aarch64_set_mem_u8 (cpu, address + i,
11476 aarch64_get_vec_u8 (cpu, vd, i));
11477 return;
11478
11479 case 1:
11480 for (i = 0; i < (all ? 8 : 4); i++)
11481 aarch64_set_mem_u16 (cpu, address + i * 2,
11482 aarch64_get_vec_u16 (cpu, vd, i));
11483 return;
11484
11485 case 2:
11486 for (i = 0; i < (all ? 4 : 2); i++)
11487 aarch64_set_mem_u32 (cpu, address + i * 4,
11488 aarch64_get_vec_u32 (cpu, vd, i));
11489 return;
11490
11491 case 3:
11492 for (i = 0; i < (all ? 2 : 1); i++)
11493 aarch64_set_mem_u64 (cpu, address + i * 8,
11494 aarch64_get_vec_u64 (cpu, vd, i));
11495 return;
2e8cf49e
NC
11496 }
11497}
11498
11499/* Store multiple 1-element structures into two registers. */
11500static void
11501ST1_2 (sim_cpu *cpu, uint64_t address)
11502{
11503 /* FIXME: This algorithm is *exactly* the same as the ST2 version.
11504 So why have two different instructions ? There must be
11505 something wrong somewhere. */
11506 vec_store (cpu, address, 2);
11507}
11508
11509/* Store multiple 1-element structures into three registers. */
11510static void
11511ST1_3 (sim_cpu *cpu, uint64_t address)
11512{
11513 /* FIXME: This algorithm is *exactly* the same as the ST3 version.
11514 So why have two different instructions ? There must be
11515 something wrong somewhere. */
11516 vec_store (cpu, address, 3);
11517}
11518
11519/* Store multiple 1-element structures into four registers. */
11520static void
11521ST1_4 (sim_cpu *cpu, uint64_t address)
11522{
11523 /* FIXME: This algorithm is *exactly* the same as the ST4 version.
11524 So why have two different instructions ? There must be
11525 something wrong somewhere. */
11526 vec_store (cpu, address, 4);
11527}
11528
11529static void
11530do_vec_LDnR (sim_cpu *cpu, uint64_t address)
11531{
11532 /* instr[31] = 0
11533 instr[30] = element selector 0=>half, 1=>all elements
11534 instr[29,24] = 00 1101
11535 instr[23] = 0=>simple, 1=>post
11536 instr[22] = 1
11537 instr[21] = width: LD1R-or-LD3R (0) / LD2R-or-LD4R (1)
11538 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
11539 11111 (immediate post inc)
11540 instr[15,14] = 11
11541 instr[13] = width: LD1R-or-LD2R (0) / LD3R-or-LD4R (1)
11542 instr[12] = 0
11543 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11544 10=> word(s), 11=> double(d)
11545 instr[9,5] = address
11546 instr[4,0] = Vd */
11547
ef0d8ffc
NC
11548 unsigned full = INSTR (30, 30);
11549 unsigned vd = INSTR (4, 0);
11550 unsigned size = INSTR (11, 10);
2e8cf49e
NC
11551 int i;
11552
11553 NYI_assert (29, 24, 0x0D);
11554 NYI_assert (22, 22, 1);
11555 NYI_assert (15, 14, 3);
11556 NYI_assert (12, 12, 0);
11557
7517e550 11558 switch ((INSTR (13, 13) << 1) | INSTR (21, 21))
2e8cf49e
NC
11559 {
11560 case 0: /* LD1R. */
11561 switch (size)
11562 {
11563 case 0:
11564 {
11565 uint8_t val = aarch64_get_mem_u8 (cpu, address);
11566 for (i = 0; i < (full ? 16 : 8); i++)
11567 aarch64_set_vec_u8 (cpu, vd, i, val);
11568 break;
11569 }
11570
11571 case 1:
11572 {
11573 uint16_t val = aarch64_get_mem_u16 (cpu, address);
11574 for (i = 0; i < (full ? 8 : 4); i++)
11575 aarch64_set_vec_u16 (cpu, vd, i, val);
11576 break;
11577 }
11578
11579 case 2:
11580 {
11581 uint32_t val = aarch64_get_mem_u32 (cpu, address);
11582 for (i = 0; i < (full ? 4 : 2); i++)
11583 aarch64_set_vec_u32 (cpu, vd, i, val);
11584 break;
11585 }
11586
11587 case 3:
11588 {
11589 uint64_t val = aarch64_get_mem_u64 (cpu, address);
11590 for (i = 0; i < (full ? 2 : 1); i++)
11591 aarch64_set_vec_u64 (cpu, vd, i, val);
11592 break;
11593 }
11594
11595 default:
11596 HALT_UNALLOC;
11597 }
11598 break;
11599
11600 case 1: /* LD2R. */
11601 switch (size)
11602 {
11603 case 0:
11604 {
11605 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11606 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11607
11608 for (i = 0; i < (full ? 16 : 8); i++)
11609 {
11610 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11611 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11612 }
11613 break;
11614 }
11615
11616 case 1:
11617 {
11618 uint16_t val1 = aarch64_get_mem_u16 (cpu, address);
11619 uint16_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11620
11621 for (i = 0; i < (full ? 8 : 4); i++)
11622 {
11623 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11624 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11625 }
11626 break;
11627 }
11628
11629 case 2:
11630 {
11631 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11632 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11633
11634 for (i = 0; i < (full ? 4 : 2); i++)
11635 {
11636 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11637 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11638 }
11639 break;
11640 }
11641
11642 case 3:
11643 {
11644 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11645 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11646
11647 for (i = 0; i < (full ? 2 : 1); i++)
11648 {
11649 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11650 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11651 }
11652 break;
11653 }
11654
11655 default:
11656 HALT_UNALLOC;
11657 }
11658 break;
11659
11660 case 2: /* LD3R. */
11661 switch (size)
11662 {
11663 case 0:
11664 {
11665 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11666 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11667 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
11668
11669 for (i = 0; i < (full ? 16 : 8); i++)
11670 {
11671 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11672 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11673 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
11674 }
11675 }
11676 break;
11677
11678 case 1:
11679 {
11680 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
11681 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11682 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
11683
11684 for (i = 0; i < (full ? 8 : 4); i++)
11685 {
11686 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11687 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11688 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
11689 }
11690 }
11691 break;
11692
11693 case 2:
11694 {
11695 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11696 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11697 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
11698
11699 for (i = 0; i < (full ? 4 : 2); i++)
11700 {
11701 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11702 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11703 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
11704 }
11705 }
11706 break;
11707
11708 case 3:
11709 {
11710 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11711 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11712 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
11713
11714 for (i = 0; i < (full ? 2 : 1); i++)
11715 {
11716 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11717 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11718 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
11719 }
11720 }
11721 break;
11722
11723 default:
11724 HALT_UNALLOC;
11725 }
11726 break;
11727
11728 case 3: /* LD4R. */
11729 switch (size)
11730 {
11731 case 0:
11732 {
11733 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11734 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11735 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
11736 uint8_t val4 = aarch64_get_mem_u8 (cpu, address + 3);
11737
11738 for (i = 0; i < (full ? 16 : 8); i++)
11739 {
11740 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11741 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11742 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
11743 aarch64_set_vec_u8 (cpu, vd + 3, 0, val4);
11744 }
11745 }
11746 break;
11747
11748 case 1:
11749 {
11750 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
11751 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11752 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
11753 uint32_t val4 = aarch64_get_mem_u16 (cpu, address + 6);
11754
11755 for (i = 0; i < (full ? 8 : 4); i++)
11756 {
11757 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11758 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11759 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
11760 aarch64_set_vec_u16 (cpu, vd + 3, 0, val4);
11761 }
11762 }
11763 break;
11764
11765 case 2:
11766 {
11767 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11768 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11769 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
11770 uint32_t val4 = aarch64_get_mem_u32 (cpu, address + 12);
11771
11772 for (i = 0; i < (full ? 4 : 2); i++)
11773 {
11774 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11775 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11776 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
11777 aarch64_set_vec_u32 (cpu, vd + 3, 0, val4);
11778 }
11779 }
11780 break;
11781
11782 case 3:
11783 {
11784 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11785 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11786 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
11787 uint64_t val4 = aarch64_get_mem_u64 (cpu, address + 24);
11788
11789 for (i = 0; i < (full ? 2 : 1); i++)
11790 {
11791 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11792 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11793 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
11794 aarch64_set_vec_u64 (cpu, vd + 3, 0, val4);
11795 }
11796 }
11797 break;
11798
11799 default:
11800 HALT_UNALLOC;
11801 }
11802 break;
11803
11804 default:
11805 HALT_UNALLOC;
11806 }
11807}
11808
11809static void
11810do_vec_load_store (sim_cpu *cpu)
11811{
11812 /* {LD|ST}<N> {Vd..Vd+N}, vaddr
11813
11814 instr[31] = 0
11815 instr[30] = element selector 0=>half, 1=>all elements
11816 instr[29,25] = 00110
11817 instr[24] = ?
11818 instr[23] = 0=>simple, 1=>post
11819 instr[22] = 0=>store, 1=>load
11820 instr[21] = 0 (LDn) / small(0)-large(1) selector (LDnR)
11821 instr[20,16] = 00000 (simple), Vinc (reg-post-inc, no SP),
11822 11111 (immediate post inc)
11823 instr[15,12] = elements and destinations. eg for load:
11824 0000=>LD4 => load multiple 4-element to
11825 four consecutive registers
11826 0100=>LD3 => load multiple 3-element to
11827 three consecutive registers
11828 1000=>LD2 => load multiple 2-element to
11829 two consecutive registers
11830 0010=>LD1 => load multiple 1-element to
11831 four consecutive registers
11832 0110=>LD1 => load multiple 1-element to
11833 three consecutive registers
11834 1010=>LD1 => load multiple 1-element to
11835 two consecutive registers
11836 0111=>LD1 => load multiple 1-element to
11837 one register
11838 1100=>LDR1,LDR2
11839 1110=>LDR3,LDR4
11840 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11841 10=> word(s), 11=> double(d)
11842 instr[9,5] = Vn, can be SP
11843 instr[4,0] = Vd */
11844
11845 int post;
11846 int load;
11847 unsigned vn;
11848 uint64_t address;
11849 int type;
11850
7517e550 11851 if (INSTR (31, 31) != 0 || INSTR (29, 25) != 0x06)
2e8cf49e
NC
11852 HALT_NYI;
11853
ef0d8ffc
NC
11854 type = INSTR (15, 12);
11855 if (type != 0xE && type != 0xE && INSTR (21, 21) != 0)
2e8cf49e
NC
11856 HALT_NYI;
11857
ef0d8ffc
NC
11858 post = INSTR (23, 23);
11859 load = INSTR (22, 22);
11860 vn = INSTR (9, 5);
2e8cf49e
NC
11861 address = aarch64_get_reg_u64 (cpu, vn, SP_OK);
11862
11863 if (post)
11864 {
ef0d8ffc 11865 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
11866
11867 if (vm == R31)
11868 {
11869 unsigned sizeof_operation;
11870
11871 switch (type)
11872 {
11873 case 0: sizeof_operation = 32; break;
11874 case 4: sizeof_operation = 24; break;
11875 case 8: sizeof_operation = 16; break;
11876
11877 case 0xC:
ef0d8ffc
NC
11878 sizeof_operation = INSTR (21, 21) ? 2 : 1;
11879 sizeof_operation <<= INSTR (11, 10);
2e8cf49e
NC
11880 break;
11881
11882 case 0xE:
ef0d8ffc
NC
11883 sizeof_operation = INSTR (21, 21) ? 8 : 4;
11884 sizeof_operation <<= INSTR (11, 10);
2e8cf49e
NC
11885 break;
11886
2e8cf49e 11887 case 7:
57aa1742
NC
11888 /* One register, immediate offset variant. */
11889 sizeof_operation = 8;
11890 break;
ef0d8ffc 11891
57aa1742
NC
11892 case 10:
11893 /* Two registers, immediate offset variant. */
11894 sizeof_operation = 16;
11895 break;
11896
11897 case 6:
11898 /* Three registers, immediate offset variant. */
11899 sizeof_operation = 24;
11900 break;
11901
11902 case 2:
11903 /* Four registers, immediate offset variant. */
11904 sizeof_operation = 32;
2e8cf49e
NC
11905 break;
11906
11907 default:
11908 HALT_UNALLOC;
11909 }
11910
ef0d8ffc 11911 if (INSTR (30, 30))
2e8cf49e
NC
11912 sizeof_operation *= 2;
11913
11914 aarch64_set_reg_u64 (cpu, vn, SP_OK, address + sizeof_operation);
11915 }
11916 else
11917 aarch64_set_reg_u64 (cpu, vn, SP_OK,
11918 address + aarch64_get_reg_u64 (cpu, vm, NO_SP));
11919 }
11920 else
11921 {
11922 NYI_assert (20, 16, 0);
11923 }
11924
11925 if (load)
11926 {
11927 switch (type)
11928 {
11929 case 0: LD4 (cpu, address); return;
11930 case 4: LD3 (cpu, address); return;
11931 case 8: LD2 (cpu, address); return;
11932 case 2: LD1_4 (cpu, address); return;
11933 case 6: LD1_3 (cpu, address); return;
11934 case 10: LD1_2 (cpu, address); return;
11935 case 7: LD1_1 (cpu, address); return;
11936
11937 case 0xE:
11938 case 0xC: do_vec_LDnR (cpu, address); return;
11939
11940 default:
11941 HALT_NYI;
11942 }
11943 }
11944
11945 /* Stores. */
11946 switch (type)
11947 {
11948 case 0: ST4 (cpu, address); return;
11949 case 4: ST3 (cpu, address); return;
11950 case 8: ST2 (cpu, address); return;
11951 case 2: ST1_4 (cpu, address); return;
11952 case 6: ST1_3 (cpu, address); return;
11953 case 10: ST1_2 (cpu, address); return;
11954 case 7: ST1_1 (cpu, address); return;
11955 default:
11956 HALT_NYI;
11957 }
11958}
11959
11960static void
11961dexLdSt (sim_cpu *cpu)
11962{
11963 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
11964 assert group == GROUP_LDST_0100 || group == GROUP_LDST_0110 ||
11965 group == GROUP_LDST_1100 || group == GROUP_LDST_1110
11966 bits [29,28:26] of a LS are the secondary dispatch vector. */
11967 uint32_t group2 = dispatchLS (aarch64_get_instr (cpu));
11968
11969 switch (group2)
11970 {
11971 case LS_EXCL_000:
11972 dexLoadExclusive (cpu); return;
11973
11974 case LS_LIT_010:
11975 case LS_LIT_011:
11976 dexLoadLiteral (cpu); return;
11977
11978 case LS_OTHER_110:
11979 case LS_OTHER_111:
11980 dexLoadOther (cpu); return;
11981
11982 case LS_ADVSIMD_001:
11983 do_vec_load_store (cpu); return;
11984
11985 case LS_PAIR_100:
11986 dex_load_store_pair_gr (cpu); return;
11987
11988 case LS_PAIR_101:
11989 dex_load_store_pair_fp (cpu); return;
11990
11991 default:
11992 /* Should never reach here. */
11993 HALT_NYI;
11994 }
11995}
11996
11997/* Specific decode and execute for group Data Processing Register. */
11998
11999static void
12000dexLogicalShiftedRegister (sim_cpu *cpu)
12001{
ef0d8ffc
NC
12002 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12003 instr[30,29] = op
12004 instr[28:24] = 01010
2e8cf49e 12005 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> ROR
ef0d8ffc
NC
12006 instr[21] = N
12007 instr[20,16] = Rm
2e8cf49e 12008 instr[15,10] = count : must be 0xxxxx for 32 bit
ef0d8ffc
NC
12009 instr[9,5] = Rn
12010 instr[4,0] = Rd */
2e8cf49e 12011
ef0d8ffc
NC
12012 uint32_t size = INSTR (31, 31);
12013 Shift shiftType = INSTR (23, 22);
12014 uint32_t count = INSTR (15, 10);
2e8cf49e 12015
ef0d8ffc
NC
12016 /* 32 bit operations must have count[5] = 0.
12017 or else we have an UNALLOC. */
12018 if (size == 0 && uimm (count, 5, 5))
2e8cf49e
NC
12019 HALT_UNALLOC;
12020
ef0d8ffc
NC
12021 /* Dispatch on size:op:N. */
12022 switch ((INSTR (31, 29) << 1) | INSTR (21, 21))
2e8cf49e
NC
12023 {
12024 case 0: and32_shift (cpu, shiftType, count); return;
12025 case 1: bic32_shift (cpu, shiftType, count); return;
12026 case 2: orr32_shift (cpu, shiftType, count); return;
12027 case 3: orn32_shift (cpu, shiftType, count); return;
12028 case 4: eor32_shift (cpu, shiftType, count); return;
12029 case 5: eon32_shift (cpu, shiftType, count); return;
12030 case 6: ands32_shift (cpu, shiftType, count); return;
12031 case 7: bics32_shift (cpu, shiftType, count); return;
12032 case 8: and64_shift (cpu, shiftType, count); return;
12033 case 9: bic64_shift (cpu, shiftType, count); return;
12034 case 10:orr64_shift (cpu, shiftType, count); return;
12035 case 11:orn64_shift (cpu, shiftType, count); return;
12036 case 12:eor64_shift (cpu, shiftType, count); return;
12037 case 13:eon64_shift (cpu, shiftType, count); return;
12038 case 14:ands64_shift (cpu, shiftType, count); return;
12039 case 15:bics64_shift (cpu, shiftType, count); return;
2e8cf49e
NC
12040 }
12041}
12042
12043/* 32 bit conditional select. */
12044static void
12045csel32 (sim_cpu *cpu, CondCode cc)
12046{
ef0d8ffc
NC
12047 unsigned rm = INSTR (20, 16);
12048 unsigned rn = INSTR (9, 5);
12049 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12050
12051 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12052 testConditionCode (cpu, cc)
12053 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12054 : aarch64_get_reg_u32 (cpu, rm, NO_SP));
12055}
12056
12057/* 64 bit conditional select. */
12058static void
12059csel64 (sim_cpu *cpu, CondCode cc)
12060{
ef0d8ffc
NC
12061 unsigned rm = INSTR (20, 16);
12062 unsigned rn = INSTR (9, 5);
12063 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12064
12065 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12066 testConditionCode (cpu, cc)
12067 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12068 : aarch64_get_reg_u64 (cpu, rm, NO_SP));
12069}
12070
12071/* 32 bit conditional increment. */
12072static void
12073csinc32 (sim_cpu *cpu, CondCode cc)
12074{
ef0d8ffc
NC
12075 unsigned rm = INSTR (20, 16);
12076 unsigned rn = INSTR (9, 5);
12077 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12078
12079 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12080 testConditionCode (cpu, cc)
12081 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12082 : aarch64_get_reg_u32 (cpu, rm, NO_SP) + 1);
12083}
12084
12085/* 64 bit conditional increment. */
12086static void
12087csinc64 (sim_cpu *cpu, CondCode cc)
12088{
ef0d8ffc
NC
12089 unsigned rm = INSTR (20, 16);
12090 unsigned rn = INSTR (9, 5);
12091 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12092
12093 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12094 testConditionCode (cpu, cc)
12095 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12096 : aarch64_get_reg_u64 (cpu, rm, NO_SP) + 1);
12097}
12098
12099/* 32 bit conditional invert. */
12100static void
12101csinv32 (sim_cpu *cpu, CondCode cc)
12102{
ef0d8ffc
NC
12103 unsigned rm = INSTR (20, 16);
12104 unsigned rn = INSTR (9, 5);
12105 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12106
12107 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12108 testConditionCode (cpu, cc)
12109 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12110 : ~ aarch64_get_reg_u32 (cpu, rm, NO_SP));
12111}
12112
12113/* 64 bit conditional invert. */
12114static void
12115csinv64 (sim_cpu *cpu, CondCode cc)
12116{
ef0d8ffc
NC
12117 unsigned rm = INSTR (20, 16);
12118 unsigned rn = INSTR (9, 5);
12119 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12120
12121 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12122 testConditionCode (cpu, cc)
12123 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12124 : ~ aarch64_get_reg_u64 (cpu, rm, NO_SP));
12125}
12126
12127/* 32 bit conditional negate. */
12128static void
12129csneg32 (sim_cpu *cpu, CondCode cc)
12130{
ef0d8ffc
NC
12131 unsigned rm = INSTR (20, 16);
12132 unsigned rn = INSTR (9, 5);
12133 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12134
12135 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12136 testConditionCode (cpu, cc)
12137 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12138 : - aarch64_get_reg_u32 (cpu, rm, NO_SP));
12139}
12140
12141/* 64 bit conditional negate. */
12142static void
12143csneg64 (sim_cpu *cpu, CondCode cc)
12144{
ef0d8ffc
NC
12145 unsigned rm = INSTR (20, 16);
12146 unsigned rn = INSTR (9, 5);
12147 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12148
12149 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12150 testConditionCode (cpu, cc)
12151 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12152 : - aarch64_get_reg_u64 (cpu, rm, NO_SP));
12153}
12154
12155static void
12156dexCondSelect (sim_cpu *cpu)
12157{
ef0d8ffc
NC
12158 /* instr[28,21] = 11011011
12159 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2e8cf49e
NC
12160 instr[30:11,10] = op : 000 ==> CSEL, 001 ==> CSINC,
12161 100 ==> CSINV, 101 ==> CSNEG,
12162 _1_ ==> UNALLOC
12163 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
12164 instr[15,12] = cond
12165 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC */
12166
ef0d8ffc
NC
12167 CondCode cc = INSTR (15, 12);
12168 uint32_t S = INSTR (29, 29);
12169 uint32_t op2 = INSTR (11, 10);
2e8cf49e
NC
12170
12171 if (S == 1)
12172 HALT_UNALLOC;
12173
12174 if (op2 & 0x2)
12175 HALT_UNALLOC;
12176
ef0d8ffc 12177 switch ((INSTR (31, 30) << 1) | op2)
2e8cf49e
NC
12178 {
12179 case 0: csel32 (cpu, cc); return;
12180 case 1: csinc32 (cpu, cc); return;
12181 case 2: csinv32 (cpu, cc); return;
12182 case 3: csneg32 (cpu, cc); return;
12183 case 4: csel64 (cpu, cc); return;
12184 case 5: csinc64 (cpu, cc); return;
12185 case 6: csinv64 (cpu, cc); return;
12186 case 7: csneg64 (cpu, cc); return;
2e8cf49e
NC
12187 }
12188}
12189
12190/* Some helpers for counting leading 1 or 0 bits. */
12191
12192/* Counts the number of leading bits which are the same
12193 in a 32 bit value in the range 1 to 32. */
12194static uint32_t
12195leading32 (uint32_t value)
12196{
12197 int32_t mask= 0xffff0000;
12198 uint32_t count= 16; /* Counts number of bits set in mask. */
12199 uint32_t lo = 1; /* Lower bound for number of sign bits. */
12200 uint32_t hi = 32; /* Upper bound for number of sign bits. */
12201
12202 while (lo + 1 < hi)
12203 {
12204 int32_t test = (value & mask);
12205
12206 if (test == 0 || test == mask)
12207 {
12208 lo = count;
12209 count = (lo + hi) / 2;
12210 mask >>= (count - lo);
12211 }
12212 else
12213 {
12214 hi = count;
12215 count = (lo + hi) / 2;
12216 mask <<= hi - count;
12217 }
12218 }
12219
12220 if (lo != hi)
12221 {
12222 int32_t test;
12223
12224 mask >>= 1;
12225 test = (value & mask);
12226
12227 if (test == 0 || test == mask)
12228 count = hi;
12229 else
12230 count = lo;
12231 }
12232
12233 return count;
12234}
12235
12236/* Counts the number of leading bits which are the same
12237 in a 64 bit value in the range 1 to 64. */
12238static uint64_t
12239leading64 (uint64_t value)
12240{
12241 int64_t mask= 0xffffffff00000000LL;
12242 uint64_t count = 32; /* Counts number of bits set in mask. */
12243 uint64_t lo = 1; /* Lower bound for number of sign bits. */
12244 uint64_t hi = 64; /* Upper bound for number of sign bits. */
12245
12246 while (lo + 1 < hi)
12247 {
12248 int64_t test = (value & mask);
12249
12250 if (test == 0 || test == mask)
12251 {
12252 lo = count;
12253 count = (lo + hi) / 2;
12254 mask >>= (count - lo);
12255 }
12256 else
12257 {
12258 hi = count;
12259 count = (lo + hi) / 2;
12260 mask <<= hi - count;
12261 }
12262 }
12263
12264 if (lo != hi)
12265 {
12266 int64_t test;
12267
12268 mask >>= 1;
12269 test = (value & mask);
12270
12271 if (test == 0 || test == mask)
12272 count = hi;
12273 else
12274 count = lo;
12275 }
12276
12277 return count;
12278}
12279
12280/* Bit operations. */
12281/* N.B register args may not be SP. */
12282
12283/* 32 bit count leading sign bits. */
12284static void
12285cls32 (sim_cpu *cpu)
12286{
ef0d8ffc
NC
12287 unsigned rn = INSTR (9, 5);
12288 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12289
12290 /* N.B. the result needs to exclude the leading bit. */
12291 aarch64_set_reg_u64
12292 (cpu, rd, NO_SP, leading32 (aarch64_get_reg_u32 (cpu, rn, NO_SP)) - 1);
12293}
12294
12295/* 64 bit count leading sign bits. */
12296static void
12297cls64 (sim_cpu *cpu)
12298{
ef0d8ffc
NC
12299 unsigned rn = INSTR (9, 5);
12300 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12301
12302 /* N.B. the result needs to exclude the leading bit. */
12303 aarch64_set_reg_u64
12304 (cpu, rd, NO_SP, leading64 (aarch64_get_reg_u64 (cpu, rn, NO_SP)) - 1);
12305}
12306
12307/* 32 bit count leading zero bits. */
12308static void
12309clz32 (sim_cpu *cpu)
12310{
ef0d8ffc
NC
12311 unsigned rn = INSTR (9, 5);
12312 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12313 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12314
12315 /* if the sign (top) bit is set then the count is 0. */
12316 if (pick32 (value, 31, 31))
12317 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
12318 else
12319 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading32 (value));
12320}
12321
12322/* 64 bit count leading zero bits. */
12323static void
12324clz64 (sim_cpu *cpu)
12325{
ef0d8ffc
NC
12326 unsigned rn = INSTR (9, 5);
12327 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12328 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12329
12330 /* if the sign (top) bit is set then the count is 0. */
12331 if (pick64 (value, 63, 63))
12332 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
12333 else
12334 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading64 (value));
12335}
12336
12337/* 32 bit reverse bits. */
12338static void
12339rbit32 (sim_cpu *cpu)
12340{
ef0d8ffc
NC
12341 unsigned rn = INSTR (9, 5);
12342 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12343 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12344 uint32_t result = 0;
12345 int i;
12346
12347 for (i = 0; i < 32; i++)
12348 {
12349 result <<= 1;
12350 result |= (value & 1);
12351 value >>= 1;
12352 }
12353 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12354}
12355
12356/* 64 bit reverse bits. */
12357static void
12358rbit64 (sim_cpu *cpu)
12359{
ef0d8ffc
NC
12360 unsigned rn = INSTR (9, 5);
12361 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12362 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12363 uint64_t result = 0;
12364 int i;
12365
12366 for (i = 0; i < 64; i++)
12367 {
12368 result <<= 1;
57aa1742 12369 result |= (value & 1UL);
2e8cf49e
NC
12370 value >>= 1;
12371 }
12372 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12373}
12374
12375/* 32 bit reverse bytes. */
12376static void
12377rev32 (sim_cpu *cpu)
12378{
ef0d8ffc
NC
12379 unsigned rn = INSTR (9, 5);
12380 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12381 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12382 uint32_t result = 0;
12383 int i;
12384
12385 for (i = 0; i < 4; i++)
12386 {
12387 result <<= 8;
12388 result |= (value & 0xff);
12389 value >>= 8;
12390 }
12391 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12392}
12393
12394/* 64 bit reverse bytes. */
12395static void
12396rev64 (sim_cpu *cpu)
12397{
ef0d8ffc
NC
12398 unsigned rn = INSTR (9, 5);
12399 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12400 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12401 uint64_t result = 0;
12402 int i;
12403
12404 for (i = 0; i < 8; i++)
12405 {
12406 result <<= 8;
12407 result |= (value & 0xffULL);
12408 value >>= 8;
12409 }
12410 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12411}
12412
12413/* 32 bit reverse shorts. */
12414/* N.B.this reverses the order of the bytes in each half word. */
12415static void
12416revh32 (sim_cpu *cpu)
12417{
ef0d8ffc
NC
12418 unsigned rn = INSTR (9, 5);
12419 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12420 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12421 uint32_t result = 0;
12422 int i;
12423
12424 for (i = 0; i < 2; i++)
12425 {
12426 result <<= 8;
12427 result |= (value & 0x00ff00ff);
12428 value >>= 8;
12429 }
12430 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12431}
12432
12433/* 64 bit reverse shorts. */
12434/* N.B.this reverses the order of the bytes in each half word. */
12435static void
12436revh64 (sim_cpu *cpu)
12437{
ef0d8ffc
NC
12438 unsigned rn = INSTR (9, 5);
12439 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12440 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12441 uint64_t result = 0;
12442 int i;
12443
12444 for (i = 0; i < 2; i++)
12445 {
12446 result <<= 8;
12447 result |= (value & 0x00ff00ff00ff00ffULL);
12448 value >>= 8;
12449 }
12450 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12451}
12452
12453static void
12454dexDataProc1Source (sim_cpu *cpu)
12455{
ef0d8ffc
NC
12456 /* instr[30] = 1
12457 instr[28,21] = 111010110
12458 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12459 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
2e8cf49e
NC
12460 instr[20,16] = opcode2 : 00000 ==> ok, ow ==> UNALLOC
12461 instr[15,10] = opcode : 000000 ==> RBIT, 000001 ==> REV16,
12462 000010 ==> REV, 000011 ==> UNALLOC
12463 000100 ==> CLZ, 000101 ==> CLS
12464 ow ==> UNALLOC
ef0d8ffc
NC
12465 instr[9,5] = rn : may not be SP
12466 instr[4,0] = rd : may not be SP. */
2e8cf49e 12467
ef0d8ffc
NC
12468 uint32_t S = INSTR (29, 29);
12469 uint32_t opcode2 = INSTR (20, 16);
12470 uint32_t opcode = INSTR (15, 10);
12471 uint32_t dispatch = ((INSTR (31, 31) << 3) | opcode);
2e8cf49e
NC
12472
12473 if (S == 1)
12474 HALT_UNALLOC;
12475
12476 if (opcode2 != 0)
12477 HALT_UNALLOC;
12478
12479 if (opcode & 0x38)
12480 HALT_UNALLOC;
12481
12482 switch (dispatch)
12483 {
12484 case 0: rbit32 (cpu); return;
12485 case 1: revh32 (cpu); return;
12486 case 2: rev32 (cpu); return;
12487 case 4: clz32 (cpu); return;
12488 case 5: cls32 (cpu); return;
12489 case 8: rbit64 (cpu); return;
12490 case 9: revh64 (cpu); return;
12491 case 10:rev32 (cpu); return;
12492 case 11:rev64 (cpu); return;
12493 case 12:clz64 (cpu); return;
12494 case 13:cls64 (cpu); return;
12495 default: HALT_UNALLOC;
12496 }
12497}
12498
12499/* Variable shift.
12500 Shifts by count supplied in register.
12501 N.B register args may not be SP.
12502 These all use the shifted auxiliary function for
12503 simplicity and clarity. Writing the actual shift
12504 inline would avoid a branch and so be faster but
12505 would also necessitate getting signs right. */
12506
12507/* 32 bit arithmetic shift right. */
12508static void
12509asrv32 (sim_cpu *cpu)
12510{
ef0d8ffc
NC
12511 unsigned rm = INSTR (20, 16);
12512 unsigned rn = INSTR (9, 5);
12513 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12514
12515 aarch64_set_reg_u64
12516 (cpu, rd, NO_SP,
12517 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ASR,
12518 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12519}
12520
12521/* 64 bit arithmetic shift right. */
12522static void
12523asrv64 (sim_cpu *cpu)
12524{
ef0d8ffc
NC
12525 unsigned rm = INSTR (20, 16);
12526 unsigned rn = INSTR (9, 5);
12527 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12528
12529 aarch64_set_reg_u64
12530 (cpu, rd, NO_SP,
12531 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ASR,
12532 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12533}
12534
12535/* 32 bit logical shift left. */
12536static void
12537lslv32 (sim_cpu *cpu)
12538{
ef0d8ffc
NC
12539 unsigned rm = INSTR (20, 16);
12540 unsigned rn = INSTR (9, 5);
12541 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12542
12543 aarch64_set_reg_u64
12544 (cpu, rd, NO_SP,
12545 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSL,
12546 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12547}
12548
12549/* 64 bit arithmetic shift left. */
12550static void
12551lslv64 (sim_cpu *cpu)
12552{
ef0d8ffc
NC
12553 unsigned rm = INSTR (20, 16);
12554 unsigned rn = INSTR (9, 5);
12555 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12556
12557 aarch64_set_reg_u64
12558 (cpu, rd, NO_SP,
12559 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSL,
12560 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12561}
12562
12563/* 32 bit logical shift right. */
12564static void
12565lsrv32 (sim_cpu *cpu)
12566{
ef0d8ffc
NC
12567 unsigned rm = INSTR (20, 16);
12568 unsigned rn = INSTR (9, 5);
12569 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12570
12571 aarch64_set_reg_u64
12572 (cpu, rd, NO_SP,
12573 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSR,
12574 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12575}
12576
12577/* 64 bit logical shift right. */
12578static void
12579lsrv64 (sim_cpu *cpu)
12580{
ef0d8ffc
NC
12581 unsigned rm = INSTR (20, 16);
12582 unsigned rn = INSTR (9, 5);
12583 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12584
12585 aarch64_set_reg_u64
12586 (cpu, rd, NO_SP,
12587 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSR,
12588 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12589}
12590
12591/* 32 bit rotate right. */
12592static void
12593rorv32 (sim_cpu *cpu)
12594{
ef0d8ffc
NC
12595 unsigned rm = INSTR (20, 16);
12596 unsigned rn = INSTR (9, 5);
12597 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12598
12599 aarch64_set_reg_u64
12600 (cpu, rd, NO_SP,
12601 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ROR,
12602 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12603}
12604
12605/* 64 bit rotate right. */
12606static void
12607rorv64 (sim_cpu *cpu)
12608{
ef0d8ffc
NC
12609 unsigned rm = INSTR (20, 16);
12610 unsigned rn = INSTR (9, 5);
12611 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12612
12613 aarch64_set_reg_u64
12614 (cpu, rd, NO_SP,
12615 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ROR,
12616 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12617}
12618
12619
12620/* divide. */
12621
12622/* 32 bit signed divide. */
12623static void
12624cpuiv32 (sim_cpu *cpu)
12625{
ef0d8ffc
NC
12626 unsigned rm = INSTR (20, 16);
12627 unsigned rn = INSTR (9, 5);
12628 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12629 /* N.B. the pseudo-code does the divide using 64 bit data. */
12630 /* TODO : check that this rounds towards zero as required. */
12631 int64_t dividend = aarch64_get_reg_s32 (cpu, rn, NO_SP);
12632 int64_t divisor = aarch64_get_reg_s32 (cpu, rm, NO_SP);
12633
12634 aarch64_set_reg_s64 (cpu, rd, NO_SP,
12635 divisor ? ((int32_t) (dividend / divisor)) : 0);
12636}
12637
12638/* 64 bit signed divide. */
12639static void
12640cpuiv64 (sim_cpu *cpu)
12641{
ef0d8ffc
NC
12642 unsigned rm = INSTR (20, 16);
12643 unsigned rn = INSTR (9, 5);
12644 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12645
12646 /* TODO : check that this rounds towards zero as required. */
12647 int64_t divisor = aarch64_get_reg_s64 (cpu, rm, NO_SP);
12648
12649 aarch64_set_reg_s64
12650 (cpu, rd, NO_SP,
12651 divisor ? (aarch64_get_reg_s64 (cpu, rn, NO_SP) / divisor) : 0);
12652}
12653
12654/* 32 bit unsigned divide. */
12655static void
12656udiv32 (sim_cpu *cpu)
12657{
ef0d8ffc
NC
12658 unsigned rm = INSTR (20, 16);
12659 unsigned rn = INSTR (9, 5);
12660 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12661
12662 /* N.B. the pseudo-code does the divide using 64 bit data. */
12663 uint64_t dividend = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12664 uint64_t divisor = aarch64_get_reg_u32 (cpu, rm, NO_SP);
12665
12666 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12667 divisor ? (uint32_t) (dividend / divisor) : 0);
12668}
12669
12670/* 64 bit unsigned divide. */
12671static void
12672udiv64 (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
12678 /* TODO : check that this rounds towards zero as required. */
12679 uint64_t divisor = aarch64_get_reg_u64 (cpu, rm, NO_SP);
12680
12681 aarch64_set_reg_u64
12682 (cpu, rd, NO_SP,
12683 divisor ? (aarch64_get_reg_u64 (cpu, rn, NO_SP) / divisor) : 0);
12684}
12685
12686static void
12687dexDataProc2Source (sim_cpu *cpu)
12688{
12689 /* assert instr[30] == 0
12690 instr[28,21] == 11010110
12691 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12692 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
12693 instr[15,10] = opcode : 000010 ==> UDIV, 000011 ==> CPUIV,
12694 001000 ==> LSLV, 001001 ==> LSRV
12695 001010 ==> ASRV, 001011 ==> RORV
12696 ow ==> UNALLOC. */
12697
12698 uint32_t dispatch;
ef0d8ffc
NC
12699 uint32_t S = INSTR (29, 29);
12700 uint32_t opcode = INSTR (15, 10);
2e8cf49e
NC
12701
12702 if (S == 1)
12703 HALT_UNALLOC;
12704
12705 if (opcode & 0x34)
12706 HALT_UNALLOC;
12707
ef0d8ffc 12708 dispatch = ( (INSTR (31, 31) << 3)
2e8cf49e
NC
12709 | (uimm (opcode, 3, 3) << 2)
12710 | uimm (opcode, 1, 0));
12711 switch (dispatch)
12712 {
12713 case 2: udiv32 (cpu); return;
12714 case 3: cpuiv32 (cpu); return;
12715 case 4: lslv32 (cpu); return;
12716 case 5: lsrv32 (cpu); return;
12717 case 6: asrv32 (cpu); return;
12718 case 7: rorv32 (cpu); return;
12719 case 10: udiv64 (cpu); return;
12720 case 11: cpuiv64 (cpu); return;
12721 case 12: lslv64 (cpu); return;
12722 case 13: lsrv64 (cpu); return;
12723 case 14: asrv64 (cpu); return;
12724 case 15: rorv64 (cpu); return;
12725 default: HALT_UNALLOC;
12726 }
12727}
12728
12729
12730/* Multiply. */
12731
12732/* 32 bit multiply and add. */
12733static void
12734madd32 (sim_cpu *cpu)
12735{
ef0d8ffc
NC
12736 unsigned rm = INSTR (20, 16);
12737 unsigned ra = INSTR (14, 10);
12738 unsigned rn = INSTR (9, 5);
12739 unsigned rd = INSTR (4, 0);
2e8cf49e 12740
2cdad34c 12741 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12742 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12743 aarch64_get_reg_u32 (cpu, ra, NO_SP)
12744 + aarch64_get_reg_u32 (cpu, rn, NO_SP)
12745 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
12746}
12747
12748/* 64 bit multiply and add. */
12749static void
12750madd64 (sim_cpu *cpu)
12751{
ef0d8ffc
NC
12752 unsigned rm = INSTR (20, 16);
12753 unsigned ra = INSTR (14, 10);
12754 unsigned rn = INSTR (9, 5);
12755 unsigned rd = INSTR (4, 0);
2e8cf49e 12756
2cdad34c 12757 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12758 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12759 aarch64_get_reg_u64 (cpu, ra, NO_SP)
2cdad34c
NC
12760 + (aarch64_get_reg_u64 (cpu, rn, NO_SP)
12761 * aarch64_get_reg_u64 (cpu, rm, NO_SP)));
2e8cf49e
NC
12762}
12763
12764/* 32 bit multiply and sub. */
12765static void
12766msub32 (sim_cpu *cpu)
12767{
ef0d8ffc
NC
12768 unsigned rm = INSTR (20, 16);
12769 unsigned ra = INSTR (14, 10);
12770 unsigned rn = INSTR (9, 5);
12771 unsigned rd = INSTR (4, 0);
2e8cf49e 12772
2cdad34c 12773 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12774 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12775 aarch64_get_reg_u32 (cpu, ra, NO_SP)
12776 - aarch64_get_reg_u32 (cpu, rn, NO_SP)
12777 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
12778}
12779
12780/* 64 bit multiply and sub. */
12781static void
12782msub64 (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_u64 (cpu, ra, NO_SP)
12792 - aarch64_get_reg_u64 (cpu, rn, NO_SP)
12793 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
12794}
12795
12796/* Signed multiply add long -- source, source2 : 32 bit, source3 : 64 bit. */
12797static void
12798smaddl (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
NC
12804
12805 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12806 obtain a 64 bit product. */
12807 aarch64_set_reg_s64
12808 (cpu, rd, NO_SP,
12809 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12810 + ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12811 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12812}
12813
12814/* Signed multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12815static void
12816smsubl (sim_cpu *cpu)
12817{
ef0d8ffc
NC
12818 unsigned rm = INSTR (20, 16);
12819 unsigned ra = INSTR (14, 10);
12820 unsigned rn = INSTR (9, 5);
12821 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12822
12823 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12824 obtain a 64 bit product. */
12825 aarch64_set_reg_s64
12826 (cpu, rd, NO_SP,
12827 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12828 - ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12829 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12830}
12831
12832/* Integer Multiply/Divide. */
12833
12834/* First some macros and a helper function. */
12835/* Macros to test or access elements of 64 bit words. */
12836
12837/* Mask used to access lo 32 bits of 64 bit unsigned int. */
12838#define LOW_WORD_MASK ((1ULL << 32) - 1)
12839/* Return the lo 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12840#define lowWordToU64(_value_u64) ((_value_u64) & LOW_WORD_MASK)
12841/* Return the hi 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12842#define highWordToU64(_value_u64) ((_value_u64) >> 32)
12843
12844/* Offset of sign bit in 64 bit signed integger. */
12845#define SIGN_SHIFT_U64 63
12846/* The sign bit itself -- also identifies the minimum negative int value. */
12847#define SIGN_BIT_U64 (1UL << SIGN_SHIFT_U64)
12848/* Return true if a 64 bit signed int presented as an unsigned int is the
12849 most negative value. */
12850#define isMinimumU64(_value_u64) ((_value_u64) == SIGN_BIT_U64)
12851/* Return true (non-zero) if a 64 bit signed int presented as an unsigned
12852 int has its sign bit set to false. */
12853#define isSignSetU64(_value_u64) ((_value_u64) & SIGN_BIT_U64)
12854/* Return 1L or -1L according to whether a 64 bit signed int presented as
12855 an unsigned int has its sign bit set or not. */
12856#define signOfU64(_value_u64) (1L + (((value_u64) >> SIGN_SHIFT_U64) * -2L)
12857/* Clear the sign bit of a 64 bit signed int presented as an unsigned int. */
12858#define clearSignU64(_value_u64) ((_value_u64) &= ~SIGN_BIT_U64)
12859
12860/* Multiply two 64 bit ints and return.
12861 the hi 64 bits of the 128 bit product. */
12862
12863static uint64_t
12864mul64hi (uint64_t value1, uint64_t value2)
12865{
12866 uint64_t resultmid1;
12867 uint64_t result;
12868 uint64_t value1_lo = lowWordToU64 (value1);
12869 uint64_t value1_hi = highWordToU64 (value1) ;
12870 uint64_t value2_lo = lowWordToU64 (value2);
12871 uint64_t value2_hi = highWordToU64 (value2);
12872
12873 /* Cross-multiply and collect results. */
2e8cf49e
NC
12874 uint64_t xproductlo = value1_lo * value2_lo;
12875 uint64_t xproductmid1 = value1_lo * value2_hi;
12876 uint64_t xproductmid2 = value1_hi * value2_lo;
12877 uint64_t xproducthi = value1_hi * value2_hi;
12878 uint64_t carry = 0;
12879 /* Start accumulating 64 bit results. */
12880 /* Drop bottom half of lowest cross-product. */
12881 uint64_t resultmid = xproductlo >> 32;
12882 /* Add in middle products. */
12883 resultmid = resultmid + xproductmid1;
12884
12885 /* Check for overflow. */
12886 if (resultmid < xproductmid1)
12887 /* Carry over 1 into top cross-product. */
12888 carry++;
12889
12890 resultmid1 = resultmid + xproductmid2;
12891
12892 /* Check for overflow. */
12893 if (resultmid1 < xproductmid2)
12894 /* Carry over 1 into top cross-product. */
12895 carry++;
12896
12897 /* Drop lowest 32 bits of middle cross-product. */
12898 result = resultmid1 >> 32;
12899
12900 /* Add top cross-product plus and any carry. */
12901 result += xproducthi + carry;
12902
12903 return result;
12904}
12905
12906/* Signed multiply high, source, source2 :
12907 64 bit, dest <-- high 64-bit of result. */
12908static void
12909smulh (sim_cpu *cpu)
12910{
12911 uint64_t uresult;
ef0d8ffc
NC
12912 int64_t result;
12913 unsigned rm = INSTR (20, 16);
12914 unsigned rn = INSTR (9, 5);
12915 unsigned rd = INSTR (4, 0);
12916 GReg ra = INSTR (14, 10);
12917 int64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12918 int64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2e8cf49e
NC
12919 uint64_t uvalue1;
12920 uint64_t uvalue2;
ef0d8ffc 12921 int64_t signum = 1;
2e8cf49e
NC
12922
12923 if (ra != R31)
12924 HALT_UNALLOC;
12925
12926 /* Convert to unsigned and use the unsigned mul64hi routine
12927 the fix the sign up afterwards. */
12928 if (value1 < 0)
12929 {
12930 signum *= -1L;
12931 uvalue1 = -value1;
12932 }
12933 else
12934 {
12935 uvalue1 = value1;
12936 }
12937
12938 if (value2 < 0)
12939 {
12940 signum *= -1L;
12941 uvalue2 = -value2;
12942 }
12943 else
12944 {
12945 uvalue2 = value2;
12946 }
12947
2cdad34c 12948 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12949 uresult = mul64hi (uvalue1, uvalue2);
12950 result = uresult;
12951 result *= signum;
12952
12953 aarch64_set_reg_s64 (cpu, rd, NO_SP, result);
12954}
12955
12956/* Unsigned multiply add long -- source, source2 :
12957 32 bit, source3 : 64 bit. */
12958static void
12959umaddl (sim_cpu *cpu)
12960{
ef0d8ffc
NC
12961 unsigned rm = INSTR (20, 16);
12962 unsigned ra = INSTR (14, 10);
12963 unsigned rn = INSTR (9, 5);
12964 unsigned rd = INSTR (4, 0);
2e8cf49e 12965
2cdad34c 12966 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12967 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12968 obtain a 64 bit product. */
12969 aarch64_set_reg_u64
12970 (cpu, rd, NO_SP,
12971 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12972 + ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12973 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12974}
12975
12976/* Unsigned multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12977static void
12978umsubl (sim_cpu *cpu)
12979{
ef0d8ffc
NC
12980 unsigned rm = INSTR (20, 16);
12981 unsigned ra = INSTR (14, 10);
12982 unsigned rn = INSTR (9, 5);
12983 unsigned rd = INSTR (4, 0);
2e8cf49e 12984
2cdad34c 12985 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12986 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12987 obtain a 64 bit product. */
12988 aarch64_set_reg_u64
12989 (cpu, rd, NO_SP,
12990 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12991 - ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12992 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12993}
12994
12995/* Unsigned multiply high, source, source2 :
12996 64 bit, dest <-- high 64-bit of result. */
12997static void
12998umulh (sim_cpu *cpu)
12999{
ef0d8ffc
NC
13000 unsigned rm = INSTR (20, 16);
13001 unsigned rn = INSTR (9, 5);
13002 unsigned rd = INSTR (4, 0);
13003 GReg ra = INSTR (14, 10);
2e8cf49e
NC
13004
13005 if (ra != R31)
13006 HALT_UNALLOC;
13007
2cdad34c 13008 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13009 aarch64_set_reg_u64 (cpu, rd, NO_SP,
13010 mul64hi (aarch64_get_reg_u64 (cpu, rn, NO_SP),
13011 aarch64_get_reg_u64 (cpu, rm, NO_SP)));
13012}
13013
13014static void
13015dexDataProc3Source (sim_cpu *cpu)
13016{
13017 /* assert instr[28,24] == 11011. */
13018 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit (for rd at least)
13019 instr[30,29] = op54 : 00 ==> ok, ow ==> UNALLOC
13020 instr[23,21] = op31 : 111 ==> UNALLOC, o2 ==> ok
13021 instr[15] = o0 : 0/1 ==> ok
13022 instr[23,21:15] ==> op : 0000 ==> MADD, 0001 ==> MSUB, (32/64 bit)
13023 0010 ==> SMADDL, 0011 ==> SMSUBL, (64 bit only)
13024 0100 ==> SMULH, (64 bit only)
13025 1010 ==> UMADDL, 1011 ==> UNSUBL, (64 bit only)
13026 1100 ==> UMULH (64 bit only)
13027 ow ==> UNALLOC. */
13028
13029 uint32_t dispatch;
ef0d8ffc
NC
13030 uint32_t size = INSTR (31, 31);
13031 uint32_t op54 = INSTR (30, 29);
13032 uint32_t op31 = INSTR (23, 21);
13033 uint32_t o0 = INSTR (15, 15);
2e8cf49e
NC
13034
13035 if (op54 != 0)
13036 HALT_UNALLOC;
13037
13038 if (size == 0)
13039 {
13040 if (op31 != 0)
13041 HALT_UNALLOC;
13042
13043 if (o0 == 0)
13044 madd32 (cpu);
13045 else
13046 msub32 (cpu);
13047 return;
13048 }
13049
13050 dispatch = (op31 << 1) | o0;
13051
13052 switch (dispatch)
13053 {
13054 case 0: madd64 (cpu); return;
13055 case 1: msub64 (cpu); return;
13056 case 2: smaddl (cpu); return;
13057 case 3: smsubl (cpu); return;
13058 case 4: smulh (cpu); return;
13059 case 10: umaddl (cpu); return;
13060 case 11: umsubl (cpu); return;
13061 case 12: umulh (cpu); return;
13062 default: HALT_UNALLOC;
13063 }
13064}
13065
13066static void
13067dexDPReg (sim_cpu *cpu)
13068{
13069 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
13070 assert group == GROUP_DPREG_0101 || group == GROUP_DPREG_1101
13071 bits [28:24:21] of a DPReg are the secondary dispatch vector. */
13072 uint32_t group2 = dispatchDPReg (aarch64_get_instr (cpu));
13073
13074 switch (group2)
13075 {
13076 case DPREG_LOG_000:
13077 case DPREG_LOG_001:
13078 dexLogicalShiftedRegister (cpu); return;
13079
13080 case DPREG_ADDSHF_010:
13081 dexAddSubtractShiftedRegister (cpu); return;
13082
13083 case DPREG_ADDEXT_011:
13084 dexAddSubtractExtendedRegister (cpu); return;
13085
13086 case DPREG_ADDCOND_100:
13087 {
13088 /* This set bundles a variety of different operations. */
13089 /* Check for. */
13090 /* 1) add/sub w carry. */
13091 uint32_t mask1 = 0x1FE00000U;
13092 uint32_t val1 = 0x1A000000U;
13093 /* 2) cond compare register/immediate. */
13094 uint32_t mask2 = 0x1FE00000U;
13095 uint32_t val2 = 0x1A400000U;
13096 /* 3) cond select. */
13097 uint32_t mask3 = 0x1FE00000U;
13098 uint32_t val3 = 0x1A800000U;
13099 /* 4) data proc 1/2 source. */
13100 uint32_t mask4 = 0x1FE00000U;
13101 uint32_t val4 = 0x1AC00000U;
13102
13103 if ((aarch64_get_instr (cpu) & mask1) == val1)
13104 dexAddSubtractWithCarry (cpu);
13105
13106 else if ((aarch64_get_instr (cpu) & mask2) == val2)
13107 CondCompare (cpu);
13108
13109 else if ((aarch64_get_instr (cpu) & mask3) == val3)
13110 dexCondSelect (cpu);
13111
13112 else if ((aarch64_get_instr (cpu) & mask4) == val4)
13113 {
13114 /* Bit 30 is clear for data proc 2 source
13115 and set for data proc 1 source. */
13116 if (aarch64_get_instr (cpu) & (1U << 30))
13117 dexDataProc1Source (cpu);
13118 else
13119 dexDataProc2Source (cpu);
13120 }
13121
13122 else
13123 /* Should not reach here. */
13124 HALT_NYI;
13125
13126 return;
13127 }
13128
13129 case DPREG_3SRC_110:
13130 dexDataProc3Source (cpu); return;
13131
13132 case DPREG_UNALLOC_101:
13133 HALT_UNALLOC;
13134
13135 case DPREG_3SRC_111:
13136 dexDataProc3Source (cpu); return;
13137
13138 default:
13139 /* Should never reach here. */
13140 HALT_NYI;
13141 }
13142}
13143
13144/* Unconditional Branch immediate.
13145 Offset is a PC-relative byte offset in the range +/- 128MiB.
13146 The offset is assumed to be raw from the decode i.e. the
13147 simulator is expected to scale them from word offsets to byte. */
13148
13149/* Unconditional branch. */
13150static void
13151buc (sim_cpu *cpu, int32_t offset)
13152{
13153 aarch64_set_next_PC_by_offset (cpu, offset);
13154}
13155
13156static unsigned stack_depth = 0;
13157
13158/* Unconditional branch and link -- writes return PC to LR. */
13159static void
13160bl (sim_cpu *cpu, int32_t offset)
13161{
2cdad34c 13162 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13163 aarch64_save_LR (cpu);
13164 aarch64_set_next_PC_by_offset (cpu, offset);
13165
13166 if (TRACE_BRANCH_P (cpu))
13167 {
13168 ++ stack_depth;
13169 TRACE_BRANCH (cpu,
13170 " %*scall %" PRIx64 " [%s]"
13171 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
13172 stack_depth, " ", aarch64_get_next_PC (cpu),
5357150c
MF
13173 aarch64_get_func (CPU_STATE (cpu),
13174 aarch64_get_next_PC (cpu)),
2e8cf49e
NC
13175 aarch64_get_reg_u64 (cpu, 0, NO_SP),
13176 aarch64_get_reg_u64 (cpu, 1, NO_SP),
13177 aarch64_get_reg_u64 (cpu, 2, NO_SP)
13178 );
13179 }
13180}
13181
13182/* Unconditional Branch register.
13183 Branch/return address is in source register. */
13184
13185/* Unconditional branch. */
13186static void
13187br (sim_cpu *cpu)
13188{
ef0d8ffc 13189 unsigned rn = INSTR (9, 5);
2cdad34c 13190 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13191 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13192}
13193
13194/* Unconditional branch and link -- writes return PC to LR. */
13195static void
13196blr (sim_cpu *cpu)
13197{
ef0d8ffc 13198 unsigned rn = INSTR (9, 5);
2e8cf49e 13199
2cdad34c 13200 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13201 /* The pseudo code in the spec says we update LR before fetching.
13202 the value from the rn. */
13203 aarch64_save_LR (cpu);
13204 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13205
13206 if (TRACE_BRANCH_P (cpu))
13207 {
13208 ++ stack_depth;
13209 TRACE_BRANCH (cpu,
13210 " %*scall %" PRIx64 " [%s]"
13211 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
13212 stack_depth, " ", aarch64_get_next_PC (cpu),
5357150c
MF
13213 aarch64_get_func (CPU_STATE (cpu),
13214 aarch64_get_next_PC (cpu)),
2e8cf49e
NC
13215 aarch64_get_reg_u64 (cpu, 0, NO_SP),
13216 aarch64_get_reg_u64 (cpu, 1, NO_SP),
13217 aarch64_get_reg_u64 (cpu, 2, NO_SP)
13218 );
13219 }
13220}
13221
13222/* Return -- assembler will default source to LR this is functionally
13223 equivalent to br but, presumably, unlike br it side effects the
13224 branch predictor. */
13225static void
13226ret (sim_cpu *cpu)
13227{
ef0d8ffc 13228 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
13229 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13230
2cdad34c 13231 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13232 if (TRACE_BRANCH_P (cpu))
13233 {
13234 TRACE_BRANCH (cpu,
13235 " %*sreturn [result: %" PRIx64 "]",
13236 stack_depth, " ", aarch64_get_reg_u64 (cpu, 0, NO_SP));
13237 -- stack_depth;
13238 }
13239}
13240
13241/* NOP -- we implement this and call it from the decode in case we
13242 want to intercept it later. */
13243
13244static void
13245nop (sim_cpu *cpu)
13246{
2cdad34c 13247 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13248}
13249
13250/* Data synchronization barrier. */
13251
13252static void
13253dsb (sim_cpu *cpu)
13254{
2cdad34c 13255 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13256}
13257
13258/* Data memory barrier. */
13259
13260static void
13261dmb (sim_cpu *cpu)
13262{
2cdad34c 13263 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13264}
13265
13266/* Instruction synchronization barrier. */
13267
13268static void
13269isb (sim_cpu *cpu)
13270{
2cdad34c 13271 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13272}
13273
13274static void
13275dexBranchImmediate (sim_cpu *cpu)
13276{
13277 /* assert instr[30,26] == 00101
13278 instr[31] ==> 0 == B, 1 == BL
13279 instr[25,0] == imm26 branch offset counted in words. */
13280
ef0d8ffc 13281 uint32_t top = INSTR (31, 31);
2e8cf49e
NC
13282 /* We have a 26 byte signed word offset which we need to pass to the
13283 execute routine as a signed byte offset. */
13284 int32_t offset = simm32 (aarch64_get_instr (cpu), 25, 0) << 2;
13285
13286 if (top)
13287 bl (cpu, offset);
13288 else
13289 buc (cpu, offset);
13290}
13291
13292/* Control Flow. */
13293
13294/* Conditional branch
13295
13296 Offset is a PC-relative byte offset in the range +/- 1MiB pos is
13297 a bit position in the range 0 .. 63
13298
13299 cc is a CondCode enum value as pulled out of the decode
13300
13301 N.B. any offset register (source) can only be Xn or Wn. */
13302
13303static void
13304bcc (sim_cpu *cpu, int32_t offset, CondCode cc)
13305{
2cdad34c
NC
13306 /* The test returns TRUE if CC is met. */
13307 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13308 if (testConditionCode (cpu, cc))
13309 aarch64_set_next_PC_by_offset (cpu, offset);
13310}
13311
13312/* 32 bit branch on register non-zero. */
13313static void
13314cbnz32 (sim_cpu *cpu, int32_t offset)
13315{
ef0d8ffc 13316 unsigned rt = INSTR (4, 0);
2e8cf49e 13317
2cdad34c 13318 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13319 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) != 0)
13320 aarch64_set_next_PC_by_offset (cpu, offset);
13321}
13322
13323/* 64 bit branch on register zero. */
13324static void
13325cbnz (sim_cpu *cpu, int32_t offset)
13326{
ef0d8ffc 13327 unsigned rt = INSTR (4, 0);
2e8cf49e 13328
2cdad34c 13329 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13330 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) != 0)
13331 aarch64_set_next_PC_by_offset (cpu, offset);
13332}
13333
13334/* 32 bit branch on register non-zero. */
13335static void
13336cbz32 (sim_cpu *cpu, int32_t offset)
13337{
ef0d8ffc 13338 unsigned rt = INSTR (4, 0);
2e8cf49e 13339
2cdad34c 13340 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13341 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) == 0)
13342 aarch64_set_next_PC_by_offset (cpu, offset);
13343}
13344
13345/* 64 bit branch on register zero. */
13346static void
13347cbz (sim_cpu *cpu, int32_t offset)
13348{
ef0d8ffc 13349 unsigned rt = INSTR (4, 0);
2e8cf49e 13350
2cdad34c 13351 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13352 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) == 0)
13353 aarch64_set_next_PC_by_offset (cpu, offset);
13354}
13355
13356/* Branch on register bit test non-zero -- one size fits all. */
13357static void
13358tbnz (sim_cpu *cpu, uint32_t pos, int32_t offset)
13359{
ef0d8ffc 13360 unsigned rt = INSTR (4, 0);
2e8cf49e 13361
2cdad34c 13362 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
668650d5 13363 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) & (((uint64_t) 1) << pos))
2e8cf49e
NC
13364 aarch64_set_next_PC_by_offset (cpu, offset);
13365}
13366
2cdad34c 13367/* Branch on register bit test zero -- one size fits all. */
2e8cf49e
NC
13368static void
13369tbz (sim_cpu *cpu, uint32_t pos, int32_t offset)
13370{
ef0d8ffc 13371 unsigned rt = INSTR (4, 0);
2e8cf49e 13372
2cdad34c 13373 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
668650d5 13374 if (!(aarch64_get_reg_u64 (cpu, rt, NO_SP) & (((uint64_t) 1) << pos)))
2e8cf49e
NC
13375 aarch64_set_next_PC_by_offset (cpu, offset);
13376}
13377
13378static void
13379dexCompareBranchImmediate (sim_cpu *cpu)
13380{
13381 /* instr[30,25] = 01 1010
13382 instr[31] = size : 0 ==> 32, 1 ==> 64
13383 instr[24] = op : 0 ==> CBZ, 1 ==> CBNZ
13384 instr[23,5] = simm19 branch offset counted in words
13385 instr[4,0] = rt */
13386
ef0d8ffc
NC
13387 uint32_t size = INSTR (31, 31);
13388 uint32_t op = INSTR (24, 24);
2e8cf49e
NC
13389 int32_t offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
13390
13391 if (size == 0)
13392 {
13393 if (op == 0)
13394 cbz32 (cpu, offset);
13395 else
13396 cbnz32 (cpu, offset);
13397 }
13398 else
13399 {
13400 if (op == 0)
13401 cbz (cpu, offset);
13402 else
13403 cbnz (cpu, offset);
13404 }
13405}
13406
13407static void
13408dexTestBranchImmediate (sim_cpu *cpu)
13409{
13410 /* instr[31] = b5 : bit 5 of test bit idx
13411 instr[30,25] = 01 1011
13412 instr[24] = op : 0 ==> TBZ, 1 == TBNZ
13413 instr[23,19] = b40 : bits 4 to 0 of test bit idx
13414 instr[18,5] = simm14 : signed offset counted in words
13415 instr[4,0] = uimm5 */
13416
668650d5 13417 uint32_t pos = ((INSTR (31, 31) << 5) | INSTR (23, 19));
2e8cf49e
NC
13418 int32_t offset = simm32 (aarch64_get_instr (cpu), 18, 5) << 2;
13419
13420 NYI_assert (30, 25, 0x1b);
13421
ef0d8ffc 13422 if (INSTR (24, 24) == 0)
2e8cf49e
NC
13423 tbz (cpu, pos, offset);
13424 else
13425 tbnz (cpu, pos, offset);
13426}
13427
13428static void
13429dexCondBranchImmediate (sim_cpu *cpu)
13430{
13431 /* instr[31,25] = 010 1010
13432 instr[24] = op1; op => 00 ==> B.cond
13433 instr[23,5] = simm19 : signed offset counted in words
13434 instr[4] = op0
13435 instr[3,0] = cond */
13436
13437 int32_t offset;
ef0d8ffc 13438 uint32_t op = ((INSTR (24, 24) << 1) | INSTR (4, 4));
2e8cf49e
NC
13439
13440 NYI_assert (31, 25, 0x2a);
13441
13442 if (op != 0)
13443 HALT_UNALLOC;
13444
13445 offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
2e8cf49e 13446
ef0d8ffc 13447 bcc (cpu, offset, INSTR (3, 0));
2e8cf49e
NC
13448}
13449
13450static void
13451dexBranchRegister (sim_cpu *cpu)
13452{
13453 /* instr[31,25] = 110 1011
13454 instr[24,21] = op : 0 ==> BR, 1 => BLR, 2 => RET, 3 => ERET, 4 => DRPS
13455 instr[20,16] = op2 : must be 11111
13456 instr[15,10] = op3 : must be 000000
13457 instr[4,0] = op2 : must be 11111. */
13458
ef0d8ffc
NC
13459 uint32_t op = INSTR (24, 21);
13460 uint32_t op2 = INSTR (20, 16);
13461 uint32_t op3 = INSTR (15, 10);
13462 uint32_t op4 = INSTR (4, 0);
2e8cf49e
NC
13463
13464 NYI_assert (31, 25, 0x6b);
13465
13466 if (op2 != 0x1F || op3 != 0 || op4 != 0)
13467 HALT_UNALLOC;
13468
13469 if (op == 0)
13470 br (cpu);
13471
13472 else if (op == 1)
13473 blr (cpu);
13474
13475 else if (op == 2)
13476 ret (cpu);
13477
13478 else
13479 {
ef0d8ffc 13480 /* ERET and DRPS accept 0b11111 for rn = instr [4,0]. */
2e8cf49e 13481 /* anything else is unallocated. */
ef0d8ffc 13482 uint32_t rn = INSTR (4, 0);
2e8cf49e
NC
13483
13484 if (rn != 0x1f)
13485 HALT_UNALLOC;
13486
13487 if (op == 4 || op == 5)
13488 HALT_NYI;
13489
13490 HALT_UNALLOC;
13491 }
13492}
13493
13494/* FIXME: We should get the Angel SWI values from ../../libgloss/aarch64/svc.h
13495 but this may not be available. So instead we define the values we need
13496 here. */
13497#define AngelSVC_Reason_Open 0x01
13498#define AngelSVC_Reason_Close 0x02
13499#define AngelSVC_Reason_Write 0x05
13500#define AngelSVC_Reason_Read 0x06
13501#define AngelSVC_Reason_IsTTY 0x09
13502#define AngelSVC_Reason_Seek 0x0A
13503#define AngelSVC_Reason_FLen 0x0C
13504#define AngelSVC_Reason_Remove 0x0E
13505#define AngelSVC_Reason_Rename 0x0F
13506#define AngelSVC_Reason_Clock 0x10
13507#define AngelSVC_Reason_Time 0x11
13508#define AngelSVC_Reason_System 0x12
13509#define AngelSVC_Reason_Errno 0x13
13510#define AngelSVC_Reason_GetCmdLine 0x15
13511#define AngelSVC_Reason_HeapInfo 0x16
13512#define AngelSVC_Reason_ReportException 0x18
13513#define AngelSVC_Reason_Elapsed 0x30
13514
13515
13516static void
13517handle_halt (sim_cpu *cpu, uint32_t val)
13518{
13519 uint64_t result = 0;
13520
2cdad34c 13521 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13522 if (val != 0xf000)
13523 {
13524 TRACE_SYSCALL (cpu, " HLT [0x%x]", val);
13525 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13526 sim_stopped, SIM_SIGTRAP);
13527 }
13528
13529 /* We have encountered an Angel SVC call. See if we can process it. */
13530 switch (aarch64_get_reg_u32 (cpu, 0, NO_SP))
13531 {
13532 case AngelSVC_Reason_HeapInfo:
13533 {
13534 /* Get the values. */
13535 uint64_t stack_top = aarch64_get_stack_start (cpu);
13536 uint64_t heap_base = aarch64_get_heap_start (cpu);
13537
13538 /* Get the pointer */
13539 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13540 ptr = aarch64_get_mem_u64 (cpu, ptr);
13541
13542 /* Fill in the memory block. */
13543 /* Start addr of heap. */
13544 aarch64_set_mem_u64 (cpu, ptr + 0, heap_base);
13545 /* End addr of heap. */
13546 aarch64_set_mem_u64 (cpu, ptr + 8, stack_top);
13547 /* Lowest stack addr. */
13548 aarch64_set_mem_u64 (cpu, ptr + 16, heap_base);
13549 /* Initial stack addr. */
13550 aarch64_set_mem_u64 (cpu, ptr + 24, stack_top);
13551
13552 TRACE_SYSCALL (cpu, " AngelSVC: Get Heap Info");
13553 }
13554 break;
13555
13556 case AngelSVC_Reason_Open:
13557 {
13558 /* Get the pointer */
13559 /* uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);. */
13560 /* FIXME: For now we just assume that we will only be asked
13561 to open the standard file descriptors. */
13562 static int fd = 0;
13563 result = fd ++;
13564
13565 TRACE_SYSCALL (cpu, " AngelSVC: Open file %d", fd - 1);
13566 }
13567 break;
13568
13569 case AngelSVC_Reason_Close:
13570 {
13571 uint64_t fh = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13572 TRACE_SYSCALL (cpu, " AngelSVC: Close file %d", (int) fh);
13573 result = 0;
13574 }
13575 break;
13576
13577 case AngelSVC_Reason_Errno:
13578 result = 0;
13579 TRACE_SYSCALL (cpu, " AngelSVC: Get Errno");
13580 break;
13581
13582 case AngelSVC_Reason_Clock:
13583 result =
13584#ifdef CLOCKS_PER_SEC
13585 (CLOCKS_PER_SEC >= 100)
13586 ? (clock () / (CLOCKS_PER_SEC / 100))
13587 : ((clock () * 100) / CLOCKS_PER_SEC)
13588#else
13589 /* Presume unix... clock() returns microseconds. */
13590 (clock () / 10000)
13591#endif
13592 ;
13593 TRACE_SYSCALL (cpu, " AngelSVC: Get Clock");
13594 break;
13595
13596 case AngelSVC_Reason_GetCmdLine:
13597 {
13598 /* Get the pointer */
13599 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13600 ptr = aarch64_get_mem_u64 (cpu, ptr);
13601
13602 /* FIXME: No command line for now. */
13603 aarch64_set_mem_u64 (cpu, ptr, 0);
13604 TRACE_SYSCALL (cpu, " AngelSVC: Get Command Line");
13605 }
13606 break;
13607
13608 case AngelSVC_Reason_IsTTY:
13609 result = 1;
13610 TRACE_SYSCALL (cpu, " AngelSVC: IsTTY ?");
13611 break;
13612
13613 case AngelSVC_Reason_Write:
13614 {
13615 /* Get the pointer */
13616 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13617 /* Get the write control block. */
13618 uint64_t fd = aarch64_get_mem_u64 (cpu, ptr);
13619 uint64_t buf = aarch64_get_mem_u64 (cpu, ptr + 8);
13620 uint64_t len = aarch64_get_mem_u64 (cpu, ptr + 16);
13621
13622 TRACE_SYSCALL (cpu, "write of %" PRIx64 " bytes from %"
13623 PRIx64 " on descriptor %" PRIx64,
13624 len, buf, fd);
13625
13626 if (len > 1280)
13627 {
13628 TRACE_SYSCALL (cpu,
13629 " AngelSVC: Write: Suspiciously long write: %ld",
13630 (long) len);
13631 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13632 sim_stopped, SIM_SIGBUS);
13633 }
13634 else if (fd == 1)
13635 {
13636 printf ("%.*s", (int) len, aarch64_get_mem_ptr (cpu, buf));
2e8cf49e
NC
13637 }
13638 else if (fd == 2)
13639 {
13640 TRACE (cpu, 0, "\n");
13641 sim_io_eprintf (CPU_STATE (cpu), "%.*s",
13642 (int) len, aarch64_get_mem_ptr (cpu, buf));
13643 TRACE (cpu, 0, "\n");
13644 }
13645 else
13646 {
13647 TRACE_SYSCALL (cpu,
13648 " AngelSVC: Write: Unexpected file handle: %d",
13649 (int) fd);
13650 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13651 sim_stopped, SIM_SIGABRT);
13652 }
13653 }
13654 break;
13655
13656 case AngelSVC_Reason_ReportException:
13657 {
13658 /* Get the pointer */
13659 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13660 /*ptr = aarch64_get_mem_u64 (cpu, ptr);. */
13661 uint64_t type = aarch64_get_mem_u64 (cpu, ptr);
13662 uint64_t state = aarch64_get_mem_u64 (cpu, ptr + 8);
13663
13664 TRACE_SYSCALL (cpu,
13665 "Angel Exception: type 0x%" PRIx64 " state %" PRIx64,
13666 type, state);
13667
13668 if (type == 0x20026)
13669 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13670 sim_exited, state);
13671 else
13672 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13673 sim_stopped, SIM_SIGINT);
13674 }
13675 break;
13676
13677 case AngelSVC_Reason_Read:
13678 case AngelSVC_Reason_FLen:
13679 case AngelSVC_Reason_Seek:
13680 case AngelSVC_Reason_Remove:
13681 case AngelSVC_Reason_Time:
13682 case AngelSVC_Reason_System:
13683 case AngelSVC_Reason_Rename:
13684 case AngelSVC_Reason_Elapsed:
13685 default:
13686 TRACE_SYSCALL (cpu, " HLT [Unknown angel %x]",
13687 aarch64_get_reg_u32 (cpu, 0, NO_SP));
13688 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13689 sim_stopped, SIM_SIGTRAP);
13690 }
13691
13692 aarch64_set_reg_u64 (cpu, 0, NO_SP, result);
13693}
13694
13695static void
13696dexExcpnGen (sim_cpu *cpu)
13697{
13698 /* instr[31:24] = 11010100
13699 instr[23,21] = opc : 000 ==> GEN EXCPN, 001 ==> BRK
13700 010 ==> HLT, 101 ==> DBG GEN EXCPN
13701 instr[20,5] = imm16
13702 instr[4,2] = opc2 000 ==> OK, ow ==> UNALLOC
13703 instr[1,0] = LL : discriminates opc */
13704
ef0d8ffc
NC
13705 uint32_t opc = INSTR (23, 21);
13706 uint32_t imm16 = INSTR (20, 5);
13707 uint32_t opc2 = INSTR (4, 2);
2e8cf49e
NC
13708 uint32_t LL;
13709
13710 NYI_assert (31, 24, 0xd4);
13711
13712 if (opc2 != 0)
13713 HALT_UNALLOC;
13714
ef0d8ffc 13715 LL = INSTR (1, 0);
2e8cf49e
NC
13716
13717 /* We only implement HLT and BRK for now. */
13718 if (opc == 1 && LL == 0)
13719 {
13720 TRACE_EVENTS (cpu, " BRK [0x%x]", imm16);
13721 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13722 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13723 }
13724
13725 if (opc == 2 && LL == 0)
13726 handle_halt (cpu, imm16);
13727
13728 else if (opc == 0 || opc == 5)
13729 HALT_NYI;
13730
13731 else
13732 HALT_UNALLOC;
13733}
13734
5ab6d79e 13735/* Stub for accessing system registers. */
caa8d700
NC
13736
13737static uint64_t
13738system_get (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
13739 unsigned crm, unsigned op2)
13740{
13741 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 7)
13742 /* DCZID_EL0 - the Data Cache Zero ID register.
13743 We do not support DC ZVA at the moment, so
5ab6d79e
NC
13744 we return a value with the disable bit set.
13745 We implement support for the DCZID register since
13746 it is used by the C library's memset function. */
caa8d700
NC
13747 return ((uint64_t) 1) << 4;
13748
5ab6d79e
NC
13749 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 1)
13750 /* Cache Type Register. */
13751 return 0x80008000UL;
13752
13753 if (crn == 13 && op1 == 3 && crm == 0 && op2 == 2)
13754 /* TPIDR_EL0 - thread pointer id. */
13755 return aarch64_get_thread_id (cpu);
13756
13757 if (op1 == 3 && crm == 4 && op2 == 0)
13758 return aarch64_get_FPCR (cpu);
13759
13760 if (op1 == 3 && crm == 4 && op2 == 1)
13761 return aarch64_get_FPSR (cpu);
13762
13763 else if (op1 == 3 && crm == 2 && op2 == 0)
13764 return aarch64_get_CPSR (cpu);
13765
caa8d700
NC
13766 HALT_NYI;
13767}
13768
5ab6d79e
NC
13769static void
13770system_set (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
13771 unsigned crm, unsigned op2, uint64_t val)
13772{
13773 if (op1 == 3 && crm == 4 && op2 == 0)
13774 aarch64_set_FPCR (cpu, val);
13775
13776 else if (op1 == 3 && crm == 4 && op2 == 1)
13777 aarch64_set_FPSR (cpu, val);
13778
13779 else if (op1 == 3 && crm == 2 && op2 == 0)
13780 aarch64_set_CPSR (cpu, val);
13781
13782 else
13783 HALT_NYI;
13784}
ef0d8ffc 13785
caa8d700
NC
13786static void
13787do_mrs (sim_cpu *cpu)
13788{
5ab6d79e 13789 /* instr[31:20] = 1101 0101 0001 1
caa8d700
NC
13790 instr[19] = op0
13791 instr[18,16] = op1
13792 instr[15,12] = CRn
13793 instr[11,8] = CRm
13794 instr[7,5] = op2
13795 instr[4,0] = Rt */
ef0d8ffc
NC
13796 unsigned sys_op0 = INSTR (19, 19) + 2;
13797 unsigned sys_op1 = INSTR (18, 16);
13798 unsigned sys_crn = INSTR (15, 12);
13799 unsigned sys_crm = INSTR (11, 8);
13800 unsigned sys_op2 = INSTR (7, 5);
13801 unsigned rt = INSTR (4, 0);
caa8d700 13802
2cdad34c 13803 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
caa8d700
NC
13804 aarch64_set_reg_u64 (cpu, rt, NO_SP,
13805 system_get (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2));
13806}
13807
5ab6d79e
NC
13808static void
13809do_MSR_immediate (sim_cpu *cpu)
13810{
13811 /* instr[31:19] = 1101 0101 0000 0
13812 instr[18,16] = op1
13813 instr[15,12] = 0100
13814 instr[11,8] = CRm
13815 instr[7,5] = op2
13816 instr[4,0] = 1 1111 */
13817
ef0d8ffc
NC
13818 unsigned op1 = INSTR (18, 16);
13819 /*unsigned crm = INSTR (11, 8);*/
13820 unsigned op2 = INSTR (7, 5);
5ab6d79e
NC
13821
13822 NYI_assert (31, 19, 0x1AA0);
13823 NYI_assert (15, 12, 0x4);
13824 NYI_assert (4, 0, 0x1F);
13825
13826 if (op1 == 0)
13827 {
13828 if (op2 == 5)
13829 HALT_NYI; /* set SPSel. */
13830 else
13831 HALT_UNALLOC;
13832 }
13833 else if (op1 == 3)
13834 {
13835 if (op2 == 6)
13836 HALT_NYI; /* set DAIFset. */
13837 else if (op2 == 7)
13838 HALT_NYI; /* set DAIFclr. */
13839 else
13840 HALT_UNALLOC;
13841 }
13842 else
13843 HALT_UNALLOC;
13844}
13845
13846static void
13847do_MSR_reg (sim_cpu *cpu)
13848{
13849 /* instr[31:20] = 1101 0101 0001
13850 instr[19] = op0
13851 instr[18,16] = op1
13852 instr[15,12] = CRn
13853 instr[11,8] = CRm
13854 instr[7,5] = op2
13855 instr[4,0] = Rt */
13856
ef0d8ffc
NC
13857 unsigned sys_op0 = INSTR (19, 19) + 2;
13858 unsigned sys_op1 = INSTR (18, 16);
13859 unsigned sys_crn = INSTR (15, 12);
13860 unsigned sys_crm = INSTR (11, 8);
13861 unsigned sys_op2 = INSTR (7, 5);
13862 unsigned rt = INSTR (4, 0);
5ab6d79e
NC
13863
13864 NYI_assert (31, 20, 0xD51);
ef0d8ffc 13865
2cdad34c 13866 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
13867 system_set (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2,
13868 aarch64_get_reg_u64 (cpu, rt, NO_SP));
13869}
13870
13871static void
ef0d8ffc 13872do_SYS (sim_cpu *cpu)
5ab6d79e
NC
13873{
13874 /* instr[31,19] = 1101 0101 0000 1
13875 instr[18,16] = op1
13876 instr[15,12] = CRn
13877 instr[11,8] = CRm
13878 instr[7,5] = op2
13879 instr[4,0] = Rt */
13880 NYI_assert (31, 19, 0x1AA1);
13881
13882 /* FIXME: For now we just silently accept system ops. */
13883}
ef0d8ffc 13884
2e8cf49e
NC
13885static void
13886dexSystem (sim_cpu *cpu)
13887{
13888 /* instr[31:22] = 1101 01010 0
13889 instr[21] = L
13890 instr[20,19] = op0
13891 instr[18,16] = op1
13892 instr[15,12] = CRn
13893 instr[11,8] = CRm
13894 instr[7,5] = op2
13895 instr[4,0] = uimm5 */
13896
13897 /* We are interested in HINT, DSB, DMB and ISB
13898
13899 Hint #0 encodes NOOP (this is the only hint we care about)
13900 L == 0, op0 == 0, op1 = 011, CRn = 0010, Rt = 11111,
13901 CRm op2 != 0000 000 OR CRm op2 == 0000 000 || CRm op > 0000 101
13902
13903 DSB, DMB, ISB are data store barrier, data memory barrier and
13904 instruction store barrier, respectively, where
13905
13906 L == 0, op0 == 0, op1 = 011, CRn = 0011, Rt = 11111,
13907 op2 : DSB ==> 100, DMB ==> 101, ISB ==> 110
13908 CRm<3:2> ==> domain, CRm<1:0> ==> types,
13909 domain : 00 ==> OuterShareable, 01 ==> Nonshareable,
13910 10 ==> InerShareable, 11 ==> FullSystem
13911 types : 01 ==> Reads, 10 ==> Writes,
13912 11 ==> All, 00 ==> All (domain == FullSystem). */
13913
ef0d8ffc 13914 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
13915
13916 NYI_assert (31, 22, 0x354);
13917
5ab6d79e 13918 switch (INSTR (21, 12))
2e8cf49e
NC
13919 {
13920 case 0x032:
13921 if (rt == 0x1F)
13922 {
13923 /* NOP has CRm != 0000 OR. */
13924 /* (CRm == 0000 AND (op2 == 000 OR op2 > 101)). */
ef0d8ffc
NC
13925 uint32_t crm = INSTR (11, 8);
13926 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
13927
13928 if (crm != 0 || (op2 == 0 || op2 > 5))
13929 {
13930 /* Actually call nop method so we can reimplement it later. */
13931 nop (cpu);
13932 return;
13933 }
13934 }
13935 HALT_NYI;
13936
13937 case 0x033:
13938 {
ef0d8ffc 13939 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
13940
13941 switch (op2)
13942 {
caa8d700 13943 case 2: HALT_NYI;
2e8cf49e
NC
13944 case 4: dsb (cpu); return;
13945 case 5: dmb (cpu); return;
13946 case 6: isb (cpu); return;
2e8cf49e
NC
13947 default: HALT_UNALLOC;
13948 }
13949 }
13950
13951 case 0x3B0:
2e8cf49e
NC
13952 case 0x3B4:
13953 case 0x3BD:
caa8d700 13954 do_mrs (cpu);
2e8cf49e
NC
13955 return;
13956
13957 case 0x0B7:
5ab6d79e 13958 do_SYS (cpu); /* DC is an alias of SYS. */
2e8cf49e
NC
13959 return;
13960
13961 default:
ef0d8ffc 13962 if (INSTR (21, 20) == 0x1)
5ab6d79e
NC
13963 do_MSR_reg (cpu);
13964 else if (INSTR (21, 19) == 0 && INSTR (15, 12) == 0x4)
13965 do_MSR_immediate (cpu);
13966 else
13967 HALT_NYI;
caa8d700 13968 return;
2e8cf49e
NC
13969 }
13970}
13971
13972static void
13973dexBr (sim_cpu *cpu)
13974{
13975 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
13976 assert group == GROUP_BREXSYS_1010 || group == GROUP_BREXSYS_1011
13977 bits [31,29] of a BrExSys are the secondary dispatch vector. */
13978 uint32_t group2 = dispatchBrExSys (aarch64_get_instr (cpu));
13979
13980 switch (group2)
13981 {
13982 case BR_IMM_000:
13983 return dexBranchImmediate (cpu);
13984
13985 case BR_IMMCMP_001:
13986 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 13987 if (!INSTR (25, 25))
2e8cf49e
NC
13988 dexCompareBranchImmediate (cpu);
13989 else
13990 dexTestBranchImmediate (cpu);
13991 return;
13992
13993 case BR_IMMCOND_010:
13994 /* This is a conditional branch if bit 25 is clear otherwise
13995 unallocated. */
ef0d8ffc 13996 if (!INSTR (25, 25))
2e8cf49e
NC
13997 dexCondBranchImmediate (cpu);
13998 else
13999 HALT_UNALLOC;
14000 return;
14001
14002 case BR_UNALLOC_011:
14003 HALT_UNALLOC;
14004
14005 case BR_IMM_100:
14006 dexBranchImmediate (cpu);
14007 return;
14008
14009 case BR_IMMCMP_101:
14010 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 14011 if (!INSTR (25, 25))
2e8cf49e
NC
14012 dexCompareBranchImmediate (cpu);
14013 else
14014 dexTestBranchImmediate (cpu);
14015 return;
14016
14017 case BR_REG_110:
14018 /* Unconditional branch reg has bit 25 set. */
ef0d8ffc 14019 if (INSTR (25, 25))
2e8cf49e
NC
14020 dexBranchRegister (cpu);
14021
14022 /* This includes both Excpn Gen, System and unalloc operations.
14023 We need to decode the Excpn Gen operation BRK so we can plant
14024 debugger entry points.
ef0d8ffc 14025 Excpn Gen operations have instr [24] = 0.
2e8cf49e
NC
14026 we need to decode at least one of the System operations NOP
14027 which is an alias for HINT #0.
ef0d8ffc
NC
14028 System operations have instr [24,22] = 100. */
14029 else if (INSTR (24, 24) == 0)
2e8cf49e
NC
14030 dexExcpnGen (cpu);
14031
ef0d8ffc 14032 else if (INSTR (24, 22) == 4)
2e8cf49e
NC
14033 dexSystem (cpu);
14034
14035 else
14036 HALT_UNALLOC;
14037
14038 return;
14039
14040 case BR_UNALLOC_111:
14041 HALT_UNALLOC;
14042
14043 default:
14044 /* Should never reach here. */
14045 HALT_NYI;
14046 }
14047}
14048
14049static void
14050aarch64_decode_and_execute (sim_cpu *cpu, uint64_t pc)
14051{
14052 /* We need to check if gdb wants an in here. */
14053 /* checkBreak (cpu);. */
14054
14055 uint64_t group = dispatchGroup (aarch64_get_instr (cpu));
14056
14057 switch (group)
14058 {
14059 case GROUP_PSEUDO_0000: dexPseudo (cpu); break;
14060 case GROUP_LDST_0100: dexLdSt (cpu); break;
14061 case GROUP_DPREG_0101: dexDPReg (cpu); break;
14062 case GROUP_LDST_0110: dexLdSt (cpu); break;
14063 case GROUP_ADVSIMD_0111: dexAdvSIMD0 (cpu); break;
14064 case GROUP_DPIMM_1000: dexDPImm (cpu); break;
14065 case GROUP_DPIMM_1001: dexDPImm (cpu); break;
14066 case GROUP_BREXSYS_1010: dexBr (cpu); break;
14067 case GROUP_BREXSYS_1011: dexBr (cpu); break;
14068 case GROUP_LDST_1100: dexLdSt (cpu); break;
14069 case GROUP_DPREG_1101: dexDPReg (cpu); break;
14070 case GROUP_LDST_1110: dexLdSt (cpu); break;
14071 case GROUP_ADVSIMD_1111: dexAdvSIMD1 (cpu); break;
14072
14073 case GROUP_UNALLOC_0001:
14074 case GROUP_UNALLOC_0010:
14075 case GROUP_UNALLOC_0011:
14076 HALT_UNALLOC;
14077
14078 default:
14079 /* Should never reach here. */
14080 HALT_NYI;
14081 }
14082}
14083
b14bdb3b 14084static bfd_boolean
2e8cf49e
NC
14085aarch64_step (sim_cpu *cpu)
14086{
14087 uint64_t pc = aarch64_get_PC (cpu);
14088
14089 if (pc == TOP_LEVEL_RETURN_PC)
14090 return FALSE;
14091
14092 aarch64_set_next_PC (cpu, pc + 4);
c7be4414
JW
14093
14094 /* Code is always little-endian. */
14095 sim_core_read_buffer (CPU_STATE (cpu), cpu, read_map,
14096 & aarch64_get_instr (cpu), pc, 4);
14097 aarch64_get_instr (cpu) = endian_le2h_4 (aarch64_get_instr (cpu));
2e8cf49e 14098
57aa1742 14099 TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %08x", pc,
1a846c62
MF
14100 aarch64_get_instr (cpu));
14101 TRACE_DISASM (cpu, pc);
2e8cf49e
NC
14102
14103 aarch64_decode_and_execute (cpu, pc);
14104
14105 return TRUE;
14106}
14107
14108void
14109aarch64_run (SIM_DESC sd)
14110{
14111 sim_cpu *cpu = STATE_CPU (sd, 0);
14112
14113 while (aarch64_step (cpu))
b14bdb3b
NC
14114 {
14115 aarch64_update_PC (cpu);
14116
14117 if (sim_events_tick (sd))
14118 sim_events_process (sd);
14119 }
2e8cf49e 14120
b14bdb3b
NC
14121 sim_engine_halt (sd, cpu, NULL, aarch64_get_PC (cpu),
14122 sim_exited, aarch64_get_reg_s32 (cpu, R0, NO_SP));
2e8cf49e
NC
14123}
14124
14125void
14126aarch64_init (sim_cpu *cpu, uint64_t pc)
14127{
14128 uint64_t sp = aarch64_get_stack_start (cpu);
14129
14130 /* Install SP, FP and PC and set LR to -20
14131 so we can detect a top-level return. */
14132 aarch64_set_reg_u64 (cpu, SP, SP_OK, sp);
14133 aarch64_set_reg_u64 (cpu, FP, SP_OK, sp);
14134 aarch64_set_reg_u64 (cpu, LR, SP_OK, TOP_LEVEL_RETURN_PC);
14135 aarch64_set_next_PC (cpu, pc);
14136 aarch64_update_PC (cpu);
14137 aarch64_init_LIT_table ();
14138}