Automatic Copyright Year update after running gdb/copyright.py
[deliverable/binutils-gdb.git] / sim / aarch64 / simulator.c
CommitLineData
2e8cf49e
NC
1/* simulator.c -- Interface for the AArch64 simulator.
2
88b9d363 3 Copyright (C) 2015-2022 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
6df01ab8
MF
22/* This must come before any other includes. */
23#include "defs.h"
24
2e8cf49e
NC
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <sys/types.h>
2e8cf49e
NC
29#include <math.h>
30#include <time.h>
31#include <limits.h>
32
2e8cf49e
NC
33#include "simulator.h"
34#include "cpustate.h"
35#include "memory.h"
36
1fef66b0
MF
37#include "sim-signal.h"
38
2e8cf49e
NC
39#define NO_SP 0
40#define SP_OK 1
41
2e8cf49e 42#define TST(_flag) (aarch64_test_CPSR_bit (cpu, _flag))
e101a78b
NC
43#define IS_SET(_X) (TST (( _X )) ? 1 : 0)
44#define IS_CLEAR(_X) (TST (( _X )) ? 0 : 1)
2e8cf49e 45
ef0d8ffc
NC
46/* Space saver macro. */
47#define INSTR(HIGH, LOW) uimm (aarch64_get_instr (cpu), (HIGH), (LOW))
48
2e8cf49e
NC
49#define HALT_UNALLOC \
50 do \
51 { \
1a846c62
MF
52 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
53 TRACE_INSN (cpu, \
54 "Unallocated instruction detected at sim line %d," \
55 " exe addr %" PRIx64, \
56 __LINE__, aarch64_get_PC (cpu)); \
2e8cf49e
NC
57 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
58 sim_stopped, SIM_SIGILL); \
59 } \
60 while (0)
61
62#define HALT_NYI \
63 do \
64 { \
1a846c62
MF
65 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
66 TRACE_INSN (cpu, \
67 "Unimplemented instruction detected at sim line %d," \
68 " exe addr %" PRIx64, \
69 __LINE__, aarch64_get_PC (cpu)); \
5ab6d79e 70 if (! TRACE_ANY_P (cpu)) \
6a277579
NC
71 sim_io_eprintf (CPU_STATE (cpu), "SIM Error: Unimplemented instruction: %#08x\n", \
72 aarch64_get_instr (cpu)); \
2e8cf49e
NC
73 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
74 sim_stopped, SIM_SIGABRT); \
75 } \
76 while (0)
77
78#define NYI_assert(HI, LO, EXPECTED) \
79 do \
80 { \
ef0d8ffc 81 if (INSTR ((HI), (LO)) != (EXPECTED)) \
2e8cf49e
NC
82 HALT_NYI; \
83 } \
84 while (0)
85
2e8cf49e
NC
86/* Helper functions used by expandLogicalImmediate. */
87
88/* for i = 1, ... N result<i-1> = 1 other bits are zero */
89static inline uint64_t
90ones (int N)
91{
92 return (N == 64 ? (uint64_t)-1UL : ((1UL << N) - 1));
93}
94
95/* result<0> to val<N> */
96static inline uint64_t
97pickbit (uint64_t val, int N)
98{
99 return pickbits64 (val, N, N);
100}
101
102static uint64_t
103expand_logical_immediate (uint32_t S, uint32_t R, uint32_t N)
104{
105 uint64_t mask;
106 uint64_t imm;
107 unsigned simd_size;
108
109 /* The immediate value is S+1 bits to 1, left rotated by SIMDsize - R
110 (in other words, right rotated by R), then replicated. */
111 if (N != 0)
112 {
113 simd_size = 64;
114 mask = 0xffffffffffffffffull;
115 }
116 else
117 {
118 switch (S)
119 {
120 case 0x00 ... 0x1f: /* 0xxxxx */ simd_size = 32; break;
121 case 0x20 ... 0x2f: /* 10xxxx */ simd_size = 16; S &= 0xf; break;
122 case 0x30 ... 0x37: /* 110xxx */ simd_size = 8; S &= 0x7; break;
123 case 0x38 ... 0x3b: /* 1110xx */ simd_size = 4; S &= 0x3; break;
124 case 0x3c ... 0x3d: /* 11110x */ simd_size = 2; S &= 0x1; break;
125 default: return 0;
126 }
127 mask = (1ull << simd_size) - 1;
128 /* Top bits are IGNORED. */
129 R &= simd_size - 1;
130 }
131
132 /* NOTE: if S = simd_size - 1 we get 0xf..f which is rejected. */
133 if (S == simd_size - 1)
134 return 0;
135
136 /* S+1 consecutive bits to 1. */
137 /* NOTE: S can't be 63 due to detection above. */
138 imm = (1ull << (S + 1)) - 1;
139
140 /* Rotate to the left by simd_size - R. */
141 if (R != 0)
142 imm = ((imm << (simd_size - R)) & mask) | (imm >> R);
143
144 /* Replicate the value according to SIMD size. */
145 switch (simd_size)
146 {
147 case 2: imm = (imm << 2) | imm;
148 case 4: imm = (imm << 4) | imm;
149 case 8: imm = (imm << 8) | imm;
150 case 16: imm = (imm << 16) | imm;
151 case 32: imm = (imm << 32) | imm;
152 case 64: break;
153 default: return 0;
154 }
155
156 return imm;
157}
158
159/* Instr[22,10] encodes N immr and imms. we want a lookup table
160 for each possible combination i.e. 13 bits worth of int entries. */
161#define LI_TABLE_SIZE (1 << 13)
162static uint64_t LITable[LI_TABLE_SIZE];
163
164void
165aarch64_init_LIT_table (void)
166{
167 unsigned index;
168
169 for (index = 0; index < LI_TABLE_SIZE; index++)
170 {
171 uint32_t N = uimm (index, 12, 12);
172 uint32_t immr = uimm (index, 11, 6);
173 uint32_t imms = uimm (index, 5, 0);
174
175 LITable [index] = expand_logical_immediate (imms, immr, N);
176 }
177}
178
179static void
180dexNotify (sim_cpu *cpu)
181{
182 /* instr[14,0] == type : 0 ==> method entry, 1 ==> method reentry
183 2 ==> exit Java, 3 ==> start next bytecode. */
ef0d8ffc 184 uint32_t type = INSTR (14, 0);
2e8cf49e
NC
185
186 TRACE_EVENTS (cpu, "Notify Insn encountered, type = 0x%x", type);
187
188 switch (type)
189 {
190 case 0:
191 /* aarch64_notifyMethodEntry (aarch64_get_reg_u64 (cpu, R23, 0),
192 aarch64_get_reg_u64 (cpu, R22, 0)); */
193 break;
194 case 1:
195 /* aarch64_notifyMethodReentry (aarch64_get_reg_u64 (cpu, R23, 0),
196 aarch64_get_reg_u64 (cpu, R22, 0)); */
197 break;
198 case 2:
199 /* aarch64_notifyMethodExit (); */
200 break;
201 case 3:
202 /* aarch64_notifyBCStart (aarch64_get_reg_u64 (cpu, R23, 0),
203 aarch64_get_reg_u64 (cpu, R22, 0)); */
204 break;
205 }
206}
207
208/* secondary decode within top level groups */
209
210static void
211dexPseudo (sim_cpu *cpu)
212{
213 /* assert instr[28,27] = 00
214
215 We provide 2 pseudo instructions:
216
217 HALT stops execution of the simulator causing an immediate
218 return to the x86 code which entered it.
219
220 CALLOUT initiates recursive entry into x86 code. A register
221 argument holds the address of the x86 routine. Immediate
222 values in the instruction identify the number of general
223 purpose and floating point register arguments to be passed
224 and the type of any value to be returned. */
225
226 uint32_t PSEUDO_HALT = 0xE0000000U;
227 uint32_t PSEUDO_CALLOUT = 0x00018000U;
228 uint32_t PSEUDO_CALLOUTR = 0x00018001U;
229 uint32_t PSEUDO_NOTIFY = 0x00014000U;
230 uint32_t dispatch;
231
232 if (aarch64_get_instr (cpu) == PSEUDO_HALT)
233 {
234 TRACE_EVENTS (cpu, " Pseudo Halt Instruction");
235 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
236 sim_stopped, SIM_SIGTRAP);
237 }
238
ef0d8ffc 239 dispatch = INSTR (31, 15);
2e8cf49e
NC
240
241 /* We do not handle callouts at the moment. */
242 if (dispatch == PSEUDO_CALLOUT || dispatch == PSEUDO_CALLOUTR)
243 {
244 TRACE_EVENTS (cpu, " Callout");
245 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
246 sim_stopped, SIM_SIGABRT);
247 }
248
249 else if (dispatch == PSEUDO_NOTIFY)
250 dexNotify (cpu);
251
252 else
253 HALT_UNALLOC;
254}
255
256/* Load-store single register (unscaled offset)
257 These instructions employ a base register plus an unscaled signed
258 9 bit offset.
259
260 N.B. the base register (source) can be Xn or SP. all other
261 registers may not be SP. */
262
263/* 32 bit load 32 bit unscaled signed 9 bit. */
264static void
265ldur32 (sim_cpu *cpu, int32_t offset)
266{
ef0d8ffc
NC
267 unsigned rn = INSTR (9, 5);
268 unsigned rt = INSTR (4, 0);
2e8cf49e 269
2cdad34c 270 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
271 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
272 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
273 + offset));
274}
275
276/* 64 bit load 64 bit unscaled signed 9 bit. */
277static void
278ldur64 (sim_cpu *cpu, int32_t offset)
279{
ef0d8ffc
NC
280 unsigned rn = INSTR (9, 5);
281 unsigned rt = INSTR (4, 0);
2e8cf49e 282
2cdad34c 283 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
284 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
285 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
286 + offset));
287}
288
289/* 32 bit load zero-extended byte unscaled signed 9 bit. */
290static void
291ldurb32 (sim_cpu *cpu, int32_t offset)
292{
ef0d8ffc
NC
293 unsigned rn = INSTR (9, 5);
294 unsigned rt = INSTR (4, 0);
2e8cf49e 295
2cdad34c 296 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
297 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8
298 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
299 + offset));
300}
301
302/* 32 bit load sign-extended byte unscaled signed 9 bit. */
303static void
304ldursb32 (sim_cpu *cpu, int32_t offset)
305{
ef0d8ffc
NC
306 unsigned rn = INSTR (9, 5);
307 unsigned rt = INSTR (4, 0);
2e8cf49e 308
2cdad34c 309 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
310 aarch64_set_reg_u64 (cpu, rt, NO_SP, (uint32_t) aarch64_get_mem_s8
311 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
312 + offset));
313}
314
315/* 64 bit load sign-extended byte unscaled signed 9 bit. */
316static void
317ldursb64 (sim_cpu *cpu, int32_t offset)
318{
ef0d8ffc
NC
319 unsigned rn = INSTR (9, 5);
320 unsigned rt = INSTR (4, 0);
2e8cf49e 321
2cdad34c 322 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
323 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s8
324 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
325 + offset));
326}
327
328/* 32 bit load zero-extended short unscaled signed 9 bit */
329static void
330ldurh32 (sim_cpu *cpu, int32_t offset)
331{
ef0d8ffc
NC
332 unsigned rn = INSTR (9, 5);
333 unsigned rd = INSTR (4, 0);
2e8cf49e 334
2cdad34c 335 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
336 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_mem_u16
337 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
338 + offset));
339}
340
341/* 32 bit load sign-extended short unscaled signed 9 bit */
342static void
343ldursh32 (sim_cpu *cpu, int32_t offset)
344{
ef0d8ffc
NC
345 unsigned rn = INSTR (9, 5);
346 unsigned rd = INSTR (4, 0);
2e8cf49e 347
2cdad34c 348 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
349 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s16
350 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
351 + offset));
352}
353
354/* 64 bit load sign-extended short unscaled signed 9 bit */
355static void
356ldursh64 (sim_cpu *cpu, int32_t offset)
357{
ef0d8ffc
NC
358 unsigned rn = INSTR (9, 5);
359 unsigned rt = INSTR (4, 0);
2e8cf49e 360
2cdad34c 361 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
362 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s16
363 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
364 + offset));
365}
366
367/* 64 bit load sign-extended word unscaled signed 9 bit */
368static void
369ldursw (sim_cpu *cpu, int32_t offset)
370{
ef0d8ffc
NC
371 unsigned rn = INSTR (9, 5);
372 unsigned rd = INSTR (4, 0);
2e8cf49e 373
2cdad34c 374 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
375 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s32
376 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
377 + offset));
378}
379
380/* N.B. with stores the value in source is written to the address
381 identified by source2 modified by offset. */
382
383/* 32 bit store 32 bit unscaled signed 9 bit. */
384static void
385stur32 (sim_cpu *cpu, int32_t offset)
386{
ef0d8ffc
NC
387 unsigned rn = INSTR (9, 5);
388 unsigned rd = INSTR (4, 0);
2e8cf49e 389
2cdad34c 390 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
391 aarch64_set_mem_u32 (cpu,
392 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
393 aarch64_get_reg_u32 (cpu, rd, NO_SP));
394}
395
396/* 64 bit store 64 bit unscaled signed 9 bit */
397static void
398stur64 (sim_cpu *cpu, int32_t offset)
399{
ef0d8ffc
NC
400 unsigned rn = INSTR (9, 5);
401 unsigned rd = INSTR (4, 0);
2e8cf49e 402
2cdad34c 403 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
404 aarch64_set_mem_u64 (cpu,
405 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
406 aarch64_get_reg_u64 (cpu, rd, NO_SP));
407}
408
409/* 32 bit store byte unscaled signed 9 bit */
410static void
411sturb (sim_cpu *cpu, int32_t offset)
412{
ef0d8ffc
NC
413 unsigned rn = INSTR (9, 5);
414 unsigned rd = INSTR (4, 0);
2e8cf49e 415
2cdad34c 416 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
417 aarch64_set_mem_u8 (cpu,
418 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
419 aarch64_get_reg_u8 (cpu, rd, NO_SP));
420}
421
422/* 32 bit store short unscaled signed 9 bit */
423static void
424sturh (sim_cpu *cpu, int32_t offset)
425{
ef0d8ffc
NC
426 unsigned rn = INSTR (9, 5);
427 unsigned rd = INSTR (4, 0);
2e8cf49e 428
2cdad34c 429 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
430 aarch64_set_mem_u16 (cpu,
431 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
432 aarch64_get_reg_u16 (cpu, rd, NO_SP));
433}
434
435/* Load single register pc-relative label
436 Offset is a signed 19 bit immediate count in words
437 rt may not be SP. */
438
439/* 32 bit pc-relative load */
440static void
441ldr32_pcrel (sim_cpu *cpu, int32_t offset)
442{
ef0d8ffc 443 unsigned rd = INSTR (4, 0);
2e8cf49e 444
2cdad34c 445 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
446 aarch64_set_reg_u64 (cpu, rd, NO_SP,
447 aarch64_get_mem_u32
448 (cpu, aarch64_get_PC (cpu) + offset * 4));
449}
450
451/* 64 bit pc-relative load */
452static void
453ldr_pcrel (sim_cpu *cpu, int32_t offset)
454{
ef0d8ffc 455 unsigned rd = INSTR (4, 0);
2e8cf49e 456
2cdad34c 457 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
458 aarch64_set_reg_u64 (cpu, rd, NO_SP,
459 aarch64_get_mem_u64
460 (cpu, aarch64_get_PC (cpu) + offset * 4));
461}
462
463/* sign extended 32 bit pc-relative load */
464static void
465ldrsw_pcrel (sim_cpu *cpu, int32_t offset)
466{
ef0d8ffc 467 unsigned rd = INSTR (4, 0);
2e8cf49e 468
2cdad34c 469 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
470 aarch64_set_reg_u64 (cpu, rd, NO_SP,
471 aarch64_get_mem_s32
472 (cpu, aarch64_get_PC (cpu) + offset * 4));
473}
474
475/* float pc-relative load */
476static void
477fldrs_pcrel (sim_cpu *cpu, int32_t offset)
478{
ef0d8ffc 479 unsigned int rd = INSTR (4, 0);
2e8cf49e 480
2cdad34c 481 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
482 aarch64_set_vec_u32 (cpu, rd, 0,
483 aarch64_get_mem_u32
484 (cpu, aarch64_get_PC (cpu) + offset * 4));
2e8cf49e
NC
485}
486
487/* double pc-relative load */
488static void
489fldrd_pcrel (sim_cpu *cpu, int32_t offset)
490{
ef0d8ffc 491 unsigned int st = INSTR (4, 0);
2e8cf49e 492
2cdad34c 493 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
494 aarch64_set_vec_u64 (cpu, st, 0,
495 aarch64_get_mem_u64
496 (cpu, aarch64_get_PC (cpu) + offset * 4));
2e8cf49e
NC
497}
498
499/* long double pc-relative load. */
500static void
501fldrq_pcrel (sim_cpu *cpu, int32_t offset)
502{
ef0d8ffc 503 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
504 uint64_t addr = aarch64_get_PC (cpu) + offset * 4;
505 FRegister a;
506
2cdad34c 507 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
508 aarch64_get_mem_long_double (cpu, addr, & a);
509 aarch64_set_FP_long_double (cpu, st, a);
510}
511
512/* This can be used to scale an offset by applying
513 the requisite shift. the second argument is either
514 16, 32 or 64. */
515
516#define SCALE(_offset, _elementSize) \
517 ((_offset) << ScaleShift ## _elementSize)
518
519/* This can be used to optionally scale a register derived offset
520 by applying the requisite shift as indicated by the Scaling
7517e550 521 argument. The second argument is either Byte, Short, Word
2e8cf49e
NC
522 or Long. The third argument is either Scaled or Unscaled.
523 N.B. when _Scaling is Scaled the shift gets ANDed with
524 all 1s while when it is Unscaled it gets ANDed with 0. */
525
526#define OPT_SCALE(_offset, _elementType, _Scaling) \
527 ((_offset) << (_Scaling ? ScaleShift ## _elementType : 0))
528
529/* This can be used to zero or sign extend a 32 bit register derived
530 value to a 64 bit value. the first argument must be the value as
531 a uint32_t and the second must be either UXTW or SXTW. The result
532 is returned as an int64_t. */
533
534static inline int64_t
535extend (uint32_t value, Extension extension)
536{
537 union
538 {
539 uint32_t u;
540 int32_t n;
541 } x;
542
543 /* A branchless variant of this ought to be possible. */
544 if (extension == UXTW || extension == NoExtension)
545 return value;
546
547 x.u = value;
548 return x.n;
549}
550
551/* Scalar Floating Point
552
553 FP load/store single register (4 addressing modes)
554
555 N.B. the base register (source) can be the stack pointer.
556 The secondary source register (source2) can only be an Xn register. */
557
558/* Load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
559static void
560fldrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
561{
ef0d8ffc
NC
562 unsigned rn = INSTR (9, 5);
563 unsigned st = INSTR (4, 0);
2e8cf49e
NC
564 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
565
566 if (wb != Post)
567 address += offset;
568
2cdad34c 569 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b 570 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32 (cpu, address));
2e8cf49e
NC
571 if (wb == Post)
572 address += offset;
573
574 if (wb != NoWriteBack)
575 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
576}
577
5ab6d79e
NC
578/* Load 8 bit with unsigned 12 bit offset. */
579static void
580fldrb_abs (sim_cpu *cpu, uint32_t offset)
581{
ef0d8ffc
NC
582 unsigned rd = INSTR (4, 0);
583 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
584 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
585
2cdad34c 586 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
587 aarch64_set_vec_u8 (cpu, rd, 0, aarch64_get_mem_u32 (cpu, addr));
588}
589
590/* Load 16 bit scaled unsigned 12 bit. */
591static void
592fldrh_abs (sim_cpu *cpu, uint32_t offset)
593{
ef0d8ffc
NC
594 unsigned rd = INSTR (4, 0);
595 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
596 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16);
597
2cdad34c 598 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
599 aarch64_set_vec_u16 (cpu, rd, 0, aarch64_get_mem_u16 (cpu, addr));
600}
601
2e8cf49e
NC
602/* Load 32 bit scaled unsigned 12 bit. */
603static void
604fldrs_abs (sim_cpu *cpu, uint32_t offset)
605{
ef0d8ffc
NC
606 unsigned rd = INSTR (4, 0);
607 unsigned rn = INSTR (9, 5);
5ab6d79e 608 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32);
2e8cf49e 609
2cdad34c 610 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
611 aarch64_set_vec_u32 (cpu, rd, 0, aarch64_get_mem_u32 (cpu, addr));
612}
613
614/* Load 64 bit scaled unsigned 12 bit. */
615static void
616fldrd_abs (sim_cpu *cpu, uint32_t offset)
617{
ef0d8ffc
NC
618 unsigned rd = INSTR (4, 0);
619 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
620 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64);
621
2cdad34c 622 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
623 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_mem_u64 (cpu, addr));
624}
625
626/* Load 128 bit scaled unsigned 12 bit. */
627static void
628fldrq_abs (sim_cpu *cpu, uint32_t offset)
629{
ef0d8ffc
NC
630 unsigned rd = INSTR (4, 0);
631 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
632 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
633
2cdad34c 634 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
635 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_mem_u64 (cpu, addr));
636 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_mem_u64 (cpu, addr + 8));
2e8cf49e
NC
637}
638
639/* Load 32 bit scaled or unscaled zero- or sign-extended
640 32-bit register offset. */
641static void
642fldrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
643{
ef0d8ffc
NC
644 unsigned rm = INSTR (20, 16);
645 unsigned rn = INSTR (9, 5);
646 unsigned st = INSTR (4, 0);
2e8cf49e
NC
647 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
648 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
649 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
650
2cdad34c 651 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
652 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
653 (cpu, address + displacement));
2e8cf49e
NC
654}
655
656/* Load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
657static void
658fldrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
659{
ef0d8ffc
NC
660 unsigned rn = INSTR (9, 5);
661 unsigned st = INSTR (4, 0);
2e8cf49e
NC
662 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
663
664 if (wb != Post)
665 address += offset;
666
2cdad34c 667 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b 668 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64 (cpu, address));
2e8cf49e
NC
669
670 if (wb == Post)
671 address += offset;
672
673 if (wb != NoWriteBack)
674 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
675}
676
2e8cf49e
NC
677/* Load 64 bit scaled or unscaled zero- or sign-extended 32-bit register offset. */
678static void
679fldrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
680{
ef0d8ffc 681 unsigned rm = INSTR (20, 16);
2e8cf49e
NC
682 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
683 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
684
685 fldrd_wb (cpu, displacement, NoWriteBack);
686}
687
688/* Load 128 bit unscaled signed 9 bit with pre- or post-writeback. */
689static void
690fldrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
691{
692 FRegister a;
ef0d8ffc
NC
693 unsigned rn = INSTR (9, 5);
694 unsigned st = INSTR (4, 0);
2e8cf49e
NC
695 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
696
697 if (wb != Post)
698 address += offset;
699
2cdad34c 700 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
701 aarch64_get_mem_long_double (cpu, address, & a);
702 aarch64_set_FP_long_double (cpu, st, a);
703
704 if (wb == Post)
705 address += offset;
706
707 if (wb != NoWriteBack)
708 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
709}
710
2e8cf49e
NC
711/* Load 128 bit scaled or unscaled zero- or sign-extended 32-bit register offset */
712static void
713fldrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
714{
ef0d8ffc 715 unsigned rm = INSTR (20, 16);
2e8cf49e
NC
716 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
717 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
718
719 fldrq_wb (cpu, displacement, NoWriteBack);
720}
721
722/* Memory Access
723
724 load-store single register
725 There are four addressing modes available here which all employ a
726 64 bit source (base) register.
727
728 N.B. the base register (source) can be the stack pointer.
729 The secondary source register (source2)can only be an Xn register.
730
731 Scaled, 12-bit, unsigned immediate offset, without pre- and
732 post-index options.
733 Unscaled, 9-bit, signed immediate offset with pre- or post-index
734 writeback.
735 scaled or unscaled 64-bit register offset.
736 scaled or unscaled 32-bit extended register offset.
737
738 All offsets are assumed to be raw from the decode i.e. the
739 simulator is expected to adjust scaled offsets based on the
740 accessed data size with register or extended register offset
741 versions the same applies except that in the latter case the
742 operation may also require a sign extend.
743
744 A separate method is provided for each possible addressing mode. */
745
746/* 32 bit load 32 bit scaled unsigned 12 bit */
747static void
748ldr32_abs (sim_cpu *cpu, uint32_t offset)
749{
ef0d8ffc
NC
750 unsigned rn = INSTR (9, 5);
751 unsigned rt = INSTR (4, 0);
2e8cf49e 752
2cdad34c 753 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
754 /* The target register may not be SP but the source may be. */
755 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
756 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
757 + SCALE (offset, 32)));
758}
759
760/* 32 bit load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
761static void
762ldr32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
763{
ef0d8ffc
NC
764 unsigned rn = INSTR (9, 5);
765 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
766 uint64_t address;
767
768 if (rn == rt && wb != NoWriteBack)
769 HALT_UNALLOC;
770
771 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
772
773 if (wb != Post)
774 address += offset;
775
2cdad34c 776 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
777 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
778
779 if (wb == Post)
780 address += offset;
781
782 if (wb != NoWriteBack)
783 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
784}
785
786/* 32 bit load 32 bit scaled or unscaled
787 zero- or sign-extended 32-bit register offset */
788static void
789ldr32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
790{
ef0d8ffc
NC
791 unsigned rm = INSTR (20, 16);
792 unsigned rn = INSTR (9, 5);
793 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
794 /* rn may reference SP, rm and rt must reference ZR */
795
796 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
797 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
798 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
799
2cdad34c 800 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
801 aarch64_set_reg_u64 (cpu, rt, NO_SP,
802 aarch64_get_mem_u32 (cpu, address + displacement));
803}
804
805/* 64 bit load 64 bit scaled unsigned 12 bit */
806static void
807ldr_abs (sim_cpu *cpu, uint32_t offset)
808{
ef0d8ffc
NC
809 unsigned rn = INSTR (9, 5);
810 unsigned rt = INSTR (4, 0);
2e8cf49e 811
2cdad34c 812 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
813 /* The target register may not be SP but the source may be. */
814 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
815 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
816 + SCALE (offset, 64)));
817}
818
819/* 64 bit load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
820static void
821ldr_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
822{
ef0d8ffc
NC
823 unsigned rn = INSTR (9, 5);
824 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
825 uint64_t address;
826
827 if (rn == rt && wb != NoWriteBack)
828 HALT_UNALLOC;
829
830 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
831
832 if (wb != Post)
833 address += offset;
834
2cdad34c 835 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
836 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
837
838 if (wb == Post)
839 address += offset;
840
841 if (wb != NoWriteBack)
842 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
843}
844
845/* 64 bit load 64 bit scaled or unscaled zero-
846 or sign-extended 32-bit register offset. */
847static void
848ldr_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
849{
ef0d8ffc
NC
850 unsigned rm = INSTR (20, 16);
851 unsigned rn = INSTR (9, 5);
852 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
853 /* rn may reference SP, rm and rt must reference ZR */
854
855 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
856 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
857 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
858
2cdad34c 859 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
860 aarch64_set_reg_u64 (cpu, rt, NO_SP,
861 aarch64_get_mem_u64 (cpu, address + displacement));
862}
863
864/* 32 bit load zero-extended byte scaled unsigned 12 bit. */
865static void
866ldrb32_abs (sim_cpu *cpu, uint32_t offset)
867{
ef0d8ffc
NC
868 unsigned rn = INSTR (9, 5);
869 unsigned rt = INSTR (4, 0);
2e8cf49e 870
2cdad34c 871 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
872 /* The target register may not be SP but the source may be
873 there is no scaling required for a byte load. */
874 aarch64_set_reg_u64 (cpu, rt, NO_SP,
875 aarch64_get_mem_u8
876 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
877}
878
879/* 32 bit load zero-extended byte unscaled signed 9 bit with pre- or post-writeback. */
880static void
881ldrb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
882{
ef0d8ffc
NC
883 unsigned rn = INSTR (9, 5);
884 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
885 uint64_t address;
886
887 if (rn == rt && wb != NoWriteBack)
888 HALT_UNALLOC;
889
890 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
891
892 if (wb != Post)
893 address += offset;
894
2cdad34c 895 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
896 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
897
898 if (wb == Post)
899 address += offset;
900
901 if (wb != NoWriteBack)
902 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
903}
904
905/* 32 bit load zero-extended byte scaled or unscaled zero-
906 or sign-extended 32-bit register offset. */
907static void
908ldrb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
909{
ef0d8ffc
NC
910 unsigned rm = INSTR (20, 16);
911 unsigned rn = INSTR (9, 5);
912 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
913 /* rn may reference SP, rm and rt must reference ZR */
914
915 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
916 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
917 extension);
918
2cdad34c 919 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
920 /* There is no scaling required for a byte load. */
921 aarch64_set_reg_u64 (cpu, rt, NO_SP,
922 aarch64_get_mem_u8 (cpu, address + displacement));
923}
924
925/* 64 bit load sign-extended byte unscaled signed 9 bit
926 with pre- or post-writeback. */
927static void
928ldrsb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
929{
ef0d8ffc
NC
930 unsigned rn = INSTR (9, 5);
931 unsigned rt = INSTR (4, 0);
2e8cf49e 932 uint64_t address;
7517e550 933 int64_t val;
2e8cf49e
NC
934
935 if (rn == rt && wb != NoWriteBack)
936 HALT_UNALLOC;
937
938 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
939
940 if (wb != Post)
941 address += offset;
942
2cdad34c 943 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
944 val = aarch64_get_mem_s8 (cpu, address);
945 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
946
947 if (wb == Post)
948 address += offset;
949
950 if (wb != NoWriteBack)
951 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
952}
953
954/* 64 bit load sign-extended byte scaled unsigned 12 bit. */
955static void
956ldrsb_abs (sim_cpu *cpu, uint32_t offset)
957{
958 ldrsb_wb (cpu, offset, NoWriteBack);
959}
960
961/* 64 bit load sign-extended byte scaled or unscaled zero-
962 or sign-extended 32-bit register offset. */
963static void
964ldrsb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
965{
ef0d8ffc
NC
966 unsigned rm = INSTR (20, 16);
967 unsigned rn = INSTR (9, 5);
968 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
969 /* rn may reference SP, rm and rt must reference ZR */
970
971 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
972 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
973 extension);
2cdad34c 974 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 975 /* There is no scaling required for a byte load. */
7517e550 976 aarch64_set_reg_s64 (cpu, rt, NO_SP,
2e8cf49e
NC
977 aarch64_get_mem_s8 (cpu, address + displacement));
978}
979
980/* 32 bit load zero-extended short scaled unsigned 12 bit. */
981static void
982ldrh32_abs (sim_cpu *cpu, uint32_t offset)
983{
ef0d8ffc
NC
984 unsigned rn = INSTR (9, 5);
985 unsigned rt = INSTR (4, 0);
7517e550 986 uint32_t val;
2e8cf49e 987
2cdad34c 988 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 989 /* The target register may not be SP but the source may be. */
7517e550
NC
990 val = aarch64_get_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
991 + SCALE (offset, 16));
992 aarch64_set_reg_u32 (cpu, rt, NO_SP, val);
2e8cf49e
NC
993}
994
995/* 32 bit load zero-extended short unscaled signed 9 bit
996 with pre- or post-writeback. */
997static void
998ldrh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
999{
ef0d8ffc
NC
1000 unsigned rn = INSTR (9, 5);
1001 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1002 uint64_t address;
1003
1004 if (rn == rt && wb != NoWriteBack)
1005 HALT_UNALLOC;
1006
1007 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1008
1009 if (wb != Post)
1010 address += offset;
1011
2cdad34c 1012 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 1013 aarch64_set_reg_u32 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
2e8cf49e
NC
1014
1015 if (wb == Post)
1016 address += offset;
1017
1018 if (wb != NoWriteBack)
1019 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1020}
1021
1022/* 32 bit load zero-extended short scaled or unscaled zero-
1023 or sign-extended 32-bit register offset. */
1024static void
1025ldrh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1026{
ef0d8ffc
NC
1027 unsigned rm = INSTR (20, 16);
1028 unsigned rn = INSTR (9, 5);
1029 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1030 /* rn may reference SP, rm and rt must reference ZR */
1031
1032 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1033 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1034 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1035
2cdad34c 1036 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 1037 aarch64_set_reg_u32 (cpu, rt, NO_SP,
2e8cf49e
NC
1038 aarch64_get_mem_u16 (cpu, address + displacement));
1039}
1040
1041/* 32 bit load sign-extended short scaled unsigned 12 bit. */
1042static void
1043ldrsh32_abs (sim_cpu *cpu, uint32_t offset)
1044{
ef0d8ffc
NC
1045 unsigned rn = INSTR (9, 5);
1046 unsigned rt = INSTR (4, 0);
7517e550 1047 int32_t val;
2e8cf49e 1048
2cdad34c 1049 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 1050 /* The target register may not be SP but the source may be. */
7517e550
NC
1051 val = aarch64_get_mem_s16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1052 + SCALE (offset, 16));
1053 aarch64_set_reg_s32 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1054}
1055
1056/* 32 bit load sign-extended short unscaled signed 9 bit
1057 with pre- or post-writeback. */
1058static void
1059ldrsh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1060{
ef0d8ffc
NC
1061 unsigned rn = INSTR (9, 5);
1062 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1063 uint64_t address;
1064
1065 if (rn == rt && wb != NoWriteBack)
1066 HALT_UNALLOC;
1067
1068 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1069
1070 if (wb != Post)
1071 address += offset;
1072
2cdad34c 1073 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1074 aarch64_set_reg_s32 (cpu, rt, NO_SP,
1075 (int32_t) aarch64_get_mem_s16 (cpu, address));
2e8cf49e
NC
1076
1077 if (wb == Post)
1078 address += offset;
1079
1080 if (wb != NoWriteBack)
1081 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1082}
1083
1084/* 32 bit load sign-extended short scaled or unscaled zero-
1085 or sign-extended 32-bit register offset. */
1086static void
1087ldrsh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1088{
ef0d8ffc
NC
1089 unsigned rm = INSTR (20, 16);
1090 unsigned rn = INSTR (9, 5);
1091 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1092 /* rn may reference SP, rm and rt must reference ZR */
1093
1094 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1095 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1096 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1097
2cdad34c 1098 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1099 aarch64_set_reg_s32 (cpu, rt, NO_SP,
1100 (int32_t) aarch64_get_mem_s16
2e8cf49e
NC
1101 (cpu, address + displacement));
1102}
1103
1104/* 64 bit load sign-extended short scaled unsigned 12 bit. */
1105static void
1106ldrsh_abs (sim_cpu *cpu, uint32_t offset)
1107{
ef0d8ffc
NC
1108 unsigned rn = INSTR (9, 5);
1109 unsigned rt = INSTR (4, 0);
7517e550 1110 int64_t val;
2e8cf49e 1111
2cdad34c 1112 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 1113 /* The target register may not be SP but the source may be. */
7517e550
NC
1114 val = aarch64_get_mem_s16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1115 + SCALE (offset, 16));
1116 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1117}
1118
1119/* 64 bit load sign-extended short unscaled signed 9 bit
1120 with pre- or post-writeback. */
1121static void
1122ldrsh64_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1123{
ef0d8ffc
NC
1124 unsigned rn = INSTR (9, 5);
1125 unsigned rt = INSTR (4, 0);
2e8cf49e 1126 uint64_t address;
7517e550 1127 int64_t val;
2e8cf49e
NC
1128
1129 if (rn == rt && wb != NoWriteBack)
1130 HALT_UNALLOC;
1131
2cdad34c 1132 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1133 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1134
1135 if (wb != Post)
1136 address += offset;
1137
7517e550
NC
1138 val = aarch64_get_mem_s16 (cpu, address);
1139 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1140
1141 if (wb == Post)
1142 address += offset;
1143
1144 if (wb != NoWriteBack)
1145 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1146}
1147
1148/* 64 bit load sign-extended short scaled or unscaled zero-
1149 or sign-extended 32-bit register offset. */
1150static void
1151ldrsh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1152{
ef0d8ffc
NC
1153 unsigned rm = INSTR (20, 16);
1154 unsigned rn = INSTR (9, 5);
1155 unsigned rt = INSTR (4, 0);
7517e550 1156
2e8cf49e
NC
1157 /* rn may reference SP, rm and rt must reference ZR */
1158
1159 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1160 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1161 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
7517e550 1162 int64_t val;
2e8cf49e 1163
2cdad34c 1164 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1165 val = aarch64_get_mem_s16 (cpu, address + displacement);
1166 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1167}
1168
1169/* 64 bit load sign-extended 32 bit scaled unsigned 12 bit. */
1170static void
1171ldrsw_abs (sim_cpu *cpu, uint32_t offset)
1172{
ef0d8ffc
NC
1173 unsigned rn = INSTR (9, 5);
1174 unsigned rt = INSTR (4, 0);
7517e550 1175 int64_t val;
2e8cf49e 1176
2cdad34c 1177 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
1178 val = aarch64_get_mem_s32 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1179 + SCALE (offset, 32));
2e8cf49e 1180 /* The target register may not be SP but the source may be. */
7517e550 1181 return aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1182}
1183
1184/* 64 bit load sign-extended 32 bit unscaled signed 9 bit
1185 with pre- or post-writeback. */
1186static void
1187ldrsw_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1188{
ef0d8ffc
NC
1189 unsigned rn = INSTR (9, 5);
1190 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1191 uint64_t address;
1192
1193 if (rn == rt && wb != NoWriteBack)
1194 HALT_UNALLOC;
1195
1196 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1197
1198 if (wb != Post)
1199 address += offset;
1200
2cdad34c 1201 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1202 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32 (cpu, address));
1203
1204 if (wb == Post)
1205 address += offset;
1206
1207 if (wb != NoWriteBack)
1208 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1209}
1210
1211/* 64 bit load sign-extended 32 bit scaled or unscaled zero-
1212 or sign-extended 32-bit register offset. */
1213static void
1214ldrsw_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1215{
ef0d8ffc
NC
1216 unsigned rm = INSTR (20, 16);
1217 unsigned rn = INSTR (9, 5);
1218 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1219 /* rn may reference SP, rm and rt must reference ZR */
1220
1221 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1222 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1223 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1224
2cdad34c 1225 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1226 aarch64_set_reg_s64 (cpu, rt, NO_SP,
1227 aarch64_get_mem_s32 (cpu, address + displacement));
1228}
1229
1230/* N.B. with stores the value in source is written to the
1231 address identified by source2 modified by source3/offset. */
1232
1233/* 32 bit store scaled unsigned 12 bit. */
1234static void
1235str32_abs (sim_cpu *cpu, uint32_t offset)
1236{
ef0d8ffc
NC
1237 unsigned rn = INSTR (9, 5);
1238 unsigned rt = INSTR (4, 0);
2e8cf49e 1239
2cdad34c 1240 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1241 /* The target register may not be SP but the source may be. */
1242 aarch64_set_mem_u32 (cpu, (aarch64_get_reg_u64 (cpu, rn, SP_OK)
1243 + SCALE (offset, 32)),
1244 aarch64_get_reg_u32 (cpu, rt, NO_SP));
1245}
1246
1247/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
1248static void
1249str32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1250{
ef0d8ffc
NC
1251 unsigned rn = INSTR (9, 5);
1252 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1253 uint64_t address;
1254
1255 if (rn == rt && wb != NoWriteBack)
1256 HALT_UNALLOC;
1257
1258 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1259 if (wb != Post)
1260 address += offset;
1261
2cdad34c 1262 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1263 aarch64_set_mem_u32 (cpu, address, aarch64_get_reg_u32 (cpu, rt, NO_SP));
1264
1265 if (wb == Post)
1266 address += offset;
1267
1268 if (wb != NoWriteBack)
1269 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1270}
1271
1272/* 32 bit store scaled or unscaled zero- or
1273 sign-extended 32-bit register offset. */
1274static void
1275str32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1276{
ef0d8ffc
NC
1277 unsigned rm = INSTR (20, 16);
1278 unsigned rn = INSTR (9, 5);
1279 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1280
1281 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1282 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1283 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1284
2cdad34c 1285 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1286 aarch64_set_mem_u32 (cpu, address + displacement,
1287 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1288}
1289
1290/* 64 bit store scaled unsigned 12 bit. */
1291static void
1292str_abs (sim_cpu *cpu, uint32_t offset)
1293{
ef0d8ffc
NC
1294 unsigned rn = INSTR (9, 5);
1295 unsigned rt = INSTR (4, 0);
2e8cf49e 1296
2cdad34c 1297 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1298 aarch64_set_mem_u64 (cpu,
1299 aarch64_get_reg_u64 (cpu, rn, SP_OK)
1300 + SCALE (offset, 64),
1301 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1302}
1303
1304/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
1305static void
1306str_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1307{
ef0d8ffc
NC
1308 unsigned rn = INSTR (9, 5);
1309 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1310 uint64_t address;
1311
1312 if (rn == rt && wb != NoWriteBack)
1313 HALT_UNALLOC;
1314
1315 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1316
1317 if (wb != Post)
1318 address += offset;
1319
2cdad34c 1320 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1321 aarch64_set_mem_u64 (cpu, address, aarch64_get_reg_u64 (cpu, rt, NO_SP));
1322
1323 if (wb == Post)
1324 address += offset;
1325
1326 if (wb != NoWriteBack)
1327 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1328}
1329
1330/* 64 bit store scaled or unscaled zero-
1331 or sign-extended 32-bit register offset. */
1332static void
1333str_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1334{
ef0d8ffc
NC
1335 unsigned rm = INSTR (20, 16);
1336 unsigned rn = INSTR (9, 5);
1337 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1338 /* rn may reference SP, rm and rt must reference ZR */
1339
1340 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1341 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1342 extension);
1343 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1344
2cdad34c 1345 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1346 aarch64_set_mem_u64 (cpu, address + displacement,
1347 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1348}
1349
1350/* 32 bit store byte scaled unsigned 12 bit. */
1351static void
1352strb_abs (sim_cpu *cpu, uint32_t offset)
1353{
ef0d8ffc
NC
1354 unsigned rn = INSTR (9, 5);
1355 unsigned rt = INSTR (4, 0);
2e8cf49e 1356
2cdad34c 1357 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1358 /* The target register may not be SP but the source may be.
1359 There is no scaling required for a byte load. */
1360 aarch64_set_mem_u8 (cpu,
1361 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
1362 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1363}
1364
1365/* 32 bit store byte unscaled signed 9 bit with pre- or post-writeback. */
1366static void
1367strb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1368{
ef0d8ffc
NC
1369 unsigned rn = INSTR (9, 5);
1370 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1371 uint64_t address;
1372
1373 if (rn == rt && wb != NoWriteBack)
1374 HALT_UNALLOC;
1375
1376 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1377
1378 if (wb != Post)
1379 address += offset;
1380
2cdad34c 1381 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1382 aarch64_set_mem_u8 (cpu, address, aarch64_get_reg_u8 (cpu, rt, NO_SP));
1383
1384 if (wb == Post)
1385 address += offset;
1386
1387 if (wb != NoWriteBack)
1388 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1389}
1390
1391/* 32 bit store byte scaled or unscaled zero-
1392 or sign-extended 32-bit register offset. */
1393static void
1394strb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1395{
ef0d8ffc
NC
1396 unsigned rm = INSTR (20, 16);
1397 unsigned rn = INSTR (9, 5);
1398 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1399 /* rn may reference SP, rm and rt must reference ZR */
1400
1401 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1402 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1403 extension);
1404
2cdad34c 1405 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1406 /* There is no scaling required for a byte load. */
1407 aarch64_set_mem_u8 (cpu, address + displacement,
1408 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1409}
1410
1411/* 32 bit store short scaled unsigned 12 bit. */
1412static void
1413strh_abs (sim_cpu *cpu, uint32_t offset)
1414{
ef0d8ffc
NC
1415 unsigned rn = INSTR (9, 5);
1416 unsigned rt = INSTR (4, 0);
2e8cf49e 1417
2cdad34c 1418 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1419 /* The target register may not be SP but the source may be. */
1420 aarch64_set_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1421 + SCALE (offset, 16),
1422 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1423}
1424
1425/* 32 bit store short unscaled signed 9 bit with pre- or post-writeback. */
1426static void
1427strh_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1428{
ef0d8ffc
NC
1429 unsigned rn = INSTR (9, 5);
1430 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1431 uint64_t address;
1432
1433 if (rn == rt && wb != NoWriteBack)
1434 HALT_UNALLOC;
1435
1436 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1437
1438 if (wb != Post)
1439 address += offset;
1440
2cdad34c 1441 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1442 aarch64_set_mem_u16 (cpu, address, aarch64_get_reg_u16 (cpu, rt, NO_SP));
1443
1444 if (wb == Post)
1445 address += offset;
1446
1447 if (wb != NoWriteBack)
1448 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1449}
1450
1451/* 32 bit store short scaled or unscaled zero-
1452 or sign-extended 32-bit register offset. */
1453static void
1454strh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1455{
ef0d8ffc
NC
1456 unsigned rm = INSTR (20, 16);
1457 unsigned rn = INSTR (9, 5);
1458 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1459 /* rn may reference SP, rm and rt must reference ZR */
1460
1461 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1462 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1463 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1464
2cdad34c 1465 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1466 aarch64_set_mem_u16 (cpu, address + displacement,
1467 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1468}
1469
1470/* Prefetch unsigned 12 bit. */
1471static void
1472prfm_abs (sim_cpu *cpu, uint32_t offset)
1473{
1474 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1475 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1476 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1477 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1478 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1479 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1480 ow ==> UNALLOC
ef0d8ffc 1481 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1482 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK)
1483 + SCALE (offset, 64). */
1484
1485 /* TODO : implement prefetch of address. */
1486}
1487
1488/* Prefetch scaled or unscaled zero- or sign-extended 32-bit register offset. */
1489static void
1490prfm_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1491{
1492 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1493 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1494 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1495 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1496 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1497 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1498 ow ==> UNALLOC
1499 rn may reference SP, rm may only reference ZR
ef0d8ffc 1500 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1501 uint64_t base = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1502 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1503 extension);
1504 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1505 uint64_t address = base + displacement. */
1506
1507 /* TODO : implement prefetch of address */
1508}
1509
1510/* 64 bit pc-relative prefetch. */
1511static void
1512prfm_pcrel (sim_cpu *cpu, int32_t offset)
1513{
1514 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1515 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1516 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1517 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1518 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1519 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1520 ow ==> UNALLOC
ef0d8ffc 1521 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1522 uint64_t address = aarch64_get_PC (cpu) + offset. */
1523
1524 /* TODO : implement this */
1525}
1526
1527/* Load-store exclusive. */
1528
1529static void
1530ldxr (sim_cpu *cpu)
1531{
ef0d8ffc
NC
1532 unsigned rn = INSTR (9, 5);
1533 unsigned rt = INSTR (4, 0);
2e8cf49e 1534 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
ef0d8ffc
NC
1535 int size = INSTR (31, 30);
1536 /* int ordered = INSTR (15, 15); */
1537 /* int exclusive = ! INSTR (23, 23); */
2e8cf49e 1538
2cdad34c 1539 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1540 switch (size)
1541 {
1542 case 0:
1543 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
1544 break;
1545 case 1:
1546 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
1547 break;
1548 case 2:
1549 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
1550 break;
1551 case 3:
1552 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
1553 break;
2e8cf49e
NC
1554 }
1555}
1556
1557static void
1558stxr (sim_cpu *cpu)
1559{
ef0d8ffc
NC
1560 unsigned rn = INSTR (9, 5);
1561 unsigned rt = INSTR (4, 0);
1562 unsigned rs = INSTR (20, 16);
2e8cf49e 1563 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
ef0d8ffc 1564 int size = INSTR (31, 30);
2e8cf49e
NC
1565 uint64_t data = aarch64_get_reg_u64 (cpu, rt, NO_SP);
1566
1567 switch (size)
1568 {
1569 case 0: aarch64_set_mem_u8 (cpu, address, data); break;
1570 case 1: aarch64_set_mem_u16 (cpu, address, data); break;
1571 case 2: aarch64_set_mem_u32 (cpu, address, data); break;
1572 case 3: aarch64_set_mem_u64 (cpu, address, data); break;
2e8cf49e
NC
1573 }
1574
2cdad34c 1575 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1576 aarch64_set_reg_u64 (cpu, rs, NO_SP, 0); /* Always exclusive... */
1577}
1578
1579static void
1580dexLoadLiteral (sim_cpu *cpu)
1581{
1582 /* instr[29,27] == 011
1583 instr[25,24] == 00
1584 instr[31,30:26] = opc: 000 ==> LDRW, 001 ==> FLDRS
1585 010 ==> LDRX, 011 ==> FLDRD
1586 100 ==> LDRSW, 101 ==> FLDRQ
1587 110 ==> PRFM, 111 ==> UNALLOC
1588 instr[26] ==> V : 0 ==> GReg, 1 ==> FReg
1589 instr[23, 5] == simm19 */
1590
ef0d8ffc 1591 /* unsigned rt = INSTR (4, 0); */
7517e550 1592 uint32_t dispatch = (INSTR (31, 30) << 1) | INSTR (26, 26);
2e8cf49e
NC
1593 int32_t imm = simm32 (aarch64_get_instr (cpu), 23, 5);
1594
1595 switch (dispatch)
1596 {
1597 case 0: ldr32_pcrel (cpu, imm); break;
1598 case 1: fldrs_pcrel (cpu, imm); break;
1599 case 2: ldr_pcrel (cpu, imm); break;
1600 case 3: fldrd_pcrel (cpu, imm); break;
1601 case 4: ldrsw_pcrel (cpu, imm); break;
1602 case 5: fldrq_pcrel (cpu, imm); break;
1603 case 6: prfm_pcrel (cpu, imm); break;
1604 case 7:
1605 default:
1606 HALT_UNALLOC;
1607 }
1608}
1609
1610/* Immediate arithmetic
1611 The aimm argument is a 12 bit unsigned value or a 12 bit unsigned
1612 value left shifted by 12 bits (done at decode).
1613
1614 N.B. the register args (dest, source) can normally be Xn or SP.
1615 the exception occurs for flag setting instructions which may
1616 only use Xn for the output (dest). */
1617
1618/* 32 bit add immediate. */
1619static void
1620add32 (sim_cpu *cpu, uint32_t aimm)
1621{
ef0d8ffc
NC
1622 unsigned rn = INSTR (9, 5);
1623 unsigned rd = INSTR (4, 0);
2e8cf49e 1624
2cdad34c 1625 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1626 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1627 aarch64_get_reg_u32 (cpu, rn, SP_OK) + aimm);
1628}
1629
1630/* 64 bit add immediate. */
1631static void
1632add64 (sim_cpu *cpu, uint32_t aimm)
1633{
ef0d8ffc
NC
1634 unsigned rn = INSTR (9, 5);
1635 unsigned rd = INSTR (4, 0);
2e8cf49e 1636
2cdad34c 1637 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1638 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1639 aarch64_get_reg_u64 (cpu, rn, SP_OK) + aimm);
1640}
1641
1642static void
1643set_flags_for_add32 (sim_cpu *cpu, int32_t value1, int32_t value2)
1644{
1645 int32_t result = value1 + value2;
1646 int64_t sresult = (int64_t) value1 + (int64_t) value2;
1647 uint64_t uresult = (uint64_t)(uint32_t) value1
1648 + (uint64_t)(uint32_t) value2;
1649 uint32_t flags = 0;
1650
1651 if (result == 0)
1652 flags |= Z;
1653
1654 if (result & (1 << 31))
1655 flags |= N;
1656
0592e80b 1657 if (uresult != (uint32_t)uresult)
2e8cf49e
NC
1658 flags |= C;
1659
0592e80b 1660 if (sresult != (int32_t)sresult)
2e8cf49e
NC
1661 flags |= V;
1662
1663 aarch64_set_CPSR (cpu, flags);
1664}
1665
963201cf
JW
1666#define NEG(a) (((a) & signbit) == signbit)
1667#define POS(a) (((a) & signbit) == 0)
1668
2e8cf49e
NC
1669static void
1670set_flags_for_add64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1671{
963201cf
JW
1672 uint64_t result = value1 + value2;
1673 uint32_t flags = 0;
1674 uint64_t signbit = 1ULL << 63;
2e8cf49e
NC
1675
1676 if (result == 0)
1677 flags |= Z;
1678
963201cf 1679 if (NEG (result))
2e8cf49e
NC
1680 flags |= N;
1681
963201cf
JW
1682 if ( (NEG (value1) && NEG (value2))
1683 || (NEG (value1) && POS (result))
1684 || (NEG (value2) && POS (result)))
1685 flags |= C;
1686
1687 if ( (NEG (value1) && NEG (value2) && POS (result))
1688 || (POS (value1) && POS (value2) && NEG (result)))
1689 flags |= V;
2e8cf49e
NC
1690
1691 aarch64_set_CPSR (cpu, flags);
1692}
1693
2e8cf49e
NC
1694static void
1695set_flags_for_sub32 (sim_cpu *cpu, uint32_t value1, uint32_t value2)
1696{
1697 uint32_t result = value1 - value2;
1698 uint32_t flags = 0;
57aa1742 1699 uint32_t signbit = 1U << 31;
2e8cf49e
NC
1700
1701 if (result == 0)
1702 flags |= Z;
1703
1704 if (NEG (result))
1705 flags |= N;
1706
1707 if ( (NEG (value1) && POS (value2))
1708 || (NEG (value1) && POS (result))
1709 || (POS (value2) && POS (result)))
1710 flags |= C;
1711
1712 if ( (NEG (value1) && POS (value2) && POS (result))
1713 || (POS (value1) && NEG (value2) && NEG (result)))
1714 flags |= V;
1715
1716 aarch64_set_CPSR (cpu, flags);
1717}
1718
1719static void
1720set_flags_for_sub64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1721{
1722 uint64_t result = value1 - value2;
1723 uint32_t flags = 0;
1724 uint64_t signbit = 1ULL << 63;
1725
1726 if (result == 0)
1727 flags |= Z;
1728
1729 if (NEG (result))
1730 flags |= N;
1731
1732 if ( (NEG (value1) && POS (value2))
1733 || (NEG (value1) && POS (result))
1734 || (POS (value2) && POS (result)))
1735 flags |= C;
1736
1737 if ( (NEG (value1) && POS (value2) && POS (result))
1738 || (POS (value1) && NEG (value2) && NEG (result)))
1739 flags |= V;
1740
1741 aarch64_set_CPSR (cpu, flags);
1742}
1743
1744static void
1745set_flags_for_binop32 (sim_cpu *cpu, uint32_t result)
1746{
1747 uint32_t flags = 0;
1748
1749 if (result == 0)
1750 flags |= Z;
1751 else
1752 flags &= ~ Z;
1753
1754 if (result & (1 << 31))
1755 flags |= N;
1756 else
1757 flags &= ~ N;
1758
1759 aarch64_set_CPSR (cpu, flags);
1760}
1761
1762static void
1763set_flags_for_binop64 (sim_cpu *cpu, uint64_t result)
1764{
1765 uint32_t flags = 0;
1766
1767 if (result == 0)
1768 flags |= Z;
1769 else
1770 flags &= ~ Z;
1771
1772 if (result & (1ULL << 63))
1773 flags |= N;
1774 else
1775 flags &= ~ N;
1776
1777 aarch64_set_CPSR (cpu, flags);
1778}
1779
1780/* 32 bit add immediate set flags. */
1781static void
1782adds32 (sim_cpu *cpu, uint32_t aimm)
1783{
ef0d8ffc
NC
1784 unsigned rn = INSTR (9, 5);
1785 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1786 /* TODO : do we need to worry about signs here? */
1787 int32_t value1 = aarch64_get_reg_s32 (cpu, rn, SP_OK);
1788
2cdad34c 1789 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1790 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + aimm);
1791 set_flags_for_add32 (cpu, value1, aimm);
1792}
1793
1794/* 64 bit add immediate set flags. */
1795static void
1796adds64 (sim_cpu *cpu, uint32_t aimm)
1797{
ef0d8ffc
NC
1798 unsigned rn = INSTR (9, 5);
1799 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1800 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1801 uint64_t value2 = aimm;
1802
2cdad34c 1803 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1804 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1805 set_flags_for_add64 (cpu, value1, value2);
1806}
1807
1808/* 32 bit sub immediate. */
1809static void
1810sub32 (sim_cpu *cpu, uint32_t aimm)
1811{
ef0d8ffc
NC
1812 unsigned rn = INSTR (9, 5);
1813 unsigned rd = INSTR (4, 0);
2e8cf49e 1814
2cdad34c 1815 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1816 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1817 aarch64_get_reg_u32 (cpu, rn, SP_OK) - aimm);
1818}
1819
1820/* 64 bit sub immediate. */
1821static void
1822sub64 (sim_cpu *cpu, uint32_t aimm)
1823{
ef0d8ffc
NC
1824 unsigned rn = INSTR (9, 5);
1825 unsigned rd = INSTR (4, 0);
2e8cf49e 1826
2cdad34c 1827 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1828 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1829 aarch64_get_reg_u64 (cpu, rn, SP_OK) - aimm);
1830}
1831
1832/* 32 bit sub immediate set flags. */
1833static void
1834subs32 (sim_cpu *cpu, uint32_t aimm)
1835{
ef0d8ffc
NC
1836 unsigned rn = INSTR (9, 5);
1837 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1838 uint32_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1839 uint32_t value2 = aimm;
1840
2cdad34c 1841 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1842 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1843 set_flags_for_sub32 (cpu, value1, value2);
1844}
1845
1846/* 64 bit sub immediate set flags. */
1847static void
1848subs64 (sim_cpu *cpu, uint32_t aimm)
1849{
ef0d8ffc
NC
1850 unsigned rn = INSTR (9, 5);
1851 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1852 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1853 uint32_t value2 = aimm;
1854
2cdad34c 1855 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1856 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1857 set_flags_for_sub64 (cpu, value1, value2);
1858}
1859
1860/* Data Processing Register. */
1861
1862/* First two helpers to perform the shift operations. */
1863
1864static inline uint32_t
1865shifted32 (uint32_t value, Shift shift, uint32_t count)
1866{
1867 switch (shift)
1868 {
1869 default:
1870 case LSL:
1871 return (value << count);
1872 case LSR:
1873 return (value >> count);
1874 case ASR:
1875 {
1876 int32_t svalue = value;
1877 return (svalue >> count);
1878 }
1879 case ROR:
1880 {
1881 uint32_t top = value >> count;
1882 uint32_t bottom = value << (32 - count);
1883 return (bottom | top);
1884 }
1885 }
1886}
1887
1888static inline uint64_t
1889shifted64 (uint64_t value, Shift shift, uint32_t count)
1890{
1891 switch (shift)
1892 {
1893 default:
1894 case LSL:
1895 return (value << count);
1896 case LSR:
1897 return (value >> count);
1898 case ASR:
1899 {
1900 int64_t svalue = value;
1901 return (svalue >> count);
1902 }
1903 case ROR:
1904 {
1905 uint64_t top = value >> count;
1906 uint64_t bottom = value << (64 - count);
1907 return (bottom | top);
1908 }
1909 }
1910}
1911
1912/* Arithmetic shifted register.
1913 These allow an optional LSL, ASR or LSR to the second source
1914 register with a count up to the register bit count.
1915
1916 N.B register args may not be SP. */
1917
1918/* 32 bit ADD shifted register. */
1919static void
1920add32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1921{
ef0d8ffc
NC
1922 unsigned rm = INSTR (20, 16);
1923 unsigned rn = INSTR (9, 5);
1924 unsigned rd = INSTR (4, 0);
2e8cf49e 1925
2cdad34c 1926 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1927 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1928 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1929 + shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1930 shift, count));
1931}
1932
1933/* 64 bit ADD shifted register. */
1934static void
1935add64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1936{
ef0d8ffc
NC
1937 unsigned rm = INSTR (20, 16);
1938 unsigned rn = INSTR (9, 5);
1939 unsigned rd = INSTR (4, 0);
2e8cf49e 1940
2cdad34c 1941 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1942 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1943 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1944 + shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1945 shift, count));
1946}
1947
1948/* 32 bit ADD shifted register setting flags. */
1949static void
1950adds32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1951{
ef0d8ffc
NC
1952 unsigned rm = INSTR (20, 16);
1953 unsigned rn = INSTR (9, 5);
1954 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1955
1956 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1957 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1958 shift, count);
1959
2cdad34c 1960 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1961 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1962 set_flags_for_add32 (cpu, value1, value2);
1963}
1964
1965/* 64 bit ADD shifted register setting flags. */
1966static void
1967adds64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1968{
ef0d8ffc
NC
1969 unsigned rm = INSTR (20, 16);
1970 unsigned rn = INSTR (9, 5);
1971 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1972
1973 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1974 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1975 shift, count);
1976
2cdad34c 1977 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1978 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1979 set_flags_for_add64 (cpu, value1, value2);
1980}
1981
1982/* 32 bit SUB shifted register. */
1983static void
1984sub32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1985{
ef0d8ffc
NC
1986 unsigned rm = INSTR (20, 16);
1987 unsigned rn = INSTR (9, 5);
1988 unsigned rd = INSTR (4, 0);
2e8cf49e 1989
2cdad34c 1990 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
1991 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1992 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1993 - shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1994 shift, count));
1995}
1996
1997/* 64 bit SUB shifted register. */
1998static void
1999sub64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
2000{
ef0d8ffc
NC
2001 unsigned rm = INSTR (20, 16);
2002 unsigned rn = INSTR (9, 5);
2003 unsigned rd = INSTR (4, 0);
2e8cf49e 2004
2cdad34c 2005 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2006 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2007 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2008 - shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
2009 shift, count));
2010}
2011
2012/* 32 bit SUB shifted register setting flags. */
2013static void
2014subs32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
2015{
ef0d8ffc
NC
2016 unsigned rm = INSTR (20, 16);
2017 unsigned rn = INSTR (9, 5);
2018 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2019
2020 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2021 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
2022 shift, count);
2023
2cdad34c 2024 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2025 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2026 set_flags_for_sub32 (cpu, value1, value2);
2027}
2028
2029/* 64 bit SUB shifted register setting flags. */
2030static void
2031subs64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
2032{
ef0d8ffc
NC
2033 unsigned rm = INSTR (20, 16);
2034 unsigned rn = INSTR (9, 5);
2035 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2036
2037 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2038 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
2039 shift, count);
2040
2cdad34c 2041 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2042 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2043 set_flags_for_sub64 (cpu, value1, value2);
2044}
2045
2046/* First a couple more helpers to fetch the
2047 relevant source register element either
2048 sign or zero extended as required by the
2049 extension value. */
2050
2051static uint32_t
2052extreg32 (sim_cpu *cpu, unsigned int lo, Extension extension)
2053{
2054 switch (extension)
2055 {
2056 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
2057 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
2058 case UXTW: /* Fall through. */
2059 case UXTX: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
2060 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
2061 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
2062 case SXTW: /* Fall through. */
2063 case SXTX: /* Fall through. */
2064 default: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
2065 }
2066}
2067
2068static uint64_t
2069extreg64 (sim_cpu *cpu, unsigned int lo, Extension extension)
2070{
2071 switch (extension)
2072 {
2073 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
2074 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
2075 case UXTW: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
2076 case UXTX: return aarch64_get_reg_u64 (cpu, lo, NO_SP);
2077 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
2078 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
2079 case SXTW: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
2080 case SXTX:
2081 default: return aarch64_get_reg_s64 (cpu, lo, NO_SP);
2082 }
2083}
2084
2085/* Arithmetic extending register
2086 These allow an optional sign extension of some portion of the
2087 second source register followed by an optional left shift of
2088 between 1 and 4 bits (i.e. a shift of 0-4 bits???)
2089
2090 N.B output (dest) and first input arg (source) may normally be Xn
2091 or SP. However, for flag setting operations dest can only be
2092 Xn. Second input registers are always Xn. */
2093
2094/* 32 bit ADD extending register. */
2095static void
2096add32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2097{
ef0d8ffc
NC
2098 unsigned rm = INSTR (20, 16);
2099 unsigned rn = INSTR (9, 5);
2100 unsigned rd = INSTR (4, 0);
2e8cf49e 2101
2cdad34c 2102 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2103 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2104 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2105 + (extreg32 (cpu, rm, extension) << shift));
2106}
2107
2108/* 64 bit ADD extending register.
2109 N.B. This subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2110static void
2111add64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2112{
ef0d8ffc
NC
2113 unsigned rm = INSTR (20, 16);
2114 unsigned rn = INSTR (9, 5);
2115 unsigned rd = INSTR (4, 0);
2e8cf49e 2116
2cdad34c 2117 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2118 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2119 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2120 + (extreg64 (cpu, rm, extension) << shift));
2121}
2122
2123/* 32 bit ADD extending register setting flags. */
2124static void
2125adds32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2126{
ef0d8ffc
NC
2127 unsigned rm = INSTR (20, 16);
2128 unsigned rn = INSTR (9, 5);
2129 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2130
2131 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2132 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2133
2cdad34c 2134 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2135 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2136 set_flags_for_add32 (cpu, value1, value2);
2137}
2138
2139/* 64 bit ADD extending register setting flags */
2140/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2141static void
2142adds64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2143{
ef0d8ffc
NC
2144 unsigned rm = INSTR (20, 16);
2145 unsigned rn = INSTR (9, 5);
2146 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2147
2148 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2149 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2150
2cdad34c 2151 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2152 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2153 set_flags_for_add64 (cpu, value1, value2);
2154}
2155
2156/* 32 bit SUB extending register. */
2157static void
2158sub32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2159{
ef0d8ffc
NC
2160 unsigned rm = INSTR (20, 16);
2161 unsigned rn = INSTR (9, 5);
2162 unsigned rd = INSTR (4, 0);
2e8cf49e 2163
2cdad34c 2164 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2165 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2166 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2167 - (extreg32 (cpu, rm, extension) << shift));
2168}
2169
2170/* 64 bit SUB extending register. */
2171/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2172static void
2173sub64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2174{
ef0d8ffc
NC
2175 unsigned rm = INSTR (20, 16);
2176 unsigned rn = INSTR (9, 5);
2177 unsigned rd = INSTR (4, 0);
2e8cf49e 2178
2cdad34c 2179 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2180 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2181 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2182 - (extreg64 (cpu, rm, extension) << shift));
2183}
2184
2185/* 32 bit SUB extending register setting flags. */
2186static void
2187subs32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2188{
ef0d8ffc
NC
2189 unsigned rm = INSTR (20, 16);
2190 unsigned rn = INSTR (9, 5);
2191 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2192
2193 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2194 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2195
2cdad34c 2196 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2197 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2198 set_flags_for_sub32 (cpu, value1, value2);
2199}
2200
2201/* 64 bit SUB extending register setting flags */
2202/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2203static void
2204subs64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2205{
ef0d8ffc
NC
2206 unsigned rm = INSTR (20, 16);
2207 unsigned rn = INSTR (9, 5);
2208 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2209
2210 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2211 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2212
2cdad34c 2213 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2214 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2215 set_flags_for_sub64 (cpu, value1, value2);
2216}
2217
2218static void
2219dexAddSubtractImmediate (sim_cpu *cpu)
2220{
2221 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2222 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2223 instr[29] = set : 0 ==> no flags, 1 ==> set flags
2224 instr[28,24] = 10001
2225 instr[23,22] = shift : 00 == LSL#0, 01 = LSL#12 1x = UNALLOC
2226 instr[21,10] = uimm12
2227 instr[9,5] = Rn
2228 instr[4,0] = Rd */
2229
2230 /* N.B. the shift is applied at decode before calling the add/sub routine. */
ef0d8ffc
NC
2231 uint32_t shift = INSTR (23, 22);
2232 uint32_t imm = INSTR (21, 10);
2233 uint32_t dispatch = INSTR (31, 29);
2e8cf49e
NC
2234
2235 NYI_assert (28, 24, 0x11);
2236
2237 if (shift > 1)
2238 HALT_UNALLOC;
2239
2240 if (shift)
2241 imm <<= 12;
2242
2243 switch (dispatch)
2244 {
2245 case 0: add32 (cpu, imm); break;
2246 case 1: adds32 (cpu, imm); break;
2247 case 2: sub32 (cpu, imm); break;
2248 case 3: subs32 (cpu, imm); break;
2249 case 4: add64 (cpu, imm); break;
2250 case 5: adds64 (cpu, imm); break;
2251 case 6: sub64 (cpu, imm); break;
2252 case 7: subs64 (cpu, imm); break;
2e8cf49e
NC
2253 }
2254}
2255
2256static void
2257dexAddSubtractShiftedRegister (sim_cpu *cpu)
2258{
2259 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2260 instr[30,29] = op : 00 ==> ADD, 01 ==> ADDS, 10 ==> SUB, 11 ==> SUBS
2261 instr[28,24] = 01011
2262 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> UNALLOC
2263 instr[21] = 0
2264 instr[20,16] = Rm
2265 instr[15,10] = count : must be 0xxxxx for 32 bit
2266 instr[9,5] = Rn
2267 instr[4,0] = Rd */
2268
ef0d8ffc
NC
2269 uint32_t size = INSTR (31, 31);
2270 uint32_t count = INSTR (15, 10);
2271 Shift shiftType = INSTR (23, 22);
2e8cf49e
NC
2272
2273 NYI_assert (28, 24, 0x0B);
2274 NYI_assert (21, 21, 0);
2275
ef0d8ffc 2276 /* Shift encoded as ROR is unallocated. */
2e8cf49e
NC
2277 if (shiftType == ROR)
2278 HALT_UNALLOC;
2279
ef0d8ffc
NC
2280 /* 32 bit operations must have count[5] = 0
2281 or else we have an UNALLOC. */
2282 if (size == 0 && uimm (count, 5, 5))
2e8cf49e
NC
2283 HALT_UNALLOC;
2284
ef0d8ffc
NC
2285 /* Dispatch on size:op i.e instr [31,29]. */
2286 switch (INSTR (31, 29))
2e8cf49e
NC
2287 {
2288 case 0: add32_shift (cpu, shiftType, count); break;
2289 case 1: adds32_shift (cpu, shiftType, count); break;
2290 case 2: sub32_shift (cpu, shiftType, count); break;
2291 case 3: subs32_shift (cpu, shiftType, count); break;
2292 case 4: add64_shift (cpu, shiftType, count); break;
2293 case 5: adds64_shift (cpu, shiftType, count); break;
2294 case 6: sub64_shift (cpu, shiftType, count); break;
2295 case 7: subs64_shift (cpu, shiftType, count); break;
2e8cf49e
NC
2296 }
2297}
2298
2299static void
2300dexAddSubtractExtendedRegister (sim_cpu *cpu)
2301{
2302 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2303 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2304 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2305 instr[28,24] = 01011
2306 instr[23,22] = opt : 0 ==> ok, 1,2,3 ==> UNALLOC
2307 instr[21] = 1
2308 instr[20,16] = Rm
2309 instr[15,13] = option : 000 ==> UXTB, 001 ==> UXTH,
2310 000 ==> LSL|UXTW, 001 ==> UXTZ,
2311 000 ==> SXTB, 001 ==> SXTH,
2312 000 ==> SXTW, 001 ==> SXTX,
2313 instr[12,10] = shift : 0,1,2,3,4 ==> ok, 5,6,7 ==> UNALLOC
2314 instr[9,5] = Rn
2315 instr[4,0] = Rd */
2316
ef0d8ffc
NC
2317 Extension extensionType = INSTR (15, 13);
2318 uint32_t shift = INSTR (12, 10);
2e8cf49e
NC
2319
2320 NYI_assert (28, 24, 0x0B);
2321 NYI_assert (21, 21, 1);
2322
2323 /* Shift may not exceed 4. */
2324 if (shift > 4)
2325 HALT_UNALLOC;
2326
ef0d8ffc
NC
2327 /* Dispatch on size:op:set?. */
2328 switch (INSTR (31, 29))
2e8cf49e
NC
2329 {
2330 case 0: add32_ext (cpu, extensionType, shift); break;
2331 case 1: adds32_ext (cpu, extensionType, shift); break;
2332 case 2: sub32_ext (cpu, extensionType, shift); break;
2333 case 3: subs32_ext (cpu, extensionType, shift); break;
2334 case 4: add64_ext (cpu, extensionType, shift); break;
2335 case 5: adds64_ext (cpu, extensionType, shift); break;
2336 case 6: sub64_ext (cpu, extensionType, shift); break;
2337 case 7: subs64_ext (cpu, extensionType, shift); break;
2e8cf49e
NC
2338 }
2339}
2340
2341/* Conditional data processing
2342 Condition register is implicit 3rd source. */
2343
2344/* 32 bit add with carry. */
2345/* N.B register args may not be SP. */
2346
2347static void
2348adc32 (sim_cpu *cpu)
2349{
ef0d8ffc
NC
2350 unsigned rm = INSTR (20, 16);
2351 unsigned rn = INSTR (9, 5);
2352 unsigned rd = INSTR (4, 0);
2e8cf49e 2353
2cdad34c 2354 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2355 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2356 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2357 + aarch64_get_reg_u32 (cpu, rm, NO_SP)
2358 + IS_SET (C));
2359}
2360
2361/* 64 bit add with carry */
2362static void
2363adc64 (sim_cpu *cpu)
2364{
ef0d8ffc
NC
2365 unsigned rm = INSTR (20, 16);
2366 unsigned rn = INSTR (9, 5);
2367 unsigned rd = INSTR (4, 0);
2e8cf49e 2368
2cdad34c 2369 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2370 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2371 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2372 + aarch64_get_reg_u64 (cpu, rm, NO_SP)
2373 + IS_SET (C));
2374}
2375
2376/* 32 bit add with carry setting flags. */
2377static void
2378adcs32 (sim_cpu *cpu)
2379{
ef0d8ffc
NC
2380 unsigned rm = INSTR (20, 16);
2381 unsigned rn = INSTR (9, 5);
2382 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2383
2384 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2385 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2386 uint32_t carry = IS_SET (C);
2387
2cdad34c 2388 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2389 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2390 set_flags_for_add32 (cpu, value1, value2 + carry);
2391}
2392
2393/* 64 bit add with carry setting flags. */
2394static void
2395adcs64 (sim_cpu *cpu)
2396{
ef0d8ffc
NC
2397 unsigned rm = INSTR (20, 16);
2398 unsigned rn = INSTR (9, 5);
2399 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2400
2401 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2402 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2403 uint64_t carry = IS_SET (C);
2404
2cdad34c 2405 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2406 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2407 set_flags_for_add64 (cpu, value1, value2 + carry);
2408}
2409
2410/* 32 bit sub with carry. */
2411static void
2412sbc32 (sim_cpu *cpu)
2413{
ef0d8ffc
NC
2414 unsigned rm = INSTR (20, 16);
2415 unsigned rn = INSTR (9, 5); /* ngc iff rn == 31. */
2416 unsigned rd = INSTR (4, 0);
2e8cf49e 2417
2cdad34c 2418 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2419 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2420 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2421 - aarch64_get_reg_u32 (cpu, rm, NO_SP)
2422 - 1 + IS_SET (C));
2423}
2424
2425/* 64 bit sub with carry */
2426static void
2427sbc64 (sim_cpu *cpu)
2428{
ef0d8ffc
NC
2429 unsigned rm = INSTR (20, 16);
2430 unsigned rn = INSTR (9, 5);
2431 unsigned rd = INSTR (4, 0);
2e8cf49e 2432
2cdad34c 2433 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2434 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2435 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2436 - aarch64_get_reg_u64 (cpu, rm, NO_SP)
2437 - 1 + IS_SET (C));
2438}
2439
2440/* 32 bit sub with carry setting flags */
2441static void
2442sbcs32 (sim_cpu *cpu)
2443{
ef0d8ffc
NC
2444 unsigned rm = INSTR (20, 16);
2445 unsigned rn = INSTR (9, 5);
2446 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2447
2448 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2449 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2450 uint32_t carry = IS_SET (C);
2451 uint32_t result = value1 - value2 + 1 - carry;
2452
2cdad34c 2453 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2454 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2455 set_flags_for_sub32 (cpu, value1, value2 + 1 - carry);
2456}
2457
2458/* 64 bit sub with carry setting flags */
2459static void
2460sbcs64 (sim_cpu *cpu)
2461{
ef0d8ffc
NC
2462 unsigned rm = INSTR (20, 16);
2463 unsigned rn = INSTR (9, 5);
2464 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2465
2466 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2467 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2468 uint64_t carry = IS_SET (C);
2469 uint64_t result = value1 - value2 + 1 - carry;
2470
2cdad34c 2471 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2472 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2473 set_flags_for_sub64 (cpu, value1, value2 + 1 - carry);
2474}
2475
2476static void
2477dexAddSubtractWithCarry (sim_cpu *cpu)
2478{
2479 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2480 instr[30] = op : 0 ==> ADC, 1 ==> SBC
2481 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2482 instr[28,21] = 1 1010 000
2483 instr[20,16] = Rm
2484 instr[15,10] = op2 : 00000 ==> ok, ow ==> UNALLOC
2485 instr[9,5] = Rn
2486 instr[4,0] = Rd */
2487
ef0d8ffc 2488 uint32_t op2 = INSTR (15, 10);
2e8cf49e
NC
2489
2490 NYI_assert (28, 21, 0xD0);
2491
2492 if (op2 != 0)
2493 HALT_UNALLOC;
2494
ef0d8ffc
NC
2495 /* Dispatch on size:op:set?. */
2496 switch (INSTR (31, 29))
2e8cf49e
NC
2497 {
2498 case 0: adc32 (cpu); break;
2499 case 1: adcs32 (cpu); break;
2500 case 2: sbc32 (cpu); break;
2501 case 3: sbcs32 (cpu); break;
2502 case 4: adc64 (cpu); break;
2503 case 5: adcs64 (cpu); break;
2504 case 6: sbc64 (cpu); break;
2505 case 7: sbcs64 (cpu); break;
2e8cf49e
NC
2506 }
2507}
2508
2509static uint32_t
2510testConditionCode (sim_cpu *cpu, CondCode cc)
2511{
2512 /* This should be reduceable to branchless logic
2513 by some careful testing of bits in CC followed
2514 by the requisite masking and combining of bits
2515 from the flag register.
2516
2517 For now we do it with a switch. */
2518 int res;
2519
2520 switch (cc)
2521 {
2522 case EQ: res = IS_SET (Z); break;
2523 case NE: res = IS_CLEAR (Z); break;
2524 case CS: res = IS_SET (C); break;
2525 case CC: res = IS_CLEAR (C); break;
2526 case MI: res = IS_SET (N); break;
2527 case PL: res = IS_CLEAR (N); break;
2528 case VS: res = IS_SET (V); break;
2529 case VC: res = IS_CLEAR (V); break;
2530 case HI: res = IS_SET (C) && IS_CLEAR (Z); break;
2531 case LS: res = IS_CLEAR (C) || IS_SET (Z); break;
2532 case GE: res = IS_SET (N) == IS_SET (V); break;
2533 case LT: res = IS_SET (N) != IS_SET (V); break;
2534 case GT: res = IS_CLEAR (Z) && (IS_SET (N) == IS_SET (V)); break;
2535 case LE: res = IS_SET (Z) || (IS_SET (N) != IS_SET (V)); break;
2536 case AL:
2537 case NV:
2538 default:
2539 res = 1;
2540 break;
2541 }
2542 return res;
2543}
2544
2545static void
2546CondCompare (sim_cpu *cpu) /* aka: ccmp and ccmn */
2547{
2548 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
57aa1742 2549 instr[30] = compare with positive (1) or negative value (0)
2e8cf49e
NC
2550 instr[29,21] = 1 1101 0010
2551 instr[20,16] = Rm or const
2552 instr[15,12] = cond
2553 instr[11] = compare reg (0) or const (1)
2554 instr[10] = 0
2555 instr[9,5] = Rn
2556 instr[4] = 0
2557 instr[3,0] = value for CPSR bits if the comparison does not take place. */
2558 signed int negate;
2559 unsigned rm;
2560 unsigned rn;
2561
2562 NYI_assert (29, 21, 0x1d2);
2563 NYI_assert (10, 10, 0);
2564 NYI_assert (4, 4, 0);
2565
2cdad34c 2566 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2567 if (! testConditionCode (cpu, INSTR (15, 12)))
2e8cf49e 2568 {
ef0d8ffc 2569 aarch64_set_CPSR (cpu, INSTR (3, 0));
2e8cf49e
NC
2570 return;
2571 }
2572
ef0d8ffc
NC
2573 negate = INSTR (30, 30) ? 1 : -1;
2574 rm = INSTR (20, 16);
2575 rn = INSTR ( 9, 5);
2e8cf49e 2576
ef0d8ffc 2577 if (INSTR (31, 31))
2e8cf49e 2578 {
ef0d8ffc 2579 if (INSTR (11, 11))
2e8cf49e
NC
2580 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2581 negate * (uint64_t) rm);
2582 else
2583 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2584 negate * aarch64_get_reg_u64 (cpu, rm, SP_OK));
2585 }
2586 else
2587 {
ef0d8ffc 2588 if (INSTR (11, 11))
2e8cf49e
NC
2589 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2590 negate * rm);
2591 else
2592 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2593 negate * aarch64_get_reg_u32 (cpu, rm, SP_OK));
2594 }
2595}
2596
2597static void
2598do_vec_MOV_whole_vector (sim_cpu *cpu)
2599{
2600 /* MOV Vd.T, Vs.T (alias for ORR Vd.T, Vn.T, Vm.T where Vn == Vm)
2601
2602 instr[31] = 0
2603 instr[30] = half(0)/full(1)
2604 instr[29,21] = 001110101
2605 instr[20,16] = Vs
2606 instr[15,10] = 000111
2607 instr[9,5] = Vs
2608 instr[4,0] = Vd */
2609
ef0d8ffc
NC
2610 unsigned vs = INSTR (9, 5);
2611 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2612
2613 NYI_assert (29, 21, 0x075);
2614 NYI_assert (15, 10, 0x07);
2615
ef0d8ffc 2616 if (INSTR (20, 16) != vs)
2e8cf49e
NC
2617 HALT_NYI;
2618
2cdad34c 2619 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2620 if (INSTR (30, 30))
2e8cf49e
NC
2621 aarch64_set_vec_u64 (cpu, vd, 1, aarch64_get_vec_u64 (cpu, vs, 1));
2622
2623 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vs, 0));
2624}
2625
2626static void
152e1e1b 2627do_vec_SMOV_into_scalar (sim_cpu *cpu)
2e8cf49e
NC
2628{
2629 /* instr[31] = 0
2630 instr[30] = word(0)/long(1)
2631 instr[29,21] = 00 1110 000
152e1e1b
JW
2632 instr[20,16] = element size and index
2633 instr[15,10] = 00 0010 11
2e8cf49e
NC
2634 instr[9,5] = V source
2635 instr[4,0] = R dest */
2636
ef0d8ffc
NC
2637 unsigned vs = INSTR (9, 5);
2638 unsigned rd = INSTR (4, 0);
152e1e1b
JW
2639 unsigned imm5 = INSTR (20, 16);
2640 unsigned full = INSTR (30, 30);
2641 int size, index;
2e8cf49e
NC
2642
2643 NYI_assert (29, 21, 0x070);
152e1e1b 2644 NYI_assert (15, 10, 0x0B);
2e8cf49e 2645
2cdad34c 2646 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
152e1e1b
JW
2647
2648 if (imm5 & 0x1)
2649 {
2650 size = 0;
2651 index = (imm5 >> 1) & 0xF;
2652 }
2653 else if (imm5 & 0x2)
2654 {
2655 size = 1;
2656 index = (imm5 >> 2) & 0x7;
2657 }
2658 else if (full && (imm5 & 0x4))
2659 {
2660 size = 2;
2661 index = (imm5 >> 3) & 0x3;
2662 }
2663 else
2664 HALT_UNALLOC;
2665
2666 switch (size)
2e8cf49e 2667 {
152e1e1b
JW
2668 case 0:
2669 if (full)
2670 aarch64_set_reg_s64 (cpu, rd, NO_SP,
2671 aarch64_get_vec_s8 (cpu, vs, index));
2672 else
2673 aarch64_set_reg_s32 (cpu, rd, NO_SP,
2674 aarch64_get_vec_s8 (cpu, vs, index));
2e8cf49e
NC
2675 break;
2676
152e1e1b
JW
2677 case 1:
2678 if (full)
2679 aarch64_set_reg_s64 (cpu, rd, NO_SP,
2680 aarch64_get_vec_s16 (cpu, vs, index));
2681 else
2682 aarch64_set_reg_s32 (cpu, rd, NO_SP,
2683 aarch64_get_vec_s16 (cpu, vs, index));
2e8cf49e
NC
2684 break;
2685
152e1e1b
JW
2686 case 2:
2687 aarch64_set_reg_s64 (cpu, rd, NO_SP,
2688 aarch64_get_vec_s32 (cpu, vs, index));
2e8cf49e
NC
2689 break;
2690
2691 default:
152e1e1b
JW
2692 HALT_UNALLOC;
2693 }
2694}
2695
2696static void
2697do_vec_UMOV_into_scalar (sim_cpu *cpu)
2698{
2699 /* instr[31] = 0
2700 instr[30] = word(0)/long(1)
2701 instr[29,21] = 00 1110 000
2702 instr[20,16] = element size and index
2703 instr[15,10] = 00 0011 11
2704 instr[9,5] = V source
2705 instr[4,0] = R dest */
2706
2707 unsigned vs = INSTR (9, 5);
2708 unsigned rd = INSTR (4, 0);
2709 unsigned imm5 = INSTR (20, 16);
2710 unsigned full = INSTR (30, 30);
2711 int size, index;
2712
2713 NYI_assert (29, 21, 0x070);
2714 NYI_assert (15, 10, 0x0F);
2715
2716 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2717
2718 if (!full)
2719 {
2720 if (imm5 & 0x1)
2721 {
2722 size = 0;
2723 index = (imm5 >> 1) & 0xF;
2724 }
2725 else if (imm5 & 0x2)
2726 {
2727 size = 1;
2728 index = (imm5 >> 2) & 0x7;
2729 }
2730 else if (imm5 & 0x4)
2731 {
2732 size = 2;
2733 index = (imm5 >> 3) & 0x3;
2734 }
2735 else
2736 HALT_UNALLOC;
2737 }
2738 else if (imm5 & 0x8)
2739 {
2740 size = 3;
2741 index = (imm5 >> 4) & 0x1;
2742 }
2743 else
2744 HALT_UNALLOC;
2745
2746 switch (size)
2747 {
2748 case 0:
2749 aarch64_set_reg_u32 (cpu, rd, NO_SP,
2750 aarch64_get_vec_u8 (cpu, vs, index));
2751 break;
2752
2753 case 1:
2754 aarch64_set_reg_u32 (cpu, rd, NO_SP,
2755 aarch64_get_vec_u16 (cpu, vs, index));
2756 break;
2757
2758 case 2:
2759 aarch64_set_reg_u32 (cpu, rd, NO_SP,
2760 aarch64_get_vec_u32 (cpu, vs, index));
2761 break;
2762
2763 case 3:
2764 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2765 aarch64_get_vec_u64 (cpu, vs, index));
2766 break;
2767
2768 default:
2769 HALT_UNALLOC;
2e8cf49e
NC
2770 }
2771}
2772
2773static void
2774do_vec_INS (sim_cpu *cpu)
2775{
2776 /* instr[31,21] = 01001110000
2777 instr[20,16] = element size and index
2778 instr[15,10] = 000111
2779 instr[9,5] = W source
2780 instr[4,0] = V dest */
2781
2782 int index;
ef0d8ffc
NC
2783 unsigned rs = INSTR (9, 5);
2784 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2785
2786 NYI_assert (31, 21, 0x270);
2787 NYI_assert (15, 10, 0x07);
2788
2cdad34c 2789 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2790 if (INSTR (16, 16))
2e8cf49e 2791 {
ef0d8ffc 2792 index = INSTR (20, 17);
2e8cf49e
NC
2793 aarch64_set_vec_u8 (cpu, vd, index,
2794 aarch64_get_reg_u8 (cpu, rs, NO_SP));
2795 }
ef0d8ffc 2796 else if (INSTR (17, 17))
2e8cf49e 2797 {
ef0d8ffc 2798 index = INSTR (20, 18);
2e8cf49e
NC
2799 aarch64_set_vec_u16 (cpu, vd, index,
2800 aarch64_get_reg_u16 (cpu, rs, NO_SP));
2801 }
ef0d8ffc 2802 else if (INSTR (18, 18))
2e8cf49e 2803 {
ef0d8ffc 2804 index = INSTR (20, 19);
2e8cf49e
NC
2805 aarch64_set_vec_u32 (cpu, vd, index,
2806 aarch64_get_reg_u32 (cpu, rs, NO_SP));
2807 }
ef0d8ffc 2808 else if (INSTR (19, 19))
2e8cf49e 2809 {
ef0d8ffc 2810 index = INSTR (20, 20);
2e8cf49e
NC
2811 aarch64_set_vec_u64 (cpu, vd, index,
2812 aarch64_get_reg_u64 (cpu, rs, NO_SP));
2813 }
2814 else
2815 HALT_NYI;
2816}
2817
2818static void
2819do_vec_DUP_vector_into_vector (sim_cpu *cpu)
2820{
2821 /* instr[31] = 0
2822 instr[30] = half(0)/full(1)
2823 instr[29,21] = 00 1110 000
2824 instr[20,16] = element size and index
2825 instr[15,10] = 0000 01
2826 instr[9,5] = V source
2827 instr[4,0] = V dest. */
2828
ef0d8ffc
NC
2829 unsigned full = INSTR (30, 30);
2830 unsigned vs = INSTR (9, 5);
2831 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2832 int i, index;
2833
2834 NYI_assert (29, 21, 0x070);
2835 NYI_assert (15, 10, 0x01);
2836
2cdad34c 2837 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2838 if (INSTR (16, 16))
2e8cf49e 2839 {
ef0d8ffc 2840 index = INSTR (20, 17);
2e8cf49e
NC
2841
2842 for (i = 0; i < (full ? 16 : 8); i++)
2843 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, index));
2844 }
ef0d8ffc 2845 else if (INSTR (17, 17))
2e8cf49e 2846 {
ef0d8ffc 2847 index = INSTR (20, 18);
2e8cf49e
NC
2848
2849 for (i = 0; i < (full ? 8 : 4); i++)
2850 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, index));
2851 }
ef0d8ffc 2852 else if (INSTR (18, 18))
2e8cf49e 2853 {
ef0d8ffc 2854 index = INSTR (20, 19);
2e8cf49e
NC
2855
2856 for (i = 0; i < (full ? 4 : 2); i++)
2857 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, index));
2858 }
2859 else
2860 {
ef0d8ffc 2861 if (INSTR (19, 19) == 0)
2e8cf49e
NC
2862 HALT_UNALLOC;
2863
2864 if (! full)
2865 HALT_UNALLOC;
2866
ef0d8ffc 2867 index = INSTR (20, 20);
2e8cf49e
NC
2868
2869 for (i = 0; i < 2; i++)
2870 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, index));
2871 }
2872}
2873
2874static void
2875do_vec_TBL (sim_cpu *cpu)
2876{
2877 /* instr[31] = 0
2878 instr[30] = half(0)/full(1)
2879 instr[29,21] = 00 1110 000
2880 instr[20,16] = Vm
2881 instr[15] = 0
2882 instr[14,13] = vec length
2883 instr[12,10] = 000
2884 instr[9,5] = V start
2885 instr[4,0] = V dest */
2886
ef0d8ffc
NC
2887 int full = INSTR (30, 30);
2888 int len = INSTR (14, 13) + 1;
2889 unsigned vm = INSTR (20, 16);
2890 unsigned vn = INSTR (9, 5);
2891 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2892 unsigned i;
2893
2894 NYI_assert (29, 21, 0x070);
2895 NYI_assert (12, 10, 0);
2896
2cdad34c 2897 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
2898 for (i = 0; i < (full ? 16 : 8); i++)
2899 {
2900 unsigned int selector = aarch64_get_vec_u8 (cpu, vm, i);
2901 uint8_t val;
2902
2903 if (selector < 16)
2904 val = aarch64_get_vec_u8 (cpu, vn, selector);
2905 else if (selector < 32)
2906 val = len < 2 ? 0 : aarch64_get_vec_u8 (cpu, vn + 1, selector - 16);
2907 else if (selector < 48)
2908 val = len < 3 ? 0 : aarch64_get_vec_u8 (cpu, vn + 2, selector - 32);
2909 else if (selector < 64)
2910 val = len < 4 ? 0 : aarch64_get_vec_u8 (cpu, vn + 3, selector - 48);
2911 else
2912 val = 0;
2913
2914 aarch64_set_vec_u8 (cpu, vd, i, val);
2915 }
2916}
2917
2918static void
2919do_vec_TRN (sim_cpu *cpu)
2920{
2921 /* instr[31] = 0
2922 instr[30] = half(0)/full(1)
2923 instr[29,24] = 00 1110
2924 instr[23,22] = size
2925 instr[21] = 0
2926 instr[20,16] = Vm
2927 instr[15] = 0
2928 instr[14] = TRN1 (0) / TRN2 (1)
2929 instr[13,10] = 1010
2930 instr[9,5] = V source
2931 instr[4,0] = V dest. */
2932
ef0d8ffc
NC
2933 int full = INSTR (30, 30);
2934 int second = INSTR (14, 14);
2935 unsigned vm = INSTR (20, 16);
2936 unsigned vn = INSTR (9, 5);
2937 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2938 unsigned i;
2939
2940 NYI_assert (29, 24, 0x0E);
2941 NYI_assert (13, 10, 0xA);
2942
2cdad34c 2943 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 2944 switch (INSTR (23, 22))
2e8cf49e
NC
2945 {
2946 case 0:
2947 for (i = 0; i < (full ? 8 : 4); i++)
2948 {
2949 aarch64_set_vec_u8
2950 (cpu, vd, i * 2,
2951 aarch64_get_vec_u8 (cpu, second ? vm : vn, i * 2));
2952 aarch64_set_vec_u8
2953 (cpu, vd, 1 * 2 + 1,
2954 aarch64_get_vec_u8 (cpu, second ? vn : vm, i * 2 + 1));
2955 }
2956 break;
2957
2958 case 1:
2959 for (i = 0; i < (full ? 4 : 2); i++)
2960 {
2961 aarch64_set_vec_u16
2962 (cpu, vd, i * 2,
2963 aarch64_get_vec_u16 (cpu, second ? vm : vn, i * 2));
2964 aarch64_set_vec_u16
2965 (cpu, vd, 1 * 2 + 1,
2966 aarch64_get_vec_u16 (cpu, second ? vn : vm, i * 2 + 1));
2967 }
2968 break;
2969
2970 case 2:
2971 aarch64_set_vec_u32
2972 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, second ? vm : vn, 0));
2973 aarch64_set_vec_u32
2974 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, second ? vn : vm, 1));
2975 aarch64_set_vec_u32
2976 (cpu, vd, 2, aarch64_get_vec_u32 (cpu, second ? vm : vn, 2));
2977 aarch64_set_vec_u32
2978 (cpu, vd, 3, aarch64_get_vec_u32 (cpu, second ? vn : vm, 3));
2979 break;
2980
2981 case 3:
2982 if (! full)
2983 HALT_UNALLOC;
2984
2985 aarch64_set_vec_u64 (cpu, vd, 0,
2986 aarch64_get_vec_u64 (cpu, second ? vm : vn, 0));
2987 aarch64_set_vec_u64 (cpu, vd, 1,
2988 aarch64_get_vec_u64 (cpu, second ? vn : vm, 1));
2989 break;
2e8cf49e
NC
2990 }
2991}
2992
2993static void
2994do_vec_DUP_scalar_into_vector (sim_cpu *cpu)
2995{
2996 /* instr[31] = 0
2997 instr[30] = 0=> zero top 64-bits, 1=> duplicate into top 64-bits
2998 [must be 1 for 64-bit xfer]
2999 instr[29,20] = 00 1110 0000
3000 instr[19,16] = element size: 0001=> 8-bits, 0010=> 16-bits,
3001 0100=> 32-bits. 1000=>64-bits
3002 instr[15,10] = 0000 11
3003 instr[9,5] = W source
3004 instr[4,0] = V dest. */
3005
3006 unsigned i;
ef0d8ffc
NC
3007 unsigned Vd = INSTR (4, 0);
3008 unsigned Rs = INSTR (9, 5);
3009 int both = INSTR (30, 30);
2e8cf49e
NC
3010
3011 NYI_assert (29, 20, 0x0E0);
3012 NYI_assert (15, 10, 0x03);
3013
2cdad34c 3014 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3015 switch (INSTR (19, 16))
2e8cf49e
NC
3016 {
3017 case 1:
3018 for (i = 0; i < (both ? 16 : 8); i++)
3019 aarch64_set_vec_u8 (cpu, Vd, i, aarch64_get_reg_u8 (cpu, Rs, NO_SP));
3020 break;
3021
3022 case 2:
3023 for (i = 0; i < (both ? 8 : 4); i++)
3024 aarch64_set_vec_u16 (cpu, Vd, i, aarch64_get_reg_u16 (cpu, Rs, NO_SP));
3025 break;
3026
3027 case 4:
3028 for (i = 0; i < (both ? 4 : 2); i++)
3029 aarch64_set_vec_u32 (cpu, Vd, i, aarch64_get_reg_u32 (cpu, Rs, NO_SP));
3030 break;
3031
3032 case 8:
3033 if (!both)
3034 HALT_NYI;
3035 aarch64_set_vec_u64 (cpu, Vd, 0, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
3036 aarch64_set_vec_u64 (cpu, Vd, 1, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
3037 break;
3038
3039 default:
3040 HALT_NYI;
3041 }
3042}
3043
3044static void
3045do_vec_UZP (sim_cpu *cpu)
3046{
3047 /* instr[31] = 0
3048 instr[30] = half(0)/full(1)
3049 instr[29,24] = 00 1110
3050 instr[23,22] = size: byte(00), half(01), word (10), long (11)
3051 instr[21] = 0
3052 instr[20,16] = Vm
3053 instr[15] = 0
3054 instr[14] = lower (0) / upper (1)
3055 instr[13,10] = 0110
3056 instr[9,5] = Vn
3057 instr[4,0] = Vd. */
3058
ef0d8ffc
NC
3059 int full = INSTR (30, 30);
3060 int upper = INSTR (14, 14);
2e8cf49e 3061
ef0d8ffc
NC
3062 unsigned vm = INSTR (20, 16);
3063 unsigned vn = INSTR (9, 5);
3064 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3065
3066 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
3067 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
3068 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
3069 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
3070
a4fb5981
JW
3071 uint64_t val1;
3072 uint64_t val2;
2e8cf49e 3073
a4fb5981 3074 uint64_t input2 = full ? val_n2 : val_m1;
2e8cf49e
NC
3075
3076 NYI_assert (29, 24, 0x0E);
3077 NYI_assert (21, 21, 0);
3078 NYI_assert (15, 15, 0);
3079 NYI_assert (13, 10, 6);
3080
2cdad34c 3081 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
a4fb5981 3082 switch (INSTR (23, 22))
2e8cf49e
NC
3083 {
3084 case 0:
a4fb5981
JW
3085 val1 = (val_n1 >> (upper * 8)) & 0xFFULL;
3086 val1 |= (val_n1 >> ((upper * 8) + 8)) & 0xFF00ULL;
3087 val1 |= (val_n1 >> ((upper * 8) + 16)) & 0xFF0000ULL;
3088 val1 |= (val_n1 >> ((upper * 8) + 24)) & 0xFF000000ULL;
3089
3090 val1 |= (input2 << (32 - (upper * 8))) & 0xFF00000000ULL;
3091 val1 |= (input2 << (24 - (upper * 8))) & 0xFF0000000000ULL;
3092 val1 |= (input2 << (16 - (upper * 8))) & 0xFF000000000000ULL;
3093 val1 |= (input2 << (8 - (upper * 8))) & 0xFF00000000000000ULL;
3094
3095 if (full)
2e8cf49e 3096 {
a4fb5981
JW
3097 val2 = (val_m1 >> (upper * 8)) & 0xFFULL;
3098 val2 |= (val_m1 >> ((upper * 8) + 8)) & 0xFF00ULL;
3099 val2 |= (val_m1 >> ((upper * 8) + 16)) & 0xFF0000ULL;
3100 val2 |= (val_m1 >> ((upper * 8) + 24)) & 0xFF000000ULL;
3101
3102 val2 |= (val_m2 << (32 - (upper * 8))) & 0xFF00000000ULL;
3103 val2 |= (val_m2 << (24 - (upper * 8))) & 0xFF0000000000ULL;
3104 val2 |= (val_m2 << (16 - (upper * 8))) & 0xFF000000000000ULL;
3105 val2 |= (val_m2 << (8 - (upper * 8))) & 0xFF00000000000000ULL;
2e8cf49e
NC
3106 }
3107 break;
3108
3109 case 1:
a4fb5981
JW
3110 val1 = (val_n1 >> (upper * 16)) & 0xFFFFULL;
3111 val1 |= (val_n1 >> ((upper * 16) + 16)) & 0xFFFF0000ULL;
3112
3113 val1 |= (input2 << (32 - (upper * 16))) & 0xFFFF00000000ULL;;
3114 val1 |= (input2 << (16 - (upper * 16))) & 0xFFFF000000000000ULL;
3115
3116 if (full)
2e8cf49e 3117 {
a4fb5981
JW
3118 val2 = (val_m1 >> (upper * 16)) & 0xFFFFULL;
3119 val2 |= (val_m1 >> ((upper * 16) + 16)) & 0xFFFF0000ULL;
3120
3121 val2 |= (val_m2 << (32 - (upper * 16))) & 0xFFFF00000000ULL;
3122 val2 |= (val_m2 << (16 - (upper * 16))) & 0xFFFF000000000000ULL;
2e8cf49e
NC
3123 }
3124 break;
3125
3126 case 2:
a4fb5981
JW
3127 val1 = (val_n1 >> (upper * 32)) & 0xFFFFFFFF;
3128 val1 |= (input2 << (32 - (upper * 32))) & 0xFFFFFFFF00000000ULL;
3129
3130 if (full)
3131 {
3132 val2 = (val_m1 >> (upper * 32)) & 0xFFFFFFFF;
3133 val2 |= (val_m2 << (32 - (upper * 32))) & 0xFFFFFFFF00000000ULL;
3134 }
3135 break;
2e8cf49e
NC
3136
3137 case 3:
a4fb5981
JW
3138 if (! full)
3139 HALT_UNALLOC;
3140
3141 val1 = upper ? val_n2 : val_n1;
3142 val2 = upper ? val_m2 : val_m1;
3143 break;
2e8cf49e
NC
3144 }
3145
3146 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3147 if (full)
3148 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3149}
3150
3151static void
3152do_vec_ZIP (sim_cpu *cpu)
3153{
3154 /* instr[31] = 0
3155 instr[30] = half(0)/full(1)
3156 instr[29,24] = 00 1110
3157 instr[23,22] = size: byte(00), hald(01), word (10), long (11)
3158 instr[21] = 0
3159 instr[20,16] = Vm
3160 instr[15] = 0
3161 instr[14] = lower (0) / upper (1)
3162 instr[13,10] = 1110
3163 instr[9,5] = Vn
3164 instr[4,0] = Vd. */
3165
ef0d8ffc
NC
3166 int full = INSTR (30, 30);
3167 int upper = INSTR (14, 14);
2e8cf49e 3168
ef0d8ffc
NC
3169 unsigned vm = INSTR (20, 16);
3170 unsigned vn = INSTR (9, 5);
3171 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3172
3173 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
3174 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
3175 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
3176 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
3177
3178 uint64_t val1 = 0;
3179 uint64_t val2 = 0;
3180
3181 uint64_t input1 = upper ? val_n1 : val_m1;
3182 uint64_t input2 = upper ? val_n2 : val_m2;
3183
3184 NYI_assert (29, 24, 0x0E);
3185 NYI_assert (21, 21, 0);
3186 NYI_assert (15, 15, 0);
3187 NYI_assert (13, 10, 0xE);
3188
2cdad34c 3189 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3190 switch (INSTR (23, 23))
2e8cf49e
NC
3191 {
3192 case 0:
3193 val1 =
3194 ((input1 << 0) & (0xFF << 0))
3195 | ((input2 << 8) & (0xFF << 8))
3196 | ((input1 << 8) & (0xFF << 16))
3197 | ((input2 << 16) & (0xFF << 24))
3198 | ((input1 << 16) & (0xFFULL << 32))
3199 | ((input2 << 24) & (0xFFULL << 40))
3200 | ((input1 << 24) & (0xFFULL << 48))
3201 | ((input2 << 32) & (0xFFULL << 56));
3202
3203 val2 =
3204 ((input1 >> 32) & (0xFF << 0))
3205 | ((input2 >> 24) & (0xFF << 8))
3206 | ((input1 >> 24) & (0xFF << 16))
3207 | ((input2 >> 16) & (0xFF << 24))
3208 | ((input1 >> 16) & (0xFFULL << 32))
3209 | ((input2 >> 8) & (0xFFULL << 40))
3210 | ((input1 >> 8) & (0xFFULL << 48))
3211 | ((input2 >> 0) & (0xFFULL << 56));
3212 break;
3213
3214 case 1:
3215 val1 =
3216 ((input1 << 0) & (0xFFFF << 0))
3217 | ((input2 << 16) & (0xFFFF << 16))
3218 | ((input1 << 16) & (0xFFFFULL << 32))
3219 | ((input2 << 32) & (0xFFFFULL << 48));
3220
3221 val2 =
3222 ((input1 >> 32) & (0xFFFF << 0))
3223 | ((input2 >> 16) & (0xFFFF << 16))
3224 | ((input1 >> 16) & (0xFFFFULL << 32))
3225 | ((input2 >> 0) & (0xFFFFULL << 48));
3226 break;
3227
3228 case 2:
3229 val1 = (input1 & 0xFFFFFFFFULL) | (input2 << 32);
3230 val2 = (input2 & 0xFFFFFFFFULL) | (input1 << 32);
3231 break;
3232
3233 case 3:
3234 val1 = input1;
3235 val2 = input2;
3236 break;
3237 }
3238
3239 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3240 if (full)
3241 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3242}
3243
3244/* Floating point immediates are encoded in 8 bits.
3245 fpimm[7] = sign bit.
3246 fpimm[6:4] = signed exponent.
3247 fpimm[3:0] = fraction (assuming leading 1).
3248 i.e. F = s * 1.f * 2^(e - b). */
3249
3250static float
3251fp_immediate_for_encoding_32 (uint32_t imm8)
3252{
3253 float u;
3254 uint32_t s, e, f, i;
3255
3256 s = (imm8 >> 7) & 0x1;
3257 e = (imm8 >> 4) & 0x7;
3258 f = imm8 & 0xf;
3259
3260 /* The fp value is s * n/16 * 2r where n is 16+e. */
3261 u = (16.0 + f) / 16.0;
3262
3263 /* N.B. exponent is signed. */
3264 if (e < 4)
3265 {
3266 int epos = e;
3267
3268 for (i = 0; i <= epos; i++)
3269 u *= 2.0;
3270 }
3271 else
3272 {
3273 int eneg = 7 - e;
3274
3275 for (i = 0; i < eneg; i++)
3276 u /= 2.0;
3277 }
3278
3279 if (s)
3280 u = - u;
3281
3282 return u;
3283}
3284
3285static double
3286fp_immediate_for_encoding_64 (uint32_t imm8)
3287{
3288 double u;
3289 uint32_t s, e, f, i;
3290
3291 s = (imm8 >> 7) & 0x1;
3292 e = (imm8 >> 4) & 0x7;
3293 f = imm8 & 0xf;
3294
3295 /* The fp value is s * n/16 * 2r where n is 16+e. */
3296 u = (16.0 + f) / 16.0;
3297
3298 /* N.B. exponent is signed. */
3299 if (e < 4)
3300 {
3301 int epos = e;
3302
3303 for (i = 0; i <= epos; i++)
3304 u *= 2.0;
3305 }
3306 else
3307 {
3308 int eneg = 7 - e;
3309
3310 for (i = 0; i < eneg; i++)
3311 u /= 2.0;
3312 }
3313
3314 if (s)
3315 u = - u;
3316
3317 return u;
3318}
3319
3320static void
3321do_vec_MOV_immediate (sim_cpu *cpu)
3322{
3323 /* instr[31] = 0
3324 instr[30] = full/half selector
3325 instr[29,19] = 00111100000
3326 instr[18,16] = high 3 bits of uimm8
3327 instr[15,12] = size & shift:
3328 0000 => 32-bit
3329 0010 => 32-bit + LSL#8
3330 0100 => 32-bit + LSL#16
3331 0110 => 32-bit + LSL#24
3332 1010 => 16-bit + LSL#8
3333 1000 => 16-bit
3334 1101 => 32-bit + MSL#16
3335 1100 => 32-bit + MSL#8
3336 1110 => 8-bit
3337 1111 => double
3338 instr[11,10] = 01
3339 instr[9,5] = low 5-bits of uimm8
3340 instr[4,0] = Vd. */
3341
ef0d8ffc
NC
3342 int full = INSTR (30, 30);
3343 unsigned vd = INSTR (4, 0);
7517e550 3344 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3345 unsigned i;
3346
3347 NYI_assert (29, 19, 0x1E0);
3348 NYI_assert (11, 10, 1);
3349
2cdad34c 3350 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3351 switch (INSTR (15, 12))
2e8cf49e
NC
3352 {
3353 case 0x0: /* 32-bit, no shift. */
3354 case 0x2: /* 32-bit, shift by 8. */
3355 case 0x4: /* 32-bit, shift by 16. */
3356 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3357 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3358 for (i = 0; i < (full ? 4 : 2); i++)
3359 aarch64_set_vec_u32 (cpu, vd, i, val);
3360 break;
3361
3362 case 0xa: /* 16-bit, shift by 8. */
3363 val <<= 8;
3364 /* Fall through. */
3365 case 0x8: /* 16-bit, no shift. */
3366 for (i = 0; i < (full ? 8 : 4); i++)
3367 aarch64_set_vec_u16 (cpu, vd, i, val);
c0386d4d
JW
3368 break;
3369
2e8cf49e
NC
3370 case 0xd: /* 32-bit, mask shift by 16. */
3371 val <<= 8;
3372 val |= 0xFF;
3373 /* Fall through. */
3374 case 0xc: /* 32-bit, mask shift by 8. */
3375 val <<= 8;
3376 val |= 0xFF;
3377 for (i = 0; i < (full ? 4 : 2); i++)
3378 aarch64_set_vec_u32 (cpu, vd, i, val);
3379 break;
3380
3381 case 0xe: /* 8-bit, no shift. */
3382 for (i = 0; i < (full ? 16 : 8); i++)
3383 aarch64_set_vec_u8 (cpu, vd, i, val);
3384 break;
3385
3386 case 0xf: /* FMOV Vs.{2|4}S, #fpimm. */
3387 {
3388 float u = fp_immediate_for_encoding_32 (val);
3389 for (i = 0; i < (full ? 4 : 2); i++)
3390 aarch64_set_vec_float (cpu, vd, i, u);
3391 break;
3392 }
3393
3394 default:
3395 HALT_NYI;
3396 }
3397}
3398
3399static void
3400do_vec_MVNI (sim_cpu *cpu)
3401{
3402 /* instr[31] = 0
3403 instr[30] = full/half selector
3404 instr[29,19] = 10111100000
3405 instr[18,16] = high 3 bits of uimm8
3406 instr[15,12] = selector
3407 instr[11,10] = 01
3408 instr[9,5] = low 5-bits of uimm8
3409 instr[4,0] = Vd. */
3410
ef0d8ffc
NC
3411 int full = INSTR (30, 30);
3412 unsigned vd = INSTR (4, 0);
7517e550 3413 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3414 unsigned i;
3415
3416 NYI_assert (29, 19, 0x5E0);
3417 NYI_assert (11, 10, 1);
3418
2cdad34c 3419 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3420 switch (INSTR (15, 12))
2e8cf49e
NC
3421 {
3422 case 0x0: /* 32-bit, no shift. */
3423 case 0x2: /* 32-bit, shift by 8. */
3424 case 0x4: /* 32-bit, shift by 16. */
3425 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3426 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3427 val = ~ val;
3428 for (i = 0; i < (full ? 4 : 2); i++)
3429 aarch64_set_vec_u32 (cpu, vd, i, val);
3430 return;
3431
3432 case 0xa: /* 16-bit, 8 bit shift. */
3433 val <<= 8;
3434 case 0x8: /* 16-bit, no shift. */
3435 val = ~ val;
3436 for (i = 0; i < (full ? 8 : 4); i++)
3437 aarch64_set_vec_u16 (cpu, vd, i, val);
3438 return;
3439
3440 case 0xd: /* 32-bit, mask shift by 16. */
3441 val <<= 8;
3442 val |= 0xFF;
3443 case 0xc: /* 32-bit, mask shift by 8. */
3444 val <<= 8;
3445 val |= 0xFF;
3446 val = ~ val;
3447 for (i = 0; i < (full ? 4 : 2); i++)
3448 aarch64_set_vec_u32 (cpu, vd, i, val);
3449 return;
3450
3451 case 0xE: /* MOVI Dn, #mask64 */
3452 {
3453 uint64_t mask = 0;
3454
3455 for (i = 0; i < 8; i++)
3456 if (val & (1 << i))
7517e550 3457 mask |= (0xFFUL << (i * 8));
2e8cf49e 3458 aarch64_set_vec_u64 (cpu, vd, 0, mask);
7517e550 3459 aarch64_set_vec_u64 (cpu, vd, 1, mask);
2e8cf49e
NC
3460 return;
3461 }
3462
3463 case 0xf: /* FMOV Vd.2D, #fpimm. */
3464 {
3465 double u = fp_immediate_for_encoding_64 (val);
3466
3467 if (! full)
3468 HALT_UNALLOC;
3469
3470 aarch64_set_vec_double (cpu, vd, 0, u);
3471 aarch64_set_vec_double (cpu, vd, 1, u);
3472 return;
3473 }
3474
3475 default:
3476 HALT_NYI;
3477 }
3478}
3479
3480#define ABS(A) ((A) < 0 ? - (A) : (A))
3481
3482static void
3483do_vec_ABS (sim_cpu *cpu)
3484{
3485 /* instr[31] = 0
3486 instr[30] = half(0)/full(1)
3487 instr[29,24] = 00 1110
3488 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3489 instr[21,10] = 10 0000 1011 10
3490 instr[9,5] = Vn
3491 instr[4.0] = Vd. */
3492
ef0d8ffc
NC
3493 unsigned vn = INSTR (9, 5);
3494 unsigned vd = INSTR (4, 0);
3495 unsigned full = INSTR (30, 30);
2e8cf49e
NC
3496 unsigned i;
3497
3498 NYI_assert (29, 24, 0x0E);
3499 NYI_assert (21, 10, 0x82E);
3500
2cdad34c 3501 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3502 switch (INSTR (23, 22))
2e8cf49e
NC
3503 {
3504 case 0:
3505 for (i = 0; i < (full ? 16 : 8); i++)
3506 aarch64_set_vec_s8 (cpu, vd, i,
3507 ABS (aarch64_get_vec_s8 (cpu, vn, i)));
3508 break;
3509
3510 case 1:
3511 for (i = 0; i < (full ? 8 : 4); i++)
3512 aarch64_set_vec_s16 (cpu, vd, i,
3513 ABS (aarch64_get_vec_s16 (cpu, vn, i)));
3514 break;
3515
3516 case 2:
3517 for (i = 0; i < (full ? 4 : 2); i++)
3518 aarch64_set_vec_s32 (cpu, vd, i,
3519 ABS (aarch64_get_vec_s32 (cpu, vn, i)));
3520 break;
3521
3522 case 3:
3523 if (! full)
3524 HALT_NYI;
3525 for (i = 0; i < 2; i++)
3526 aarch64_set_vec_s64 (cpu, vd, i,
3527 ABS (aarch64_get_vec_s64 (cpu, vn, i)));
3528 break;
3529 }
3530}
3531
3532static void
3533do_vec_ADDV (sim_cpu *cpu)
3534{
3535 /* instr[31] = 0
3536 instr[30] = full/half selector
3537 instr[29,24] = 00 1110
3538 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3539 instr[21,10] = 11 0001 1011 10
3540 instr[9,5] = Vm
3541 instr[4.0] = Rd. */
3542
ef0d8ffc
NC
3543 unsigned vm = INSTR (9, 5);
3544 unsigned rd = INSTR (4, 0);
2e8cf49e 3545 unsigned i;
ef0d8ffc 3546 int full = INSTR (30, 30);
2e8cf49e
NC
3547
3548 NYI_assert (29, 24, 0x0E);
3549 NYI_assert (21, 10, 0xC6E);
3550
2cdad34c 3551 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3552 switch (INSTR (23, 22))
2e8cf49e
NC
3553 {
3554 case 0:
2e7e5e28
JW
3555 {
3556 uint8_t val = 0;
3557 for (i = 0; i < (full ? 16 : 8); i++)
3558 val += aarch64_get_vec_u8 (cpu, vm, i);
3559 aarch64_set_vec_u64 (cpu, rd, 0, val);
3560 return;
3561 }
2e8cf49e
NC
3562
3563 case 1:
2e7e5e28
JW
3564 {
3565 uint16_t val = 0;
3566 for (i = 0; i < (full ? 8 : 4); i++)
3567 val += aarch64_get_vec_u16 (cpu, vm, i);
3568 aarch64_set_vec_u64 (cpu, rd, 0, val);
3569 return;
3570 }
2e8cf49e
NC
3571
3572 case 2:
2e7e5e28
JW
3573 {
3574 uint32_t val = 0;
3575 if (! full)
3576 HALT_UNALLOC;
3577 for (i = 0; i < 4; i++)
3578 val += aarch64_get_vec_u32 (cpu, vm, i);
3579 aarch64_set_vec_u64 (cpu, rd, 0, val);
3580 return;
3581 }
2e8cf49e
NC
3582
3583 case 3:
05b3d79d 3584 HALT_UNALLOC;
2e8cf49e
NC
3585 }
3586}
3587
3588static void
3589do_vec_ins_2 (sim_cpu *cpu)
3590{
3591 /* instr[31,21] = 01001110000
3592 instr[20,18] = size & element selector
3593 instr[17,14] = 0000
3594 instr[13] = direction: to vec(0), from vec (1)
3595 instr[12,10] = 111
3596 instr[9,5] = Vm
3597 instr[4,0] = Vd. */
3598
3599 unsigned elem;
ef0d8ffc
NC
3600 unsigned vm = INSTR (9, 5);
3601 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3602
3603 NYI_assert (31, 21, 0x270);
3604 NYI_assert (17, 14, 0);
3605 NYI_assert (12, 10, 7);
3606
2cdad34c 3607 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3608 if (INSTR (13, 13) == 1)
2e8cf49e 3609 {
ef0d8ffc 3610 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3611 {
3612 /* 32-bit moves. */
ef0d8ffc 3613 elem = INSTR (20, 19);
2e8cf49e
NC
3614 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3615 aarch64_get_vec_u32 (cpu, vm, elem));
3616 }
3617 else
3618 {
3619 /* 64-bit moves. */
ef0d8ffc 3620 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3621 HALT_NYI;
3622
ef0d8ffc 3623 elem = INSTR (20, 20);
2e8cf49e
NC
3624 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3625 aarch64_get_vec_u64 (cpu, vm, elem));
3626 }
3627 }
3628 else
3629 {
ef0d8ffc 3630 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3631 {
3632 /* 32-bit moves. */
ef0d8ffc 3633 elem = INSTR (20, 19);
2e8cf49e
NC
3634 aarch64_set_vec_u32 (cpu, vd, elem,
3635 aarch64_get_reg_u32 (cpu, vm, NO_SP));
3636 }
3637 else
3638 {
3639 /* 64-bit moves. */
ef0d8ffc 3640 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3641 HALT_NYI;
3642
ef0d8ffc 3643 elem = INSTR (20, 20);
2e8cf49e
NC
3644 aarch64_set_vec_u64 (cpu, vd, elem,
3645 aarch64_get_reg_u64 (cpu, vm, NO_SP));
3646 }
3647 }
3648}
3649
7517e550
NC
3650#define DO_VEC_WIDENING_MUL(N, DST_TYPE, READ_TYPE, WRITE_TYPE) \
3651 do \
3652 { \
3653 DST_TYPE a[N], b[N]; \
3654 \
3655 for (i = 0; i < (N); i++) \
3656 { \
3657 a[i] = aarch64_get_vec_##READ_TYPE (cpu, vn, i + bias); \
3658 b[i] = aarch64_get_vec_##READ_TYPE (cpu, vm, i + bias); \
3659 } \
3660 for (i = 0; i < (N); i++) \
3661 aarch64_set_vec_##WRITE_TYPE (cpu, vd, i, a[i] * b[i]); \
3662 } \
3663 while (0)
3664
2e8cf49e
NC
3665static void
3666do_vec_mull (sim_cpu *cpu)
3667{
3668 /* instr[31] = 0
3669 instr[30] = lower(0)/upper(1) selector
3670 instr[29] = signed(0)/unsigned(1)
3671 instr[28,24] = 0 1110
3672 instr[23,22] = size: 8-bit (00), 16-bit (01), 32-bit (10)
3673 instr[21] = 1
3674 instr[20,16] = Vm
3675 instr[15,10] = 11 0000
3676 instr[9,5] = Vn
3677 instr[4.0] = Vd. */
3678
ef0d8ffc
NC
3679 int unsign = INSTR (29, 29);
3680 int bias = INSTR (30, 30);
3681 unsigned vm = INSTR (20, 16);
3682 unsigned vn = INSTR ( 9, 5);
3683 unsigned vd = INSTR ( 4, 0);
2e8cf49e
NC
3684 unsigned i;
3685
3686 NYI_assert (28, 24, 0x0E);
3687 NYI_assert (15, 10, 0x30);
3688
2cdad34c 3689 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
3690 /* NB: Read source values before writing results, in case
3691 the source and destination vectors are the same. */
ef0d8ffc 3692 switch (INSTR (23, 22))
2e8cf49e
NC
3693 {
3694 case 0:
3695 if (bias)
3696 bias = 8;
3697 if (unsign)
7517e550 3698 DO_VEC_WIDENING_MUL (8, uint16_t, u8, u16);
2e8cf49e 3699 else
7517e550 3700 DO_VEC_WIDENING_MUL (8, int16_t, s8, s16);
2e8cf49e
NC
3701 return;
3702
3703 case 1:
3704 if (bias)
3705 bias = 4;
3706 if (unsign)
7517e550 3707 DO_VEC_WIDENING_MUL (4, uint32_t, u16, u32);
2e8cf49e 3708 else
7517e550 3709 DO_VEC_WIDENING_MUL (4, int32_t, s16, s32);
2e8cf49e
NC
3710 return;
3711
3712 case 2:
3713 if (bias)
3714 bias = 2;
3715 if (unsign)
7517e550 3716 DO_VEC_WIDENING_MUL (2, uint64_t, u32, u64);
2e8cf49e 3717 else
7517e550 3718 DO_VEC_WIDENING_MUL (2, int64_t, s32, s64);
2e8cf49e
NC
3719 return;
3720
3721 case 3:
2e8cf49e
NC
3722 HALT_NYI;
3723 }
3724}
3725
3726static void
3727do_vec_fadd (sim_cpu *cpu)
3728{
3729 /* instr[31] = 0
3730 instr[30] = half(0)/full(1)
3731 instr[29,24] = 001110
3732 instr[23] = FADD(0)/FSUB(1)
3733 instr[22] = float (0)/double(1)
3734 instr[21] = 1
3735 instr[20,16] = Vm
3736 instr[15,10] = 110101
3737 instr[9,5] = Vn
3738 instr[4.0] = Vd. */
3739
ef0d8ffc
NC
3740 unsigned vm = INSTR (20, 16);
3741 unsigned vn = INSTR (9, 5);
3742 unsigned vd = INSTR (4, 0);
2e8cf49e 3743 unsigned i;
ef0d8ffc 3744 int full = INSTR (30, 30);
2e8cf49e
NC
3745
3746 NYI_assert (29, 24, 0x0E);
3747 NYI_assert (21, 21, 1);
3748 NYI_assert (15, 10, 0x35);
3749
2cdad34c 3750 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3751 if (INSTR (23, 23))
2e8cf49e 3752 {
ef0d8ffc 3753 if (INSTR (22, 22))
2e8cf49e
NC
3754 {
3755 if (! full)
3756 HALT_NYI;
3757
3758 for (i = 0; i < 2; i++)
3759 aarch64_set_vec_double (cpu, vd, i,
3760 aarch64_get_vec_double (cpu, vn, i)
3761 - aarch64_get_vec_double (cpu, vm, i));
3762 }
3763 else
3764 {
3765 for (i = 0; i < (full ? 4 : 2); i++)
3766 aarch64_set_vec_float (cpu, vd, i,
3767 aarch64_get_vec_float (cpu, vn, i)
3768 - aarch64_get_vec_float (cpu, vm, i));
3769 }
3770 }
3771 else
3772 {
ef0d8ffc 3773 if (INSTR (22, 22))
2e8cf49e
NC
3774 {
3775 if (! full)
3776 HALT_NYI;
3777
3778 for (i = 0; i < 2; i++)
3779 aarch64_set_vec_double (cpu, vd, i,
3780 aarch64_get_vec_double (cpu, vm, i)
3781 + aarch64_get_vec_double (cpu, vn, i));
3782 }
3783 else
3784 {
3785 for (i = 0; i < (full ? 4 : 2); i++)
3786 aarch64_set_vec_float (cpu, vd, i,
3787 aarch64_get_vec_float (cpu, vm, i)
3788 + aarch64_get_vec_float (cpu, vn, i));
3789 }
3790 }
3791}
3792
3793static void
3794do_vec_add (sim_cpu *cpu)
3795{
3796 /* instr[31] = 0
3797 instr[30] = full/half selector
3798 instr[29,24] = 001110
3799 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3800 instr[21] = 1
3801 instr[20,16] = Vn
3802 instr[15,10] = 100001
3803 instr[9,5] = Vm
3804 instr[4.0] = Vd. */
3805
ef0d8ffc
NC
3806 unsigned vm = INSTR (20, 16);
3807 unsigned vn = INSTR (9, 5);
3808 unsigned vd = INSTR (4, 0);
2e8cf49e 3809 unsigned i;
ef0d8ffc 3810 int full = INSTR (30, 30);
2e8cf49e
NC
3811
3812 NYI_assert (29, 24, 0x0E);
3813 NYI_assert (21, 21, 1);
3814 NYI_assert (15, 10, 0x21);
3815
2cdad34c 3816 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3817 switch (INSTR (23, 22))
2e8cf49e
NC
3818 {
3819 case 0:
3820 for (i = 0; i < (full ? 16 : 8); i++)
3821 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
3822 + aarch64_get_vec_u8 (cpu, vm, i));
3823 return;
3824
3825 case 1:
3826 for (i = 0; i < (full ? 8 : 4); i++)
3827 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
3828 + aarch64_get_vec_u16 (cpu, vm, i));
3829 return;
3830
3831 case 2:
3832 for (i = 0; i < (full ? 4 : 2); i++)
3833 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
3834 + aarch64_get_vec_u32 (cpu, vm, i));
3835 return;
3836
3837 case 3:
3838 if (! full)
3839 HALT_UNALLOC;
3840 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vn, 0)
3841 + aarch64_get_vec_u64 (cpu, vm, 0));
3842 aarch64_set_vec_u64 (cpu, vd, 1,
3843 aarch64_get_vec_u64 (cpu, vn, 1)
3844 + aarch64_get_vec_u64 (cpu, vm, 1));
3845 return;
2e8cf49e
NC
3846 }
3847}
3848
3849static void
3850do_vec_mul (sim_cpu *cpu)
3851{
3852 /* instr[31] = 0
3853 instr[30] = full/half selector
3854 instr[29,24] = 00 1110
3855 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3856 instr[21] = 1
3857 instr[20,16] = Vn
3858 instr[15,10] = 10 0111
3859 instr[9,5] = Vm
3860 instr[4.0] = Vd. */
3861
ef0d8ffc
NC
3862 unsigned vm = INSTR (20, 16);
3863 unsigned vn = INSTR (9, 5);
3864 unsigned vd = INSTR (4, 0);
2e8cf49e 3865 unsigned i;
ef0d8ffc 3866 int full = INSTR (30, 30);
7517e550 3867 int bias = 0;
2e8cf49e
NC
3868
3869 NYI_assert (29, 24, 0x0E);
3870 NYI_assert (21, 21, 1);
3871 NYI_assert (15, 10, 0x27);
3872
2cdad34c 3873 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3874 switch (INSTR (23, 22))
2e8cf49e
NC
3875 {
3876 case 0:
c0386d4d 3877 DO_VEC_WIDENING_MUL (full ? 16 : 8, uint8_t, u8, u8);
2e8cf49e
NC
3878 return;
3879
3880 case 1:
c0386d4d 3881 DO_VEC_WIDENING_MUL (full ? 8 : 4, uint16_t, u16, u16);
2e8cf49e
NC
3882 return;
3883
3884 case 2:
c0386d4d 3885 DO_VEC_WIDENING_MUL (full ? 4 : 2, uint32_t, u32, u32);
2e8cf49e
NC
3886 return;
3887
2e8cf49e
NC
3888 case 3:
3889 HALT_UNALLOC;
3890 }
3891}
3892
3893static void
3894do_vec_MLA (sim_cpu *cpu)
3895{
3896 /* instr[31] = 0
3897 instr[30] = full/half selector
3898 instr[29,24] = 00 1110
3899 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3900 instr[21] = 1
3901 instr[20,16] = Vn
3902 instr[15,10] = 1001 01
3903 instr[9,5] = Vm
3904 instr[4.0] = Vd. */
3905
ef0d8ffc
NC
3906 unsigned vm = INSTR (20, 16);
3907 unsigned vn = INSTR (9, 5);
3908 unsigned vd = INSTR (4, 0);
2e8cf49e 3909 unsigned i;
ef0d8ffc 3910 int full = INSTR (30, 30);
2e8cf49e
NC
3911
3912 NYI_assert (29, 24, 0x0E);
3913 NYI_assert (21, 21, 1);
3914 NYI_assert (15, 10, 0x25);
3915
2cdad34c 3916 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 3917 switch (INSTR (23, 22))
2e8cf49e
NC
3918 {
3919 case 0:
742e3a77
JW
3920 for (i = 0; i < (full ? 16 : 8); i++)
3921 aarch64_set_vec_u8 (cpu, vd, i,
3922 aarch64_get_vec_u8 (cpu, vd, i)
3923 + (aarch64_get_vec_u8 (cpu, vn, i)
3924 * aarch64_get_vec_u8 (cpu, vm, i)));
2e8cf49e
NC
3925 return;
3926
3927 case 1:
742e3a77
JW
3928 for (i = 0; i < (full ? 8 : 4); i++)
3929 aarch64_set_vec_u16 (cpu, vd, i,
3930 aarch64_get_vec_u16 (cpu, vd, i)
3931 + (aarch64_get_vec_u16 (cpu, vn, i)
3932 * aarch64_get_vec_u16 (cpu, vm, i)));
2e8cf49e
NC
3933 return;
3934
3935 case 2:
742e3a77
JW
3936 for (i = 0; i < (full ? 4 : 2); i++)
3937 aarch64_set_vec_u32 (cpu, vd, i,
3938 aarch64_get_vec_u32 (cpu, vd, i)
3939 + (aarch64_get_vec_u32 (cpu, vn, i)
3940 * aarch64_get_vec_u32 (cpu, vm, i)));
2e8cf49e
NC
3941 return;
3942
742e3a77 3943 default:
2e8cf49e
NC
3944 HALT_UNALLOC;
3945 }
3946}
3947
3948static float
3949fmaxnm (float a, float b)
3950{
c0386d4d 3951 if (! isnan (a))
2e8cf49e 3952 {
c0386d4d 3953 if (! isnan (b))
2e8cf49e
NC
3954 return a > b ? a : b;
3955 return a;
3956 }
c0386d4d 3957 else if (! isnan (b))
2e8cf49e
NC
3958 return b;
3959 return a;
3960}
3961
3962static float
3963fminnm (float a, float b)
3964{
c0386d4d 3965 if (! isnan (a))
2e8cf49e 3966 {
c0386d4d 3967 if (! isnan (b))
2e8cf49e
NC
3968 return a < b ? a : b;
3969 return a;
3970 }
c0386d4d 3971 else if (! isnan (b))
2e8cf49e
NC
3972 return b;
3973 return a;
3974}
3975
3976static double
3977dmaxnm (double a, double b)
3978{
c0386d4d 3979 if (! isnan (a))
2e8cf49e 3980 {
c0386d4d 3981 if (! isnan (b))
2e8cf49e
NC
3982 return a > b ? a : b;
3983 return a;
3984 }
c0386d4d 3985 else if (! isnan (b))
2e8cf49e
NC
3986 return b;
3987 return a;
3988}
3989
3990static double
3991dminnm (double a, double b)
3992{
c0386d4d 3993 if (! isnan (a))
2e8cf49e 3994 {
c0386d4d 3995 if (! isnan (b))
2e8cf49e
NC
3996 return a < b ? a : b;
3997 return a;
3998 }
c0386d4d 3999 else if (! isnan (b))
2e8cf49e
NC
4000 return b;
4001 return a;
4002}
4003
4004static void
4005do_vec_FminmaxNMP (sim_cpu *cpu)
4006{
ef0d8ffc
NC
4007 /* instr [31] = 0
4008 instr [30] = half (0)/full (1)
4009 instr [29,24] = 10 1110
4010 instr [23] = max(0)/min(1)
4011 instr [22] = float (0)/double (1)
4012 instr [21] = 1
4013 instr [20,16] = Vn
4014 instr [15,10] = 1100 01
4015 instr [9,5] = Vm
4016 instr [4.0] = Vd. */
4017
4018 unsigned vm = INSTR (20, 16);
4019 unsigned vn = INSTR (9, 5);
4020 unsigned vd = INSTR (4, 0);
4021 int full = INSTR (30, 30);
2e8cf49e
NC
4022
4023 NYI_assert (29, 24, 0x2E);
4024 NYI_assert (21, 21, 1);
4025 NYI_assert (15, 10, 0x31);
4026
2cdad34c 4027 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4028 if (INSTR (22, 22))
2e8cf49e 4029 {
ef0d8ffc 4030 double (* fn)(double, double) = INSTR (23, 23)
2e8cf49e
NC
4031 ? dminnm : dmaxnm;
4032
4033 if (! full)
4034 HALT_NYI;
4035 aarch64_set_vec_double (cpu, vd, 0,
4036 fn (aarch64_get_vec_double (cpu, vn, 0),
4037 aarch64_get_vec_double (cpu, vn, 1)));
4038 aarch64_set_vec_double (cpu, vd, 0,
4039 fn (aarch64_get_vec_double (cpu, vm, 0),
4040 aarch64_get_vec_double (cpu, vm, 1)));
4041 }
4042 else
4043 {
ef0d8ffc 4044 float (* fn)(float, float) = INSTR (23, 23)
2e8cf49e
NC
4045 ? fminnm : fmaxnm;
4046
4047 aarch64_set_vec_float (cpu, vd, 0,
4048 fn (aarch64_get_vec_float (cpu, vn, 0),
4049 aarch64_get_vec_float (cpu, vn, 1)));
4050 if (full)
4051 aarch64_set_vec_float (cpu, vd, 1,
4052 fn (aarch64_get_vec_float (cpu, vn, 2),
4053 aarch64_get_vec_float (cpu, vn, 3)));
4054
4055 aarch64_set_vec_float (cpu, vd, (full ? 2 : 1),
4056 fn (aarch64_get_vec_float (cpu, vm, 0),
4057 aarch64_get_vec_float (cpu, vm, 1)));
4058 if (full)
4059 aarch64_set_vec_float (cpu, vd, 3,
4060 fn (aarch64_get_vec_float (cpu, vm, 2),
4061 aarch64_get_vec_float (cpu, vm, 3)));
4062 }
4063}
4064
4065static void
4066do_vec_AND (sim_cpu *cpu)
4067{
4068 /* instr[31] = 0
4069 instr[30] = half (0)/full (1)
4070 instr[29,21] = 001110001
4071 instr[20,16] = Vm
4072 instr[15,10] = 000111
4073 instr[9,5] = Vn
4074 instr[4.0] = Vd. */
4075
ef0d8ffc
NC
4076 unsigned vm = INSTR (20, 16);
4077 unsigned vn = INSTR (9, 5);
4078 unsigned vd = INSTR (4, 0);
2e8cf49e 4079 unsigned i;
ef0d8ffc 4080 int full = INSTR (30, 30);
2e8cf49e
NC
4081
4082 NYI_assert (29, 21, 0x071);
4083 NYI_assert (15, 10, 0x07);
4084
2cdad34c 4085 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4086 for (i = 0; i < (full ? 4 : 2); i++)
4087 aarch64_set_vec_u32 (cpu, vd, i,
4088 aarch64_get_vec_u32 (cpu, vn, i)
4089 & aarch64_get_vec_u32 (cpu, vm, i));
4090}
4091
4092static void
4093do_vec_BSL (sim_cpu *cpu)
4094{
4095 /* instr[31] = 0
4096 instr[30] = half (0)/full (1)
4097 instr[29,21] = 101110011
4098 instr[20,16] = Vm
4099 instr[15,10] = 000111
4100 instr[9,5] = Vn
4101 instr[4.0] = Vd. */
4102
ef0d8ffc
NC
4103 unsigned vm = INSTR (20, 16);
4104 unsigned vn = INSTR (9, 5);
4105 unsigned vd = INSTR (4, 0);
2e8cf49e 4106 unsigned i;
ef0d8ffc 4107 int full = INSTR (30, 30);
2e8cf49e
NC
4108
4109 NYI_assert (29, 21, 0x173);
4110 NYI_assert (15, 10, 0x07);
4111
2cdad34c 4112 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4113 for (i = 0; i < (full ? 16 : 8); i++)
4114 aarch64_set_vec_u8 (cpu, vd, i,
4115 ( aarch64_get_vec_u8 (cpu, vd, i)
4116 & aarch64_get_vec_u8 (cpu, vn, i))
4117 | ((~ aarch64_get_vec_u8 (cpu, vd, i))
4118 & aarch64_get_vec_u8 (cpu, vm, i)));
4119}
4120
4121static void
4122do_vec_EOR (sim_cpu *cpu)
4123{
4124 /* instr[31] = 0
4125 instr[30] = half (0)/full (1)
4126 instr[29,21] = 10 1110 001
4127 instr[20,16] = Vm
4128 instr[15,10] = 000111
4129 instr[9,5] = Vn
4130 instr[4.0] = Vd. */
4131
ef0d8ffc
NC
4132 unsigned vm = INSTR (20, 16);
4133 unsigned vn = INSTR (9, 5);
4134 unsigned vd = INSTR (4, 0);
2e8cf49e 4135 unsigned i;
ef0d8ffc 4136 int full = INSTR (30, 30);
2e8cf49e
NC
4137
4138 NYI_assert (29, 21, 0x171);
4139 NYI_assert (15, 10, 0x07);
4140
2cdad34c 4141 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4142 for (i = 0; i < (full ? 4 : 2); i++)
4143 aarch64_set_vec_u32 (cpu, vd, i,
4144 aarch64_get_vec_u32 (cpu, vn, i)
4145 ^ aarch64_get_vec_u32 (cpu, vm, i));
4146}
4147
4148static void
4149do_vec_bit (sim_cpu *cpu)
4150{
4151 /* instr[31] = 0
4152 instr[30] = half (0)/full (1)
4153 instr[29,23] = 10 1110 1
4154 instr[22] = BIT (0) / BIF (1)
4155 instr[21] = 1
4156 instr[20,16] = Vm
4157 instr[15,10] = 0001 11
4158 instr[9,5] = Vn
4159 instr[4.0] = Vd. */
4160
ef0d8ffc
NC
4161 unsigned vm = INSTR (20, 16);
4162 unsigned vn = INSTR (9, 5);
4163 unsigned vd = INSTR (4, 0);
4164 unsigned full = INSTR (30, 30);
4165 unsigned test_false = INSTR (22, 22);
2e8cf49e
NC
4166 unsigned i;
4167
4168 NYI_assert (29, 23, 0x5D);
4169 NYI_assert (21, 21, 1);
4170 NYI_assert (15, 10, 0x07);
4171
2cdad34c 4172 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
bf25e9a0 4173 for (i = 0; i < (full ? 4 : 2); i++)
2e8cf49e 4174 {
bf25e9a0
JW
4175 uint32_t vd_val = aarch64_get_vec_u32 (cpu, vd, i);
4176 uint32_t vn_val = aarch64_get_vec_u32 (cpu, vn, i);
4177 uint32_t vm_val = aarch64_get_vec_u32 (cpu, vm, i);
4178 if (test_false)
4179 aarch64_set_vec_u32 (cpu, vd, i,
4180 (vd_val & vm_val) | (vn_val & ~vm_val));
4181 else
4182 aarch64_set_vec_u32 (cpu, vd, i,
4183 (vd_val & ~vm_val) | (vn_val & vm_val));
2e8cf49e
NC
4184 }
4185}
4186
4187static void
4188do_vec_ORN (sim_cpu *cpu)
4189{
4190 /* instr[31] = 0
4191 instr[30] = half (0)/full (1)
4192 instr[29,21] = 00 1110 111
4193 instr[20,16] = Vm
4194 instr[15,10] = 00 0111
4195 instr[9,5] = Vn
4196 instr[4.0] = Vd. */
4197
ef0d8ffc
NC
4198 unsigned vm = INSTR (20, 16);
4199 unsigned vn = INSTR (9, 5);
4200 unsigned vd = INSTR (4, 0);
2e8cf49e 4201 unsigned i;
ef0d8ffc 4202 int full = INSTR (30, 30);
2e8cf49e
NC
4203
4204 NYI_assert (29, 21, 0x077);
4205 NYI_assert (15, 10, 0x07);
4206
2cdad34c 4207 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4208 for (i = 0; i < (full ? 16 : 8); i++)
4209 aarch64_set_vec_u8 (cpu, vd, i,
4210 aarch64_get_vec_u8 (cpu, vn, i)
4211 | ~ aarch64_get_vec_u8 (cpu, vm, i));
4212}
4213
4214static void
4215do_vec_ORR (sim_cpu *cpu)
4216{
4217 /* instr[31] = 0
4218 instr[30] = half (0)/full (1)
4219 instr[29,21] = 00 1110 101
4220 instr[20,16] = Vm
4221 instr[15,10] = 0001 11
4222 instr[9,5] = Vn
4223 instr[4.0] = Vd. */
4224
ef0d8ffc
NC
4225 unsigned vm = INSTR (20, 16);
4226 unsigned vn = INSTR (9, 5);
4227 unsigned vd = INSTR (4, 0);
2e8cf49e 4228 unsigned i;
ef0d8ffc 4229 int full = INSTR (30, 30);
2e8cf49e
NC
4230
4231 NYI_assert (29, 21, 0x075);
4232 NYI_assert (15, 10, 0x07);
4233
2cdad34c 4234 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4235 for (i = 0; i < (full ? 16 : 8); i++)
4236 aarch64_set_vec_u8 (cpu, vd, i,
4237 aarch64_get_vec_u8 (cpu, vn, i)
4238 | aarch64_get_vec_u8 (cpu, vm, i));
4239}
4240
4241static void
4242do_vec_BIC (sim_cpu *cpu)
4243{
4244 /* instr[31] = 0
4245 instr[30] = half (0)/full (1)
4246 instr[29,21] = 00 1110 011
4247 instr[20,16] = Vm
4248 instr[15,10] = 00 0111
4249 instr[9,5] = Vn
4250 instr[4.0] = Vd. */
4251
ef0d8ffc
NC
4252 unsigned vm = INSTR (20, 16);
4253 unsigned vn = INSTR (9, 5);
4254 unsigned vd = INSTR (4, 0);
2e8cf49e 4255 unsigned i;
ef0d8ffc 4256 int full = INSTR (30, 30);
2e8cf49e
NC
4257
4258 NYI_assert (29, 21, 0x073);
4259 NYI_assert (15, 10, 0x07);
4260
2cdad34c 4261 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4262 for (i = 0; i < (full ? 16 : 8); i++)
4263 aarch64_set_vec_u8 (cpu, vd, i,
4264 aarch64_get_vec_u8 (cpu, vn, i)
4265 & ~ aarch64_get_vec_u8 (cpu, vm, i));
4266}
4267
4268static void
4269do_vec_XTN (sim_cpu *cpu)
4270{
4271 /* instr[31] = 0
4272 instr[30] = first part (0)/ second part (1)
4273 instr[29,24] = 00 1110
4274 instr[23,22] = size: byte(00), half(01), word (10)
4275 instr[21,10] = 1000 0100 1010
4276 instr[9,5] = Vs
4277 instr[4,0] = Vd. */
4278
ef0d8ffc
NC
4279 unsigned vs = INSTR (9, 5);
4280 unsigned vd = INSTR (4, 0);
4281 unsigned bias = INSTR (30, 30);
2e8cf49e
NC
4282 unsigned i;
4283
4284 NYI_assert (29, 24, 0x0E);
4285 NYI_assert (21, 10, 0x84A);
4286
2cdad34c 4287 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4288 switch (INSTR (23, 22))
2e8cf49e
NC
4289 {
4290 case 0:
05b3d79d
JW
4291 for (i = 0; i < 8; i++)
4292 aarch64_set_vec_u8 (cpu, vd, i + (bias * 8),
4293 aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4294 return;
4295
4296 case 1:
05b3d79d
JW
4297 for (i = 0; i < 4; i++)
4298 aarch64_set_vec_u16 (cpu, vd, i + (bias * 4),
4299 aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e
NC
4300 return;
4301
4302 case 2:
05b3d79d
JW
4303 for (i = 0; i < 2; i++)
4304 aarch64_set_vec_u32 (cpu, vd, i + (bias * 2),
4305 aarch64_get_vec_u64 (cpu, vs, i));
2e8cf49e 4306 return;
2e8cf49e
NC
4307 }
4308}
4309
ac189e7b
JW
4310/* Return the number of bits set in the input value. */
4311#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
4312# define popcount __builtin_popcount
4313#else
4314static int
4315popcount (unsigned char x)
4316{
4317 static const unsigned char popcnt[16] =
4318 {
4319 0, 1, 1, 2,
4320 1, 2, 2, 3,
4321 1, 2, 2, 3,
4322 2, 3, 3, 4
4323 };
4324
4325 /* Only counts the low 8 bits of the input as that is all we need. */
4326 return popcnt[x % 16] + popcnt[x / 16];
4327}
4328#endif
4329
4330static void
4331do_vec_CNT (sim_cpu *cpu)
4332{
4333 /* instr[31] = 0
4334 instr[30] = half (0)/ full (1)
4335 instr[29,24] = 00 1110
4336 instr[23,22] = size: byte(00)
4337 instr[21,10] = 1000 0001 0110
4338 instr[9,5] = Vs
4339 instr[4,0] = Vd. */
4340
4341 unsigned vs = INSTR (9, 5);
4342 unsigned vd = INSTR (4, 0);
4343 int full = INSTR (30, 30);
4344 int size = INSTR (23, 22);
4345 int i;
4346
4347 NYI_assert (29, 24, 0x0E);
4348 NYI_assert (21, 10, 0x816);
4349
4350 if (size != 0)
4351 HALT_UNALLOC;
4352
4353 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
4354
4355 for (i = 0; i < (full ? 16 : 8); i++)
4356 aarch64_set_vec_u8 (cpu, vd, i,
4357 popcount (aarch64_get_vec_u8 (cpu, vs, i)));
4358}
4359
2e8cf49e
NC
4360static void
4361do_vec_maxv (sim_cpu *cpu)
4362{
4363 /* instr[31] = 0
4364 instr[30] = half(0)/full(1)
4365 instr[29] = signed (0)/unsigned(1)
4366 instr[28,24] = 0 1110
4367 instr[23,22] = size: byte(00), half(01), word (10)
4368 instr[21] = 1
4369 instr[20,17] = 1 000
4370 instr[16] = max(0)/min(1)
4371 instr[15,10] = 1010 10
4372 instr[9,5] = V source
4373 instr[4.0] = R dest. */
4374
ef0d8ffc
NC
4375 unsigned vs = INSTR (9, 5);
4376 unsigned rd = INSTR (4, 0);
4377 unsigned full = INSTR (30, 30);
2e8cf49e
NC
4378 unsigned i;
4379
4380 NYI_assert (28, 24, 0x0E);
4381 NYI_assert (21, 21, 1);
4382 NYI_assert (20, 17, 8);
4383 NYI_assert (15, 10, 0x2A);
4384
2cdad34c 4385 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550 4386 switch ((INSTR (29, 29) << 1) | INSTR (16, 16))
2e8cf49e
NC
4387 {
4388 case 0: /* SMAXV. */
4389 {
4390 int64_t smax;
ef0d8ffc 4391 switch (INSTR (23, 22))
2e8cf49e
NC
4392 {
4393 case 0:
4394 smax = aarch64_get_vec_s8 (cpu, vs, 0);
4395 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4396 smax = max (smax, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4397 break;
4398 case 1:
4399 smax = aarch64_get_vec_s16 (cpu, vs, 0);
4400 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4401 smax = max (smax, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4402 break;
4403 case 2:
4404 smax = aarch64_get_vec_s32 (cpu, vs, 0);
4405 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4406 smax = max (smax, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4407 break;
2e8cf49e
NC
4408 case 3:
4409 HALT_UNALLOC;
4410 }
4411 aarch64_set_reg_s64 (cpu, rd, NO_SP, smax);
4412 return;
4413 }
4414
4415 case 1: /* SMINV. */
4416 {
4417 int64_t smin;
ef0d8ffc 4418 switch (INSTR (23, 22))
2e8cf49e
NC
4419 {
4420 case 0:
4421 smin = aarch64_get_vec_s8 (cpu, vs, 0);
4422 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4423 smin = min (smin, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4424 break;
4425 case 1:
4426 smin = aarch64_get_vec_s16 (cpu, vs, 0);
4427 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4428 smin = min (smin, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4429 break;
4430 case 2:
4431 smin = aarch64_get_vec_s32 (cpu, vs, 0);
4432 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4433 smin = min (smin, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4434 break;
5ab6d79e 4435
2e8cf49e
NC
4436 case 3:
4437 HALT_UNALLOC;
4438 }
4439 aarch64_set_reg_s64 (cpu, rd, NO_SP, smin);
4440 return;
4441 }
4442
4443 case 2: /* UMAXV. */
4444 {
4445 uint64_t umax;
ef0d8ffc 4446 switch (INSTR (23, 22))
2e8cf49e
NC
4447 {
4448 case 0:
4449 umax = aarch64_get_vec_u8 (cpu, vs, 0);
4450 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4451 umax = max (umax, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4452 break;
4453 case 1:
4454 umax = aarch64_get_vec_u16 (cpu, vs, 0);
4455 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4456 umax = max (umax, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4457 break;
4458 case 2:
4459 umax = aarch64_get_vec_u32 (cpu, vs, 0);
4460 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4461 umax = max (umax, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4462 break;
5ab6d79e 4463
2e8cf49e
NC
4464 case 3:
4465 HALT_UNALLOC;
4466 }
4467 aarch64_set_reg_u64 (cpu, rd, NO_SP, umax);
4468 return;
4469 }
4470
4471 case 3: /* UMINV. */
4472 {
4473 uint64_t umin;
ef0d8ffc 4474 switch (INSTR (23, 22))
2e8cf49e
NC
4475 {
4476 case 0:
4477 umin = aarch64_get_vec_u8 (cpu, vs, 0);
4478 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4479 umin = min (umin, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4480 break;
4481 case 1:
4482 umin = aarch64_get_vec_u16 (cpu, vs, 0);
4483 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4484 umin = min (umin, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4485 break;
4486 case 2:
4487 umin = aarch64_get_vec_u32 (cpu, vs, 0);
4488 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4489 umin = min (umin, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4490 break;
5ab6d79e 4491
2e8cf49e
NC
4492 case 3:
4493 HALT_UNALLOC;
4494 }
4495 aarch64_set_reg_u64 (cpu, rd, NO_SP, umin);
4496 return;
4497 }
2e8cf49e
NC
4498 }
4499}
4500
4501static void
4502do_vec_fminmaxV (sim_cpu *cpu)
4503{
4504 /* instr[31,24] = 0110 1110
4505 instr[23] = max(0)/min(1)
4506 instr[22,14] = 011 0000 11
4507 instr[13,12] = nm(00)/normal(11)
4508 instr[11,10] = 10
4509 instr[9,5] = V source
4510 instr[4.0] = R dest. */
4511
ef0d8ffc
NC
4512 unsigned vs = INSTR (9, 5);
4513 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
4514 unsigned i;
4515 float res = aarch64_get_vec_float (cpu, vs, 0);
4516
4517 NYI_assert (31, 24, 0x6E);
4518 NYI_assert (22, 14, 0x0C3);
4519 NYI_assert (11, 10, 2);
4520
2cdad34c 4521 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4522 if (INSTR (23, 23))
2e8cf49e 4523 {
ef0d8ffc 4524 switch (INSTR (13, 12))
2e8cf49e
NC
4525 {
4526 case 0: /* FMNINNMV. */
4527 for (i = 1; i < 4; i++)
4528 res = fminnm (res, aarch64_get_vec_float (cpu, vs, i));
4529 break;
4530
4531 case 3: /* FMINV. */
4532 for (i = 1; i < 4; i++)
bc273e17 4533 res = min (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4534 break;
4535
4536 default:
4537 HALT_NYI;
4538 }
4539 }
4540 else
4541 {
ef0d8ffc 4542 switch (INSTR (13, 12))
2e8cf49e
NC
4543 {
4544 case 0: /* FMNAXNMV. */
4545 for (i = 1; i < 4; i++)
4546 res = fmaxnm (res, aarch64_get_vec_float (cpu, vs, i));
4547 break;
4548
4549 case 3: /* FMAXV. */
4550 for (i = 1; i < 4; i++)
bc273e17 4551 res = max (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4552 break;
4553
4554 default:
4555 HALT_NYI;
4556 }
4557 }
4558
4559 aarch64_set_FP_float (cpu, rd, res);
4560}
4561
4562static void
4563do_vec_Fminmax (sim_cpu *cpu)
4564{
4565 /* instr[31] = 0
4566 instr[30] = half(0)/full(1)
4567 instr[29,24] = 00 1110
4568 instr[23] = max(0)/min(1)
4569 instr[22] = float(0)/double(1)
4570 instr[21] = 1
4571 instr[20,16] = Vm
4572 instr[15,14] = 11
4573 instr[13,12] = nm(00)/normal(11)
4574 instr[11,10] = 01
4575 instr[9,5] = Vn
4576 instr[4,0] = Vd. */
4577
ef0d8ffc
NC
4578 unsigned vm = INSTR (20, 16);
4579 unsigned vn = INSTR (9, 5);
4580 unsigned vd = INSTR (4, 0);
4581 unsigned full = INSTR (30, 30);
4582 unsigned min = INSTR (23, 23);
2e8cf49e
NC
4583 unsigned i;
4584
4585 NYI_assert (29, 24, 0x0E);
4586 NYI_assert (21, 21, 1);
4587 NYI_assert (15, 14, 3);
4588 NYI_assert (11, 10, 1);
4589
2cdad34c 4590 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4591 if (INSTR (22, 22))
2e8cf49e
NC
4592 {
4593 double (* func)(double, double);
4594
4595 if (! full)
4596 HALT_NYI;
4597
ef0d8ffc 4598 if (INSTR (13, 12) == 0)
2e8cf49e 4599 func = min ? dminnm : dmaxnm;
ef0d8ffc 4600 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4601 func = min ? fmin : fmax;
4602 else
4603 HALT_NYI;
4604
4605 for (i = 0; i < 2; i++)
4606 aarch64_set_vec_double (cpu, vd, i,
4607 func (aarch64_get_vec_double (cpu, vn, i),
4608 aarch64_get_vec_double (cpu, vm, i)));
4609 }
4610 else
4611 {
4612 float (* func)(float, float);
4613
ef0d8ffc 4614 if (INSTR (13, 12) == 0)
2e8cf49e 4615 func = min ? fminnm : fmaxnm;
ef0d8ffc 4616 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4617 func = min ? fminf : fmaxf;
4618 else
4619 HALT_NYI;
4620
4621 for (i = 0; i < (full ? 4 : 2); i++)
4622 aarch64_set_vec_float (cpu, vd, i,
4623 func (aarch64_get_vec_float (cpu, vn, i),
4624 aarch64_get_vec_float (cpu, vm, i)));
4625 }
4626}
4627
4628static void
4629do_vec_SCVTF (sim_cpu *cpu)
4630{
4631 /* instr[31] = 0
4632 instr[30] = Q
4633 instr[29,23] = 00 1110 0
4634 instr[22] = float(0)/double(1)
4635 instr[21,10] = 10 0001 1101 10
4636 instr[9,5] = Vn
4637 instr[4,0] = Vd. */
4638
ef0d8ffc
NC
4639 unsigned vn = INSTR (9, 5);
4640 unsigned vd = INSTR (4, 0);
4641 unsigned full = INSTR (30, 30);
4642 unsigned size = INSTR (22, 22);
2e8cf49e
NC
4643 unsigned i;
4644
4645 NYI_assert (29, 23, 0x1C);
4646 NYI_assert (21, 10, 0x876);
4647
2cdad34c 4648 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
4649 if (size)
4650 {
4651 if (! full)
4652 HALT_UNALLOC;
4653
4654 for (i = 0; i < 2; i++)
4655 {
4656 double val = (double) aarch64_get_vec_u64 (cpu, vn, i);
4657 aarch64_set_vec_double (cpu, vd, i, val);
4658 }
4659 }
4660 else
4661 {
4662 for (i = 0; i < (full ? 4 : 2); i++)
4663 {
4664 float val = (float) aarch64_get_vec_u32 (cpu, vn, i);
4665 aarch64_set_vec_float (cpu, vd, i, val);
4666 }
4667 }
4668}
4669
4670#define VEC_CMP(SOURCE, CMP) \
4671 do \
4672 { \
4673 switch (size) \
4674 { \
4675 case 0: \
4676 for (i = 0; i < (full ? 16 : 8); i++) \
4677 aarch64_set_vec_u8 (cpu, vd, i, \
4678 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4679 CMP \
4680 aarch64_get_vec_##SOURCE##8 (cpu, vm, i) \
4681 ? -1 : 0); \
4682 return; \
4683 case 1: \
4684 for (i = 0; i < (full ? 8 : 4); i++) \
4685 aarch64_set_vec_u16 (cpu, vd, i, \
4686 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4687 CMP \
4688 aarch64_get_vec_##SOURCE##16 (cpu, vm, i) \
4689 ? -1 : 0); \
4690 return; \
4691 case 2: \
4692 for (i = 0; i < (full ? 4 : 2); i++) \
4693 aarch64_set_vec_u32 (cpu, vd, i, \
4694 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4695 CMP \
4696 aarch64_get_vec_##SOURCE##32 (cpu, vm, i) \
4697 ? -1 : 0); \
4698 return; \
4699 case 3: \
4700 if (! full) \
4701 HALT_UNALLOC; \
4702 for (i = 0; i < 2; i++) \
4703 aarch64_set_vec_u64 (cpu, vd, i, \
4704 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4705 CMP \
4706 aarch64_get_vec_##SOURCE##64 (cpu, vm, i) \
4707 ? -1ULL : 0); \
4708 return; \
2e8cf49e
NC
4709 } \
4710 } \
4711 while (0)
4712
4713#define VEC_CMP0(SOURCE, CMP) \
4714 do \
4715 { \
4716 switch (size) \
4717 { \
4718 case 0: \
4719 for (i = 0; i < (full ? 16 : 8); i++) \
4720 aarch64_set_vec_u8 (cpu, vd, i, \
4721 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4722 CMP 0 ? -1 : 0); \
4723 return; \
4724 case 1: \
4725 for (i = 0; i < (full ? 8 : 4); i++) \
4726 aarch64_set_vec_u16 (cpu, vd, i, \
4727 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4728 CMP 0 ? -1 : 0); \
4729 return; \
4730 case 2: \
4731 for (i = 0; i < (full ? 4 : 2); i++) \
4732 aarch64_set_vec_u32 (cpu, vd, i, \
4733 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4734 CMP 0 ? -1 : 0); \
4735 return; \
4736 case 3: \
4737 if (! full) \
4738 HALT_UNALLOC; \
4739 for (i = 0; i < 2; i++) \
4740 aarch64_set_vec_u64 (cpu, vd, i, \
4741 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4742 CMP 0 ? -1ULL : 0); \
4743 return; \
2e8cf49e
NC
4744 } \
4745 } \
4746 while (0)
4747
4748#define VEC_FCMP0(CMP) \
4749 do \
4750 { \
4751 if (vm != 0) \
4752 HALT_NYI; \
2cdad34c 4753 if (INSTR (22, 22)) \
2e8cf49e
NC
4754 { \
4755 if (! full) \
4756 HALT_NYI; \
4757 for (i = 0; i < 2; i++) \
4758 aarch64_set_vec_u64 (cpu, vd, i, \
4759 aarch64_get_vec_double (cpu, vn, i) \
4760 CMP 0.0 ? -1 : 0); \
4761 } \
4762 else \
4763 { \
4764 for (i = 0; i < (full ? 4 : 2); i++) \
4765 aarch64_set_vec_u32 (cpu, vd, i, \
4766 aarch64_get_vec_float (cpu, vn, i) \
4767 CMP 0.0 ? -1 : 0); \
4768 } \
4769 return; \
4770 } \
4771 while (0)
4772
4773#define VEC_FCMP(CMP) \
4774 do \
4775 { \
2cdad34c 4776 if (INSTR (22, 22)) \
2e8cf49e
NC
4777 { \
4778 if (! full) \
4779 HALT_NYI; \
4780 for (i = 0; i < 2; i++) \
4781 aarch64_set_vec_u64 (cpu, vd, i, \
4782 aarch64_get_vec_double (cpu, vn, i) \
4783 CMP \
4784 aarch64_get_vec_double (cpu, vm, i) \
4785 ? -1 : 0); \
4786 } \
4787 else \
4788 { \
4789 for (i = 0; i < (full ? 4 : 2); i++) \
4790 aarch64_set_vec_u32 (cpu, vd, i, \
4791 aarch64_get_vec_float (cpu, vn, i) \
4792 CMP \
4793 aarch64_get_vec_float (cpu, vm, i) \
4794 ? -1 : 0); \
4795 } \
4796 return; \
4797 } \
4798 while (0)
4799
4800static void
4801do_vec_compare (sim_cpu *cpu)
4802{
4803 /* instr[31] = 0
4804 instr[30] = half(0)/full(1)
4805 instr[29] = part-of-comparison-type
4806 instr[28,24] = 0 1110
4807 instr[23,22] = size of integer compares: byte(00), half(01), word (10), long (11)
4808 type of float compares: single (-0) / double (-1)
4809 instr[21] = 1
4810 instr[20,16] = Vm or 00000 (compare vs 0)
4811 instr[15,10] = part-of-comparison-type
4812 instr[9,5] = Vn
4813 instr[4.0] = Vd. */
4814
ef0d8ffc
NC
4815 int full = INSTR (30, 30);
4816 int size = INSTR (23, 22);
4817 unsigned vm = INSTR (20, 16);
4818 unsigned vn = INSTR (9, 5);
4819 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
4820 unsigned i;
4821
4822 NYI_assert (28, 24, 0x0E);
4823 NYI_assert (21, 21, 1);
4824
2cdad34c 4825 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc
NC
4826 if ((INSTR (11, 11)
4827 && INSTR (14, 14))
4828 || ((INSTR (11, 11) == 0
4829 && INSTR (10, 10) == 0)))
2e8cf49e
NC
4830 {
4831 /* A compare vs 0. */
4832 if (vm != 0)
4833 {
ef0d8ffc 4834 if (INSTR (15, 10) == 0x2A)
2e8cf49e 4835 do_vec_maxv (cpu);
ef0d8ffc
NC
4836 else if (INSTR (15, 10) == 0x32
4837 || INSTR (15, 10) == 0x3E)
2e8cf49e 4838 do_vec_fminmaxV (cpu);
ef0d8ffc
NC
4839 else if (INSTR (29, 23) == 0x1C
4840 && INSTR (21, 10) == 0x876)
2e8cf49e
NC
4841 do_vec_SCVTF (cpu);
4842 else
4843 HALT_NYI;
4844 return;
4845 }
4846 }
4847
ef0d8ffc 4848 if (INSTR (14, 14))
2e8cf49e
NC
4849 {
4850 /* A floating point compare. */
7517e550 4851 unsigned decode = (INSTR (29, 29) << 5) | (INSTR (23, 23) << 4)
ef0d8ffc 4852 | INSTR (13, 10);
2e8cf49e
NC
4853
4854 NYI_assert (15, 15, 1);
4855
4856 switch (decode)
4857 {
4858 case /* 0b010010: GT#0 */ 0x12: VEC_FCMP0 (>);
4859 case /* 0b110010: GE#0 */ 0x32: VEC_FCMP0 (>=);
4860 case /* 0b010110: EQ#0 */ 0x16: VEC_FCMP0 (==);
4861 case /* 0b110110: LE#0 */ 0x36: VEC_FCMP0 (<=);
4862 case /* 0b011010: LT#0 */ 0x1A: VEC_FCMP0 (<);
4863 case /* 0b111001: GT */ 0x39: VEC_FCMP (>);
4864 case /* 0b101001: GE */ 0x29: VEC_FCMP (>=);
4865 case /* 0b001001: EQ */ 0x09: VEC_FCMP (==);
4866
4867 default:
4868 HALT_NYI;
4869 }
4870 }
4871 else
4872 {
7517e550 4873 unsigned decode = (INSTR (29, 29) << 6) | INSTR (15, 10);
2e8cf49e
NC
4874
4875 switch (decode)
4876 {
4877 case 0x0D: /* 0001101 GT */ VEC_CMP (s, > );
4878 case 0x0F: /* 0001111 GE */ VEC_CMP (s, >= );
4879 case 0x22: /* 0100010 GT #0 */ VEC_CMP0 (s, > );
fbf32f63 4880 case 0x23: /* 0100011 TST */ VEC_CMP (u, & );
2e8cf49e
NC
4881 case 0x26: /* 0100110 EQ #0 */ VEC_CMP0 (s, == );
4882 case 0x2A: /* 0101010 LT #0 */ VEC_CMP0 (s, < );
4883 case 0x4D: /* 1001101 HI */ VEC_CMP (u, > );
4884 case 0x4F: /* 1001111 HS */ VEC_CMP (u, >= );
4885 case 0x62: /* 1100010 GE #0 */ VEC_CMP0 (s, >= );
4886 case 0x63: /* 1100011 EQ */ VEC_CMP (u, == );
4887 case 0x66: /* 1100110 LE #0 */ VEC_CMP0 (s, <= );
4888 default:
4889 if (vm == 0)
4890 HALT_NYI;
4891 do_vec_maxv (cpu);
4892 }
4893 }
4894}
4895
4896static void
4897do_vec_SSHL (sim_cpu *cpu)
4898{
4899 /* instr[31] = 0
4900 instr[30] = first part (0)/ second part (1)
4901 instr[29,24] = 00 1110
4902 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4903 instr[21] = 1
4904 instr[20,16] = Vm
4905 instr[15,10] = 0100 01
4906 instr[9,5] = Vn
4907 instr[4,0] = Vd. */
4908
ef0d8ffc
NC
4909 unsigned full = INSTR (30, 30);
4910 unsigned vm = INSTR (20, 16);
4911 unsigned vn = INSTR (9, 5);
4912 unsigned vd = INSTR (4, 0);
2e8cf49e 4913 unsigned i;
5ab6d79e 4914 signed int shift;
2e8cf49e
NC
4915
4916 NYI_assert (29, 24, 0x0E);
4917 NYI_assert (21, 21, 1);
4918 NYI_assert (15, 10, 0x11);
4919
4920 /* FIXME: What is a signed shift left in this context ?. */
4921
2cdad34c 4922 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 4923 switch (INSTR (23, 22))
2e8cf49e
NC
4924 {
4925 case 0:
4926 for (i = 0; i < (full ? 16 : 8); i++)
5ab6d79e
NC
4927 {
4928 shift = aarch64_get_vec_s8 (cpu, vm, i);
4929 if (shift >= 0)
4930 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4931 << shift);
4932 else
4933 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4934 >> - shift);
4935 }
2e8cf49e
NC
4936 return;
4937
4938 case 1:
4939 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 4940 {
7517e550 4941 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
4942 if (shift >= 0)
4943 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4944 << shift);
4945 else
4946 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4947 >> - shift);
4948 }
2e8cf49e
NC
4949 return;
4950
4951 case 2:
4952 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 4953 {
7517e550 4954 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
4955 if (shift >= 0)
4956 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4957 << shift);
4958 else
4959 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4960 >> - shift);
4961 }
2e8cf49e
NC
4962 return;
4963
4964 case 3:
4965 if (! full)
4966 HALT_UNALLOC;
4967 for (i = 0; i < 2; i++)
5ab6d79e 4968 {
7517e550 4969 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
4970 if (shift >= 0)
4971 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4972 << shift);
4973 else
4974 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4975 >> - shift);
4976 }
2e8cf49e 4977 return;
2e8cf49e
NC
4978 }
4979}
4980
4981static void
4982do_vec_USHL (sim_cpu *cpu)
4983{
4984 /* instr[31] = 0
4985 instr[30] = first part (0)/ second part (1)
4986 instr[29,24] = 10 1110
4987 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4988 instr[21] = 1
4989 instr[20,16] = Vm
4990 instr[15,10] = 0100 01
4991 instr[9,5] = Vn
4992 instr[4,0] = Vd */
4993
ef0d8ffc
NC
4994 unsigned full = INSTR (30, 30);
4995 unsigned vm = INSTR (20, 16);
4996 unsigned vn = INSTR (9, 5);
4997 unsigned vd = INSTR (4, 0);
2e8cf49e 4998 unsigned i;
5ab6d79e 4999 signed int shift;
2e8cf49e
NC
5000
5001 NYI_assert (29, 24, 0x2E);
5002 NYI_assert (15, 10, 0x11);
5003
2cdad34c 5004 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5005 switch (INSTR (23, 22))
2e8cf49e
NC
5006 {
5007 case 0:
5ab6d79e
NC
5008 for (i = 0; i < (full ? 16 : 8); i++)
5009 {
5010 shift = aarch64_get_vec_s8 (cpu, vm, i);
5011 if (shift >= 0)
5012 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
5013 << shift);
5014 else
5015 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
5016 >> - shift);
5017 }
2e8cf49e
NC
5018 return;
5019
5020 case 1:
5021 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 5022 {
7517e550 5023 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
5024 if (shift >= 0)
5025 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
5026 << shift);
5027 else
5028 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
5029 >> - shift);
5030 }
2e8cf49e
NC
5031 return;
5032
5033 case 2:
5034 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 5035 {
7517e550 5036 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
5037 if (shift >= 0)
5038 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
5039 << shift);
5040 else
5041 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
5042 >> - shift);
5043 }
2e8cf49e
NC
5044 return;
5045
5046 case 3:
5047 if (! full)
5048 HALT_UNALLOC;
5049 for (i = 0; i < 2; i++)
5ab6d79e 5050 {
7517e550 5051 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
5052 if (shift >= 0)
5053 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
5054 << shift);
5055 else
5056 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
5057 >> - shift);
5058 }
2e8cf49e 5059 return;
2e8cf49e
NC
5060 }
5061}
5062
5063static void
5064do_vec_FMLA (sim_cpu *cpu)
5065{
5066 /* instr[31] = 0
5067 instr[30] = full/half selector
5068 instr[29,23] = 0011100
5069 instr[22] = size: 0=>float, 1=>double
5070 instr[21] = 1
5071 instr[20,16] = Vn
5072 instr[15,10] = 1100 11
5073 instr[9,5] = Vm
5074 instr[4.0] = Vd. */
5075
ef0d8ffc
NC
5076 unsigned vm = INSTR (20, 16);
5077 unsigned vn = INSTR (9, 5);
5078 unsigned vd = INSTR (4, 0);
2e8cf49e 5079 unsigned i;
ef0d8ffc 5080 int full = INSTR (30, 30);
2e8cf49e
NC
5081
5082 NYI_assert (29, 23, 0x1C);
5083 NYI_assert (21, 21, 1);
5084 NYI_assert (15, 10, 0x33);
5085
2cdad34c 5086 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5087 if (INSTR (22, 22))
2e8cf49e
NC
5088 {
5089 if (! full)
5090 HALT_UNALLOC;
5091 for (i = 0; i < 2; i++)
5092 aarch64_set_vec_double (cpu, vd, i,
5093 aarch64_get_vec_double (cpu, vn, i) *
5094 aarch64_get_vec_double (cpu, vm, i) +
5095 aarch64_get_vec_double (cpu, vd, i));
5096 }
5097 else
5098 {
5099 for (i = 0; i < (full ? 4 : 2); i++)
5100 aarch64_set_vec_float (cpu, vd, i,
5101 aarch64_get_vec_float (cpu, vn, i) *
5102 aarch64_get_vec_float (cpu, vm, i) +
5103 aarch64_get_vec_float (cpu, vd, i));
5104 }
5105}
5106
5107static void
5108do_vec_max (sim_cpu *cpu)
5109{
5110 /* instr[31] = 0
5111 instr[30] = full/half selector
5112 instr[29] = SMAX (0) / UMAX (1)
5113 instr[28,24] = 0 1110
5114 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
5115 instr[21] = 1
5116 instr[20,16] = Vn
5117 instr[15,10] = 0110 01
5118 instr[9,5] = Vm
5119 instr[4.0] = Vd. */
5120
ef0d8ffc
NC
5121 unsigned vm = INSTR (20, 16);
5122 unsigned vn = INSTR (9, 5);
5123 unsigned vd = INSTR (4, 0);
2e8cf49e 5124 unsigned i;
ef0d8ffc 5125 int full = INSTR (30, 30);
2e8cf49e
NC
5126
5127 NYI_assert (28, 24, 0x0E);
5128 NYI_assert (21, 21, 1);
5129 NYI_assert (15, 10, 0x19);
5130
2cdad34c 5131 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5132 if (INSTR (29, 29))
2e8cf49e 5133 {
ef0d8ffc 5134 switch (INSTR (23, 22))
2e8cf49e
NC
5135 {
5136 case 0:
5137 for (i = 0; i < (full ? 16 : 8); i++)
5138 aarch64_set_vec_u8 (cpu, vd, i,
5139 aarch64_get_vec_u8 (cpu, vn, i)
5140 > aarch64_get_vec_u8 (cpu, vm, i)
5141 ? aarch64_get_vec_u8 (cpu, vn, i)
5142 : aarch64_get_vec_u8 (cpu, vm, i));
5143 return;
5144
5145 case 1:
5146 for (i = 0; i < (full ? 8 : 4); i++)
5147 aarch64_set_vec_u16 (cpu, vd, i,
5148 aarch64_get_vec_u16 (cpu, vn, i)
5149 > aarch64_get_vec_u16 (cpu, vm, i)
5150 ? aarch64_get_vec_u16 (cpu, vn, i)
5151 : aarch64_get_vec_u16 (cpu, vm, i));
5152 return;
5153
5154 case 2:
5155 for (i = 0; i < (full ? 4 : 2); i++)
5156 aarch64_set_vec_u32 (cpu, vd, i,
5157 aarch64_get_vec_u32 (cpu, vn, i)
5158 > aarch64_get_vec_u32 (cpu, vm, i)
5159 ? aarch64_get_vec_u32 (cpu, vn, i)
5160 : aarch64_get_vec_u32 (cpu, vm, i));
5161 return;
5162
2e8cf49e
NC
5163 case 3:
5164 HALT_UNALLOC;
5165 }
5166 }
5167 else
5168 {
ef0d8ffc 5169 switch (INSTR (23, 22))
2e8cf49e
NC
5170 {
5171 case 0:
5172 for (i = 0; i < (full ? 16 : 8); i++)
5173 aarch64_set_vec_s8 (cpu, vd, i,
5174 aarch64_get_vec_s8 (cpu, vn, i)
5175 > aarch64_get_vec_s8 (cpu, vm, i)
5176 ? aarch64_get_vec_s8 (cpu, vn, i)
5177 : aarch64_get_vec_s8 (cpu, vm, i));
5178 return;
5179
5180 case 1:
5181 for (i = 0; i < (full ? 8 : 4); i++)
5182 aarch64_set_vec_s16 (cpu, vd, i,
5183 aarch64_get_vec_s16 (cpu, vn, i)
5184 > aarch64_get_vec_s16 (cpu, vm, i)
5185 ? aarch64_get_vec_s16 (cpu, vn, i)
5186 : aarch64_get_vec_s16 (cpu, vm, i));
5187 return;
5188
5189 case 2:
5190 for (i = 0; i < (full ? 4 : 2); i++)
5191 aarch64_set_vec_s32 (cpu, vd, i,
5192 aarch64_get_vec_s32 (cpu, vn, i)
5193 > aarch64_get_vec_s32 (cpu, vm, i)
5194 ? aarch64_get_vec_s32 (cpu, vn, i)
5195 : aarch64_get_vec_s32 (cpu, vm, i));
5196 return;
5197
2e8cf49e
NC
5198 case 3:
5199 HALT_UNALLOC;
5200 }
5201 }
5202}
5203
5204static void
5205do_vec_min (sim_cpu *cpu)
5206{
5207 /* instr[31] = 0
5208 instr[30] = full/half selector
5209 instr[29] = SMIN (0) / UMIN (1)
5210 instr[28,24] = 0 1110
5211 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
5212 instr[21] = 1
5213 instr[20,16] = Vn
5214 instr[15,10] = 0110 11
5215 instr[9,5] = Vm
5216 instr[4.0] = Vd. */
5217
ef0d8ffc
NC
5218 unsigned vm = INSTR (20, 16);
5219 unsigned vn = INSTR (9, 5);
5220 unsigned vd = INSTR (4, 0);
2e8cf49e 5221 unsigned i;
ef0d8ffc 5222 int full = INSTR (30, 30);
2e8cf49e
NC
5223
5224 NYI_assert (28, 24, 0x0E);
5225 NYI_assert (21, 21, 1);
5226 NYI_assert (15, 10, 0x1B);
5227
2cdad34c 5228 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5229 if (INSTR (29, 29))
2e8cf49e 5230 {
ef0d8ffc 5231 switch (INSTR (23, 22))
2e8cf49e
NC
5232 {
5233 case 0:
5234 for (i = 0; i < (full ? 16 : 8); i++)
5235 aarch64_set_vec_u8 (cpu, vd, i,
5236 aarch64_get_vec_u8 (cpu, vn, i)
5237 < aarch64_get_vec_u8 (cpu, vm, i)
5238 ? aarch64_get_vec_u8 (cpu, vn, i)
5239 : aarch64_get_vec_u8 (cpu, vm, i));
5240 return;
5241
5242 case 1:
5243 for (i = 0; i < (full ? 8 : 4); i++)
5244 aarch64_set_vec_u16 (cpu, vd, i,
5245 aarch64_get_vec_u16 (cpu, vn, i)
5246 < aarch64_get_vec_u16 (cpu, vm, i)
5247 ? aarch64_get_vec_u16 (cpu, vn, i)
5248 : aarch64_get_vec_u16 (cpu, vm, i));
5249 return;
5250
5251 case 2:
5252 for (i = 0; i < (full ? 4 : 2); i++)
5253 aarch64_set_vec_u32 (cpu, vd, i,
5254 aarch64_get_vec_u32 (cpu, vn, i)
5255 < aarch64_get_vec_u32 (cpu, vm, i)
5256 ? aarch64_get_vec_u32 (cpu, vn, i)
5257 : aarch64_get_vec_u32 (cpu, vm, i));
5258 return;
5259
2e8cf49e
NC
5260 case 3:
5261 HALT_UNALLOC;
5262 }
5263 }
5264 else
5265 {
ef0d8ffc 5266 switch (INSTR (23, 22))
2e8cf49e
NC
5267 {
5268 case 0:
5269 for (i = 0; i < (full ? 16 : 8); i++)
5270 aarch64_set_vec_s8 (cpu, vd, i,
5271 aarch64_get_vec_s8 (cpu, vn, i)
5272 < aarch64_get_vec_s8 (cpu, vm, i)
5273 ? aarch64_get_vec_s8 (cpu, vn, i)
5274 : aarch64_get_vec_s8 (cpu, vm, i));
5275 return;
5276
5277 case 1:
5278 for (i = 0; i < (full ? 8 : 4); i++)
5279 aarch64_set_vec_s16 (cpu, vd, i,
5280 aarch64_get_vec_s16 (cpu, vn, i)
5281 < aarch64_get_vec_s16 (cpu, vm, i)
5282 ? aarch64_get_vec_s16 (cpu, vn, i)
5283 : aarch64_get_vec_s16 (cpu, vm, i));
5284 return;
5285
5286 case 2:
5287 for (i = 0; i < (full ? 4 : 2); i++)
5288 aarch64_set_vec_s32 (cpu, vd, i,
5289 aarch64_get_vec_s32 (cpu, vn, i)
5290 < aarch64_get_vec_s32 (cpu, vm, i)
5291 ? aarch64_get_vec_s32 (cpu, vn, i)
5292 : aarch64_get_vec_s32 (cpu, vm, i));
5293 return;
5294
2e8cf49e
NC
5295 case 3:
5296 HALT_UNALLOC;
5297 }
5298 }
5299}
5300
5301static void
5302do_vec_sub_long (sim_cpu *cpu)
5303{
5304 /* instr[31] = 0
5305 instr[30] = lower (0) / upper (1)
5306 instr[29] = signed (0) / unsigned (1)
5307 instr[28,24] = 0 1110
5308 instr[23,22] = size: bytes (00), half (01), word (10)
5309 instr[21] = 1
5310 insrt[20,16] = Vm
5311 instr[15,10] = 0010 00
5312 instr[9,5] = Vn
5313 instr[4,0] = V dest. */
5314
ef0d8ffc
NC
5315 unsigned size = INSTR (23, 22);
5316 unsigned vm = INSTR (20, 16);
5317 unsigned vn = INSTR (9, 5);
5318 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5319 unsigned bias = 0;
5320 unsigned i;
5321
5322 NYI_assert (28, 24, 0x0E);
5323 NYI_assert (21, 21, 1);
5324 NYI_assert (15, 10, 0x08);
5325
5326 if (size == 3)
5327 HALT_UNALLOC;
5328
2cdad34c 5329 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5330 switch (INSTR (30, 29))
2e8cf49e
NC
5331 {
5332 case 2: /* SSUBL2. */
5333 bias = 2;
5334 case 0: /* SSUBL. */
5335 switch (size)
5336 {
5337 case 0:
5338 bias *= 3;
5339 for (i = 0; i < 8; i++)
5340 aarch64_set_vec_s16 (cpu, vd, i,
5341 aarch64_get_vec_s8 (cpu, vn, i + bias)
5342 - aarch64_get_vec_s8 (cpu, vm, i + bias));
5343 break;
5344
5345 case 1:
5346 bias *= 2;
5347 for (i = 0; i < 4; i++)
5348 aarch64_set_vec_s32 (cpu, vd, i,
5349 aarch64_get_vec_s16 (cpu, vn, i + bias)
5350 - aarch64_get_vec_s16 (cpu, vm, i + bias));
5351 break;
5352
5353 case 2:
5354 for (i = 0; i < 2; i++)
5355 aarch64_set_vec_s64 (cpu, vd, i,
5356 aarch64_get_vec_s32 (cpu, vn, i + bias)
5357 - aarch64_get_vec_s32 (cpu, vm, i + bias));
5358 break;
5359
5360 default:
5361 HALT_UNALLOC;
5362 }
5363 break;
5364
5365 case 3: /* USUBL2. */
5366 bias = 2;
5367 case 1: /* USUBL. */
5368 switch (size)
5369 {
5370 case 0:
5371 bias *= 3;
5372 for (i = 0; i < 8; i++)
5373 aarch64_set_vec_u16 (cpu, vd, i,
5374 aarch64_get_vec_u8 (cpu, vn, i + bias)
5375 - aarch64_get_vec_u8 (cpu, vm, i + bias));
5376 break;
5377
5378 case 1:
5379 bias *= 2;
5380 for (i = 0; i < 4; i++)
5381 aarch64_set_vec_u32 (cpu, vd, i,
5382 aarch64_get_vec_u16 (cpu, vn, i + bias)
5383 - aarch64_get_vec_u16 (cpu, vm, i + bias));
5384 break;
5385
5386 case 2:
5387 for (i = 0; i < 2; i++)
5388 aarch64_set_vec_u64 (cpu, vd, i,
5389 aarch64_get_vec_u32 (cpu, vn, i + bias)
5390 - aarch64_get_vec_u32 (cpu, vm, i + bias));
5391 break;
5392
5393 default:
5394 HALT_UNALLOC;
5395 }
5396 break;
5397 }
5398}
5399
2e8cf49e
NC
5400static void
5401do_vec_ADDP (sim_cpu *cpu)
5402{
5403 /* instr[31] = 0
5404 instr[30] = half(0)/full(1)
5405 instr[29,24] = 00 1110
5406 instr[23,22] = size: bytes (00), half (01), word (10), long (11)
5407 instr[21] = 1
5408 insrt[20,16] = Vm
5409 instr[15,10] = 1011 11
5410 instr[9,5] = Vn
5411 instr[4,0] = V dest. */
5412
57aa1742
NC
5413 FRegister copy_vn;
5414 FRegister copy_vm;
ef0d8ffc
NC
5415 unsigned full = INSTR (30, 30);
5416 unsigned size = INSTR (23, 22);
5417 unsigned vm = INSTR (20, 16);
5418 unsigned vn = INSTR (9, 5);
5419 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5420 unsigned i, range;
5421
5422 NYI_assert (29, 24, 0x0E);
5423 NYI_assert (21, 21, 1);
5424 NYI_assert (15, 10, 0x2F);
5425
57aa1742
NC
5426 /* Make copies of the source registers in case vd == vn/vm. */
5427 copy_vn = cpu->fr[vn];
5428 copy_vm = cpu->fr[vm];
5429
2cdad34c 5430 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
5431 switch (size)
5432 {
5433 case 0:
5434 range = full ? 8 : 4;
57aa1742
NC
5435 for (i = 0; i < range; i++)
5436 {
5437 aarch64_set_vec_u8 (cpu, vd, i,
5438 copy_vn.b[i * 2] + copy_vn.b[i * 2 + 1]);
5439 aarch64_set_vec_u8 (cpu, vd, i + range,
5440 copy_vm.b[i * 2] + copy_vm.b[i * 2 + 1]);
5441 }
2e8cf49e
NC
5442 return;
5443
5444 case 1:
5445 range = full ? 4 : 2;
57aa1742
NC
5446 for (i = 0; i < range; i++)
5447 {
5448 aarch64_set_vec_u16 (cpu, vd, i,
5449 copy_vn.h[i * 2] + copy_vn.h[i * 2 + 1]);
5450 aarch64_set_vec_u16 (cpu, vd, i + range,
5451 copy_vm.h[i * 2] + copy_vm.h[i * 2 + 1]);
5452 }
2e8cf49e
NC
5453 return;
5454
5455 case 2:
5456 range = full ? 2 : 1;
57aa1742
NC
5457 for (i = 0; i < range; i++)
5458 {
5459 aarch64_set_vec_u32 (cpu, vd, i,
5460 copy_vn.w[i * 2] + copy_vn.w[i * 2 + 1]);
5461 aarch64_set_vec_u32 (cpu, vd, i + range,
5462 copy_vm.w[i * 2] + copy_vm.w[i * 2 + 1]);
5463 }
2e8cf49e
NC
5464 return;
5465
5466 case 3:
5467 if (! full)
5468 HALT_UNALLOC;
57aa1742
NC
5469 aarch64_set_vec_u64 (cpu, vd, 0, copy_vn.v[0] + copy_vn.v[1]);
5470 aarch64_set_vec_u64 (cpu, vd, 1, copy_vm.v[0] + copy_vm.v[1]);
2e8cf49e 5471 return;
2e8cf49e
NC
5472 }
5473}
5474
b630840c
JW
5475/* Float point vector convert to longer (precision). */
5476static void
5477do_vec_FCVTL (sim_cpu *cpu)
5478{
5479 /* instr[31] = 0
5480 instr[30] = half (0) / all (1)
5481 instr[29,23] = 00 1110 0
5482 instr[22] = single (0) / double (1)
5483 instr[21,10] = 10 0001 0111 10
5484 instr[9,5] = Rn
5485 instr[4,0] = Rd. */
5486
5487 unsigned rn = INSTR (9, 5);
5488 unsigned rd = INSTR (4, 0);
5489 unsigned full = INSTR (30, 30);
5490 unsigned i;
5491
5492 NYI_assert (31, 31, 0);
5493 NYI_assert (29, 23, 0x1C);
5494 NYI_assert (21, 10, 0x85E);
5495
5496 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5497 if (INSTR (22, 22))
5498 {
5499 for (i = 0; i < 2; i++)
5500 aarch64_set_vec_double (cpu, rd, i,
5501 aarch64_get_vec_float (cpu, rn, i + 2*full));
5502 }
5503 else
5504 {
5505 HALT_NYI;
5506
5507#if 0
5508 /* TODO: Implement missing half-float support. */
5509 for (i = 0; i < 4; i++)
5510 aarch64_set_vec_float (cpu, rd, i,
5511 aarch64_get_vec_halffloat (cpu, rn, i + 4*full));
5512#endif
5513 }
5514}
5515
2e8cf49e
NC
5516static void
5517do_vec_FABS (sim_cpu *cpu)
5518{
5519 /* instr[31] = 0
5520 instr[30] = half(0)/full(1)
5521 instr[29,23] = 00 1110 1
5522 instr[22] = float(0)/double(1)
5523 instr[21,16] = 10 0000
5524 instr[15,10] = 1111 10
5525 instr[9,5] = Vn
5526 instr[4,0] = Vd. */
5527
ef0d8ffc
NC
5528 unsigned vn = INSTR (9, 5);
5529 unsigned vd = INSTR (4, 0);
5530 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5531 unsigned i;
5532
5533 NYI_assert (29, 23, 0x1D);
5534 NYI_assert (21, 10, 0x83E);
5535
2cdad34c 5536 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5537 if (INSTR (22, 22))
2e8cf49e
NC
5538 {
5539 if (! full)
5540 HALT_NYI;
5541
5542 for (i = 0; i < 2; i++)
5543 aarch64_set_vec_double (cpu, vd, i,
5544 fabs (aarch64_get_vec_double (cpu, vn, i)));
5545 }
5546 else
5547 {
5548 for (i = 0; i < (full ? 4 : 2); i++)
5549 aarch64_set_vec_float (cpu, vd, i,
5550 fabsf (aarch64_get_vec_float (cpu, vn, i)));
5551 }
5552}
5553
5554static void
5555do_vec_FCVTZS (sim_cpu *cpu)
5556{
5557 /* instr[31] = 0
5558 instr[30] = half (0) / all (1)
5559 instr[29,23] = 00 1110 1
5560 instr[22] = single (0) / double (1)
5561 instr[21,10] = 10 0001 1011 10
5562 instr[9,5] = Rn
5563 instr[4,0] = Rd. */
5564
ef0d8ffc
NC
5565 unsigned rn = INSTR (9, 5);
5566 unsigned rd = INSTR (4, 0);
5567 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5568 unsigned i;
5569
5570 NYI_assert (31, 31, 0);
5571 NYI_assert (29, 23, 0x1D);
5572 NYI_assert (21, 10, 0x86E);
5573
2cdad34c 5574 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5575 if (INSTR (22, 22))
2e8cf49e
NC
5576 {
5577 if (! full)
5578 HALT_UNALLOC;
5579
5580 for (i = 0; i < 2; i++)
5581 aarch64_set_vec_s64 (cpu, rd, i,
5582 (int64_t) aarch64_get_vec_double (cpu, rn, i));
5583 }
5584 else
5585 for (i = 0; i < (full ? 4 : 2); i++)
5586 aarch64_set_vec_s32 (cpu, rd, i,
5587 (int32_t) aarch64_get_vec_float (cpu, rn, i));
5588}
5589
67f101ee
NC
5590static void
5591do_vec_REV64 (sim_cpu *cpu)
5592{
5593 /* instr[31] = 0
5594 instr[30] = full/half
5595 instr[29,24] = 00 1110
5596 instr[23,22] = size
5597 instr[21,10] = 10 0000 0000 10
5598 instr[9,5] = Rn
5599 instr[4,0] = Rd. */
5600
5601 unsigned rn = INSTR (9, 5);
5602 unsigned rd = INSTR (4, 0);
5603 unsigned size = INSTR (23, 22);
5604 unsigned full = INSTR (30, 30);
5605 unsigned i;
5606 FRegister val;
5607
5608 NYI_assert (29, 24, 0x0E);
5609 NYI_assert (21, 10, 0x802);
5610
2cdad34c 5611 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
5612 switch (size)
5613 {
5614 case 0:
5615 for (i = 0; i < (full ? 16 : 8); i++)
5616 val.b[i ^ 0x7] = aarch64_get_vec_u8 (cpu, rn, i);
5617 break;
5618
5619 case 1:
5620 for (i = 0; i < (full ? 8 : 4); i++)
5621 val.h[i ^ 0x3] = aarch64_get_vec_u16 (cpu, rn, i);
5622 break;
5623
5624 case 2:
5625 for (i = 0; i < (full ? 4 : 2); i++)
5626 val.w[i ^ 0x1] = aarch64_get_vec_u32 (cpu, rn, i);
5627 break;
5628
5629 case 3:
5630 HALT_UNALLOC;
5631 }
5632
5633 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5634 if (full)
5635 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5636}
5637
5638static void
5639do_vec_REV16 (sim_cpu *cpu)
5640{
5641 /* instr[31] = 0
5642 instr[30] = full/half
5643 instr[29,24] = 00 1110
5644 instr[23,22] = size
5645 instr[21,10] = 10 0000 0001 10
5646 instr[9,5] = Rn
5647 instr[4,0] = Rd. */
5648
5649 unsigned rn = INSTR (9, 5);
5650 unsigned rd = INSTR (4, 0);
5651 unsigned size = INSTR (23, 22);
5652 unsigned full = INSTR (30, 30);
5653 unsigned i;
5654 FRegister val;
5655
5656 NYI_assert (29, 24, 0x0E);
5657 NYI_assert (21, 10, 0x806);
5658
2cdad34c 5659 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
5660 switch (size)
5661 {
5662 case 0:
5663 for (i = 0; i < (full ? 16 : 8); i++)
5664 val.b[i ^ 0x1] = aarch64_get_vec_u8 (cpu, rn, i);
5665 break;
5666
5667 default:
5668 HALT_UNALLOC;
5669 }
5670
5671 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5672 if (full)
5673 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5674}
5675
2e8cf49e
NC
5676static void
5677do_vec_op1 (sim_cpu *cpu)
5678{
5679 /* instr[31] = 0
5680 instr[30] = half/full
5681 instr[29,24] = 00 1110
5682 instr[23,21] = ???
5683 instr[20,16] = Vm
5684 instr[15,10] = sub-opcode
5685 instr[9,5] = Vn
5686 instr[4,0] = Vd */
5687 NYI_assert (29, 24, 0x0E);
5688
ef0d8ffc 5689 if (INSTR (21, 21) == 0)
2e8cf49e 5690 {
ef0d8ffc 5691 if (INSTR (23, 22) == 0)
2e8cf49e 5692 {
ef0d8ffc
NC
5693 if (INSTR (30, 30) == 1
5694 && INSTR (17, 14) == 0
5695 && INSTR (12, 10) == 7)
2e8cf49e
NC
5696 return do_vec_ins_2 (cpu);
5697
ef0d8ffc 5698 switch (INSTR (15, 10))
2e8cf49e
NC
5699 {
5700 case 0x01: do_vec_DUP_vector_into_vector (cpu); return;
5701 case 0x03: do_vec_DUP_scalar_into_vector (cpu); return;
5702 case 0x07: do_vec_INS (cpu); return;
152e1e1b
JW
5703 case 0x0B: do_vec_SMOV_into_scalar (cpu); return;
5704 case 0x0F: do_vec_UMOV_into_scalar (cpu); return;
2e8cf49e
NC
5705
5706 case 0x00:
5707 case 0x08:
5708 case 0x10:
5709 case 0x18:
5710 do_vec_TBL (cpu); return;
5711
5712 case 0x06:
5713 case 0x16:
5714 do_vec_UZP (cpu); return;
5715
152e1e1b
JW
5716 case 0x0A: do_vec_TRN (cpu); return;
5717
2e8cf49e
NC
5718 case 0x0E:
5719 case 0x1E:
5720 do_vec_ZIP (cpu); return;
5721
5722 default:
5723 HALT_NYI;
5724 }
5725 }
5726
ef0d8ffc 5727 switch (INSTR (13, 10))
2e8cf49e
NC
5728 {
5729 case 0x6: do_vec_UZP (cpu); return;
5730 case 0xE: do_vec_ZIP (cpu); return;
5731 case 0xA: do_vec_TRN (cpu); return;
2e8cf49e
NC
5732 default: HALT_NYI;
5733 }
5734 }
5735
ef0d8ffc 5736 switch (INSTR (15, 10))
2e8cf49e 5737 {
67f101ee
NC
5738 case 0x02: do_vec_REV64 (cpu); return;
5739 case 0x06: do_vec_REV16 (cpu); return;
5740
2e8cf49e 5741 case 0x07:
ef0d8ffc 5742 switch (INSTR (23, 21))
2e8cf49e
NC
5743 {
5744 case 1: do_vec_AND (cpu); return;
5745 case 3: do_vec_BIC (cpu); return;
5746 case 5: do_vec_ORR (cpu); return;
5747 case 7: do_vec_ORN (cpu); return;
5748 default: HALT_NYI;
5749 }
5750
5751 case 0x08: do_vec_sub_long (cpu); return;
5752 case 0x0a: do_vec_XTN (cpu); return;
5753 case 0x11: do_vec_SSHL (cpu); return;
ac189e7b 5754 case 0x16: do_vec_CNT (cpu); return;
2e8cf49e
NC
5755 case 0x19: do_vec_max (cpu); return;
5756 case 0x1B: do_vec_min (cpu); return;
5757 case 0x21: do_vec_add (cpu); return;
5758 case 0x25: do_vec_MLA (cpu); return;
5759 case 0x27: do_vec_mul (cpu); return;
5760 case 0x2F: do_vec_ADDP (cpu); return;
5761 case 0x30: do_vec_mull (cpu); return;
5762 case 0x33: do_vec_FMLA (cpu); return;
5763 case 0x35: do_vec_fadd (cpu); return;
5764
b630840c
JW
5765 case 0x1E:
5766 switch (INSTR (20, 16))
5767 {
5768 case 0x01: do_vec_FCVTL (cpu); return;
5769 default: HALT_NYI;
5770 }
5771
2e8cf49e 5772 case 0x2E:
ef0d8ffc 5773 switch (INSTR (20, 16))
2e8cf49e
NC
5774 {
5775 case 0x00: do_vec_ABS (cpu); return;
5776 case 0x01: do_vec_FCVTZS (cpu); return;
5777 case 0x11: do_vec_ADDV (cpu); return;
5778 default: HALT_NYI;
5779 }
5780
5781 case 0x31:
5782 case 0x3B:
5783 do_vec_Fminmax (cpu); return;
5784
5785 case 0x0D:
5786 case 0x0F:
5787 case 0x22:
5788 case 0x23:
5789 case 0x26:
5790 case 0x2A:
5791 case 0x32:
5792 case 0x36:
5793 case 0x39:
5794 case 0x3A:
5795 do_vec_compare (cpu); return;
5796
5797 case 0x3E:
5798 do_vec_FABS (cpu); return;
5799
5800 default:
5801 HALT_NYI;
5802 }
5803}
5804
5805static void
5806do_vec_xtl (sim_cpu *cpu)
5807{
5808 /* instr[31] = 0
5809 instr[30,29] = SXTL (00), UXTL (01), SXTL2 (10), UXTL2 (11)
5810 instr[28,22] = 0 1111 00
5811 instr[21,16] = size & shift (USHLL, SSHLL, USHLL2, SSHLL2)
5812 instr[15,10] = 1010 01
5813 instr[9,5] = V source
5814 instr[4,0] = V dest. */
5815
ef0d8ffc
NC
5816 unsigned vs = INSTR (9, 5);
5817 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5818 unsigned i, shift, bias = 0;
5819
5820 NYI_assert (28, 22, 0x3C);
5821 NYI_assert (15, 10, 0x29);
5822
2cdad34c 5823 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5824 switch (INSTR (30, 29))
2e8cf49e
NC
5825 {
5826 case 2: /* SXTL2, SSHLL2. */
5827 bias = 2;
5828 case 0: /* SXTL, SSHLL. */
ef0d8ffc 5829 if (INSTR (21, 21))
2e8cf49e 5830 {
7517e550
NC
5831 int64_t val1, val2;
5832
ef0d8ffc 5833 shift = INSTR (20, 16);
7517e550
NC
5834 /* Get the source values before setting the destination values
5835 in case the source and destination are the same. */
5836 val1 = aarch64_get_vec_s32 (cpu, vs, bias) << shift;
5837 val2 = aarch64_get_vec_s32 (cpu, vs, bias + 1) << shift;
5838 aarch64_set_vec_s64 (cpu, vd, 0, val1);
5839 aarch64_set_vec_s64 (cpu, vd, 1, val2);
2e8cf49e 5840 }
ef0d8ffc 5841 else if (INSTR (20, 20))
2e8cf49e 5842 {
7517e550
NC
5843 int32_t v[4];
5844 int32_t v1,v2,v3,v4;
5845
ef0d8ffc 5846 shift = INSTR (19, 16);
2e8cf49e
NC
5847 bias *= 2;
5848 for (i = 0; i < 4; i++)
7517e550
NC
5849 v[i] = aarch64_get_vec_s16 (cpu, vs, bias + i) << shift;
5850 for (i = 0; i < 4; i++)
5851 aarch64_set_vec_s32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5852 }
5853 else
5854 {
7517e550 5855 int16_t v[8];
2e8cf49e
NC
5856 NYI_assert (19, 19, 1);
5857
ef0d8ffc 5858 shift = INSTR (18, 16);
2e7e5e28 5859 bias *= 4;
2e8cf49e 5860 for (i = 0; i < 8; i++)
7517e550
NC
5861 v[i] = aarch64_get_vec_s8 (cpu, vs, i + bias) << shift;
5862 for (i = 0; i < 8; i++)
5863 aarch64_set_vec_s16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5864 }
5865 return;
5866
5867 case 3: /* UXTL2, USHLL2. */
5868 bias = 2;
5869 case 1: /* UXTL, USHLL. */
ef0d8ffc 5870 if (INSTR (21, 21))
2e8cf49e 5871 {
7517e550 5872 uint64_t v1, v2;
ef0d8ffc 5873 shift = INSTR (20, 16);
7517e550
NC
5874 v1 = aarch64_get_vec_u32 (cpu, vs, bias) << shift;
5875 v2 = aarch64_get_vec_u32 (cpu, vs, bias + 1) << shift;
5876 aarch64_set_vec_u64 (cpu, vd, 0, v1);
5877 aarch64_set_vec_u64 (cpu, vd, 1, v2);
2e8cf49e 5878 }
ef0d8ffc 5879 else if (INSTR (20, 20))
2e8cf49e 5880 {
7517e550 5881 uint32_t v[4];
ef0d8ffc 5882 shift = INSTR (19, 16);
2e8cf49e
NC
5883 bias *= 2;
5884 for (i = 0; i < 4; i++)
7517e550
NC
5885 v[i] = aarch64_get_vec_u16 (cpu, vs, i + bias) << shift;
5886 for (i = 0; i < 4; i++)
5887 aarch64_set_vec_u32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5888 }
5889 else
5890 {
7517e550 5891 uint16_t v[8];
2e8cf49e
NC
5892 NYI_assert (19, 19, 1);
5893
ef0d8ffc 5894 shift = INSTR (18, 16);
2e7e5e28 5895 bias *= 4;
2e8cf49e 5896 for (i = 0; i < 8; i++)
7517e550
NC
5897 v[i] = aarch64_get_vec_u8 (cpu, vs, i + bias) << shift;
5898 for (i = 0; i < 8; i++)
5899 aarch64_set_vec_u16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5900 }
5901 return;
2e8cf49e
NC
5902 }
5903}
5904
5905static void
5906do_vec_SHL (sim_cpu *cpu)
5907{
5908 /* instr [31] = 0
5909 instr [30] = half(0)/full(1)
5910 instr [29,23] = 001 1110
5911 instr [22,16] = size and shift amount
5912 instr [15,10] = 01 0101
5913 instr [9, 5] = Vs
5914 instr [4, 0] = Vd. */
5915
5916 int shift;
ef0d8ffc
NC
5917 int full = INSTR (30, 30);
5918 unsigned vs = INSTR (9, 5);
5919 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5920 unsigned i;
5921
5922 NYI_assert (29, 23, 0x1E);
5923 NYI_assert (15, 10, 0x15);
5924
2cdad34c 5925 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 5926 if (INSTR (22, 22))
2e8cf49e 5927 {
ef0d8ffc 5928 shift = INSTR (21, 16);
2e8cf49e
NC
5929
5930 if (full == 0)
5931 HALT_UNALLOC;
5932
5933 for (i = 0; i < 2; i++)
5934 {
5935 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5936 aarch64_set_vec_u64 (cpu, vd, i, val << shift);
5937 }
5938
5939 return;
5940 }
5941
ef0d8ffc 5942 if (INSTR (21, 21))
2e8cf49e 5943 {
ef0d8ffc 5944 shift = INSTR (20, 16);
2e8cf49e
NC
5945
5946 for (i = 0; i < (full ? 4 : 2); i++)
5947 {
5948 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5949 aarch64_set_vec_u32 (cpu, vd, i, val << shift);
5950 }
5951
5952 return;
5953 }
5954
ef0d8ffc 5955 if (INSTR (20, 20))
2e8cf49e 5956 {
ef0d8ffc 5957 shift = INSTR (19, 16);
2e8cf49e
NC
5958
5959 for (i = 0; i < (full ? 8 : 4); i++)
5960 {
5961 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5962 aarch64_set_vec_u16 (cpu, vd, i, val << shift);
5963 }
5964
5965 return;
5966 }
5967
ef0d8ffc 5968 if (INSTR (19, 19) == 0)
2e8cf49e
NC
5969 HALT_UNALLOC;
5970
ef0d8ffc 5971 shift = INSTR (18, 16);
2e8cf49e
NC
5972
5973 for (i = 0; i < (full ? 16 : 8); i++)
5974 {
5975 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5976 aarch64_set_vec_u8 (cpu, vd, i, val << shift);
5977 }
5978}
5979
5980static void
5981do_vec_SSHR_USHR (sim_cpu *cpu)
5982{
5983 /* instr [31] = 0
5984 instr [30] = half(0)/full(1)
5985 instr [29] = signed(0)/unsigned(1)
5ab6d79e 5986 instr [28,23] = 0 1111 0
2e8cf49e
NC
5987 instr [22,16] = size and shift amount
5988 instr [15,10] = 0000 01
5989 instr [9, 5] = Vs
5990 instr [4, 0] = Vd. */
5991
5ab6d79e
NC
5992 int full = INSTR (30, 30);
5993 int sign = ! INSTR (29, 29);
5994 unsigned shift = INSTR (22, 16);
5995 unsigned vs = INSTR (9, 5);
5996 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5997 unsigned i;
5998
5999 NYI_assert (28, 23, 0x1E);
6000 NYI_assert (15, 10, 0x01);
6001
2cdad34c 6002 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6003 if (INSTR (22, 22))
2e8cf49e 6004 {
5ab6d79e 6005 shift = 128 - shift;
2e8cf49e
NC
6006
6007 if (full == 0)
6008 HALT_UNALLOC;
6009
6010 if (sign)
6011 for (i = 0; i < 2; i++)
6012 {
6013 int64_t val = aarch64_get_vec_s64 (cpu, vs, i);
6014 aarch64_set_vec_s64 (cpu, vd, i, val >> shift);
6015 }
6016 else
6017 for (i = 0; i < 2; i++)
6018 {
6019 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
6020 aarch64_set_vec_u64 (cpu, vd, i, val >> shift);
6021 }
6022
6023 return;
6024 }
6025
ef0d8ffc 6026 if (INSTR (21, 21))
2e8cf49e 6027 {
5ab6d79e 6028 shift = 64 - shift;
2e8cf49e
NC
6029
6030 if (sign)
6031 for (i = 0; i < (full ? 4 : 2); i++)
6032 {
6033 int32_t val = aarch64_get_vec_s32 (cpu, vs, i);
6034 aarch64_set_vec_s32 (cpu, vd, i, val >> shift);
6035 }
6036 else
6037 for (i = 0; i < (full ? 4 : 2); i++)
6038 {
6039 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
6040 aarch64_set_vec_u32 (cpu, vd, i, val >> shift);
6041 }
6042
6043 return;
6044 }
6045
ef0d8ffc 6046 if (INSTR (20, 20))
2e8cf49e 6047 {
5ab6d79e 6048 shift = 32 - shift;
2e8cf49e
NC
6049
6050 if (sign)
6051 for (i = 0; i < (full ? 8 : 4); i++)
6052 {
6053 int16_t val = aarch64_get_vec_s16 (cpu, vs, i);
6054 aarch64_set_vec_s16 (cpu, vd, i, val >> shift);
6055 }
6056 else
6057 for (i = 0; i < (full ? 8 : 4); i++)
6058 {
6059 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
6060 aarch64_set_vec_u16 (cpu, vd, i, val >> shift);
6061 }
6062
6063 return;
6064 }
6065
ef0d8ffc 6066 if (INSTR (19, 19) == 0)
2e8cf49e
NC
6067 HALT_UNALLOC;
6068
5ab6d79e 6069 shift = 16 - shift;
2e8cf49e
NC
6070
6071 if (sign)
6072 for (i = 0; i < (full ? 16 : 8); i++)
6073 {
6074 int8_t val = aarch64_get_vec_s8 (cpu, vs, i);
6075 aarch64_set_vec_s8 (cpu, vd, i, val >> shift);
6076 }
6077 else
6078 for (i = 0; i < (full ? 16 : 8); i++)
6079 {
6080 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
6081 aarch64_set_vec_u8 (cpu, vd, i, val >> shift);
6082 }
6083}
6084
e101a78b
NC
6085static void
6086do_vec_MUL_by_element (sim_cpu *cpu)
6087{
6088 /* instr[31] = 0
6089 instr[30] = half/full
6090 instr[29,24] = 00 1111
6091 instr[23,22] = size
6092 instr[21] = L
6093 instr[20] = M
6094 instr[19,16] = m
6095 instr[15,12] = 1000
6096 instr[11] = H
6097 instr[10] = 0
6098 instr[9,5] = Vn
6099 instr[4,0] = Vd */
6100
ef0d8ffc
NC
6101 unsigned full = INSTR (30, 30);
6102 unsigned L = INSTR (21, 21);
6103 unsigned H = INSTR (11, 11);
6104 unsigned vn = INSTR (9, 5);
6105 unsigned vd = INSTR (4, 0);
6106 unsigned size = INSTR (23, 22);
e101a78b
NC
6107 unsigned index;
6108 unsigned vm;
6109 unsigned e;
6110
6111 NYI_assert (29, 24, 0x0F);
6112 NYI_assert (15, 12, 0x8);
6113 NYI_assert (10, 10, 0);
6114
2cdad34c 6115 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
6116 switch (size)
6117 {
6118 case 1:
6119 {
6120 /* 16 bit products. */
6121 uint16_t product;
6122 uint16_t element1;
6123 uint16_t element2;
6124
ef0d8ffc
NC
6125 index = (H << 2) | (L << 1) | INSTR (20, 20);
6126 vm = INSTR (19, 16);
e101a78b
NC
6127 element2 = aarch64_get_vec_u16 (cpu, vm, index);
6128
6129 for (e = 0; e < (full ? 8 : 4); e ++)
6130 {
6131 element1 = aarch64_get_vec_u16 (cpu, vn, e);
6132 product = element1 * element2;
6133 aarch64_set_vec_u16 (cpu, vd, e, product);
6134 }
6135 }
6136 break;
6137
6138 case 2:
6139 {
6140 /* 32 bit products. */
6141 uint32_t product;
6142 uint32_t element1;
6143 uint32_t element2;
6144
6145 index = (H << 1) | L;
ef0d8ffc 6146 vm = INSTR (20, 16);
e101a78b
NC
6147 element2 = aarch64_get_vec_u32 (cpu, vm, index);
6148
6149 for (e = 0; e < (full ? 4 : 2); e ++)
6150 {
6151 element1 = aarch64_get_vec_u32 (cpu, vn, e);
6152 product = element1 * element2;
6153 aarch64_set_vec_u32 (cpu, vd, e, product);
6154 }
6155 }
6156 break;
6157
6158 default:
6159 HALT_UNALLOC;
6160 }
6161}
6162
fd7ed446
NC
6163static void
6164do_FMLA_by_element (sim_cpu *cpu)
6165{
6166 /* instr[31] = 0
6167 instr[30] = half/full
6168 instr[29,23] = 00 1111 1
6169 instr[22] = size
6170 instr[21] = L
6171 instr[20,16] = m
6172 instr[15,12] = 0001
6173 instr[11] = H
6174 instr[10] = 0
6175 instr[9,5] = Vn
6176 instr[4,0] = Vd */
6177
6178 unsigned full = INSTR (30, 30);
6179 unsigned size = INSTR (22, 22);
6180 unsigned L = INSTR (21, 21);
6181 unsigned vm = INSTR (20, 16);
6182 unsigned H = INSTR (11, 11);
6183 unsigned vn = INSTR (9, 5);
6184 unsigned vd = INSTR (4, 0);
6185 unsigned e;
6186
6187 NYI_assert (29, 23, 0x1F);
6188 NYI_assert (15, 12, 0x1);
6189 NYI_assert (10, 10, 0);
6190
6191 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
6192 if (size)
6193 {
6194 double element1, element2;
6195
6196 if (! full || L)
6197 HALT_UNALLOC;
6198
6199 element2 = aarch64_get_vec_double (cpu, vm, H);
6200
6201 for (e = 0; e < 2; e++)
6202 {
6203 element1 = aarch64_get_vec_double (cpu, vn, e);
6204 element1 *= element2;
6205 element1 += aarch64_get_vec_double (cpu, vd, e);
6206 aarch64_set_vec_double (cpu, vd, e, element1);
6207 }
6208 }
6209 else
6210 {
6211 float element1;
6212 float element2 = aarch64_get_vec_float (cpu, vm, (H << 1) | L);
6213
6214 for (e = 0; e < (full ? 4 : 2); e++)
6215 {
6216 element1 = aarch64_get_vec_float (cpu, vn, e);
6217 element1 *= element2;
6218 element1 += aarch64_get_vec_float (cpu, vd, e);
6219 aarch64_set_vec_float (cpu, vd, e, element1);
6220 }
6221 }
6222}
6223
2e8cf49e
NC
6224static void
6225do_vec_op2 (sim_cpu *cpu)
6226{
6227 /* instr[31] = 0
6228 instr[30] = half/full
6229 instr[29,24] = 00 1111
6230 instr[23] = ?
6231 instr[22,16] = element size & index
6232 instr[15,10] = sub-opcode
6233 instr[9,5] = Vm
e101a78b 6234 instr[4,0] = Vd */
2e8cf49e
NC
6235
6236 NYI_assert (29, 24, 0x0F);
6237
ef0d8ffc 6238 if (INSTR (23, 23) != 0)
2e8cf49e 6239 {
ef0d8ffc 6240 switch (INSTR (15, 10))
e101a78b 6241 {
fd7ed446
NC
6242 case 0x04:
6243 case 0x06:
6244 do_FMLA_by_element (cpu);
6245 return;
6246
e101a78b 6247 case 0x20:
fd7ed446
NC
6248 case 0x22:
6249 do_vec_MUL_by_element (cpu);
6250 return;
6251
6252 default:
6253 HALT_NYI;
e101a78b
NC
6254 }
6255 }
6256 else
6257 {
ef0d8ffc 6258 switch (INSTR (15, 10))
e101a78b
NC
6259 {
6260 case 0x01: do_vec_SSHR_USHR (cpu); return;
6261 case 0x15: do_vec_SHL (cpu); return;
6262 case 0x20:
6263 case 0x22: do_vec_MUL_by_element (cpu); return;
6264 case 0x29: do_vec_xtl (cpu); return;
6265 default: HALT_NYI;
6266 }
2e8cf49e
NC
6267 }
6268}
6269
6270static void
6271do_vec_neg (sim_cpu *cpu)
6272{
6273 /* instr[31] = 0
6274 instr[30] = full(1)/half(0)
6275 instr[29,24] = 10 1110
6276 instr[23,22] = size: byte(00), half (01), word (10), long (11)
6277 instr[21,10] = 1000 0010 1110
6278 instr[9,5] = Vs
6279 instr[4,0] = Vd */
6280
ef0d8ffc
NC
6281 int full = INSTR (30, 30);
6282 unsigned vs = INSTR (9, 5);
6283 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6284 unsigned i;
6285
6286 NYI_assert (29, 24, 0x2E);
6287 NYI_assert (21, 10, 0x82E);
6288
2cdad34c 6289 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6290 switch (INSTR (23, 22))
2e8cf49e
NC
6291 {
6292 case 0:
6293 for (i = 0; i < (full ? 16 : 8); i++)
6294 aarch64_set_vec_s8 (cpu, vd, i, - aarch64_get_vec_s8 (cpu, vs, i));
6295 return;
6296
6297 case 1:
6298 for (i = 0; i < (full ? 8 : 4); i++)
6299 aarch64_set_vec_s16 (cpu, vd, i, - aarch64_get_vec_s16 (cpu, vs, i));
6300 return;
6301
6302 case 2:
6303 for (i = 0; i < (full ? 4 : 2); i++)
6304 aarch64_set_vec_s32 (cpu, vd, i, - aarch64_get_vec_s32 (cpu, vs, i));
6305 return;
6306
6307 case 3:
6308 if (! full)
6309 HALT_NYI;
6310 for (i = 0; i < 2; i++)
6311 aarch64_set_vec_s64 (cpu, vd, i, - aarch64_get_vec_s64 (cpu, vs, i));
6312 return;
2e8cf49e
NC
6313 }
6314}
6315
6316static void
6317do_vec_sqrt (sim_cpu *cpu)
6318{
6319 /* instr[31] = 0
6320 instr[30] = full(1)/half(0)
6321 instr[29,23] = 101 1101
6322 instr[22] = single(0)/double(1)
6323 instr[21,10] = 1000 0111 1110
6324 instr[9,5] = Vs
6325 instr[4,0] = Vd. */
6326
ef0d8ffc
NC
6327 int full = INSTR (30, 30);
6328 unsigned vs = INSTR (9, 5);
6329 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6330 unsigned i;
6331
6332 NYI_assert (29, 23, 0x5B);
6333 NYI_assert (21, 10, 0x87E);
6334
2cdad34c 6335 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6336 if (INSTR (22, 22) == 0)
2e8cf49e
NC
6337 for (i = 0; i < (full ? 4 : 2); i++)
6338 aarch64_set_vec_float (cpu, vd, i,
6339 sqrtf (aarch64_get_vec_float (cpu, vs, i)));
6340 else
6341 for (i = 0; i < 2; i++)
6342 aarch64_set_vec_double (cpu, vd, i,
6343 sqrt (aarch64_get_vec_double (cpu, vs, i)));
6344}
6345
6346static void
6347do_vec_mls_indexed (sim_cpu *cpu)
6348{
6349 /* instr[31] = 0
6350 instr[30] = half(0)/full(1)
6351 instr[29,24] = 10 1111
6352 instr[23,22] = 16-bit(01)/32-bit(10)
6353 instr[21,20+11] = index (if 16-bit)
6354 instr[21+11] = index (if 32-bit)
6355 instr[20,16] = Vm
6356 instr[15,12] = 0100
6357 instr[11] = part of index
6358 instr[10] = 0
6359 instr[9,5] = Vs
6360 instr[4,0] = Vd. */
6361
ef0d8ffc
NC
6362 int full = INSTR (30, 30);
6363 unsigned vs = INSTR (9, 5);
6364 unsigned vd = INSTR (4, 0);
6365 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
6366 unsigned i;
6367
6368 NYI_assert (15, 12, 4);
6369 NYI_assert (10, 10, 0);
6370
2cdad34c 6371 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6372 switch (INSTR (23, 22))
2e8cf49e
NC
6373 {
6374 case 1:
6375 {
6376 unsigned elem;
6377 uint32_t val;
6378
6379 if (vm > 15)
6380 HALT_NYI;
6381
7517e550 6382 elem = (INSTR (21, 20) << 1) | INSTR (11, 11);
2e8cf49e
NC
6383 val = aarch64_get_vec_u16 (cpu, vm, elem);
6384
6385 for (i = 0; i < (full ? 8 : 4); i++)
6386 aarch64_set_vec_u32 (cpu, vd, i,
6387 aarch64_get_vec_u32 (cpu, vd, i) -
6388 (aarch64_get_vec_u32 (cpu, vs, i) * val));
6389 return;
6390 }
6391
6392 case 2:
6393 {
7517e550 6394 unsigned elem = (INSTR (21, 21) << 1) | INSTR (11, 11);
2e8cf49e
NC
6395 uint64_t val = aarch64_get_vec_u32 (cpu, vm, elem);
6396
6397 for (i = 0; i < (full ? 4 : 2); i++)
6398 aarch64_set_vec_u64 (cpu, vd, i,
6399 aarch64_get_vec_u64 (cpu, vd, i) -
6400 (aarch64_get_vec_u64 (cpu, vs, i) * val));
6401 return;
6402 }
6403
6404 case 0:
6405 case 3:
6406 default:
6407 HALT_NYI;
6408 }
6409}
6410
6411static void
6412do_vec_SUB (sim_cpu *cpu)
6413{
6414 /* instr [31] = 0
6415 instr [30] = half(0)/full(1)
6416 instr [29,24] = 10 1110
6417 instr [23,22] = size: byte(00, half(01), word (10), long (11)
6418 instr [21] = 1
6419 instr [20,16] = Vm
6420 instr [15,10] = 10 0001
6421 instr [9, 5] = Vn
6422 instr [4, 0] = Vd. */
6423
ef0d8ffc
NC
6424 unsigned full = INSTR (30, 30);
6425 unsigned vm = INSTR (20, 16);
6426 unsigned vn = INSTR (9, 5);
6427 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6428 unsigned i;
6429
6430 NYI_assert (29, 24, 0x2E);
6431 NYI_assert (21, 21, 1);
6432 NYI_assert (15, 10, 0x21);
6433
2cdad34c 6434 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6435 switch (INSTR (23, 22))
2e8cf49e
NC
6436 {
6437 case 0:
6438 for (i = 0; i < (full ? 16 : 8); i++)
6439 aarch64_set_vec_s8 (cpu, vd, i,
6440 aarch64_get_vec_s8 (cpu, vn, i)
6441 - aarch64_get_vec_s8 (cpu, vm, i));
6442 return;
6443
6444 case 1:
6445 for (i = 0; i < (full ? 8 : 4); i++)
6446 aarch64_set_vec_s16 (cpu, vd, i,
6447 aarch64_get_vec_s16 (cpu, vn, i)
6448 - aarch64_get_vec_s16 (cpu, vm, i));
6449 return;
6450
6451 case 2:
6452 for (i = 0; i < (full ? 4 : 2); i++)
6453 aarch64_set_vec_s32 (cpu, vd, i,
6454 aarch64_get_vec_s32 (cpu, vn, i)
6455 - aarch64_get_vec_s32 (cpu, vm, i));
6456 return;
6457
6458 case 3:
6459 if (full == 0)
6460 HALT_UNALLOC;
6461
6462 for (i = 0; i < 2; i++)
6463 aarch64_set_vec_s64 (cpu, vd, i,
6464 aarch64_get_vec_s64 (cpu, vn, i)
6465 - aarch64_get_vec_s64 (cpu, vm, i));
6466 return;
2e8cf49e
NC
6467 }
6468}
6469
6470static void
6471do_vec_MLS (sim_cpu *cpu)
6472{
6473 /* instr [31] = 0
6474 instr [30] = half(0)/full(1)
6475 instr [29,24] = 10 1110
6476 instr [23,22] = size: byte(00, half(01), word (10)
6477 instr [21] = 1
6478 instr [20,16] = Vm
6479 instr [15,10] = 10 0101
6480 instr [9, 5] = Vn
6481 instr [4, 0] = Vd. */
6482
ef0d8ffc
NC
6483 unsigned full = INSTR (30, 30);
6484 unsigned vm = INSTR (20, 16);
6485 unsigned vn = INSTR (9, 5);
6486 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6487 unsigned i;
6488
6489 NYI_assert (29, 24, 0x2E);
6490 NYI_assert (21, 21, 1);
6491 NYI_assert (15, 10, 0x25);
6492
2cdad34c 6493 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6494 switch (INSTR (23, 22))
2e8cf49e
NC
6495 {
6496 case 0:
6497 for (i = 0; i < (full ? 16 : 8); i++)
6498 aarch64_set_vec_u8 (cpu, vd, i,
c0386d4d
JW
6499 aarch64_get_vec_u8 (cpu, vd, i)
6500 - (aarch64_get_vec_u8 (cpu, vn, i)
6501 * aarch64_get_vec_u8 (cpu, vm, i)));
2e8cf49e
NC
6502 return;
6503
6504 case 1:
6505 for (i = 0; i < (full ? 8 : 4); i++)
6506 aarch64_set_vec_u16 (cpu, vd, i,
c0386d4d
JW
6507 aarch64_get_vec_u16 (cpu, vd, i)
6508 - (aarch64_get_vec_u16 (cpu, vn, i)
6509 * aarch64_get_vec_u16 (cpu, vm, i)));
2e8cf49e
NC
6510 return;
6511
6512 case 2:
6513 for (i = 0; i < (full ? 4 : 2); i++)
6514 aarch64_set_vec_u32 (cpu, vd, i,
c0386d4d
JW
6515 aarch64_get_vec_u32 (cpu, vd, i)
6516 - (aarch64_get_vec_u32 (cpu, vn, i)
6517 * aarch64_get_vec_u32 (cpu, vm, i)));
2e8cf49e
NC
6518 return;
6519
6520 default:
6521 HALT_UNALLOC;
6522 }
6523}
6524
6525static void
6526do_vec_FDIV (sim_cpu *cpu)
6527{
6528 /* instr [31] = 0
6529 instr [30] = half(0)/full(1)
6530 instr [29,23] = 10 1110 0
6531 instr [22] = float()/double(1)
6532 instr [21] = 1
6533 instr [20,16] = Vm
6534 instr [15,10] = 1111 11
6535 instr [9, 5] = Vn
6536 instr [4, 0] = Vd. */
6537
ef0d8ffc
NC
6538 unsigned full = INSTR (30, 30);
6539 unsigned vm = INSTR (20, 16);
6540 unsigned vn = INSTR (9, 5);
6541 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6542 unsigned i;
6543
6544 NYI_assert (29, 23, 0x5C);
6545 NYI_assert (21, 21, 1);
6546 NYI_assert (15, 10, 0x3F);
6547
2cdad34c 6548 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6549 if (INSTR (22, 22))
2e8cf49e
NC
6550 {
6551 if (! full)
6552 HALT_UNALLOC;
6553
6554 for (i = 0; i < 2; i++)
6555 aarch64_set_vec_double (cpu, vd, i,
6556 aarch64_get_vec_double (cpu, vn, i)
6557 / aarch64_get_vec_double (cpu, vm, i));
6558 }
6559 else
6560 for (i = 0; i < (full ? 4 : 2); i++)
6561 aarch64_set_vec_float (cpu, vd, i,
6562 aarch64_get_vec_float (cpu, vn, i)
6563 / aarch64_get_vec_float (cpu, vm, i));
6564}
6565
6566static void
6567do_vec_FMUL (sim_cpu *cpu)
6568{
6569 /* instr [31] = 0
6570 instr [30] = half(0)/full(1)
6571 instr [29,23] = 10 1110 0
6572 instr [22] = float(0)/double(1)
6573 instr [21] = 1
6574 instr [20,16] = Vm
6575 instr [15,10] = 1101 11
6576 instr [9, 5] = Vn
6577 instr [4, 0] = Vd. */
6578
ef0d8ffc
NC
6579 unsigned full = INSTR (30, 30);
6580 unsigned vm = INSTR (20, 16);
6581 unsigned vn = INSTR (9, 5);
6582 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6583 unsigned i;
6584
6585 NYI_assert (29, 23, 0x5C);
6586 NYI_assert (21, 21, 1);
6587 NYI_assert (15, 10, 0x37);
6588
2cdad34c 6589 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6590 if (INSTR (22, 22))
2e8cf49e
NC
6591 {
6592 if (! full)
6593 HALT_UNALLOC;
6594
6595 for (i = 0; i < 2; i++)
6596 aarch64_set_vec_double (cpu, vd, i,
6597 aarch64_get_vec_double (cpu, vn, i)
6598 * aarch64_get_vec_double (cpu, vm, i));
6599 }
6600 else
6601 for (i = 0; i < (full ? 4 : 2); i++)
6602 aarch64_set_vec_float (cpu, vd, i,
6603 aarch64_get_vec_float (cpu, vn, i)
6604 * aarch64_get_vec_float (cpu, vm, i));
6605}
6606
6607static void
6608do_vec_FADDP (sim_cpu *cpu)
6609{
6610 /* instr [31] = 0
6611 instr [30] = half(0)/full(1)
6612 instr [29,23] = 10 1110 0
6613 instr [22] = float(0)/double(1)
6614 instr [21] = 1
6615 instr [20,16] = Vm
6616 instr [15,10] = 1101 01
6617 instr [9, 5] = Vn
6618 instr [4, 0] = Vd. */
6619
ef0d8ffc
NC
6620 unsigned full = INSTR (30, 30);
6621 unsigned vm = INSTR (20, 16);
6622 unsigned vn = INSTR (9, 5);
6623 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6624
6625 NYI_assert (29, 23, 0x5C);
6626 NYI_assert (21, 21, 1);
6627 NYI_assert (15, 10, 0x35);
6628
2cdad34c 6629 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6630 if (INSTR (22, 22))
2e8cf49e 6631 {
57aa1742
NC
6632 /* Extract values before adding them incase vd == vn/vm. */
6633 double tmp1 = aarch64_get_vec_double (cpu, vn, 0);
6634 double tmp2 = aarch64_get_vec_double (cpu, vn, 1);
6635 double tmp3 = aarch64_get_vec_double (cpu, vm, 0);
6636 double tmp4 = aarch64_get_vec_double (cpu, vm, 1);
6637
2e8cf49e
NC
6638 if (! full)
6639 HALT_UNALLOC;
6640
57aa1742
NC
6641 aarch64_set_vec_double (cpu, vd, 0, tmp1 + tmp2);
6642 aarch64_set_vec_double (cpu, vd, 1, tmp3 + tmp4);
2e8cf49e
NC
6643 }
6644 else
6645 {
57aa1742
NC
6646 /* Extract values before adding them incase vd == vn/vm. */
6647 float tmp1 = aarch64_get_vec_float (cpu, vn, 0);
6648 float tmp2 = aarch64_get_vec_float (cpu, vn, 1);
6649 float tmp5 = aarch64_get_vec_float (cpu, vm, 0);
6650 float tmp6 = aarch64_get_vec_float (cpu, vm, 1);
6651
2e8cf49e 6652 if (full)
57aa1742
NC
6653 {
6654 float tmp3 = aarch64_get_vec_float (cpu, vn, 2);
6655 float tmp4 = aarch64_get_vec_float (cpu, vn, 3);
6656 float tmp7 = aarch64_get_vec_float (cpu, vm, 2);
6657 float tmp8 = aarch64_get_vec_float (cpu, vm, 3);
6658
6659 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6660 aarch64_set_vec_float (cpu, vd, 1, tmp3 + tmp4);
6661 aarch64_set_vec_float (cpu, vd, 2, tmp5 + tmp6);
6662 aarch64_set_vec_float (cpu, vd, 3, tmp7 + tmp8);
6663 }
6664 else
6665 {
6666 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6667 aarch64_set_vec_float (cpu, vd, 1, tmp5 + tmp6);
6668 }
2e8cf49e
NC
6669 }
6670}
6671
6672static void
6673do_vec_FSQRT (sim_cpu *cpu)
6674{
6675 /* instr[31] = 0
6676 instr[30] = half(0)/full(1)
6677 instr[29,23] = 10 1110 1
6678 instr[22] = single(0)/double(1)
6679 instr[21,10] = 10 0001 1111 10
6680 instr[9,5] = Vsrc
6681 instr[4,0] = Vdest. */
6682
ef0d8ffc
NC
6683 unsigned vn = INSTR (9, 5);
6684 unsigned vd = INSTR (4, 0);
6685 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6686 int i;
6687
6688 NYI_assert (29, 23, 0x5D);
6689 NYI_assert (21, 10, 0x87E);
6690
2cdad34c 6691 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6692 if (INSTR (22, 22))
2e8cf49e
NC
6693 {
6694 if (! full)
6695 HALT_UNALLOC;
6696
6697 for (i = 0; i < 2; i++)
6698 aarch64_set_vec_double (cpu, vd, i,
6699 sqrt (aarch64_get_vec_double (cpu, vn, i)));
6700 }
6701 else
6702 {
6703 for (i = 0; i < (full ? 4 : 2); i++)
6704 aarch64_set_vec_float (cpu, vd, i,
6705 sqrtf (aarch64_get_vec_float (cpu, vn, i)));
6706 }
6707}
6708
6709static void
6710do_vec_FNEG (sim_cpu *cpu)
6711{
6712 /* instr[31] = 0
6713 instr[30] = half (0)/full (1)
6714 instr[29,23] = 10 1110 1
6715 instr[22] = single (0)/double (1)
6716 instr[21,10] = 10 0000 1111 10
6717 instr[9,5] = Vsrc
6718 instr[4,0] = Vdest. */
6719
ef0d8ffc
NC
6720 unsigned vn = INSTR (9, 5);
6721 unsigned vd = INSTR (4, 0);
6722 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6723 int i;
6724
6725 NYI_assert (29, 23, 0x5D);
6726 NYI_assert (21, 10, 0x83E);
6727
2cdad34c 6728 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6729 if (INSTR (22, 22))
2e8cf49e
NC
6730 {
6731 if (! full)
6732 HALT_UNALLOC;
6733
6734 for (i = 0; i < 2; i++)
6735 aarch64_set_vec_double (cpu, vd, i,
6736 - aarch64_get_vec_double (cpu, vn, i));
6737 }
6738 else
6739 {
6740 for (i = 0; i < (full ? 4 : 2); i++)
6741 aarch64_set_vec_float (cpu, vd, i,
6742 - aarch64_get_vec_float (cpu, vn, i));
6743 }
6744}
6745
6746static void
6747do_vec_NOT (sim_cpu *cpu)
6748{
6749 /* instr[31] = 0
6750 instr[30] = half (0)/full (1)
5ab6d79e 6751 instr[29,10] = 10 1110 0010 0000 0101 10
2e8cf49e
NC
6752 instr[9,5] = Vn
6753 instr[4.0] = Vd. */
6754
ef0d8ffc
NC
6755 unsigned vn = INSTR (9, 5);
6756 unsigned vd = INSTR (4, 0);
2e8cf49e 6757 unsigned i;
ef0d8ffc 6758 int full = INSTR (30, 30);
2e8cf49e
NC
6759
6760 NYI_assert (29, 10, 0xB8816);
6761
2cdad34c 6762 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
6763 for (i = 0; i < (full ? 16 : 8); i++)
6764 aarch64_set_vec_u8 (cpu, vd, i, ~ aarch64_get_vec_u8 (cpu, vn, i));
6765}
6766
5ab6d79e
NC
6767static unsigned int
6768clz (uint64_t val, unsigned size)
6769{
6770 uint64_t mask = 1;
6771 int count;
6772
6773 mask <<= (size - 1);
6774 count = 0;
6775 do
6776 {
6777 if (val & mask)
6778 break;
6779 mask >>= 1;
6780 count ++;
6781 }
6782 while (mask);
6783
6784 return count;
6785}
6786
6787static void
6788do_vec_CLZ (sim_cpu *cpu)
6789{
6790 /* instr[31] = 0
6791 instr[30] = half (0)/full (1)
6792 instr[29,24] = 10 1110
6793 instr[23,22] = size
6794 instr[21,10] = 10 0000 0100 10
6795 instr[9,5] = Vn
6796 instr[4.0] = Vd. */
6797
6798 unsigned vn = INSTR (9, 5);
6799 unsigned vd = INSTR (4, 0);
6800 unsigned i;
6801 int full = INSTR (30,30);
6802
6803 NYI_assert (29, 24, 0x2E);
6804 NYI_assert (21, 10, 0x812);
6805
2cdad34c 6806 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
6807 switch (INSTR (23, 22))
6808 {
6809 case 0:
6810 for (i = 0; i < (full ? 16 : 8); i++)
6811 aarch64_set_vec_u8 (cpu, vd, i, clz (aarch64_get_vec_u8 (cpu, vn, i), 8));
6812 break;
6813 case 1:
6814 for (i = 0; i < (full ? 8 : 4); i++)
6815 aarch64_set_vec_u16 (cpu, vd, i, clz (aarch64_get_vec_u16 (cpu, vn, i), 16));
6816 break;
6817 case 2:
6818 for (i = 0; i < (full ? 4 : 2); i++)
6819 aarch64_set_vec_u32 (cpu, vd, i, clz (aarch64_get_vec_u32 (cpu, vn, i), 32));
6820 break;
6821 case 3:
6822 if (! full)
6823 HALT_UNALLOC;
6824 aarch64_set_vec_u64 (cpu, vd, 0, clz (aarch64_get_vec_u64 (cpu, vn, 0), 64));
6825 aarch64_set_vec_u64 (cpu, vd, 1, clz (aarch64_get_vec_u64 (cpu, vn, 1), 64));
6826 break;
6827 }
6828}
6829
2e8cf49e
NC
6830static void
6831do_vec_MOV_element (sim_cpu *cpu)
6832{
6833 /* instr[31,21] = 0110 1110 000
6834 instr[20,16] = size & dest index
6835 instr[15] = 0
6836 instr[14,11] = source index
6837 instr[10] = 1
6838 instr[9,5] = Vs
6839 instr[4.0] = Vd. */
6840
ef0d8ffc
NC
6841 unsigned vs = INSTR (9, 5);
6842 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6843 unsigned src_index;
6844 unsigned dst_index;
6845
6846 NYI_assert (31, 21, 0x370);
6847 NYI_assert (15, 15, 0);
6848 NYI_assert (10, 10, 1);
6849
2cdad34c 6850 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 6851 if (INSTR (16, 16))
2e8cf49e
NC
6852 {
6853 /* Move a byte. */
ef0d8ffc
NC
6854 src_index = INSTR (14, 11);
6855 dst_index = INSTR (20, 17);
2e8cf49e
NC
6856 aarch64_set_vec_u8 (cpu, vd, dst_index,
6857 aarch64_get_vec_u8 (cpu, vs, src_index));
6858 }
ef0d8ffc 6859 else if (INSTR (17, 17))
2e8cf49e
NC
6860 {
6861 /* Move 16-bits. */
6862 NYI_assert (11, 11, 0);
ef0d8ffc
NC
6863 src_index = INSTR (14, 12);
6864 dst_index = INSTR (20, 18);
2e8cf49e
NC
6865 aarch64_set_vec_u16 (cpu, vd, dst_index,
6866 aarch64_get_vec_u16 (cpu, vs, src_index));
6867 }
ef0d8ffc 6868 else if (INSTR (18, 18))
2e8cf49e
NC
6869 {
6870 /* Move 32-bits. */
6871 NYI_assert (12, 11, 0);
ef0d8ffc
NC
6872 src_index = INSTR (14, 13);
6873 dst_index = INSTR (20, 19);
2e8cf49e
NC
6874 aarch64_set_vec_u32 (cpu, vd, dst_index,
6875 aarch64_get_vec_u32 (cpu, vs, src_index));
6876 }
6877 else
6878 {
6879 NYI_assert (19, 19, 1);
6880 NYI_assert (13, 11, 0);
ef0d8ffc
NC
6881 src_index = INSTR (14, 14);
6882 dst_index = INSTR (20, 20);
2e8cf49e
NC
6883 aarch64_set_vec_u64 (cpu, vd, dst_index,
6884 aarch64_get_vec_u64 (cpu, vs, src_index));
6885 }
6886}
6887
67f101ee
NC
6888static void
6889do_vec_REV32 (sim_cpu *cpu)
6890{
6891 /* instr[31] = 0
6892 instr[30] = full/half
6893 instr[29,24] = 10 1110
6894 instr[23,22] = size
6895 instr[21,10] = 10 0000 0000 10
6896 instr[9,5] = Rn
6897 instr[4,0] = Rd. */
6898
6899 unsigned rn = INSTR (9, 5);
6900 unsigned rd = INSTR (4, 0);
6901 unsigned size = INSTR (23, 22);
6902 unsigned full = INSTR (30, 30);
6903 unsigned i;
6904 FRegister val;
6905
6906 NYI_assert (29, 24, 0x2E);
6907 NYI_assert (21, 10, 0x802);
6908
2cdad34c 6909 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
6910 switch (size)
6911 {
6912 case 0:
6913 for (i = 0; i < (full ? 16 : 8); i++)
6914 val.b[i ^ 0x3] = aarch64_get_vec_u8 (cpu, rn, i);
6915 break;
6916
6917 case 1:
6918 for (i = 0; i < (full ? 8 : 4); i++)
6919 val.h[i ^ 0x1] = aarch64_get_vec_u16 (cpu, rn, i);
6920 break;
6921
6922 default:
6923 HALT_UNALLOC;
6924 }
6925
6926 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
6927 if (full)
6928 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
6929}
6930
6931static void
6932do_vec_EXT (sim_cpu *cpu)
6933{
6934 /* instr[31] = 0
6935 instr[30] = full/half
6936 instr[29,21] = 10 1110 000
6937 instr[20,16] = Vm
6938 instr[15] = 0
6939 instr[14,11] = source index
6940 instr[10] = 0
6941 instr[9,5] = Vn
6942 instr[4.0] = Vd. */
6943
6944 unsigned vm = INSTR (20, 16);
6945 unsigned vn = INSTR (9, 5);
6946 unsigned vd = INSTR (4, 0);
6947 unsigned src_index = INSTR (14, 11);
6948 unsigned full = INSTR (30, 30);
6949 unsigned i;
6950 unsigned j;
6951 FRegister val;
6952
6953 NYI_assert (31, 21, 0x370);
6954 NYI_assert (15, 15, 0);
6955 NYI_assert (10, 10, 0);
6956
6957 if (!full && (src_index & 0x8))
6958 HALT_UNALLOC;
6959
6960 j = 0;
6961
2cdad34c 6962 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
67f101ee
NC
6963 for (i = src_index; i < (full ? 16 : 8); i++)
6964 val.b[j ++] = aarch64_get_vec_u8 (cpu, vn, i);
6965 for (i = 0; i < src_index; i++)
6966 val.b[j ++] = aarch64_get_vec_u8 (cpu, vm, i);
6967
6968 aarch64_set_vec_u64 (cpu, vd, 0, val.v[0]);
6969 if (full)
6970 aarch64_set_vec_u64 (cpu, vd, 1, val.v[1]);
6971}
6972
2e8cf49e
NC
6973static void
6974dexAdvSIMD0 (sim_cpu *cpu)
6975{
6976 /* instr [28,25] = 0 111. */
ef0d8ffc
NC
6977 if ( INSTR (15, 10) == 0x07
6978 && (INSTR (9, 5) ==
6979 INSTR (20, 16)))
2e8cf49e 6980 {
ef0d8ffc
NC
6981 if (INSTR (31, 21) == 0x075
6982 || INSTR (31, 21) == 0x275)
2e8cf49e
NC
6983 {
6984 do_vec_MOV_whole_vector (cpu);
6985 return;
6986 }
6987 }
6988
ef0d8ffc 6989 if (INSTR (29, 19) == 0x1E0)
2e8cf49e
NC
6990 {
6991 do_vec_MOV_immediate (cpu);
6992 return;
6993 }
6994
ef0d8ffc 6995 if (INSTR (29, 19) == 0x5E0)
2e8cf49e
NC
6996 {
6997 do_vec_MVNI (cpu);
6998 return;
6999 }
7000
ef0d8ffc
NC
7001 if (INSTR (29, 19) == 0x1C0
7002 || INSTR (29, 19) == 0x1C1)
2e8cf49e 7003 {
ef0d8ffc 7004 if (INSTR (15, 10) == 0x03)
2e8cf49e
NC
7005 {
7006 do_vec_DUP_scalar_into_vector (cpu);
7007 return;
7008 }
7009 }
7010
ef0d8ffc 7011 switch (INSTR (29, 24))
2e8cf49e
NC
7012 {
7013 case 0x0E: do_vec_op1 (cpu); return;
7014 case 0x0F: do_vec_op2 (cpu); return;
7015
2e8cf49e 7016 case 0x2E:
ef0d8ffc 7017 if (INSTR (21, 21) == 1)
2e8cf49e 7018 {
ef0d8ffc 7019 switch (INSTR (15, 10))
2e8cf49e 7020 {
67f101ee
NC
7021 case 0x02:
7022 do_vec_REV32 (cpu);
7023 return;
7024
2e8cf49e 7025 case 0x07:
ef0d8ffc 7026 switch (INSTR (23, 22))
2e8cf49e
NC
7027 {
7028 case 0: do_vec_EOR (cpu); return;
7029 case 1: do_vec_BSL (cpu); return;
7030 case 2:
7031 case 3: do_vec_bit (cpu); return;
7032 }
7033 break;
7034
7035 case 0x08: do_vec_sub_long (cpu); return;
7036 case 0x11: do_vec_USHL (cpu); return;
5ab6d79e 7037 case 0x12: do_vec_CLZ (cpu); return;
2e8cf49e
NC
7038 case 0x16: do_vec_NOT (cpu); return;
7039 case 0x19: do_vec_max (cpu); return;
7040 case 0x1B: do_vec_min (cpu); return;
7041 case 0x21: do_vec_SUB (cpu); return;
7042 case 0x25: do_vec_MLS (cpu); return;
7043 case 0x31: do_vec_FminmaxNMP (cpu); return;
7044 case 0x35: do_vec_FADDP (cpu); return;
7045 case 0x37: do_vec_FMUL (cpu); return;
7046 case 0x3F: do_vec_FDIV (cpu); return;
7047
7048 case 0x3E:
ef0d8ffc 7049 switch (INSTR (20, 16))
2e8cf49e
NC
7050 {
7051 case 0x00: do_vec_FNEG (cpu); return;
7052 case 0x01: do_vec_FSQRT (cpu); return;
7053 default: HALT_NYI;
7054 }
7055
7056 case 0x0D:
7057 case 0x0F:
7058 case 0x22:
7059 case 0x23:
7060 case 0x26:
7061 case 0x2A:
7062 case 0x32:
7063 case 0x36:
7064 case 0x39:
7065 case 0x3A:
7066 do_vec_compare (cpu); return;
7067
5ab6d79e
NC
7068 default:
7069 break;
2e8cf49e
NC
7070 }
7071 }
7072
ef0d8ffc 7073 if (INSTR (31, 21) == 0x370)
2e8cf49e 7074 {
67f101ee
NC
7075 if (INSTR (10, 10))
7076 do_vec_MOV_element (cpu);
7077 else
7078 do_vec_EXT (cpu);
2e8cf49e
NC
7079 return;
7080 }
7081
ef0d8ffc 7082 switch (INSTR (21, 10))
2e8cf49e
NC
7083 {
7084 case 0x82E: do_vec_neg (cpu); return;
7085 case 0x87E: do_vec_sqrt (cpu); return;
7086 default:
ef0d8ffc 7087 if (INSTR (15, 10) == 0x30)
2e8cf49e
NC
7088 {
7089 do_vec_mull (cpu);
7090 return;
7091 }
7092 break;
7093 }
7094 break;
7095
67f101ee
NC
7096 case 0x2f:
7097 switch (INSTR (15, 10))
7098 {
7099 case 0x01: do_vec_SSHR_USHR (cpu); return;
7100 case 0x10:
7101 case 0x12: do_vec_mls_indexed (cpu); return;
7102 case 0x29: do_vec_xtl (cpu); return;
7103 default:
7104 HALT_NYI;
7105 }
7106
2e8cf49e
NC
7107 default:
7108 break;
7109 }
7110
7111 HALT_NYI;
7112}
7113
7114/* 3 sources. */
7115
7116/* Float multiply add. */
7117static void
7118fmadds (sim_cpu *cpu)
7119{
ef0d8ffc
NC
7120 unsigned sa = INSTR (14, 10);
7121 unsigned sm = INSTR (20, 16);
7122 unsigned sn = INSTR ( 9, 5);
7123 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7124
2cdad34c 7125 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7126 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
7127 + aarch64_get_FP_float (cpu, sn)
7128 * aarch64_get_FP_float (cpu, sm));
7129}
7130
7131/* Double multiply add. */
7132static void
7133fmaddd (sim_cpu *cpu)
7134{
ef0d8ffc
NC
7135 unsigned sa = INSTR (14, 10);
7136 unsigned sm = INSTR (20, 16);
7137 unsigned sn = INSTR ( 9, 5);
7138 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7139
2cdad34c 7140 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7141 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
7142 + aarch64_get_FP_double (cpu, sn)
7143 * aarch64_get_FP_double (cpu, sm));
7144}
7145
7146/* Float multiply subtract. */
7147static void
7148fmsubs (sim_cpu *cpu)
7149{
ef0d8ffc
NC
7150 unsigned sa = INSTR (14, 10);
7151 unsigned sm = INSTR (20, 16);
7152 unsigned sn = INSTR ( 9, 5);
7153 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7154
2cdad34c 7155 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7156 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
7157 - aarch64_get_FP_float (cpu, sn)
7158 * aarch64_get_FP_float (cpu, sm));
7159}
7160
7161/* Double multiply subtract. */
7162static void
7163fmsubd (sim_cpu *cpu)
7164{
ef0d8ffc
NC
7165 unsigned sa = INSTR (14, 10);
7166 unsigned sm = INSTR (20, 16);
7167 unsigned sn = INSTR ( 9, 5);
7168 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7169
2cdad34c 7170 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7171 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
7172 - aarch64_get_FP_double (cpu, sn)
7173 * aarch64_get_FP_double (cpu, sm));
7174}
7175
7176/* Float negative multiply add. */
7177static void
7178fnmadds (sim_cpu *cpu)
7179{
ef0d8ffc
NC
7180 unsigned sa = INSTR (14, 10);
7181 unsigned sm = INSTR (20, 16);
7182 unsigned sn = INSTR ( 9, 5);
7183 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7184
2cdad34c 7185 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7186 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
7187 + (- aarch64_get_FP_float (cpu, sn))
7188 * aarch64_get_FP_float (cpu, sm));
7189}
7190
7191/* Double negative multiply add. */
7192static void
7193fnmaddd (sim_cpu *cpu)
7194{
ef0d8ffc
NC
7195 unsigned sa = INSTR (14, 10);
7196 unsigned sm = INSTR (20, 16);
7197 unsigned sn = INSTR ( 9, 5);
7198 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7199
2cdad34c 7200 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7201 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
7202 + (- aarch64_get_FP_double (cpu, sn))
7203 * aarch64_get_FP_double (cpu, sm));
7204}
7205
7206/* Float negative multiply subtract. */
7207static void
7208fnmsubs (sim_cpu *cpu)
7209{
ef0d8ffc
NC
7210 unsigned sa = INSTR (14, 10);
7211 unsigned sm = INSTR (20, 16);
7212 unsigned sn = INSTR ( 9, 5);
7213 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7214
2cdad34c 7215 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7216 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
7217 + aarch64_get_FP_float (cpu, sn)
7218 * aarch64_get_FP_float (cpu, sm));
7219}
7220
7221/* Double negative multiply subtract. */
7222static void
7223fnmsubd (sim_cpu *cpu)
7224{
ef0d8ffc
NC
7225 unsigned sa = INSTR (14, 10);
7226 unsigned sm = INSTR (20, 16);
7227 unsigned sn = INSTR ( 9, 5);
7228 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7229
2cdad34c 7230 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7231 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
7232 + aarch64_get_FP_double (cpu, sn)
7233 * aarch64_get_FP_double (cpu, sm));
7234}
7235
7236static void
7237dexSimpleFPDataProc3Source (sim_cpu *cpu)
7238{
7239 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7240 instr[30] = 0
7241 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7242 instr[28,25] = 1111
7243 instr[24] = 1
7244 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7245 instr[21] ==> o1 : 0 ==> unnegated, 1 ==> negated
7246 instr[15] ==> o2 : 0 ==> ADD, 1 ==> SUB */
7247
7517e550 7248 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
2e8cf49e 7249 /* dispatch on combined type:o1:o2. */
7517e550 7250 uint32_t dispatch = (INSTR (23, 21) << 1) | INSTR (15, 15);
2e8cf49e
NC
7251
7252 if (M_S != 0)
7253 HALT_UNALLOC;
7254
7255 switch (dispatch)
7256 {
7257 case 0: fmadds (cpu); return;
7258 case 1: fmsubs (cpu); return;
7259 case 2: fnmadds (cpu); return;
7260 case 3: fnmsubs (cpu); return;
7261 case 4: fmaddd (cpu); return;
7262 case 5: fmsubd (cpu); return;
7263 case 6: fnmaddd (cpu); return;
7264 case 7: fnmsubd (cpu); return;
7265 default:
7266 /* type > 1 is currently unallocated. */
7267 HALT_UNALLOC;
7268 }
7269}
7270
7271static void
7272dexSimpleFPFixedConvert (sim_cpu *cpu)
7273{
7274 HALT_NYI;
7275}
7276
7277static void
7278dexSimpleFPCondCompare (sim_cpu *cpu)
7279{
5ab6d79e
NC
7280 /* instr [31,23] = 0001 1110 0
7281 instr [22] = type
7282 instr [21] = 1
7283 instr [20,16] = Rm
7284 instr [15,12] = condition
7285 instr [11,10] = 01
7286 instr [9,5] = Rn
7287 instr [4] = 0
7288 instr [3,0] = nzcv */
7289
7290 unsigned rm = INSTR (20, 16);
7291 unsigned rn = INSTR (9, 5);
7292
7293 NYI_assert (31, 23, 0x3C);
7294 NYI_assert (11, 10, 0x1);
7295 NYI_assert (4, 4, 0);
7296
2cdad34c 7297 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
7298 if (! testConditionCode (cpu, INSTR (15, 12)))
7299 {
7300 aarch64_set_CPSR (cpu, INSTR (3, 0));
7301 return;
7302 }
7303
7304 if (INSTR (22, 22))
7305 {
7306 /* Double precision. */
7307 double val1 = aarch64_get_vec_double (cpu, rn, 0);
7308 double val2 = aarch64_get_vec_double (cpu, rm, 0);
7309
7310 /* FIXME: Check for NaNs. */
7311 if (val1 == val2)
7312 aarch64_set_CPSR (cpu, (Z | C));
7313 else if (val1 < val2)
7314 aarch64_set_CPSR (cpu, N);
7315 else /* val1 > val2 */
7316 aarch64_set_CPSR (cpu, C);
7317 }
7318 else
7319 {
7320 /* Single precision. */
7321 float val1 = aarch64_get_vec_float (cpu, rn, 0);
7322 float val2 = aarch64_get_vec_float (cpu, rm, 0);
ef0d8ffc 7323
5ab6d79e
NC
7324 /* FIXME: Check for NaNs. */
7325 if (val1 == val2)
7326 aarch64_set_CPSR (cpu, (Z | C));
7327 else if (val1 < val2)
7328 aarch64_set_CPSR (cpu, N);
7329 else /* val1 > val2 */
7330 aarch64_set_CPSR (cpu, C);
7331 }
2e8cf49e
NC
7332}
7333
7334/* 2 sources. */
7335
7336/* Float add. */
7337static void
7338fadds (sim_cpu *cpu)
7339{
ef0d8ffc
NC
7340 unsigned sm = INSTR (20, 16);
7341 unsigned sn = INSTR ( 9, 5);
7342 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7343
2cdad34c 7344 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7345 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7346 + aarch64_get_FP_float (cpu, sm));
7347}
7348
7349/* Double add. */
7350static void
7351faddd (sim_cpu *cpu)
7352{
ef0d8ffc
NC
7353 unsigned sm = INSTR (20, 16);
7354 unsigned sn = INSTR ( 9, 5);
7355 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7356
2cdad34c 7357 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7358 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7359 + aarch64_get_FP_double (cpu, sm));
7360}
7361
7362/* Float divide. */
7363static void
7364fdivs (sim_cpu *cpu)
7365{
ef0d8ffc
NC
7366 unsigned sm = INSTR (20, 16);
7367 unsigned sn = INSTR ( 9, 5);
7368 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7369
2cdad34c 7370 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7371 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7372 / aarch64_get_FP_float (cpu, sm));
7373}
7374
7375/* Double divide. */
7376static void
7377fdivd (sim_cpu *cpu)
7378{
ef0d8ffc
NC
7379 unsigned sm = INSTR (20, 16);
7380 unsigned sn = INSTR ( 9, 5);
7381 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7382
2cdad34c 7383 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7384 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7385 / aarch64_get_FP_double (cpu, sm));
7386}
7387
7388/* Float multiply. */
7389static void
7390fmuls (sim_cpu *cpu)
7391{
ef0d8ffc
NC
7392 unsigned sm = INSTR (20, 16);
7393 unsigned sn = INSTR ( 9, 5);
7394 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7395
2cdad34c 7396 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7397 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7398 * aarch64_get_FP_float (cpu, sm));
7399}
7400
7401/* Double multiply. */
7402static void
7403fmuld (sim_cpu *cpu)
7404{
ef0d8ffc
NC
7405 unsigned sm = INSTR (20, 16);
7406 unsigned sn = INSTR ( 9, 5);
7407 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7408
2cdad34c 7409 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7410 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7411 * aarch64_get_FP_double (cpu, sm));
7412}
7413
7414/* Float negate and multiply. */
7415static void
7416fnmuls (sim_cpu *cpu)
7417{
ef0d8ffc
NC
7418 unsigned sm = INSTR (20, 16);
7419 unsigned sn = INSTR ( 9, 5);
7420 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7421
2cdad34c 7422 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7423 aarch64_set_FP_float (cpu, sd, - (aarch64_get_FP_float (cpu, sn)
7424 * aarch64_get_FP_float (cpu, sm)));
7425}
7426
7427/* Double negate and multiply. */
7428static void
7429fnmuld (sim_cpu *cpu)
7430{
ef0d8ffc
NC
7431 unsigned sm = INSTR (20, 16);
7432 unsigned sn = INSTR ( 9, 5);
7433 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7434
2cdad34c 7435 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7436 aarch64_set_FP_double (cpu, sd, - (aarch64_get_FP_double (cpu, sn)
7437 * aarch64_get_FP_double (cpu, sm)));
7438}
7439
7440/* Float subtract. */
7441static void
7442fsubs (sim_cpu *cpu)
7443{
ef0d8ffc
NC
7444 unsigned sm = INSTR (20, 16);
7445 unsigned sn = INSTR ( 9, 5);
7446 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7447
2cdad34c 7448 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7449 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7450 - aarch64_get_FP_float (cpu, sm));
7451}
7452
7453/* Double subtract. */
7454static void
7455fsubd (sim_cpu *cpu)
7456{
ef0d8ffc
NC
7457 unsigned sm = INSTR (20, 16);
7458 unsigned sn = INSTR ( 9, 5);
7459 unsigned sd = INSTR ( 4, 0);
2e8cf49e 7460
2cdad34c 7461 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7462 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7463 - aarch64_get_FP_double (cpu, sm));
7464}
7465
7466static void
7467do_FMINNM (sim_cpu *cpu)
7468{
7469 /* instr[31,23] = 0 0011 1100
7470 instr[22] = float(0)/double(1)
7471 instr[21] = 1
7472 instr[20,16] = Sm
7473 instr[15,10] = 01 1110
7474 instr[9,5] = Sn
7475 instr[4,0] = Cpu */
7476
ef0d8ffc
NC
7477 unsigned sm = INSTR (20, 16);
7478 unsigned sn = INSTR ( 9, 5);
7479 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7480
7481 NYI_assert (31, 23, 0x03C);
7482 NYI_assert (15, 10, 0x1E);
7483
2cdad34c 7484 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7485 if (INSTR (22, 22))
2e8cf49e
NC
7486 aarch64_set_FP_double (cpu, sd,
7487 dminnm (aarch64_get_FP_double (cpu, sn),
7488 aarch64_get_FP_double (cpu, sm)));
7489 else
7490 aarch64_set_FP_float (cpu, sd,
7491 fminnm (aarch64_get_FP_float (cpu, sn),
7492 aarch64_get_FP_float (cpu, sm)));
7493}
7494
7495static void
7496do_FMAXNM (sim_cpu *cpu)
7497{
7498 /* instr[31,23] = 0 0011 1100
7499 instr[22] = float(0)/double(1)
7500 instr[21] = 1
7501 instr[20,16] = Sm
7502 instr[15,10] = 01 1010
7503 instr[9,5] = Sn
7504 instr[4,0] = Cpu */
7505
ef0d8ffc
NC
7506 unsigned sm = INSTR (20, 16);
7507 unsigned sn = INSTR ( 9, 5);
7508 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7509
7510 NYI_assert (31, 23, 0x03C);
7511 NYI_assert (15, 10, 0x1A);
7512
2cdad34c 7513 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7514 if (INSTR (22, 22))
2e8cf49e
NC
7515 aarch64_set_FP_double (cpu, sd,
7516 dmaxnm (aarch64_get_FP_double (cpu, sn),
7517 aarch64_get_FP_double (cpu, sm)));
7518 else
7519 aarch64_set_FP_float (cpu, sd,
7520 fmaxnm (aarch64_get_FP_float (cpu, sn),
7521 aarch64_get_FP_float (cpu, sm)));
7522}
7523
7524static void
7525dexSimpleFPDataProc2Source (sim_cpu *cpu)
7526{
7527 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7528 instr[30] = 0
7529 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7530 instr[28,25] = 1111
7531 instr[24] = 0
7532 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7533 instr[21] = 1
7534 instr[20,16] = Vm
7535 instr[15,12] ==> opcode : 0000 ==> FMUL, 0001 ==> FDIV
7536 0010 ==> FADD, 0011 ==> FSUB,
7537 0100 ==> FMAX, 0101 ==> FMIN
7538 0110 ==> FMAXNM, 0111 ==> FMINNM
7539 1000 ==> FNMUL, ow ==> UNALLOC
7540 instr[11,10] = 10
7541 instr[9,5] = Vn
7542 instr[4,0] = Vd */
7543
7517e550 7544 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc 7545 uint32_t type = INSTR (23, 22);
2e8cf49e 7546 /* Dispatch on opcode. */
ef0d8ffc 7547 uint32_t dispatch = INSTR (15, 12);
2e8cf49e
NC
7548
7549 if (type > 1)
7550 HALT_UNALLOC;
7551
7552 if (M_S != 0)
7553 HALT_UNALLOC;
7554
7555 if (type)
7556 switch (dispatch)
7557 {
7558 case 0: fmuld (cpu); return;
7559 case 1: fdivd (cpu); return;
7560 case 2: faddd (cpu); return;
7561 case 3: fsubd (cpu); return;
7562 case 6: do_FMAXNM (cpu); return;
7563 case 7: do_FMINNM (cpu); return;
7564 case 8: fnmuld (cpu); return;
7565
7566 /* Have not yet implemented fmax and fmin. */
7567 case 4:
7568 case 5:
7569 HALT_NYI;
7570
7571 default:
7572 HALT_UNALLOC;
7573 }
7574 else /* type == 0 => floats. */
7575 switch (dispatch)
7576 {
7577 case 0: fmuls (cpu); return;
7578 case 1: fdivs (cpu); return;
7579 case 2: fadds (cpu); return;
7580 case 3: fsubs (cpu); return;
7581 case 6: do_FMAXNM (cpu); return;
7582 case 7: do_FMINNM (cpu); return;
7583 case 8: fnmuls (cpu); return;
7584
7585 case 4:
7586 case 5:
7587 HALT_NYI;
7588
7589 default:
7590 HALT_UNALLOC;
7591 }
7592}
7593
7594static void
7595dexSimpleFPCondSelect (sim_cpu *cpu)
7596{
7597 /* FCSEL
7598 instr[31,23] = 0 0011 1100
7599 instr[22] = 0=>single 1=>double
7600 instr[21] = 1
7601 instr[20,16] = Sm
7602 instr[15,12] = cond
7603 instr[11,10] = 11
7604 instr[9,5] = Sn
7605 instr[4,0] = Cpu */
ef0d8ffc
NC
7606 unsigned sm = INSTR (20, 16);
7607 unsigned sn = INSTR ( 9, 5);
7608 unsigned sd = INSTR ( 4, 0);
7609 uint32_t set = testConditionCode (cpu, INSTR (15, 12));
2e8cf49e
NC
7610
7611 NYI_assert (31, 23, 0x03C);
7612 NYI_assert (11, 10, 0x3);
7613
2cdad34c 7614 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7615 if (INSTR (22, 22))
c0386d4d
JW
7616 aarch64_set_FP_double (cpu, sd, (set ? aarch64_get_FP_double (cpu, sn)
7617 : aarch64_get_FP_double (cpu, sm)));
2e8cf49e 7618 else
c0386d4d
JW
7619 aarch64_set_FP_float (cpu, sd, (set ? aarch64_get_FP_float (cpu, sn)
7620 : aarch64_get_FP_float (cpu, sm)));
2e8cf49e
NC
7621}
7622
7623/* Store 32 bit unscaled signed 9 bit. */
7624static void
7625fsturs (sim_cpu *cpu, int32_t offset)
7626{
ef0d8ffc
NC
7627 unsigned int rn = INSTR (9, 5);
7628 unsigned int st = INSTR (4, 0);
2e8cf49e 7629
2cdad34c 7630 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1
JW
7631 aarch64_set_mem_u32 (cpu, aarch64_get_reg_u64 (cpu, rn, 1) + offset,
7632 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
7633}
7634
7635/* Store 64 bit unscaled signed 9 bit. */
7636static void
7637fsturd (sim_cpu *cpu, int32_t offset)
7638{
ef0d8ffc
NC
7639 unsigned int rn = INSTR (9, 5);
7640 unsigned int st = INSTR (4, 0);
2e8cf49e 7641
2cdad34c 7642 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1
JW
7643 aarch64_set_mem_u64 (cpu, aarch64_get_reg_u64 (cpu, rn, 1) + offset,
7644 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
7645}
7646
7647/* Store 128 bit unscaled signed 9 bit. */
7648static void
7649fsturq (sim_cpu *cpu, int32_t offset)
7650{
ef0d8ffc
NC
7651 unsigned int rn = INSTR (9, 5);
7652 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7653 FRegister a;
7654
2cdad34c 7655 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
88ddd4a1 7656 aarch64_get_FP_long_double (cpu, st, & a);
2e8cf49e 7657 aarch64_set_mem_long_double (cpu,
88ddd4a1 7658 aarch64_get_reg_u64 (cpu, rn, 1)
2e8cf49e
NC
7659 + offset, a);
7660}
7661
7662/* TODO FP move register. */
7663
7664/* 32 bit fp to fp move register. */
7665static void
7666ffmovs (sim_cpu *cpu)
7667{
ef0d8ffc
NC
7668 unsigned int rn = INSTR (9, 5);
7669 unsigned int st = INSTR (4, 0);
2e8cf49e 7670
2cdad34c 7671 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7672 aarch64_set_FP_float (cpu, st, aarch64_get_FP_float (cpu, rn));
7673}
7674
7675/* 64 bit fp to fp move register. */
7676static void
7677ffmovd (sim_cpu *cpu)
7678{
ef0d8ffc
NC
7679 unsigned int rn = INSTR (9, 5);
7680 unsigned int st = INSTR (4, 0);
2e8cf49e 7681
2cdad34c 7682 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7683 aarch64_set_FP_double (cpu, st, aarch64_get_FP_double (cpu, rn));
7684}
7685
7686/* 32 bit GReg to Vec move register. */
7687static void
7688fgmovs (sim_cpu *cpu)
7689{
ef0d8ffc
NC
7690 unsigned int rn = INSTR (9, 5);
7691 unsigned int st = INSTR (4, 0);
2e8cf49e 7692
2cdad34c 7693 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7694 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_reg_u32 (cpu, rn, NO_SP));
7695}
7696
7697/* 64 bit g to fp move register. */
7698static void
7699fgmovd (sim_cpu *cpu)
7700{
ef0d8ffc
NC
7701 unsigned int rn = INSTR (9, 5);
7702 unsigned int st = INSTR (4, 0);
2e8cf49e 7703
2cdad34c 7704 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7705 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_reg_u64 (cpu, rn, NO_SP));
7706}
7707
7708/* 32 bit fp to g move register. */
7709static void
7710gfmovs (sim_cpu *cpu)
7711{
ef0d8ffc
NC
7712 unsigned int rn = INSTR (9, 5);
7713 unsigned int st = INSTR (4, 0);
2e8cf49e 7714
2cdad34c 7715 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7716 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u32 (cpu, rn, 0));
7717}
7718
7719/* 64 bit fp to g move register. */
7720static void
7721gfmovd (sim_cpu *cpu)
7722{
ef0d8ffc
NC
7723 unsigned int rn = INSTR (9, 5);
7724 unsigned int st = INSTR (4, 0);
2e8cf49e 7725
2cdad34c 7726 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7727 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u64 (cpu, rn, 0));
7728}
7729
7730/* FP move immediate
7731
7732 These install an immediate 8 bit value in the target register
7733 where the 8 bits comprise 1 sign bit, 4 bits of fraction and a 3
7734 bit exponent. */
7735
7736static void
7737fmovs (sim_cpu *cpu)
7738{
ef0d8ffc
NC
7739 unsigned int sd = INSTR (4, 0);
7740 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7741 float f = fp_immediate_for_encoding_32 (imm);
7742
2cdad34c 7743 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7744 aarch64_set_FP_float (cpu, sd, f);
7745}
7746
7747static void
7748fmovd (sim_cpu *cpu)
7749{
ef0d8ffc
NC
7750 unsigned int sd = INSTR (4, 0);
7751 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7752 double d = fp_immediate_for_encoding_64 (imm);
7753
2cdad34c 7754 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7755 aarch64_set_FP_double (cpu, sd, d);
7756}
7757
7758static void
7759dexSimpleFPImmediate (sim_cpu *cpu)
7760{
7761 /* instr[31,23] == 00111100
7762 instr[22] == type : single(0)/double(1)
7763 instr[21] == 1
7764 instr[20,13] == imm8
7765 instr[12,10] == 100
7766 instr[9,5] == imm5 : 00000 ==> PK, ow ==> UNALLOC
7767 instr[4,0] == Rd */
ef0d8ffc 7768 uint32_t imm5 = INSTR (9, 5);
2e8cf49e
NC
7769
7770 NYI_assert (31, 23, 0x3C);
7771
7772 if (imm5 != 0)
7773 HALT_UNALLOC;
7774
ef0d8ffc 7775 if (INSTR (22, 22))
2e8cf49e
NC
7776 fmovd (cpu);
7777 else
7778 fmovs (cpu);
7779}
7780
7781/* TODO specific decode and execute for group Load Store. */
7782
7783/* TODO FP load/store single register (unscaled offset). */
7784
7785/* TODO load 8 bit unscaled signed 9 bit. */
7786/* TODO load 16 bit unscaled signed 9 bit. */
7787
7788/* Load 32 bit unscaled signed 9 bit. */
7789static void
7790fldurs (sim_cpu *cpu, int32_t offset)
7791{
ef0d8ffc
NC
7792 unsigned int rn = INSTR (9, 5);
7793 unsigned int st = INSTR (4, 0);
2e8cf49e 7794
2cdad34c 7795 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
7796 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
7797 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7798}
7799
7800/* Load 64 bit unscaled signed 9 bit. */
7801static void
7802fldurd (sim_cpu *cpu, int32_t offset)
7803{
ef0d8ffc
NC
7804 unsigned int rn = INSTR (9, 5);
7805 unsigned int st = INSTR (4, 0);
2e8cf49e 7806
2cdad34c 7807 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
7808 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64
7809 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7810}
7811
7812/* Load 128 bit unscaled signed 9 bit. */
7813static void
7814fldurq (sim_cpu *cpu, int32_t offset)
7815{
ef0d8ffc
NC
7816 unsigned int rn = INSTR (9, 5);
7817 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7818 FRegister a;
7819 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
7820
2cdad34c 7821 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7822 aarch64_get_mem_long_double (cpu, addr, & a);
7823 aarch64_set_FP_long_double (cpu, st, a);
7824}
7825
7826/* TODO store 8 bit unscaled signed 9 bit. */
7827/* TODO store 16 bit unscaled signed 9 bit. */
7828
7829
7830/* 1 source. */
7831
7832/* Float absolute value. */
7833static void
7834fabss (sim_cpu *cpu)
7835{
ef0d8ffc
NC
7836 unsigned sn = INSTR (9, 5);
7837 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7838 float value = aarch64_get_FP_float (cpu, sn);
7839
2cdad34c 7840 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7841 aarch64_set_FP_float (cpu, sd, fabsf (value));
7842}
7843
7844/* Double absolute value. */
7845static void
7846fabcpu (sim_cpu *cpu)
7847{
ef0d8ffc
NC
7848 unsigned sn = INSTR (9, 5);
7849 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7850 double value = aarch64_get_FP_double (cpu, sn);
7851
2cdad34c 7852 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7853 aarch64_set_FP_double (cpu, sd, fabs (value));
7854}
7855
7856/* Float negative value. */
7857static void
7858fnegs (sim_cpu *cpu)
7859{
ef0d8ffc
NC
7860 unsigned sn = INSTR (9, 5);
7861 unsigned sd = INSTR (4, 0);
2e8cf49e 7862
2cdad34c 7863 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7864 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sn));
7865}
7866
7867/* Double negative value. */
7868static void
7869fnegd (sim_cpu *cpu)
7870{
ef0d8ffc
NC
7871 unsigned sn = INSTR (9, 5);
7872 unsigned sd = INSTR (4, 0);
2e8cf49e 7873
2cdad34c 7874 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7875 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sn));
7876}
7877
7878/* Float square root. */
7879static void
7880fsqrts (sim_cpu *cpu)
7881{
ef0d8ffc
NC
7882 unsigned sn = INSTR (9, 5);
7883 unsigned sd = INSTR (4, 0);
2e8cf49e 7884
2cdad34c 7885 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
0f118bc7 7886 aarch64_set_FP_float (cpu, sd, sqrtf (aarch64_get_FP_float (cpu, sn)));
2e8cf49e
NC
7887}
7888
7889/* Double square root. */
7890static void
7891fsqrtd (sim_cpu *cpu)
7892{
ef0d8ffc
NC
7893 unsigned sn = INSTR (9, 5);
7894 unsigned sd = INSTR (4, 0);
2e8cf49e 7895
2cdad34c 7896 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7897 aarch64_set_FP_double (cpu, sd,
7898 sqrt (aarch64_get_FP_double (cpu, sn)));
7899}
7900
7901/* Convert double to float. */
7902static void
7903fcvtds (sim_cpu *cpu)
7904{
ef0d8ffc
NC
7905 unsigned sn = INSTR (9, 5);
7906 unsigned sd = INSTR (4, 0);
2e8cf49e 7907
2cdad34c 7908 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7909 aarch64_set_FP_float (cpu, sd, (float) aarch64_get_FP_double (cpu, sn));
7910}
7911
7912/* Convert float to double. */
7913static void
7914fcvtcpu (sim_cpu *cpu)
7915{
ef0d8ffc
NC
7916 unsigned sn = INSTR (9, 5);
7917 unsigned sd = INSTR (4, 0);
2e8cf49e 7918
2cdad34c 7919 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
7920 aarch64_set_FP_double (cpu, sd, (double) aarch64_get_FP_float (cpu, sn));
7921}
7922
7923static void
7924do_FRINT (sim_cpu *cpu)
7925{
7926 /* instr[31,23] = 0001 1110 0
7927 instr[22] = single(0)/double(1)
7928 instr[21,18] = 1001
7929 instr[17,15] = rounding mode
7930 instr[14,10] = 10000
7931 instr[9,5] = source
7932 instr[4,0] = dest */
7933
7934 float val;
ef0d8ffc
NC
7935 unsigned rs = INSTR (9, 5);
7936 unsigned rd = INSTR (4, 0);
7937 unsigned int rmode = INSTR (17, 15);
2e8cf49e
NC
7938
7939 NYI_assert (31, 23, 0x03C);
7940 NYI_assert (21, 18, 0x9);
7941 NYI_assert (14, 10, 0x10);
7942
7943 if (rmode == 6 || rmode == 7)
7944 /* FIXME: Add support for rmode == 6 exactness check. */
7945 rmode = uimm (aarch64_get_FPSR (cpu), 23, 22);
7946
2cdad34c 7947 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 7948 if (INSTR (22, 22))
2e8cf49e
NC
7949 {
7950 double val = aarch64_get_FP_double (cpu, rs);
7951
7952 switch (rmode)
7953 {
7954 case 0: /* mode N: nearest or even. */
7955 {
7956 double rval = round (val);
7957
7958 if (val - rval == 0.5)
7959 {
7960 if (((rval / 2.0) * 2.0) != rval)
7961 rval += 1.0;
7962 }
7963
7964 aarch64_set_FP_double (cpu, rd, round (val));
7965 return;
7966 }
7967
7968 case 1: /* mode P: towards +inf. */
7969 if (val < 0.0)
7970 aarch64_set_FP_double (cpu, rd, trunc (val));
7971 else
7972 aarch64_set_FP_double (cpu, rd, round (val));
7973 return;
7974
7975 case 2: /* mode M: towards -inf. */
7976 if (val < 0.0)
7977 aarch64_set_FP_double (cpu, rd, round (val));
7978 else
7979 aarch64_set_FP_double (cpu, rd, trunc (val));
7980 return;
7981
7982 case 3: /* mode Z: towards 0. */
7983 aarch64_set_FP_double (cpu, rd, trunc (val));
7984 return;
7985
7986 case 4: /* mode A: away from 0. */
7987 aarch64_set_FP_double (cpu, rd, round (val));
7988 return;
7989
7990 case 6: /* mode X: use FPCR with exactness check. */
7991 case 7: /* mode I: use FPCR mode. */
7992 HALT_NYI;
7993
7994 default:
7995 HALT_UNALLOC;
7996 }
7997 }
7998
7999 val = aarch64_get_FP_float (cpu, rs);
8000
8001 switch (rmode)
8002 {
8003 case 0: /* mode N: nearest or even. */
8004 {
8005 float rval = roundf (val);
8006
8007 if (val - rval == 0.5)
8008 {
8009 if (((rval / 2.0) * 2.0) != rval)
8010 rval += 1.0;
8011 }
8012
8013 aarch64_set_FP_float (cpu, rd, rval);
8014 return;
8015 }
8016
8017 case 1: /* mode P: towards +inf. */
8018 if (val < 0.0)
8019 aarch64_set_FP_float (cpu, rd, truncf (val));
8020 else
8021 aarch64_set_FP_float (cpu, rd, roundf (val));
8022 return;
8023
8024 case 2: /* mode M: towards -inf. */
8025 if (val < 0.0)
8026 aarch64_set_FP_float (cpu, rd, truncf (val));
8027 else
8028 aarch64_set_FP_float (cpu, rd, roundf (val));
8029 return;
8030
8031 case 3: /* mode Z: towards 0. */
8032 aarch64_set_FP_float (cpu, rd, truncf (val));
8033 return;
8034
8035 case 4: /* mode A: away from 0. */
8036 aarch64_set_FP_float (cpu, rd, roundf (val));
8037 return;
8038
8039 case 6: /* mode X: use FPCR with exactness check. */
8040 case 7: /* mode I: use FPCR mode. */
8041 HALT_NYI;
8042
8043 default:
8044 HALT_UNALLOC;
8045 }
8046}
8047
5ab6d79e
NC
8048/* Convert half to float. */
8049static void
ef0d8ffc 8050do_FCVT_half_to_single (sim_cpu *cpu)
5ab6d79e
NC
8051{
8052 unsigned rn = INSTR (9, 5);
8053 unsigned rd = INSTR (4, 0);
8054
8055 NYI_assert (31, 10, 0x7B890);
8056
2cdad34c 8057 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8058 aarch64_set_FP_float (cpu, rd, (float) aarch64_get_FP_half (cpu, rn));
8059}
8060
7517e550 8061/* Convert half to double. */
5ab6d79e 8062static void
ef0d8ffc 8063do_FCVT_half_to_double (sim_cpu *cpu)
5ab6d79e
NC
8064{
8065 unsigned rn = INSTR (9, 5);
8066 unsigned rd = INSTR (4, 0);
8067
8068 NYI_assert (31, 10, 0x7B8B0);
ef0d8ffc 8069
2cdad34c 8070 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8071 aarch64_set_FP_double (cpu, rd, (double) aarch64_get_FP_half (cpu, rn));
8072}
8073
8074static void
ef0d8ffc 8075do_FCVT_single_to_half (sim_cpu *cpu)
5ab6d79e
NC
8076{
8077 unsigned rn = INSTR (9, 5);
8078 unsigned rd = INSTR (4, 0);
8079
8080 NYI_assert (31, 10, 0x788F0);
8081
2cdad34c 8082 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8083 aarch64_set_FP_half (cpu, rd, aarch64_get_FP_float (cpu, rn));
8084}
8085
7517e550 8086/* Convert double to half. */
5ab6d79e 8087static void
ef0d8ffc 8088do_FCVT_double_to_half (sim_cpu *cpu)
5ab6d79e
NC
8089{
8090 unsigned rn = INSTR (9, 5);
8091 unsigned rd = INSTR (4, 0);
8092
8093 NYI_assert (31, 10, 0x798F0);
ef0d8ffc 8094
2cdad34c 8095 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8096 aarch64_set_FP_half (cpu, rd, (float) aarch64_get_FP_double (cpu, rn));
8097}
8098
2e8cf49e
NC
8099static void
8100dexSimpleFPDataProc1Source (sim_cpu *cpu)
8101{
8102 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
8103 instr[30] = 0
8104 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
8105 instr[28,25] = 1111
8106 instr[24] = 0
8107 instr[23,22] ==> type : 00 ==> source is single,
8108 01 ==> source is double
8109 10 ==> UNALLOC
8110 11 ==> UNALLOC or source is half
8111 instr[21] = 1
8112 instr[20,15] ==> opcode : with type 00 or 01
8113 000000 ==> FMOV, 000001 ==> FABS,
8114 000010 ==> FNEG, 000011 ==> FSQRT,
8115 000100 ==> UNALLOC, 000101 ==> FCVT,(to single/double)
8116 000110 ==> UNALLOC, 000111 ==> FCVT (to half)
8117 001000 ==> FRINTN, 001001 ==> FRINTP,
8118 001010 ==> FRINTM, 001011 ==> FRINTZ,
8119 001100 ==> FRINTA, 001101 ==> UNALLOC
8120 001110 ==> FRINTX, 001111 ==> FRINTI
8121 with type 11
8122 000100 ==> FCVT (half-to-single)
8123 000101 ==> FCVT (half-to-double)
8124 instr[14,10] = 10000. */
8125
7517e550 8126 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
8127 uint32_t type = INSTR (23, 22);
8128 uint32_t opcode = INSTR (20, 15);
2e8cf49e
NC
8129
8130 if (M_S != 0)
8131 HALT_UNALLOC;
8132
8133 if (type == 3)
8134 {
5ab6d79e
NC
8135 if (opcode == 4)
8136 do_FCVT_half_to_single (cpu);
8137 else if (opcode == 5)
8138 do_FCVT_half_to_double (cpu);
2e8cf49e
NC
8139 else
8140 HALT_UNALLOC;
5ab6d79e 8141 return;
2e8cf49e
NC
8142 }
8143
8144 if (type == 2)
8145 HALT_UNALLOC;
8146
8147 switch (opcode)
8148 {
8149 case 0:
8150 if (type)
8151 ffmovd (cpu);
8152 else
8153 ffmovs (cpu);
8154 return;
8155
8156 case 1:
8157 if (type)
8158 fabcpu (cpu);
8159 else
8160 fabss (cpu);
8161 return;
8162
8163 case 2:
8164 if (type)
8165 fnegd (cpu);
8166 else
8167 fnegs (cpu);
8168 return;
8169
8170 case 3:
8171 if (type)
8172 fsqrtd (cpu);
8173 else
8174 fsqrts (cpu);
8175 return;
8176
8177 case 4:
8178 if (type)
8179 fcvtds (cpu);
8180 else
8181 HALT_UNALLOC;
8182 return;
8183
8184 case 5:
8185 if (type)
8186 HALT_UNALLOC;
8187 fcvtcpu (cpu);
8188 return;
8189
8190 case 8: /* FRINTN etc. */
8191 case 9:
8192 case 10:
8193 case 11:
8194 case 12:
8195 case 14:
8196 case 15:
8197 do_FRINT (cpu);
8198 return;
8199
5ab6d79e
NC
8200 case 7:
8201 if (INSTR (22, 22))
8202 do_FCVT_double_to_half (cpu);
8203 else
8204 do_FCVT_single_to_half (cpu);
8205 return;
8206
2e8cf49e
NC
8207 case 13:
8208 HALT_NYI;
8209
8210 default:
8211 HALT_UNALLOC;
8212 }
8213}
8214
8215/* 32 bit signed int to float. */
8216static void
8217scvtf32 (sim_cpu *cpu)
8218{
ef0d8ffc
NC
8219 unsigned rn = INSTR (9, 5);
8220 unsigned sd = INSTR (4, 0);
2e8cf49e 8221
2cdad34c 8222 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8223 aarch64_set_FP_float
8224 (cpu, sd, (float) aarch64_get_reg_s32 (cpu, rn, NO_SP));
8225}
8226
8227/* signed int to float. */
8228static void
8229scvtf (sim_cpu *cpu)
8230{
ef0d8ffc
NC
8231 unsigned rn = INSTR (9, 5);
8232 unsigned sd = INSTR (4, 0);
2e8cf49e 8233
2cdad34c 8234 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8235 aarch64_set_FP_float
8236 (cpu, sd, (float) aarch64_get_reg_s64 (cpu, rn, NO_SP));
8237}
8238
8239/* 32 bit signed int to double. */
8240static void
8241scvtd32 (sim_cpu *cpu)
8242{
ef0d8ffc
NC
8243 unsigned rn = INSTR (9, 5);
8244 unsigned sd = INSTR (4, 0);
2e8cf49e 8245
2cdad34c 8246 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8247 aarch64_set_FP_double
8248 (cpu, sd, (double) aarch64_get_reg_s32 (cpu, rn, NO_SP));
8249}
8250
8251/* signed int to double. */
8252static void
8253scvtd (sim_cpu *cpu)
8254{
ef0d8ffc
NC
8255 unsigned rn = INSTR (9, 5);
8256 unsigned sd = INSTR (4, 0);
2e8cf49e 8257
2cdad34c 8258 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8259 aarch64_set_FP_double
8260 (cpu, sd, (double) aarch64_get_reg_s64 (cpu, rn, NO_SP));
8261}
8262
8263static const float FLOAT_INT_MAX = (float) INT_MAX;
8264static const float FLOAT_INT_MIN = (float) INT_MIN;
8265static const double DOUBLE_INT_MAX = (double) INT_MAX;
8266static const double DOUBLE_INT_MIN = (double) INT_MIN;
8267static const float FLOAT_LONG_MAX = (float) LONG_MAX;
8268static const float FLOAT_LONG_MIN = (float) LONG_MIN;
8269static const double DOUBLE_LONG_MAX = (double) LONG_MAX;
8270static const double DOUBLE_LONG_MIN = (double) LONG_MIN;
8271
c0386d4d
JW
8272#define UINT_MIN 0
8273#define ULONG_MIN 0
8274static const float FLOAT_UINT_MAX = (float) UINT_MAX;
8275static const float FLOAT_UINT_MIN = (float) UINT_MIN;
8276static const double DOUBLE_UINT_MAX = (double) UINT_MAX;
8277static const double DOUBLE_UINT_MIN = (double) UINT_MIN;
8278static const float FLOAT_ULONG_MAX = (float) ULONG_MAX;
8279static const float FLOAT_ULONG_MIN = (float) ULONG_MIN;
8280static const double DOUBLE_ULONG_MAX = (double) ULONG_MAX;
8281static const double DOUBLE_ULONG_MIN = (double) ULONG_MIN;
8282
2e8cf49e
NC
8283/* Check for FP exception conditions:
8284 NaN raises IO
8285 Infinity raises IO
8286 Out of Range raises IO and IX and saturates value
8287 Denormal raises ID and IX and sets to zero. */
8288#define RAISE_EXCEPTIONS(F, VALUE, FTYPE, ITYPE) \
8289 do \
8290 { \
8291 switch (fpclassify (F)) \
8292 { \
8293 case FP_INFINITE: \
8294 case FP_NAN: \
8295 aarch64_set_FPSR (cpu, IO); \
8296 if (signbit (F)) \
8297 VALUE = ITYPE##_MAX; \
8298 else \
8299 VALUE = ITYPE##_MIN; \
8300 break; \
8301 \
8302 case FP_NORMAL: \
8303 if (F >= FTYPE##_##ITYPE##_MAX) \
8304 { \
8305 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
8306 VALUE = ITYPE##_MAX; \
8307 } \
8308 else if (F <= FTYPE##_##ITYPE##_MIN) \
8309 { \
8310 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
8311 VALUE = ITYPE##_MIN; \
8312 } \
8313 break; \
8314 \
8315 case FP_SUBNORMAL: \
8316 aarch64_set_FPSR_bits (cpu, IO | IX | ID, IX | ID); \
8317 VALUE = 0; \
8318 break; \
8319 \
8320 default: \
8321 case FP_ZERO: \
8322 VALUE = 0; \
8323 break; \
8324 } \
8325 } \
8326 while (0)
8327
8328/* 32 bit convert float to signed int truncate towards zero. */
8329static void
8330fcvtszs32 (sim_cpu *cpu)
8331{
ef0d8ffc
NC
8332 unsigned sn = INSTR (9, 5);
8333 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8334 /* TODO : check that this rounds toward zero. */
8335 float f = aarch64_get_FP_float (cpu, sn);
8336 int32_t value = (int32_t) f;
8337
8338 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
8339
2cdad34c 8340 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8341 /* Avoid sign extension to 64 bit. */
8342 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8343}
8344
8345/* 64 bit convert float to signed int truncate towards zero. */
8346static void
8347fcvtszs (sim_cpu *cpu)
8348{
ef0d8ffc
NC
8349 unsigned sn = INSTR (9, 5);
8350 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8351 float f = aarch64_get_FP_float (cpu, sn);
8352 int64_t value = (int64_t) f;
8353
8354 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
8355
2cdad34c 8356 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8357 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8358}
8359
8360/* 32 bit convert double to signed int truncate towards zero. */
8361static void
8362fcvtszd32 (sim_cpu *cpu)
8363{
ef0d8ffc
NC
8364 unsigned sn = INSTR (9, 5);
8365 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8366 /* TODO : check that this rounds toward zero. */
8367 double d = aarch64_get_FP_double (cpu, sn);
8368 int32_t value = (int32_t) d;
8369
8370 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
8371
2cdad34c 8372 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8373 /* Avoid sign extension to 64 bit. */
8374 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8375}
8376
8377/* 64 bit convert double to signed int truncate towards zero. */
8378static void
8379fcvtszd (sim_cpu *cpu)
8380{
ef0d8ffc
NC
8381 unsigned sn = INSTR (9, 5);
8382 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8383 /* TODO : check that this rounds toward zero. */
8384 double d = aarch64_get_FP_double (cpu, sn);
8385 int64_t value;
8386
8387 value = (int64_t) d;
8388
8389 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
8390
2cdad34c 8391 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8392 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8393}
8394
8395static void
8396do_fcvtzu (sim_cpu *cpu)
8397{
8398 /* instr[31] = size: 32-bit (0), 64-bit (1)
8399 instr[30,23] = 00111100
8400 instr[22] = type: single (0)/ double (1)
8401 instr[21] = enable (0)/disable(1) precision
8402 instr[20,16] = 11001
8403 instr[15,10] = precision
8404 instr[9,5] = Rs
8405 instr[4,0] = Rd. */
8406
ef0d8ffc
NC
8407 unsigned rs = INSTR (9, 5);
8408 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8409
8410 NYI_assert (30, 23, 0x3C);
8411 NYI_assert (20, 16, 0x19);
8412
ef0d8ffc 8413 if (INSTR (21, 21) != 1)
2e8cf49e
NC
8414 /* Convert to fixed point. */
8415 HALT_NYI;
8416
2cdad34c 8417 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8418 if (INSTR (31, 31))
2e8cf49e
NC
8419 {
8420 /* Convert to unsigned 64-bit integer. */
ef0d8ffc 8421 if (INSTR (22, 22))
2e8cf49e
NC
8422 {
8423 double d = aarch64_get_FP_double (cpu, rs);
8424 uint64_t value = (uint64_t) d;
8425
8426 /* Do not raise an exception if we have reached ULONG_MAX. */
ce224813 8427 if (value != (1ULL << 63))
c0386d4d 8428 RAISE_EXCEPTIONS (d, value, DOUBLE, ULONG);
2e8cf49e
NC
8429
8430 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8431 }
8432 else
8433 {
8434 float f = aarch64_get_FP_float (cpu, rs);
8435 uint64_t value = (uint64_t) f;
8436
8437 /* Do not raise an exception if we have reached ULONG_MAX. */
ce224813 8438 if (value != (1ULL << 63))
c0386d4d 8439 RAISE_EXCEPTIONS (f, value, FLOAT, ULONG);
2e8cf49e
NC
8440
8441 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8442 }
8443 }
8444 else
8445 {
8446 uint32_t value;
8447
8448 /* Convert to unsigned 32-bit integer. */
ef0d8ffc 8449 if (INSTR (22, 22))
2e8cf49e
NC
8450 {
8451 double d = aarch64_get_FP_double (cpu, rs);
8452
8453 value = (uint32_t) d;
8454 /* Do not raise an exception if we have reached UINT_MAX. */
8455 if (value != (1UL << 31))
c0386d4d 8456 RAISE_EXCEPTIONS (d, value, DOUBLE, UINT);
2e8cf49e
NC
8457 }
8458 else
8459 {
8460 float f = aarch64_get_FP_float (cpu, rs);
8461
8462 value = (uint32_t) f;
8463 /* Do not raise an exception if we have reached UINT_MAX. */
8464 if (value != (1UL << 31))
c0386d4d 8465 RAISE_EXCEPTIONS (f, value, FLOAT, UINT);
2e8cf49e
NC
8466 }
8467
8468 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8469 }
8470}
8471
8472static void
8473do_UCVTF (sim_cpu *cpu)
8474{
8475 /* instr[31] = size: 32-bit (0), 64-bit (1)
8476 instr[30,23] = 001 1110 0
8477 instr[22] = type: single (0)/ double (1)
8478 instr[21] = enable (0)/disable(1) precision
8479 instr[20,16] = 0 0011
8480 instr[15,10] = precision
8481 instr[9,5] = Rs
8482 instr[4,0] = Rd. */
8483
ef0d8ffc
NC
8484 unsigned rs = INSTR (9, 5);
8485 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8486
8487 NYI_assert (30, 23, 0x3C);
8488 NYI_assert (20, 16, 0x03);
8489
ef0d8ffc 8490 if (INSTR (21, 21) != 1)
2e8cf49e
NC
8491 HALT_NYI;
8492
8493 /* FIXME: Add exception raising. */
2cdad34c 8494 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8495 if (INSTR (31, 31))
2e8cf49e
NC
8496 {
8497 uint64_t value = aarch64_get_reg_u64 (cpu, rs, NO_SP);
8498
ef0d8ffc 8499 if (INSTR (22, 22))
2e8cf49e
NC
8500 aarch64_set_FP_double (cpu, rd, (double) value);
8501 else
8502 aarch64_set_FP_float (cpu, rd, (float) value);
8503 }
8504 else
8505 {
8506 uint32_t value = aarch64_get_reg_u32 (cpu, rs, NO_SP);
8507
ef0d8ffc 8508 if (INSTR (22, 22))
2e8cf49e
NC
8509 aarch64_set_FP_double (cpu, rd, (double) value);
8510 else
8511 aarch64_set_FP_float (cpu, rd, (float) value);
8512 }
8513}
8514
8515static void
8516float_vector_move (sim_cpu *cpu)
8517{
8518 /* instr[31,17] == 100 1111 0101 0111
8519 instr[16] ==> direction 0=> to GR, 1=> from GR
8520 instr[15,10] => ???
8521 instr[9,5] ==> source
8522 instr[4,0] ==> dest. */
8523
ef0d8ffc
NC
8524 unsigned rn = INSTR (9, 5);
8525 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8526
8527 NYI_assert (31, 17, 0x4F57);
8528
ef0d8ffc 8529 if (INSTR (15, 10) != 0)
2e8cf49e
NC
8530 HALT_UNALLOC;
8531
2cdad34c 8532 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8533 if (INSTR (16, 16))
2e8cf49e
NC
8534 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_reg_u64 (cpu, rn, NO_SP));
8535 else
8536 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, rn, 1));
8537}
8538
8539static void
8540dexSimpleFPIntegerConvert (sim_cpu *cpu)
8541{
8542 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8543 instr[30 = 0
8544 instr[29] = S : 0 ==> OK, 1 ==> UNALLOC
8545 instr[28,25] = 1111
8546 instr[24] = 0
8547 instr[23,22] = type : 00 ==> single, 01 ==> double, 1x ==> UNALLOC
8548 instr[21] = 1
8549 instr[20,19] = rmode
8550 instr[18,16] = opcode
8551 instr[15,10] = 10 0000 */
8552
8553 uint32_t rmode_opcode;
8554 uint32_t size_type;
8555 uint32_t type;
8556 uint32_t size;
8557 uint32_t S;
8558
ef0d8ffc 8559 if (INSTR (31, 17) == 0x4F57)
2e8cf49e
NC
8560 {
8561 float_vector_move (cpu);
8562 return;
8563 }
8564
ef0d8ffc
NC
8565 size = INSTR (31, 31);
8566 S = INSTR (29, 29);
2e8cf49e
NC
8567 if (S != 0)
8568 HALT_UNALLOC;
8569
ef0d8ffc 8570 type = INSTR (23, 22);
2e8cf49e
NC
8571 if (type > 1)
8572 HALT_UNALLOC;
8573
ef0d8ffc 8574 rmode_opcode = INSTR (20, 16);
2e8cf49e
NC
8575 size_type = (size << 1) | type; /* 0==32f, 1==32d, 2==64f, 3==64d. */
8576
8577 switch (rmode_opcode)
8578 {
8579 case 2: /* SCVTF. */
8580 switch (size_type)
8581 {
8582 case 0: scvtf32 (cpu); return;
8583 case 1: scvtd32 (cpu); return;
8584 case 2: scvtf (cpu); return;
8585 case 3: scvtd (cpu); return;
2e8cf49e
NC
8586 }
8587
8588 case 6: /* FMOV GR, Vec. */
8589 switch (size_type)
8590 {
8591 case 0: gfmovs (cpu); return;
8592 case 3: gfmovd (cpu); return;
8593 default: HALT_UNALLOC;
8594 }
8595
8596 case 7: /* FMOV vec, GR. */
8597 switch (size_type)
8598 {
8599 case 0: fgmovs (cpu); return;
8600 case 3: fgmovd (cpu); return;
8601 default: HALT_UNALLOC;
8602 }
8603
8604 case 24: /* FCVTZS. */
8605 switch (size_type)
8606 {
8607 case 0: fcvtszs32 (cpu); return;
8608 case 1: fcvtszd32 (cpu); return;
8609 case 2: fcvtszs (cpu); return;
8610 case 3: fcvtszd (cpu); return;
2e8cf49e
NC
8611 }
8612
8613 case 25: do_fcvtzu (cpu); return;
8614 case 3: do_UCVTF (cpu); return;
8615
8616 case 0: /* FCVTNS. */
8617 case 1: /* FCVTNU. */
8618 case 4: /* FCVTAS. */
8619 case 5: /* FCVTAU. */
8620 case 8: /* FCVPTS. */
8621 case 9: /* FCVTPU. */
8622 case 16: /* FCVTMS. */
8623 case 17: /* FCVTMU. */
8624 default:
8625 HALT_NYI;
8626 }
8627}
8628
8629static void
8630set_flags_for_float_compare (sim_cpu *cpu, float fvalue1, float fvalue2)
8631{
8632 uint32_t flags;
8633
87903eaf 8634 /* FIXME: Add exception raising. */
2e8cf49e
NC
8635 if (isnan (fvalue1) || isnan (fvalue2))
8636 flags = C|V;
87903eaf
JW
8637 else if (isinf (fvalue1) && isinf (fvalue2))
8638 {
8639 /* Subtracting two infinities may give a NaN. We only need to compare
8640 the signs, which we can get from isinf. */
8641 int result = isinf (fvalue1) - isinf (fvalue2);
8642
8643 if (result == 0)
8644 flags = Z|C;
8645 else if (result < 0)
8646 flags = N;
8647 else /* (result > 0). */
8648 flags = C;
8649 }
2e8cf49e
NC
8650 else
8651 {
8652 float result = fvalue1 - fvalue2;
8653
8654 if (result == 0.0)
8655 flags = Z|C;
8656 else if (result < 0)
8657 flags = N;
8658 else /* (result > 0). */
8659 flags = C;
8660 }
8661
8662 aarch64_set_CPSR (cpu, flags);
8663}
8664
8665static void
8666fcmps (sim_cpu *cpu)
8667{
ef0d8ffc
NC
8668 unsigned sm = INSTR (20, 16);
8669 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8670
8671 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8672 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8673
2cdad34c 8674 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8675 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8676}
8677
8678/* Float compare to zero -- Invalid Operation exception
8679 only on signaling NaNs. */
8680static void
8681fcmpzs (sim_cpu *cpu)
8682{
ef0d8ffc 8683 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8684 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8685
2cdad34c 8686 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8687 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8688}
8689
8690/* Float compare -- Invalid Operation exception on all NaNs. */
8691static void
8692fcmpes (sim_cpu *cpu)
8693{
ef0d8ffc
NC
8694 unsigned sm = INSTR (20, 16);
8695 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8696
8697 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8698 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8699
2cdad34c 8700 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8701 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8702}
8703
8704/* Float compare to zero -- Invalid Operation exception on all NaNs. */
8705static void
8706fcmpzes (sim_cpu *cpu)
8707{
ef0d8ffc 8708 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8709 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8710
2cdad34c 8711 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8712 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8713}
8714
8715static void
8716set_flags_for_double_compare (sim_cpu *cpu, double dval1, double dval2)
8717{
8718 uint32_t flags;
8719
87903eaf 8720 /* FIXME: Add exception raising. */
2e8cf49e
NC
8721 if (isnan (dval1) || isnan (dval2))
8722 flags = C|V;
87903eaf
JW
8723 else if (isinf (dval1) && isinf (dval2))
8724 {
8725 /* Subtracting two infinities may give a NaN. We only need to compare
8726 the signs, which we can get from isinf. */
8727 int result = isinf (dval1) - isinf (dval2);
8728
8729 if (result == 0)
8730 flags = Z|C;
8731 else if (result < 0)
8732 flags = N;
8733 else /* (result > 0). */
8734 flags = C;
8735 }
2e8cf49e
NC
8736 else
8737 {
8738 double result = dval1 - dval2;
8739
8740 if (result == 0.0)
8741 flags = Z|C;
8742 else if (result < 0)
8743 flags = N;
8744 else /* (result > 0). */
8745 flags = C;
8746 }
8747
8748 aarch64_set_CPSR (cpu, flags);
8749}
8750
8751/* Double compare -- Invalid Operation exception only on signaling NaNs. */
8752static void
8753fcmpd (sim_cpu *cpu)
8754{
ef0d8ffc
NC
8755 unsigned sm = INSTR (20, 16);
8756 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8757
8758 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8759 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8760
2cdad34c 8761 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8762 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8763}
8764
8765/* Double compare to zero -- Invalid Operation exception
8766 only on signaling NaNs. */
8767static void
8768fcmpzd (sim_cpu *cpu)
8769{
ef0d8ffc 8770 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8771 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8772
2cdad34c 8773 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8774 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8775}
8776
8777/* Double compare -- Invalid Operation exception on all NaNs. */
8778static void
8779fcmped (sim_cpu *cpu)
8780{
ef0d8ffc
NC
8781 unsigned sm = INSTR (20, 16);
8782 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8783
8784 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8785 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8786
2cdad34c 8787 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8788 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8789}
8790
8791/* Double compare to zero -- Invalid Operation exception on all NaNs. */
8792static void
8793fcmpzed (sim_cpu *cpu)
8794{
ef0d8ffc 8795 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8796 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8797
2cdad34c 8798 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8799 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8800}
8801
8802static void
8803dexSimpleFPCompare (sim_cpu *cpu)
8804{
8805 /* assert instr[28,25] == 1111
8806 instr[30:24:21:13,10] = 0011000
8807 instr[31] = M : 0 ==> OK, 1 ==> UNALLOC
8808 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
8809 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
8810 instr[15,14] ==> op : 00 ==> OK, ow ==> UNALLOC
8811 instr[4,0] ==> opcode2 : 00000 ==> FCMP, 10000 ==> FCMPE,
8812 01000 ==> FCMPZ, 11000 ==> FCMPEZ,
8813 ow ==> UNALLOC */
8814 uint32_t dispatch;
7517e550 8815 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
8816 uint32_t type = INSTR (23, 22);
8817 uint32_t op = INSTR (15, 14);
8818 uint32_t op2_2_0 = INSTR (2, 0);
2e8cf49e
NC
8819
8820 if (op2_2_0 != 0)
8821 HALT_UNALLOC;
8822
8823 if (M_S != 0)
8824 HALT_UNALLOC;
8825
8826 if (type > 1)
8827 HALT_UNALLOC;
8828
8829 if (op != 0)
8830 HALT_UNALLOC;
8831
8832 /* dispatch on type and top 2 bits of opcode. */
ef0d8ffc 8833 dispatch = (type << 2) | INSTR (4, 3);
2e8cf49e
NC
8834
8835 switch (dispatch)
8836 {
8837 case 0: fcmps (cpu); return;
8838 case 1: fcmpzs (cpu); return;
8839 case 2: fcmpes (cpu); return;
8840 case 3: fcmpzes (cpu); return;
8841 case 4: fcmpd (cpu); return;
8842 case 5: fcmpzd (cpu); return;
8843 case 6: fcmped (cpu); return;
8844 case 7: fcmpzed (cpu); return;
2e8cf49e
NC
8845 }
8846}
8847
8848static void
8849do_scalar_FADDP (sim_cpu *cpu)
8850{
7517e550 8851 /* instr [31,23] = 0111 1110 0
2e8cf49e 8852 instr [22] = single(0)/double(1)
7517e550 8853 instr [21,10] = 11 0000 1101 10
2e8cf49e
NC
8854 instr [9,5] = Fn
8855 instr [4,0] = Fd. */
8856
ef0d8ffc
NC
8857 unsigned Fn = INSTR (9, 5);
8858 unsigned Fd = INSTR (4, 0);
2e8cf49e
NC
8859
8860 NYI_assert (31, 23, 0x0FC);
8861 NYI_assert (21, 10, 0xC36);
8862
2cdad34c 8863 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8864 if (INSTR (22, 22))
2e8cf49e
NC
8865 {
8866 double val1 = aarch64_get_vec_double (cpu, Fn, 0);
8867 double val2 = aarch64_get_vec_double (cpu, Fn, 1);
8868
8869 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8870 }
8871 else
8872 {
8873 float val1 = aarch64_get_vec_float (cpu, Fn, 0);
8874 float val2 = aarch64_get_vec_float (cpu, Fn, 1);
8875
8876 aarch64_set_FP_float (cpu, Fd, val1 + val2);
8877 }
8878}
8879
8880/* Floating point absolute difference. */
8881
8882static void
8883do_scalar_FABD (sim_cpu *cpu)
8884{
8885 /* instr [31,23] = 0111 1110 1
8886 instr [22] = float(0)/double(1)
8887 instr [21] = 1
8888 instr [20,16] = Rm
8889 instr [15,10] = 1101 01
8890 instr [9, 5] = Rn
8891 instr [4, 0] = Rd. */
8892
ef0d8ffc
NC
8893 unsigned rm = INSTR (20, 16);
8894 unsigned rn = INSTR (9, 5);
8895 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8896
8897 NYI_assert (31, 23, 0x0FD);
8898 NYI_assert (21, 21, 1);
8899 NYI_assert (15, 10, 0x35);
8900
2cdad34c 8901 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 8902 if (INSTR (22, 22))
2e8cf49e
NC
8903 aarch64_set_FP_double (cpu, rd,
8904 fabs (aarch64_get_FP_double (cpu, rn)
8905 - aarch64_get_FP_double (cpu, rm)));
8906 else
8907 aarch64_set_FP_float (cpu, rd,
8908 fabsf (aarch64_get_FP_float (cpu, rn)
8909 - aarch64_get_FP_float (cpu, rm)));
8910}
8911
8912static void
8913do_scalar_CMGT (sim_cpu *cpu)
8914{
8915 /* instr [31,21] = 0101 1110 111
8916 instr [20,16] = Rm
8917 instr [15,10] = 00 1101
8918 instr [9, 5] = Rn
8919 instr [4, 0] = Rd. */
8920
ef0d8ffc
NC
8921 unsigned rm = INSTR (20, 16);
8922 unsigned rn = INSTR (9, 5);
8923 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8924
8925 NYI_assert (31, 21, 0x2F7);
8926 NYI_assert (15, 10, 0x0D);
8927
2cdad34c 8928 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8929 aarch64_set_vec_u64 (cpu, rd, 0,
8930 aarch64_get_vec_u64 (cpu, rn, 0) >
8931 aarch64_get_vec_u64 (cpu, rm, 0) ? -1L : 0L);
8932}
8933
8934static void
8935do_scalar_USHR (sim_cpu *cpu)
8936{
8937 /* instr [31,23] = 0111 1111 0
8938 instr [22,16] = shift amount
8939 instr [15,10] = 0000 01
8940 instr [9, 5] = Rn
8941 instr [4, 0] = Rd. */
8942
5ab6d79e
NC
8943 unsigned amount = 128 - INSTR (22, 16);
8944 unsigned rn = INSTR (9, 5);
8945 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8946
8947 NYI_assert (31, 23, 0x0FE);
8948 NYI_assert (15, 10, 0x01);
8949
2cdad34c 8950 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
8951 aarch64_set_vec_u64 (cpu, rd, 0,
8952 aarch64_get_vec_u64 (cpu, rn, 0) >> amount);
8953}
8954
8955static void
5ab6d79e
NC
8956do_scalar_SSHL (sim_cpu *cpu)
8957{
8958 /* instr [31,21] = 0101 1110 111
8959 instr [20,16] = Rm
8960 instr [15,10] = 0100 01
8961 instr [9, 5] = Rn
8962 instr [4, 0] = Rd. */
8963
8964 unsigned rm = INSTR (20, 16);
8965 unsigned rn = INSTR (9, 5);
8966 unsigned rd = INSTR (4, 0);
8967 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
8968
8969 NYI_assert (31, 21, 0x2F7);
8970 NYI_assert (15, 10, 0x11);
8971
2cdad34c 8972 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
8973 if (shift >= 0)
8974 aarch64_set_vec_s64 (cpu, rd, 0,
8975 aarch64_get_vec_s64 (cpu, rn, 0) << shift);
8976 else
8977 aarch64_set_vec_s64 (cpu, rd, 0,
ef0d8ffc 8978 aarch64_get_vec_s64 (cpu, rn, 0) >> - shift);
5ab6d79e
NC
8979}
8980
ae27d3fe
JW
8981/* Floating point scalar compare greater than or equal to 0. */
8982static void
8983do_scalar_FCMGE_zero (sim_cpu *cpu)
8984{
8985 /* instr [31,23] = 0111 1110 1
8986 instr [22,22] = size
8987 instr [21,16] = 1000 00
8988 instr [15,10] = 1100 10
8989 instr [9, 5] = Rn
8990 instr [4, 0] = Rd. */
8991
8992 unsigned size = INSTR (22, 22);
8993 unsigned rn = INSTR (9, 5);
8994 unsigned rd = INSTR (4, 0);
8995
8996 NYI_assert (31, 23, 0x0FD);
8997 NYI_assert (21, 16, 0x20);
8998 NYI_assert (15, 10, 0x32);
8999
9000 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
9001 if (size)
9002 aarch64_set_vec_u64 (cpu, rd, 0,
9003 aarch64_get_vec_double (cpu, rn, 0) >= 0.0 ? -1 : 0);
9004 else
9005 aarch64_set_vec_u32 (cpu, rd, 0,
9006 aarch64_get_vec_float (cpu, rn, 0) >= 0.0 ? -1 : 0);
9007}
9008
9009/* Floating point scalar compare less than or equal to 0. */
9010static void
9011do_scalar_FCMLE_zero (sim_cpu *cpu)
9012{
9013 /* instr [31,23] = 0111 1110 1
9014 instr [22,22] = size
9015 instr [21,16] = 1000 00
9016 instr [15,10] = 1101 10
9017 instr [9, 5] = Rn
9018 instr [4, 0] = Rd. */
9019
9020 unsigned size = INSTR (22, 22);
9021 unsigned rn = INSTR (9, 5);
9022 unsigned rd = INSTR (4, 0);
9023
9024 NYI_assert (31, 23, 0x0FD);
9025 NYI_assert (21, 16, 0x20);
9026 NYI_assert (15, 10, 0x36);
9027
9028 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
9029 if (size)
9030 aarch64_set_vec_u64 (cpu, rd, 0,
9031 aarch64_get_vec_double (cpu, rn, 0) <= 0.0 ? -1 : 0);
9032 else
9033 aarch64_set_vec_u32 (cpu, rd, 0,
9034 aarch64_get_vec_float (cpu, rn, 0) <= 0.0 ? -1 : 0);
9035}
9036
9037/* Floating point scalar compare greater than 0. */
9038static void
9039do_scalar_FCMGT_zero (sim_cpu *cpu)
9040{
9041 /* instr [31,23] = 0101 1110 1
9042 instr [22,22] = size
9043 instr [21,16] = 1000 00
9044 instr [15,10] = 1100 10
9045 instr [9, 5] = Rn
9046 instr [4, 0] = Rd. */
9047
9048 unsigned size = INSTR (22, 22);
9049 unsigned rn = INSTR (9, 5);
9050 unsigned rd = INSTR (4, 0);
9051
9052 NYI_assert (31, 23, 0x0BD);
9053 NYI_assert (21, 16, 0x20);
9054 NYI_assert (15, 10, 0x32);
9055
9056 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
9057 if (size)
9058 aarch64_set_vec_u64 (cpu, rd, 0,
9059 aarch64_get_vec_double (cpu, rn, 0) > 0.0 ? -1 : 0);
9060 else
9061 aarch64_set_vec_u32 (cpu, rd, 0,
9062 aarch64_get_vec_float (cpu, rn, 0) > 0.0 ? -1 : 0);
9063}
9064
9065/* Floating point scalar compare equal to 0. */
9066static void
9067do_scalar_FCMEQ_zero (sim_cpu *cpu)
9068{
9069 /* instr [31,23] = 0101 1110 1
9070 instr [22,22] = size
9071 instr [21,16] = 1000 00
9072 instr [15,10] = 1101 10
9073 instr [9, 5] = Rn
9074 instr [4, 0] = Rd. */
9075
9076 unsigned size = INSTR (22, 22);
9077 unsigned rn = INSTR (9, 5);
9078 unsigned rd = INSTR (4, 0);
9079
9080 NYI_assert (31, 23, 0x0BD);
9081 NYI_assert (21, 16, 0x20);
9082 NYI_assert (15, 10, 0x36);
9083
9084 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
9085 if (size)
9086 aarch64_set_vec_u64 (cpu, rd, 0,
9087 aarch64_get_vec_double (cpu, rn, 0) == 0.0 ? -1 : 0);
9088 else
9089 aarch64_set_vec_u32 (cpu, rd, 0,
9090 aarch64_get_vec_float (cpu, rn, 0) == 0.0 ? -1 : 0);
9091}
9092
9093/* Floating point scalar compare less than 0. */
9094static void
9095do_scalar_FCMLT_zero (sim_cpu *cpu)
9096{
9097 /* instr [31,23] = 0101 1110 1
9098 instr [22,22] = size
9099 instr [21,16] = 1000 00
9100 instr [15,10] = 1110 10
9101 instr [9, 5] = Rn
9102 instr [4, 0] = Rd. */
9103
9104 unsigned size = INSTR (22, 22);
9105 unsigned rn = INSTR (9, 5);
9106 unsigned rd = INSTR (4, 0);
9107
9108 NYI_assert (31, 23, 0x0BD);
9109 NYI_assert (21, 16, 0x20);
9110 NYI_assert (15, 10, 0x3A);
9111
9112 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
9113 if (size)
9114 aarch64_set_vec_u64 (cpu, rd, 0,
9115 aarch64_get_vec_double (cpu, rn, 0) < 0.0 ? -1 : 0);
9116 else
9117 aarch64_set_vec_u32 (cpu, rd, 0,
9118 aarch64_get_vec_float (cpu, rn, 0) < 0.0 ? -1 : 0);
9119}
9120
5ab6d79e
NC
9121static void
9122do_scalar_shift (sim_cpu *cpu)
2e8cf49e 9123{
5ab6d79e 9124 /* instr [31,23] = 0101 1111 0
2e8cf49e 9125 instr [22,16] = shift amount
5ab6d79e
NC
9126 instr [15,10] = 0101 01 [SHL]
9127 instr [15,10] = 0000 01 [SSHR]
2e8cf49e
NC
9128 instr [9, 5] = Rn
9129 instr [4, 0] = Rd. */
9130
5ab6d79e
NC
9131 unsigned rn = INSTR (9, 5);
9132 unsigned rd = INSTR (4, 0);
9133 unsigned amount;
2e8cf49e
NC
9134
9135 NYI_assert (31, 23, 0x0BE);
2e8cf49e 9136
5ab6d79e 9137 if (INSTR (22, 22) == 0)
2e8cf49e
NC
9138 HALT_UNALLOC;
9139
2cdad34c 9140 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
9141 switch (INSTR (15, 10))
9142 {
9143 case 0x01: /* SSHR */
9144 amount = 128 - INSTR (22, 16);
9145 aarch64_set_vec_s64 (cpu, rd, 0,
9146 aarch64_get_vec_s64 (cpu, rn, 0) >> amount);
9147 return;
9148 case 0x15: /* SHL */
9149 amount = INSTR (22, 16) - 64;
9150 aarch64_set_vec_u64 (cpu, rd, 0,
9151 aarch64_get_vec_u64 (cpu, rn, 0) << amount);
9152 return;
9153 default:
9154 HALT_NYI;
9155 }
2e8cf49e
NC
9156}
9157
9158/* FCMEQ FCMGT FCMGE. */
9159static void
9160do_scalar_FCM (sim_cpu *cpu)
9161{
9162 /* instr [31,30] = 01
9163 instr [29] = U
9164 instr [28,24] = 1 1110
9165 instr [23] = E
9166 instr [22] = size
9167 instr [21] = 1
9168 instr [20,16] = Rm
9169 instr [15,12] = 1110
9170 instr [11] = AC
9171 instr [10] = 1
9172 instr [9, 5] = Rn
9173 instr [4, 0] = Rd. */
9174
ef0d8ffc
NC
9175 unsigned rm = INSTR (20, 16);
9176 unsigned rn = INSTR (9, 5);
9177 unsigned rd = INSTR (4, 0);
7517e550 9178 unsigned EUac = (INSTR (23, 23) << 2) | (INSTR (29, 29) << 1) | INSTR (11, 11);
2e8cf49e
NC
9179 unsigned result;
9180 float val1;
9181 float val2;
9182
9183 NYI_assert (31, 30, 1);
9184 NYI_assert (28, 24, 0x1E);
9185 NYI_assert (21, 21, 1);
9186 NYI_assert (15, 12, 0xE);
9187 NYI_assert (10, 10, 1);
9188
2cdad34c 9189 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9190 if (INSTR (22, 22))
2e8cf49e
NC
9191 {
9192 double val1 = aarch64_get_FP_double (cpu, rn);
9193 double val2 = aarch64_get_FP_double (cpu, rm);
9194
9195 switch (EUac)
9196 {
9197 case 0: /* 000 */
9198 result = val1 == val2;
9199 break;
9200
9201 case 3: /* 011 */
9202 val1 = fabs (val1);
9203 val2 = fabs (val2);
9204 /* Fall through. */
9205 case 2: /* 010 */
9206 result = val1 >= val2;
9207 break;
9208
9209 case 7: /* 111 */
9210 val1 = fabs (val1);
9211 val2 = fabs (val2);
9212 /* Fall through. */
9213 case 6: /* 110 */
9214 result = val1 > val2;
9215 break;
9216
9217 default:
9218 HALT_UNALLOC;
9219 }
9220
9221 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
9222 return;
9223 }
9224
9225 val1 = aarch64_get_FP_float (cpu, rn);
9226 val2 = aarch64_get_FP_float (cpu, rm);
9227
9228 switch (EUac)
9229 {
9230 case 0: /* 000 */
9231 result = val1 == val2;
9232 break;
9233
9234 case 3: /* 011 */
9235 val1 = fabsf (val1);
9236 val2 = fabsf (val2);
9237 /* Fall through. */
9238 case 2: /* 010 */
9239 result = val1 >= val2;
9240 break;
9241
9242 case 7: /* 111 */
9243 val1 = fabsf (val1);
9244 val2 = fabsf (val2);
9245 /* Fall through. */
9246 case 6: /* 110 */
9247 result = val1 > val2;
9248 break;
9249
9250 default:
9251 HALT_UNALLOC;
9252 }
9253
9254 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
9255}
9256
9257/* An alias of DUP. */
9258static void
9259do_scalar_MOV (sim_cpu *cpu)
9260{
9261 /* instr [31,21] = 0101 1110 000
9262 instr [20,16] = imm5
9263 instr [15,10] = 0000 01
9264 instr [9, 5] = Rn
9265 instr [4, 0] = Rd. */
9266
ef0d8ffc
NC
9267 unsigned rn = INSTR (9, 5);
9268 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9269 unsigned index;
9270
9271 NYI_assert (31, 21, 0x2F0);
9272 NYI_assert (15, 10, 0x01);
9273
2cdad34c 9274 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 9275 if (INSTR (16, 16))
2e8cf49e
NC
9276 {
9277 /* 8-bit. */
ef0d8ffc 9278 index = INSTR (20, 17);
2e8cf49e
NC
9279 aarch64_set_vec_u8
9280 (cpu, rd, 0, aarch64_get_vec_u8 (cpu, rn, index));
9281 }
ef0d8ffc 9282 else if (INSTR (17, 17))
2e8cf49e
NC
9283 {
9284 /* 16-bit. */
ef0d8ffc 9285 index = INSTR (20, 18);
2e8cf49e
NC
9286 aarch64_set_vec_u16
9287 (cpu, rd, 0, aarch64_get_vec_u16 (cpu, rn, index));
9288 }
ef0d8ffc 9289 else if (INSTR (18, 18))
2e8cf49e
NC
9290 {
9291 /* 32-bit. */
ef0d8ffc 9292 index = INSTR (20, 19);
2e8cf49e
NC
9293 aarch64_set_vec_u32
9294 (cpu, rd, 0, aarch64_get_vec_u32 (cpu, rn, index));
9295 }
ef0d8ffc 9296 else if (INSTR (19, 19))
2e8cf49e
NC
9297 {
9298 /* 64-bit. */
ef0d8ffc 9299 index = INSTR (20, 20);
2e8cf49e
NC
9300 aarch64_set_vec_u64
9301 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, index));
9302 }
9303 else
9304 HALT_UNALLOC;
9305}
9306
e101a78b
NC
9307static void
9308do_scalar_NEG (sim_cpu *cpu)
9309{
5ab6d79e 9310 /* instr [31,10] = 0111 1110 1110 0000 1011 10
e101a78b
NC
9311 instr [9, 5] = Rn
9312 instr [4, 0] = Rd. */
9313
ef0d8ffc
NC
9314 unsigned rn = INSTR (9, 5);
9315 unsigned rd = INSTR (4, 0);
e101a78b 9316
5ab6d79e 9317 NYI_assert (31, 10, 0x1FB82E);
e101a78b 9318
2cdad34c 9319 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
e101a78b
NC
9320 aarch64_set_vec_u64 (cpu, rd, 0, - aarch64_get_vec_u64 (cpu, rn, 0));
9321}
9322
5ab6d79e
NC
9323static void
9324do_scalar_USHL (sim_cpu *cpu)
9325{
9326 /* instr [31,21] = 0111 1110 111
9327 instr [20,16] = Rm
9328 instr [15,10] = 0100 01
9329 instr [9, 5] = Rn
9330 instr [4, 0] = Rd. */
9331
9332 unsigned rm = INSTR (20, 16);
9333 unsigned rn = INSTR (9, 5);
9334 unsigned rd = INSTR (4, 0);
9335 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
9336
9337 NYI_assert (31, 21, 0x3F7);
9338 NYI_assert (15, 10, 0x11);
9339
2cdad34c 9340 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
9341 if (shift >= 0)
9342 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) << shift);
9343 else
9344 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) >> - shift);
9345}
9346
2e8cf49e
NC
9347static void
9348do_double_add (sim_cpu *cpu)
9349{
5ab6d79e
NC
9350 /* instr [31,21] = 0101 1110 111
9351 instr [20,16] = Fn
9352 instr [15,10] = 1000 01
9353 instr [9,5] = Fm
9354 instr [4,0] = Fd. */
2e8cf49e
NC
9355 unsigned Fd;
9356 unsigned Fm;
9357 unsigned Fn;
9358 double val1;
9359 double val2;
9360
5ab6d79e
NC
9361 NYI_assert (31, 21, 0x2F7);
9362 NYI_assert (15, 10, 0x21);
9363
9364 Fd = INSTR (4, 0);
9365 Fm = INSTR (9, 5);
9366 Fn = INSTR (20, 16);
9367
2cdad34c 9368 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
9369 val1 = aarch64_get_FP_double (cpu, Fm);
9370 val2 = aarch64_get_FP_double (cpu, Fn);
9371
9372 aarch64_set_FP_double (cpu, Fd, val1 + val2);
9373}
9374
7517e550
NC
9375static void
9376do_scalar_UCVTF (sim_cpu *cpu)
9377{
9378 /* instr [31,23] = 0111 1110 0
9379 instr [22] = single(0)/double(1)
9380 instr [21,10] = 10 0001 1101 10
9381 instr [9,5] = rn
9382 instr [4,0] = rd. */
9383
9384 unsigned rn = INSTR (9, 5);
9385 unsigned rd = INSTR (4, 0);
9386
9387 NYI_assert (31, 23, 0x0FC);
9388 NYI_assert (21, 10, 0x876);
9389
2cdad34c 9390 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
7517e550
NC
9391 if (INSTR (22, 22))
9392 {
9393 uint64_t val = aarch64_get_vec_u64 (cpu, rn, 0);
9394
9395 aarch64_set_vec_double (cpu, rd, 0, (double) val);
9396 }
9397 else
9398 {
9399 uint32_t val = aarch64_get_vec_u32 (cpu, rn, 0);
9400
9401 aarch64_set_vec_float (cpu, rd, 0, (float) val);
9402 }
9403}
9404
5ab6d79e
NC
9405static void
9406do_scalar_vec (sim_cpu *cpu)
9407{
9408 /* instr [30] = 1. */
9409 /* instr [28,25] = 1111. */
ef0d8ffc 9410 switch (INSTR (31, 23))
2e8cf49e
NC
9411 {
9412 case 0xBC:
ef0d8ffc 9413 switch (INSTR (15, 10))
2e8cf49e
NC
9414 {
9415 case 0x01: do_scalar_MOV (cpu); return;
9416 case 0x39: do_scalar_FCM (cpu); return;
9417 case 0x3B: do_scalar_FCM (cpu); return;
9418 }
9419 break;
9420
5ab6d79e 9421 case 0xBE: do_scalar_shift (cpu); return;
2e8cf49e
NC
9422
9423 case 0xFC:
ef0d8ffc 9424 switch (INSTR (15, 10))
2e8cf49e 9425 {
7517e550
NC
9426 case 0x36:
9427 switch (INSTR (21, 16))
9428 {
9429 case 0x30: do_scalar_FADDP (cpu); return;
9430 case 0x21: do_scalar_UCVTF (cpu); return;
9431 }
9432 HALT_NYI;
2e8cf49e
NC
9433 case 0x39: do_scalar_FCM (cpu); return;
9434 case 0x3B: do_scalar_FCM (cpu); return;
9435 }
9436 break;
9437
9438 case 0xFD:
ef0d8ffc 9439 switch (INSTR (15, 10))
2e8cf49e
NC
9440 {
9441 case 0x0D: do_scalar_CMGT (cpu); return;
5ab6d79e
NC
9442 case 0x11: do_scalar_USHL (cpu); return;
9443 case 0x2E: do_scalar_NEG (cpu); return;
ae27d3fe 9444 case 0x32: do_scalar_FCMGE_zero (cpu); return;
2e8cf49e 9445 case 0x35: do_scalar_FABD (cpu); return;
ae27d3fe 9446 case 0x36: do_scalar_FCMLE_zero (cpu); return;
2e8cf49e
NC
9447 case 0x39: do_scalar_FCM (cpu); return;
9448 case 0x3B: do_scalar_FCM (cpu); return;
9449 default:
9450 HALT_NYI;
9451 }
9452
9453 case 0xFE: do_scalar_USHR (cpu); return;
5ab6d79e
NC
9454
9455 case 0xBD:
9456 switch (INSTR (15, 10))
9457 {
9458 case 0x21: do_double_add (cpu); return;
9459 case 0x11: do_scalar_SSHL (cpu); return;
ae27d3fe
JW
9460 case 0x32: do_scalar_FCMGT_zero (cpu); return;
9461 case 0x36: do_scalar_FCMEQ_zero (cpu); return;
9462 case 0x3A: do_scalar_FCMLT_zero (cpu); return;
5ab6d79e
NC
9463 default:
9464 HALT_NYI;
9465 }
ef0d8ffc 9466
2e8cf49e 9467 default:
5ab6d79e 9468 HALT_NYI;
2e8cf49e 9469 }
2e8cf49e
NC
9470}
9471
9472static void
9473dexAdvSIMD1 (sim_cpu *cpu)
9474{
9475 /* instr [28,25] = 1 111. */
9476
5ab6d79e 9477 /* We are currently only interested in the basic
2e8cf49e 9478 scalar fp routines which all have bit 30 = 0. */
ef0d8ffc 9479 if (INSTR (30, 30))
5ab6d79e 9480 do_scalar_vec (cpu);
2e8cf49e
NC
9481
9482 /* instr[24] is set for FP data processing 3-source and clear for
9483 all other basic scalar fp instruction groups. */
ef0d8ffc 9484 else if (INSTR (24, 24))
2e8cf49e
NC
9485 dexSimpleFPDataProc3Source (cpu);
9486
9487 /* instr[21] is clear for floating <-> fixed conversions and set for
9488 all other basic scalar fp instruction groups. */
ef0d8ffc 9489 else if (!INSTR (21, 21))
2e8cf49e
NC
9490 dexSimpleFPFixedConvert (cpu);
9491
9492 /* instr[11,10] : 01 ==> cond compare, 10 ==> Data Proc 2 Source
9493 11 ==> cond select, 00 ==> other. */
9494 else
ef0d8ffc 9495 switch (INSTR (11, 10))
2e8cf49e
NC
9496 {
9497 case 1: dexSimpleFPCondCompare (cpu); return;
9498 case 2: dexSimpleFPDataProc2Source (cpu); return;
9499 case 3: dexSimpleFPCondSelect (cpu); return;
9500
9501 default:
9502 /* Now an ordered cascade of tests.
ef0d8ffc
NC
9503 FP immediate has instr [12] == 1.
9504 FP compare has instr [13] == 1.
9505 FP Data Proc 1 Source has instr [14] == 1.
9506 FP floating <--> integer conversions has instr [15] == 0. */
9507 if (INSTR (12, 12))
2e8cf49e
NC
9508 dexSimpleFPImmediate (cpu);
9509
ef0d8ffc 9510 else if (INSTR (13, 13))
2e8cf49e
NC
9511 dexSimpleFPCompare (cpu);
9512
ef0d8ffc 9513 else if (INSTR (14, 14))
2e8cf49e
NC
9514 dexSimpleFPDataProc1Source (cpu);
9515
ef0d8ffc 9516 else if (!INSTR (15, 15))
2e8cf49e
NC
9517 dexSimpleFPIntegerConvert (cpu);
9518
9519 else
9520 /* If we get here then instr[15] == 1 which means UNALLOC. */
9521 HALT_UNALLOC;
9522 }
9523}
9524
9525/* PC relative addressing. */
9526
9527static void
9528pcadr (sim_cpu *cpu)
9529{
9530 /* instr[31] = op : 0 ==> ADR, 1 ==> ADRP
9531 instr[30,29] = immlo
9532 instr[23,5] = immhi. */
9533 uint64_t address;
ef0d8ffc
NC
9534 unsigned rd = INSTR (4, 0);
9535 uint32_t isPage = INSTR (31, 31);
2e8cf49e
NC
9536 union { int64_t u64; uint64_t s64; } imm;
9537 uint64_t offset;
9538
9539 imm.s64 = simm64 (aarch64_get_instr (cpu), 23, 5);
9540 offset = imm.u64;
ef0d8ffc 9541 offset = (offset << 2) | INSTR (30, 29);
2e8cf49e
NC
9542
9543 address = aarch64_get_PC (cpu);
9544
9545 if (isPage)
9546 {
9547 offset <<= 12;
9548 address &= ~0xfff;
9549 }
9550
2cdad34c 9551 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9552 aarch64_set_reg_u64 (cpu, rd, NO_SP, address + offset);
9553}
9554
9555/* Specific decode and execute for group Data Processing Immediate. */
9556
9557static void
9558dexPCRelAddressing (sim_cpu *cpu)
9559{
9560 /* assert instr[28,24] = 10000. */
9561 pcadr (cpu);
9562}
9563
9564/* Immediate logical.
9565 The bimm32/64 argument is constructed by replicating a 2, 4, 8,
9566 16, 32 or 64 bit sequence pulled out at decode and possibly
9567 inverting it..
9568
9569 N.B. the output register (dest) can normally be Xn or SP
9570 the exception occurs for flag setting instructions which may
9571 only use Xn for the output (dest). The input register can
9572 never be SP. */
9573
9574/* 32 bit and immediate. */
9575static void
9576and32 (sim_cpu *cpu, uint32_t bimm)
9577{
ef0d8ffc
NC
9578 unsigned rn = INSTR (9, 5);
9579 unsigned rd = INSTR (4, 0);
2e8cf49e 9580
2cdad34c 9581 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9582 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9583 aarch64_get_reg_u32 (cpu, rn, NO_SP) & bimm);
9584}
9585
9586/* 64 bit and immediate. */
9587static void
9588and64 (sim_cpu *cpu, uint64_t bimm)
9589{
ef0d8ffc
NC
9590 unsigned rn = INSTR (9, 5);
9591 unsigned rd = INSTR (4, 0);
2e8cf49e 9592
2cdad34c 9593 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9594 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9595 aarch64_get_reg_u64 (cpu, rn, NO_SP) & bimm);
9596}
9597
9598/* 32 bit and immediate set flags. */
9599static void
9600ands32 (sim_cpu *cpu, uint32_t bimm)
9601{
ef0d8ffc
NC
9602 unsigned rn = INSTR (9, 5);
9603 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9604
9605 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9606 uint32_t value2 = bimm;
9607
2cdad34c 9608 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9609 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9610 set_flags_for_binop32 (cpu, value1 & value2);
9611}
9612
9613/* 64 bit and immediate set flags. */
9614static void
9615ands64 (sim_cpu *cpu, uint64_t bimm)
9616{
ef0d8ffc
NC
9617 unsigned rn = INSTR (9, 5);
9618 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9619
9620 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9621 uint64_t value2 = bimm;
9622
2cdad34c 9623 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9624 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9625 set_flags_for_binop64 (cpu, value1 & value2);
9626}
9627
9628/* 32 bit exclusive or immediate. */
9629static void
9630eor32 (sim_cpu *cpu, uint32_t bimm)
9631{
ef0d8ffc
NC
9632 unsigned rn = INSTR (9, 5);
9633 unsigned rd = INSTR (4, 0);
2e8cf49e 9634
2cdad34c 9635 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9636 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9637 aarch64_get_reg_u32 (cpu, rn, NO_SP) ^ bimm);
9638}
9639
9640/* 64 bit exclusive or immediate. */
9641static void
9642eor64 (sim_cpu *cpu, uint64_t bimm)
9643{
ef0d8ffc
NC
9644 unsigned rn = INSTR (9, 5);
9645 unsigned rd = INSTR (4, 0);
2e8cf49e 9646
2cdad34c 9647 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9648 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9649 aarch64_get_reg_u64 (cpu, rn, NO_SP) ^ bimm);
9650}
9651
9652/* 32 bit or immediate. */
9653static void
9654orr32 (sim_cpu *cpu, uint32_t bimm)
9655{
ef0d8ffc
NC
9656 unsigned rn = INSTR (9, 5);
9657 unsigned rd = INSTR (4, 0);
2e8cf49e 9658
2cdad34c 9659 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9660 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9661 aarch64_get_reg_u32 (cpu, rn, NO_SP) | bimm);
9662}
9663
9664/* 64 bit or immediate. */
9665static void
9666orr64 (sim_cpu *cpu, uint64_t bimm)
9667{
ef0d8ffc
NC
9668 unsigned rn = INSTR (9, 5);
9669 unsigned rd = INSTR (4, 0);
2e8cf49e 9670
2cdad34c 9671 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9672 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9673 aarch64_get_reg_u64 (cpu, rn, NO_SP) | bimm);
9674}
9675
9676/* Logical shifted register.
9677 These allow an optional LSL, ASR, LSR or ROR to the second source
9678 register with a count up to the register bit count.
9679 N.B register args may not be SP. */
9680
9681/* 32 bit AND shifted register. */
9682static void
9683and32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9684{
ef0d8ffc
NC
9685 unsigned rm = INSTR (20, 16);
9686 unsigned rn = INSTR (9, 5);
9687 unsigned rd = INSTR (4, 0);
2e8cf49e 9688
2cdad34c 9689 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9690 aarch64_set_reg_u64
9691 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9692 & shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9693}
9694
9695/* 64 bit AND shifted register. */
9696static void
9697and64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9698{
ef0d8ffc
NC
9699 unsigned rm = INSTR (20, 16);
9700 unsigned rn = INSTR (9, 5);
9701 unsigned rd = INSTR (4, 0);
2e8cf49e 9702
2cdad34c 9703 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9704 aarch64_set_reg_u64
9705 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9706 & shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9707}
9708
9709/* 32 bit AND shifted register setting flags. */
9710static void
9711ands32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9712{
ef0d8ffc
NC
9713 unsigned rm = INSTR (20, 16);
9714 unsigned rn = INSTR (9, 5);
9715 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9716
9717 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9718 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9719 shift, count);
9720
2cdad34c 9721 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9722 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9723 set_flags_for_binop32 (cpu, value1 & value2);
9724}
9725
9726/* 64 bit AND shifted register setting flags. */
9727static void
9728ands64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9729{
ef0d8ffc
NC
9730 unsigned rm = INSTR (20, 16);
9731 unsigned rn = INSTR (9, 5);
9732 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9733
9734 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9735 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9736 shift, count);
9737
2cdad34c 9738 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9739 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9740 set_flags_for_binop64 (cpu, value1 & value2);
9741}
9742
9743/* 32 bit BIC shifted register. */
9744static void
9745bic32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9746{
ef0d8ffc
NC
9747 unsigned rm = INSTR (20, 16);
9748 unsigned rn = INSTR (9, 5);
9749 unsigned rd = INSTR (4, 0);
2e8cf49e 9750
2cdad34c 9751 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9752 aarch64_set_reg_u64
9753 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9754 & ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9755}
9756
9757/* 64 bit BIC shifted register. */
9758static void
9759bic64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9760{
ef0d8ffc
NC
9761 unsigned rm = INSTR (20, 16);
9762 unsigned rn = INSTR (9, 5);
9763 unsigned rd = INSTR (4, 0);
2e8cf49e 9764
2cdad34c 9765 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9766 aarch64_set_reg_u64
9767 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9768 & ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9769}
9770
9771/* 32 bit BIC shifted register setting flags. */
9772static void
9773bics32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9774{
ef0d8ffc
NC
9775 unsigned rm = INSTR (20, 16);
9776 unsigned rn = INSTR (9, 5);
9777 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9778
9779 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9780 uint32_t value2 = ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9781 shift, count);
9782
2cdad34c 9783 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9784 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9785 set_flags_for_binop32 (cpu, value1 & value2);
9786}
9787
9788/* 64 bit BIC shifted register setting flags. */
9789static void
9790bics64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9791{
ef0d8ffc
NC
9792 unsigned rm = INSTR (20, 16);
9793 unsigned rn = INSTR (9, 5);
9794 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9795
9796 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9797 uint64_t value2 = ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9798 shift, count);
9799
2cdad34c 9800 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9801 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9802 set_flags_for_binop64 (cpu, value1 & value2);
9803}
9804
9805/* 32 bit EON shifted register. */
9806static void
9807eon32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9808{
ef0d8ffc
NC
9809 unsigned rm = INSTR (20, 16);
9810 unsigned rn = INSTR (9, 5);
9811 unsigned rd = INSTR (4, 0);
2e8cf49e 9812
2cdad34c 9813 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9814 aarch64_set_reg_u64
9815 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9816 ^ ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9817}
9818
9819/* 64 bit EON shifted register. */
9820static void
9821eon64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9822{
ef0d8ffc
NC
9823 unsigned rm = INSTR (20, 16);
9824 unsigned rn = INSTR (9, 5);
9825 unsigned rd = INSTR (4, 0);
2e8cf49e 9826
2cdad34c 9827 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9828 aarch64_set_reg_u64
9829 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9830 ^ ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9831}
9832
9833/* 32 bit EOR shifted register. */
9834static void
9835eor32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9836{
ef0d8ffc
NC
9837 unsigned rm = INSTR (20, 16);
9838 unsigned rn = INSTR (9, 5);
9839 unsigned rd = INSTR (4, 0);
2e8cf49e 9840
2cdad34c 9841 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9842 aarch64_set_reg_u64
9843 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9844 ^ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9845}
9846
9847/* 64 bit EOR shifted register. */
9848static void
9849eor64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9850{
ef0d8ffc
NC
9851 unsigned rm = INSTR (20, 16);
9852 unsigned rn = INSTR (9, 5);
9853 unsigned rd = INSTR (4, 0);
2e8cf49e 9854
2cdad34c 9855 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9856 aarch64_set_reg_u64
9857 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9858 ^ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9859}
9860
9861/* 32 bit ORR shifted register. */
9862static void
9863orr32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9864{
ef0d8ffc
NC
9865 unsigned rm = INSTR (20, 16);
9866 unsigned rn = INSTR (9, 5);
9867 unsigned rd = INSTR (4, 0);
2e8cf49e 9868
2cdad34c 9869 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9870 aarch64_set_reg_u64
9871 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9872 | shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9873}
9874
9875/* 64 bit ORR shifted register. */
9876static void
9877orr64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9878{
ef0d8ffc
NC
9879 unsigned rm = INSTR (20, 16);
9880 unsigned rn = INSTR (9, 5);
9881 unsigned rd = INSTR (4, 0);
2e8cf49e 9882
2cdad34c 9883 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9884 aarch64_set_reg_u64
9885 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9886 | shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9887}
9888
9889/* 32 bit ORN shifted register. */
9890static void
9891orn32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9892{
ef0d8ffc
NC
9893 unsigned rm = INSTR (20, 16);
9894 unsigned rn = INSTR (9, 5);
9895 unsigned rd = INSTR (4, 0);
2e8cf49e 9896
2cdad34c 9897 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9898 aarch64_set_reg_u64
9899 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9900 | ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9901}
9902
9903/* 64 bit ORN shifted register. */
9904static void
9905orn64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9906{
ef0d8ffc
NC
9907 unsigned rm = INSTR (20, 16);
9908 unsigned rn = INSTR (9, 5);
9909 unsigned rd = INSTR (4, 0);
2e8cf49e 9910
2cdad34c 9911 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9912 aarch64_set_reg_u64
9913 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9914 | ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9915}
9916
9917static void
9918dexLogicalImmediate (sim_cpu *cpu)
9919{
9920 /* assert instr[28,23] = 1001000
9921 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9922 instr[30,29] = op : 0 ==> AND, 1 ==> ORR, 2 ==> EOR, 3 ==> ANDS
9923 instr[22] = N : used to construct immediate mask
9924 instr[21,16] = immr
9925 instr[15,10] = imms
9926 instr[9,5] = Rn
9927 instr[4,0] = Rd */
9928
9929 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
ef0d8ffc
NC
9930 uint32_t size = INSTR (31, 31);
9931 uint32_t N = INSTR (22, 22);
9932 /* uint32_t immr = INSTR (21, 16);. */
9933 /* uint32_t imms = INSTR (15, 10);. */
9934 uint32_t index = INSTR (22, 10);
2e8cf49e 9935 uint64_t bimm64 = LITable [index];
ef0d8ffc 9936 uint32_t dispatch = INSTR (30, 29);
2e8cf49e
NC
9937
9938 if (~size & N)
9939 HALT_UNALLOC;
9940
9941 if (!bimm64)
9942 HALT_UNALLOC;
9943
9944 if (size == 0)
9945 {
9946 uint32_t bimm = (uint32_t) bimm64;
9947
9948 switch (dispatch)
9949 {
9950 case 0: and32 (cpu, bimm); return;
9951 case 1: orr32 (cpu, bimm); return;
9952 case 2: eor32 (cpu, bimm); return;
9953 case 3: ands32 (cpu, bimm); return;
9954 }
9955 }
9956 else
9957 {
9958 switch (dispatch)
9959 {
9960 case 0: and64 (cpu, bimm64); return;
9961 case 1: orr64 (cpu, bimm64); return;
9962 case 2: eor64 (cpu, bimm64); return;
9963 case 3: ands64 (cpu, bimm64); return;
9964 }
9965 }
9966 HALT_UNALLOC;
9967}
9968
9969/* Immediate move.
9970 The uimm argument is a 16 bit value to be inserted into the
9971 target register the pos argument locates the 16 bit word in the
9972 dest register i.e. it is in {0, 1} for 32 bit and {0, 1, 2,
9973 3} for 64 bit.
9974 N.B register arg may not be SP so it should be.
9975 accessed using the setGZRegisterXXX accessors. */
9976
9977/* 32 bit move 16 bit immediate zero remaining shorts. */
9978static void
9979movz32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9980{
ef0d8ffc 9981 unsigned rd = INSTR (4, 0);
2e8cf49e 9982
2cdad34c 9983 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9984 aarch64_set_reg_u64 (cpu, rd, NO_SP, val << (pos * 16));
9985}
9986
9987/* 64 bit move 16 bit immediate zero remaining shorts. */
9988static void
9989movz64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9990{
ef0d8ffc 9991 unsigned rd = INSTR (4, 0);
2e8cf49e 9992
2cdad34c 9993 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
9994 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((uint64_t) val) << (pos * 16));
9995}
9996
9997/* 32 bit move 16 bit immediate negated. */
9998static void
9999movn32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
10000{
ef0d8ffc 10001 unsigned rd = INSTR (4, 0);
2e8cf49e 10002
2cdad34c 10003 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10004 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((val << (pos * 16)) ^ 0xffffffffU));
10005}
10006
10007/* 64 bit move 16 bit immediate negated. */
10008static void
10009movn64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
10010{
ef0d8ffc 10011 unsigned rd = INSTR (4, 0);
2e8cf49e 10012
2cdad34c 10013 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10014 aarch64_set_reg_u64
10015 (cpu, rd, NO_SP, ((((uint64_t) val) << (pos * 16))
10016 ^ 0xffffffffffffffffULL));
10017}
10018
10019/* 32 bit move 16 bit immediate keep remaining shorts. */
10020static void
10021movk32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
10022{
ef0d8ffc 10023 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
10024 uint32_t current = aarch64_get_reg_u32 (cpu, rd, NO_SP);
10025 uint32_t value = val << (pos * 16);
10026 uint32_t mask = ~(0xffffU << (pos * 16));
10027
2cdad34c 10028 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10029 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
10030}
10031
10032/* 64 bit move 16 it immediate keep remaining shorts. */
10033static void
10034movk64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
10035{
ef0d8ffc 10036 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
10037 uint64_t current = aarch64_get_reg_u64 (cpu, rd, NO_SP);
10038 uint64_t value = (uint64_t) val << (pos * 16);
10039 uint64_t mask = ~(0xffffULL << (pos * 16));
10040
2cdad34c 10041 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10042 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
10043}
10044
10045static void
10046dexMoveWideImmediate (sim_cpu *cpu)
10047{
10048 /* assert instr[28:23] = 100101
10049 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
10050 instr[30,29] = op : 0 ==> MOVN, 1 ==> UNALLOC, 2 ==> MOVZ, 3 ==> MOVK
10051 instr[22,21] = shift : 00 == LSL#0, 01 = LSL#16, 10 = LSL#32, 11 = LSL#48
10052 instr[20,5] = uimm16
10053 instr[4,0] = Rd */
10054
10055 /* N.B. the (multiple of 16) shift is applied by the called routine,
10056 we just pass the multiplier. */
10057
10058 uint32_t imm;
ef0d8ffc
NC
10059 uint32_t size = INSTR (31, 31);
10060 uint32_t op = INSTR (30, 29);
10061 uint32_t shift = INSTR (22, 21);
2e8cf49e
NC
10062
10063 /* 32 bit can only shift 0 or 1 lot of 16.
10064 anything else is an unallocated instruction. */
10065 if (size == 0 && (shift > 1))
10066 HALT_UNALLOC;
10067
10068 if (op == 1)
10069 HALT_UNALLOC;
10070
ef0d8ffc 10071 imm = INSTR (20, 5);
2e8cf49e
NC
10072
10073 if (size == 0)
10074 {
10075 if (op == 0)
10076 movn32 (cpu, imm, shift);
10077 else if (op == 2)
10078 movz32 (cpu, imm, shift);
10079 else
10080 movk32 (cpu, imm, shift);
10081 }
10082 else
10083 {
10084 if (op == 0)
10085 movn64 (cpu, imm, shift);
10086 else if (op == 2)
10087 movz64 (cpu, imm, shift);
10088 else
10089 movk64 (cpu, imm, shift);
10090 }
10091}
10092
10093/* Bitfield operations.
10094 These take a pair of bit positions r and s which are in {0..31}
10095 or {0..63} depending on the instruction word size.
10096 N.B register args may not be SP. */
10097
10098/* OK, we start with ubfm which just needs to pick
10099 some bits out of source zero the rest and write
10100 the result to dest. Just need two logical shifts. */
10101
10102/* 32 bit bitfield move, left and right of affected zeroed
10103 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
10104static void
10105ubfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
10106{
10107 unsigned rd;
ef0d8ffc 10108 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10109 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
10110
10111 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
10112 if (r <= s)
10113 {
10114 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
10115 We want only bits s:xxx:r at the bottom of the word
10116 so we LSL bit s up to bit 31 i.e. by 31 - s
10117 and then we LSR to bring bit 31 down to bit s - r
10118 i.e. by 31 + r - s. */
10119 value <<= 31 - s;
10120 value >>= 31 + r - s;
10121 }
10122 else
10123 {
10124 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0
10125 We want only bits s:xxx:0 starting at it 31-(r-1)
10126 so we LSL bit s up to bit 31 i.e. by 31 - s
10127 and then we LSL to bring bit 31 down to 31-(r-1)+s
10128 i.e. by r - (s + 1). */
10129 value <<= 31 - s;
10130 value >>= r - (s + 1);
10131 }
10132
2cdad34c 10133 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 10134 rd = INSTR (4, 0);
2e8cf49e
NC
10135 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
10136}
10137
10138/* 64 bit bitfield move, left and right of affected zeroed
10139 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
10140static void
10141ubfm (sim_cpu *cpu, uint32_t r, uint32_t s)
10142{
10143 unsigned rd;
ef0d8ffc 10144 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10145 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
10146
10147 if (r <= s)
10148 {
10149 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
10150 We want only bits s:xxx:r at the bottom of the word.
10151 So we LSL bit s up to bit 63 i.e. by 63 - s
10152 and then we LSR to bring bit 63 down to bit s - r
10153 i.e. by 63 + r - s. */
10154 value <<= 63 - s;
10155 value >>= 63 + r - s;
10156 }
10157 else
10158 {
10159 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0.
10160 We want only bits s:xxx:0 starting at it 63-(r-1).
10161 So we LSL bit s up to bit 63 i.e. by 63 - s
10162 and then we LSL to bring bit 63 down to 63-(r-1)+s
10163 i.e. by r - (s + 1). */
10164 value <<= 63 - s;
10165 value >>= r - (s + 1);
10166 }
10167
2cdad34c 10168 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 10169 rd = INSTR (4, 0);
2e8cf49e
NC
10170 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
10171}
10172
10173/* The signed versions need to insert sign bits
10174 on the left of the inserted bit field. so we do
10175 much the same as the unsigned version except we
10176 use an arithmetic shift right -- this just means
10177 we need to operate on signed values. */
10178
10179/* 32 bit bitfield move, left of affected sign-extended, right zeroed. */
10180/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
10181static void
10182sbfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
10183{
10184 unsigned rd;
ef0d8ffc 10185 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10186 /* as per ubfm32 but use an ASR instead of an LSR. */
10187 int32_t value = aarch64_get_reg_s32 (cpu, rn, NO_SP);
10188
10189 if (r <= s)
10190 {
10191 value <<= 31 - s;
10192 value >>= 31 + r - s;
10193 }
10194 else
10195 {
10196 value <<= 31 - s;
10197 value >>= r - (s + 1);
10198 }
10199
2cdad34c 10200 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 10201 rd = INSTR (4, 0);
2e8cf49e
NC
10202 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
10203}
10204
10205/* 64 bit bitfield move, left of affected sign-extended, right zeroed. */
10206/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
10207static void
10208sbfm (sim_cpu *cpu, uint32_t r, uint32_t s)
10209{
10210 unsigned rd;
ef0d8ffc 10211 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10212 /* acpu per ubfm but use an ASR instead of an LSR. */
10213 int64_t value = aarch64_get_reg_s64 (cpu, rn, NO_SP);
10214
10215 if (r <= s)
10216 {
10217 value <<= 63 - s;
10218 value >>= 63 + r - s;
10219 }
10220 else
10221 {
10222 value <<= 63 - s;
10223 value >>= r - (s + 1);
10224 }
10225
2cdad34c 10226 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 10227 rd = INSTR (4, 0);
2e8cf49e
NC
10228 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
10229}
10230
10231/* Finally, these versions leave non-affected bits
10232 as is. so we need to generate the bits as per
10233 ubfm and also generate a mask to pick the
10234 bits from the original and computed values. */
10235
10236/* 32 bit bitfield move, non-affected bits left as is.
10237 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
10238static void
10239bfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
10240{
ef0d8ffc 10241 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10242 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
10243 uint32_t mask = -1;
10244 unsigned rd;
10245 uint32_t value2;
10246
10247 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
10248 if (r <= s)
10249 {
10250 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
10251 We want only bits s:xxx:r at the bottom of the word
10252 so we LSL bit s up to bit 31 i.e. by 31 - s
10253 and then we LSR to bring bit 31 down to bit s - r
10254 i.e. by 31 + r - s. */
10255 value <<= 31 - s;
10256 value >>= 31 + r - s;
10257 /* the mask must include the same bits. */
10258 mask <<= 31 - s;
10259 mask >>= 31 + r - s;
10260 }
10261 else
10262 {
10263 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0.
10264 We want only bits s:xxx:0 starting at it 31-(r-1)
10265 so we LSL bit s up to bit 31 i.e. by 31 - s
10266 and then we LSL to bring bit 31 down to 31-(r-1)+s
10267 i.e. by r - (s + 1). */
10268 value <<= 31 - s;
10269 value >>= r - (s + 1);
10270 /* The mask must include the same bits. */
10271 mask <<= 31 - s;
10272 mask >>= r - (s + 1);
10273 }
10274
ef0d8ffc 10275 rd = INSTR (4, 0);
2e8cf49e
NC
10276 value2 = aarch64_get_reg_u32 (cpu, rd, NO_SP);
10277
10278 value2 &= ~mask;
10279 value2 |= value;
10280
2cdad34c 10281 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10282 aarch64_set_reg_u64
10283 (cpu, rd, NO_SP, (aarch64_get_reg_u32 (cpu, rd, NO_SP) & ~mask) | value);
10284}
10285
10286/* 64 bit bitfield move, non-affected bits left as is.
10287 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
10288static void
10289bfm (sim_cpu *cpu, uint32_t r, uint32_t s)
10290{
10291 unsigned rd;
ef0d8ffc 10292 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10293 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
10294 uint64_t mask = 0xffffffffffffffffULL;
10295
10296 if (r <= s)
10297 {
10298 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
10299 We want only bits s:xxx:r at the bottom of the word
10300 so we LSL bit s up to bit 63 i.e. by 63 - s
10301 and then we LSR to bring bit 63 down to bit s - r
10302 i.e. by 63 + r - s. */
10303 value <<= 63 - s;
10304 value >>= 63 + r - s;
10305 /* The mask must include the same bits. */
10306 mask <<= 63 - s;
10307 mask >>= 63 + r - s;
10308 }
10309 else
10310 {
10311 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0
10312 We want only bits s:xxx:0 starting at it 63-(r-1)
10313 so we LSL bit s up to bit 63 i.e. by 63 - s
10314 and then we LSL to bring bit 63 down to 63-(r-1)+s
10315 i.e. by r - (s + 1). */
10316 value <<= 63 - s;
10317 value >>= r - (s + 1);
10318 /* The mask must include the same bits. */
10319 mask <<= 63 - s;
10320 mask >>= r - (s + 1);
10321 }
10322
2cdad34c 10323 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
ef0d8ffc 10324 rd = INSTR (4, 0);
2e8cf49e
NC
10325 aarch64_set_reg_u64
10326 (cpu, rd, NO_SP, (aarch64_get_reg_u64 (cpu, rd, NO_SP) & ~mask) | value);
10327}
10328
10329static void
10330dexBitfieldImmediate (sim_cpu *cpu)
10331{
10332 /* assert instr[28:23] = 100110
10333 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
10334 instr[30,29] = op : 0 ==> SBFM, 1 ==> BFM, 2 ==> UBFM, 3 ==> UNALLOC
10335 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit ow UNALLOC
10336 instr[21,16] = immr : 0xxxxx for 32 bit, xxxxxx for 64 bit
10337 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
10338 instr[9,5] = Rn
10339 instr[4,0] = Rd */
10340
10341 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
10342 uint32_t dispatch;
10343 uint32_t imms;
ef0d8ffc
NC
10344 uint32_t size = INSTR (31, 31);
10345 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
10346 /* 32 bit operations must have immr[5] = 0 and imms[5] = 0. */
10347 /* or else we have an UNALLOC. */
ef0d8ffc 10348 uint32_t immr = INSTR (21, 16);
2e8cf49e
NC
10349
10350 if (~size & N)
10351 HALT_UNALLOC;
10352
10353 if (!size && uimm (immr, 5, 5))
10354 HALT_UNALLOC;
10355
ef0d8ffc 10356 imms = INSTR (15, 10);
2e8cf49e
NC
10357 if (!size && uimm (imms, 5, 5))
10358 HALT_UNALLOC;
10359
10360 /* Switch on combined size and op. */
ef0d8ffc 10361 dispatch = INSTR (31, 29);
2e8cf49e
NC
10362 switch (dispatch)
10363 {
10364 case 0: sbfm32 (cpu, immr, imms); return;
10365 case 1: bfm32 (cpu, immr, imms); return;
10366 case 2: ubfm32 (cpu, immr, imms); return;
10367 case 4: sbfm (cpu, immr, imms); return;
10368 case 5: bfm (cpu, immr, imms); return;
10369 case 6: ubfm (cpu, immr, imms); return;
10370 default: HALT_UNALLOC;
10371 }
10372}
10373
10374static void
10375do_EXTR_32 (sim_cpu *cpu)
10376{
10377 /* instr[31:21] = 00010011100
10378 instr[20,16] = Rm
10379 instr[15,10] = imms : 0xxxxx for 32 bit
10380 instr[9,5] = Rn
10381 instr[4,0] = Rd */
ef0d8ffc
NC
10382 unsigned rm = INSTR (20, 16);
10383 unsigned imms = INSTR (15, 10) & 31;
10384 unsigned rn = INSTR ( 9, 5);
10385 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
10386 uint64_t val1;
10387 uint64_t val2;
10388
10389 val1 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
10390 val1 >>= imms;
10391 val2 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
10392 val2 <<= (32 - imms);
10393
2cdad34c 10394 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
10395 aarch64_set_reg_u64 (cpu, rd, NO_SP, val1 | val2);
10396}
10397
10398static void
10399do_EXTR_64 (sim_cpu *cpu)
10400{
10401 /* instr[31:21] = 10010011100
10402 instr[20,16] = Rm
10403 instr[15,10] = imms
10404 instr[9,5] = Rn
10405 instr[4,0] = Rd */
ef0d8ffc
NC
10406 unsigned rm = INSTR (20, 16);
10407 unsigned imms = INSTR (15, 10) & 63;
10408 unsigned rn = INSTR ( 9, 5);
10409 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
10410 uint64_t val;
10411
10412 val = aarch64_get_reg_u64 (cpu, rm, NO_SP);
10413 val >>= imms;
10414 val |= (aarch64_get_reg_u64 (cpu, rn, NO_SP) << (64 - imms));
10415
10416 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
10417}
10418
10419static void
10420dexExtractImmediate (sim_cpu *cpu)
10421{
10422 /* assert instr[28:23] = 100111
10423 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
10424 instr[30,29] = op21 : 0 ==> EXTR, 1,2,3 ==> UNALLOC
10425 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit or UNALLOC
10426 instr[21] = op0 : must be 0 or UNALLOC
10427 instr[20,16] = Rm
10428 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
10429 instr[9,5] = Rn
10430 instr[4,0] = Rd */
10431
10432 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
10433 /* 64 bit operations must have N = 1 or else we have an UNALLOC. */
10434 uint32_t dispatch;
ef0d8ffc
NC
10435 uint32_t size = INSTR (31, 31);
10436 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
10437 /* 32 bit operations must have imms[5] = 0
10438 or else we have an UNALLOC. */
ef0d8ffc 10439 uint32_t imms = INSTR (15, 10);
2e8cf49e
NC
10440
10441 if (size ^ N)
10442 HALT_UNALLOC;
10443
10444 if (!size && uimm (imms, 5, 5))
10445 HALT_UNALLOC;
10446
10447 /* Switch on combined size and op. */
ef0d8ffc 10448 dispatch = INSTR (31, 29);
2e8cf49e
NC
10449
10450 if (dispatch == 0)
10451 do_EXTR_32 (cpu);
10452
10453 else if (dispatch == 4)
10454 do_EXTR_64 (cpu);
10455
10456 else if (dispatch == 1)
10457 HALT_NYI;
10458 else
10459 HALT_UNALLOC;
10460}
10461
10462static void
10463dexDPImm (sim_cpu *cpu)
10464{
10465 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
10466 assert group == GROUP_DPIMM_1000 || grpoup == GROUP_DPIMM_1001
10467 bits [25,23] of a DPImm are the secondary dispatch vector. */
10468 uint32_t group2 = dispatchDPImm (aarch64_get_instr (cpu));
10469
10470 switch (group2)
10471 {
10472 case DPIMM_PCADR_000:
10473 case DPIMM_PCADR_001:
10474 dexPCRelAddressing (cpu);
10475 return;
10476
10477 case DPIMM_ADDSUB_010:
10478 case DPIMM_ADDSUB_011:
10479 dexAddSubtractImmediate (cpu);
10480 return;
10481
10482 case DPIMM_LOG_100:
10483 dexLogicalImmediate (cpu);
10484 return;
10485
10486 case DPIMM_MOV_101:
10487 dexMoveWideImmediate (cpu);
10488 return;
10489
10490 case DPIMM_BITF_110:
10491 dexBitfieldImmediate (cpu);
10492 return;
10493
10494 case DPIMM_EXTR_111:
10495 dexExtractImmediate (cpu);
10496 return;
10497
10498 default:
10499 /* Should never reach here. */
10500 HALT_NYI;
10501 }
10502}
10503
10504static void
10505dexLoadUnscaledImmediate (sim_cpu *cpu)
10506{
10507 /* instr[29,24] == 111_00
10508 instr[21] == 0
10509 instr[11,10] == 00
10510 instr[31,30] = size
10511 instr[26] = V
10512 instr[23,22] = opc
10513 instr[20,12] = simm9
10514 instr[9,5] = rn may be SP. */
ef0d8ffc
NC
10515 /* unsigned rt = INSTR (4, 0); */
10516 uint32_t V = INSTR (26, 26);
7517e550 10517 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
2e8cf49e
NC
10518 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
10519
10520 if (!V)
10521 {
10522 /* GReg operations. */
10523 switch (dispatch)
10524 {
10525 case 0: sturb (cpu, imm); return;
10526 case 1: ldurb32 (cpu, imm); return;
10527 case 2: ldursb64 (cpu, imm); return;
10528 case 3: ldursb32 (cpu, imm); return;
10529 case 4: sturh (cpu, imm); return;
10530 case 5: ldurh32 (cpu, imm); return;
10531 case 6: ldursh64 (cpu, imm); return;
10532 case 7: ldursh32 (cpu, imm); return;
10533 case 8: stur32 (cpu, imm); return;
10534 case 9: ldur32 (cpu, imm); return;
10535 case 10: ldursw (cpu, imm); return;
10536 case 12: stur64 (cpu, imm); return;
10537 case 13: ldur64 (cpu, imm); return;
10538
10539 case 14:
10540 /* PRFUM NYI. */
10541 HALT_NYI;
10542
10543 default:
10544 case 11:
10545 case 15:
10546 HALT_UNALLOC;
10547 }
10548 }
10549
10550 /* FReg operations. */
10551 switch (dispatch)
10552 {
10553 case 2: fsturq (cpu, imm); return;
10554 case 3: fldurq (cpu, imm); return;
10555 case 8: fsturs (cpu, imm); return;
10556 case 9: fldurs (cpu, imm); return;
10557 case 12: fsturd (cpu, imm); return;
10558 case 13: fldurd (cpu, imm); return;
10559
10560 case 0: /* STUR 8 bit FP. */
10561 case 1: /* LDUR 8 bit FP. */
10562 case 4: /* STUR 16 bit FP. */
10563 case 5: /* LDUR 8 bit FP. */
10564 HALT_NYI;
10565
10566 default:
10567 case 6:
10568 case 7:
10569 case 10:
10570 case 11:
10571 case 14:
10572 case 15:
10573 HALT_UNALLOC;
10574 }
10575}
10576
10577/* N.B. A preliminary note regarding all the ldrs<x>32
10578 instructions
10579
10580 The signed value loaded by these instructions is cast to unsigned
10581 before being assigned to aarch64_get_reg_u64 (cpu, N) i.e. to the
10582 64 bit element of the GReg union. this performs a 32 bit sign extension
10583 (as required) but avoids 64 bit sign extension, thus ensuring that the
10584 top half of the register word is zero. this is what the spec demands
10585 when a 32 bit load occurs. */
10586
10587/* 32 bit load sign-extended byte scaled unsigned 12 bit. */
10588static void
10589ldrsb32_abs (sim_cpu *cpu, uint32_t offset)
10590{
ef0d8ffc
NC
10591 unsigned int rn = INSTR (9, 5);
10592 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10593
10594 /* The target register may not be SP but the source may be
10595 there is no scaling required for a byte load. */
10596 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
10597 aarch64_set_reg_u64 (cpu, rt, NO_SP,
10598 (int64_t) aarch64_get_mem_s8 (cpu, address));
10599}
10600
10601/* 32 bit load sign-extended byte scaled or unscaled zero-
10602 or sign-extended 32-bit register offset. */
10603static void
10604ldrsb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10605{
ef0d8ffc
NC
10606 unsigned int rm = INSTR (20, 16);
10607 unsigned int rn = INSTR (9, 5);
10608 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10609
10610 /* rn may reference SP, rm and rt must reference ZR. */
10611
10612 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10613 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10614 extension);
10615
10616 /* There is no scaling required for a byte load. */
10617 aarch64_set_reg_u64
10618 (cpu, rt, NO_SP, (int64_t) aarch64_get_mem_s8 (cpu, address
10619 + displacement));
10620}
10621
10622/* 32 bit load sign-extended byte unscaled signed 9 bit with
10623 pre- or post-writeback. */
10624static void
10625ldrsb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10626{
10627 uint64_t address;
ef0d8ffc
NC
10628 unsigned int rn = INSTR (9, 5);
10629 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
10630
10631 if (rn == rt && wb != NoWriteBack)
10632 HALT_UNALLOC;
10633
10634 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10635
10636 if (wb == Pre)
10637 address += offset;
10638
10639 aarch64_set_reg_u64 (cpu, rt, NO_SP,
10640 (int64_t) aarch64_get_mem_s8 (cpu, address));
10641
10642 if (wb == Post)
10643 address += offset;
10644
10645 if (wb != NoWriteBack)
10646 aarch64_set_reg_u64 (cpu, rn, NO_SP, address);
10647}
10648
10649/* 8 bit store scaled. */
10650static void
10651fstrb_abs (sim_cpu *cpu, uint32_t offset)
10652{
ef0d8ffc
NC
10653 unsigned st = INSTR (4, 0);
10654 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10655
10656 aarch64_set_mem_u8 (cpu,
10657 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
10658 aarch64_get_vec_u8 (cpu, st, 0));
10659}
10660
10661/* 8 bit store scaled or unscaled zero- or
10662 sign-extended 8-bit register offset. */
10663static void
10664fstrb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10665{
ef0d8ffc
NC
10666 unsigned rm = INSTR (20, 16);
10667 unsigned rn = INSTR (9, 5);
10668 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10669
10670 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10671 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10672 extension);
7517e550 10673 uint64_t displacement = scaling == Scaled ? extended : 0;
2e8cf49e
NC
10674
10675 aarch64_set_mem_u8
10676 (cpu, address + displacement, aarch64_get_vec_u8 (cpu, st, 0));
10677}
10678
10679/* 16 bit store scaled. */
10680static void
10681fstrh_abs (sim_cpu *cpu, uint32_t offset)
10682{
ef0d8ffc
NC
10683 unsigned st = INSTR (4, 0);
10684 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10685
10686 aarch64_set_mem_u16
10687 (cpu,
10688 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16),
10689 aarch64_get_vec_u16 (cpu, st, 0));
10690}
10691
10692/* 16 bit store scaled or unscaled zero-
10693 or sign-extended 16-bit register offset. */
10694static void
10695fstrh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10696{
ef0d8ffc
NC
10697 unsigned rm = INSTR (20, 16);
10698 unsigned rn = INSTR (9, 5);
10699 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10700
10701 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10702 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10703 extension);
7517e550 10704 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
2e8cf49e
NC
10705
10706 aarch64_set_mem_u16
10707 (cpu, address + displacement, aarch64_get_vec_u16 (cpu, st, 0));
10708}
10709
10710/* 32 bit store scaled unsigned 12 bit. */
10711static void
10712fstrs_abs (sim_cpu *cpu, uint32_t offset)
10713{
ef0d8ffc
NC
10714 unsigned st = INSTR (4, 0);
10715 unsigned rn = INSTR (9, 5);
2e8cf49e 10716
e101a78b 10717 aarch64_set_mem_u32
2e8cf49e
NC
10718 (cpu,
10719 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
e101a78b 10720 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10721}
10722
10723/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
10724static void
10725fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10726{
ef0d8ffc
NC
10727 unsigned rn = INSTR (9, 5);
10728 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10729
10730 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10731
10732 if (wb != Post)
10733 address += offset;
10734
e101a78b 10735 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10736
10737 if (wb == Post)
10738 address += offset;
10739
10740 if (wb != NoWriteBack)
10741 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10742}
10743
10744/* 32 bit store scaled or unscaled zero-
10745 or sign-extended 32-bit register offset. */
10746static void
10747fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10748{
ef0d8ffc
NC
10749 unsigned rm = INSTR (20, 16);
10750 unsigned rn = INSTR (9, 5);
10751 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10752
10753 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10754 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10755 extension);
10756 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
10757
e101a78b
NC
10758 aarch64_set_mem_u32
10759 (cpu, address + displacement, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10760}
10761
10762/* 64 bit store scaled unsigned 12 bit. */
10763static void
10764fstrd_abs (sim_cpu *cpu, uint32_t offset)
10765{
ef0d8ffc
NC
10766 unsigned st = INSTR (4, 0);
10767 unsigned rn = INSTR (9, 5);
2e8cf49e 10768
e101a78b 10769 aarch64_set_mem_u64
2e8cf49e
NC
10770 (cpu,
10771 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
e101a78b 10772 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10773}
10774
10775/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
10776static void
10777fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10778{
ef0d8ffc
NC
10779 unsigned rn = INSTR (9, 5);
10780 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10781
10782 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10783
10784 if (wb != Post)
10785 address += offset;
10786
e101a78b 10787 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10788
10789 if (wb == Post)
10790 address += offset;
10791
10792 if (wb != NoWriteBack)
10793 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10794}
10795
10796/* 64 bit store scaled or unscaled zero-
10797 or sign-extended 32-bit register offset. */
10798static void
10799fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10800{
ef0d8ffc
NC
10801 unsigned rm = INSTR (20, 16);
10802 unsigned rn = INSTR (9, 5);
10803 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10804
10805 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10806 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10807 extension);
10808 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
10809
e101a78b
NC
10810 aarch64_set_mem_u64
10811 (cpu, address + displacement, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10812}
10813
10814/* 128 bit store scaled unsigned 12 bit. */
10815static void
10816fstrq_abs (sim_cpu *cpu, uint32_t offset)
10817{
10818 FRegister a;
ef0d8ffc
NC
10819 unsigned st = INSTR (4, 0);
10820 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10821 uint64_t addr;
10822
10823 aarch64_get_FP_long_double (cpu, st, & a);
10824
10825 addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
10826 aarch64_set_mem_long_double (cpu, addr, a);
10827}
10828
10829/* 128 bit store unscaled signed 9 bit with pre- or post-writeback. */
10830static void
10831fstrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10832{
10833 FRegister a;
ef0d8ffc
NC
10834 unsigned rn = INSTR (9, 5);
10835 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10836 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10837
10838 if (wb != Post)
10839 address += offset;
10840
10841 aarch64_get_FP_long_double (cpu, st, & a);
10842 aarch64_set_mem_long_double (cpu, address, a);
10843
10844 if (wb == Post)
10845 address += offset;
10846
10847 if (wb != NoWriteBack)
10848 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10849}
10850
10851/* 128 bit store scaled or unscaled zero-
10852 or sign-extended 32-bit register offset. */
10853static void
10854fstrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10855{
ef0d8ffc
NC
10856 unsigned rm = INSTR (20, 16);
10857 unsigned rn = INSTR (9, 5);
10858 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10859
10860 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10861 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10862 extension);
10863 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
10864
10865 FRegister a;
10866
10867 aarch64_get_FP_long_double (cpu, st, & a);
10868 aarch64_set_mem_long_double (cpu, address + displacement, a);
10869}
10870
10871static void
10872dexLoadImmediatePrePost (sim_cpu *cpu)
10873{
ef0d8ffc
NC
10874 /* instr[31,30] = size
10875 instr[29,27] = 111
10876 instr[26] = V
10877 instr[25,24] = 00
2e8cf49e 10878 instr[23,22] = opc
ef0d8ffc 10879 instr[21] = 0
2e8cf49e 10880 instr[20,12] = simm9
ef0d8ffc
NC
10881 instr[11] = wb : 0 ==> Post, 1 ==> Pre
10882 instr[10] = 0
10883 instr[9,5] = Rn may be SP.
10884 instr[4,0] = Rt */
10885
10886 uint32_t V = INSTR (26, 26);
10887 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10888 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
10889 WriteBack wb = INSTR (11, 11);
2e8cf49e
NC
10890
10891 if (!V)
10892 {
10893 /* GReg operations. */
10894 switch (dispatch)
10895 {
10896 case 0: strb_wb (cpu, imm, wb); return;
10897 case 1: ldrb32_wb (cpu, imm, wb); return;
10898 case 2: ldrsb_wb (cpu, imm, wb); return;
10899 case 3: ldrsb32_wb (cpu, imm, wb); return;
10900 case 4: strh_wb (cpu, imm, wb); return;
10901 case 5: ldrh32_wb (cpu, imm, wb); return;
10902 case 6: ldrsh64_wb (cpu, imm, wb); return;
10903 case 7: ldrsh32_wb (cpu, imm, wb); return;
10904 case 8: str32_wb (cpu, imm, wb); return;
10905 case 9: ldr32_wb (cpu, imm, wb); return;
10906 case 10: ldrsw_wb (cpu, imm, wb); return;
10907 case 12: str_wb (cpu, imm, wb); return;
10908 case 13: ldr_wb (cpu, imm, wb); return;
10909
10910 default:
10911 case 11:
10912 case 14:
10913 case 15:
10914 HALT_UNALLOC;
10915 }
10916 }
10917
10918 /* FReg operations. */
10919 switch (dispatch)
10920 {
10921 case 2: fstrq_wb (cpu, imm, wb); return;
10922 case 3: fldrq_wb (cpu, imm, wb); return;
10923 case 8: fstrs_wb (cpu, imm, wb); return;
10924 case 9: fldrs_wb (cpu, imm, wb); return;
10925 case 12: fstrd_wb (cpu, imm, wb); return;
10926 case 13: fldrd_wb (cpu, imm, wb); return;
10927
10928 case 0: /* STUR 8 bit FP. */
10929 case 1: /* LDUR 8 bit FP. */
10930 case 4: /* STUR 16 bit FP. */
10931 case 5: /* LDUR 8 bit FP. */
10932 HALT_NYI;
10933
10934 default:
10935 case 6:
10936 case 7:
10937 case 10:
10938 case 11:
10939 case 14:
10940 case 15:
10941 HALT_UNALLOC;
10942 }
10943}
10944
10945static void
10946dexLoadRegisterOffset (sim_cpu *cpu)
10947{
10948 /* instr[31,30] = size
10949 instr[29,27] = 111
10950 instr[26] = V
10951 instr[25,24] = 00
10952 instr[23,22] = opc
10953 instr[21] = 1
10954 instr[20,16] = rm
10955 instr[15,13] = option : 010 ==> UXTW, 011 ==> UXTX/LSL,
10956 110 ==> SXTW, 111 ==> SXTX,
10957 ow ==> RESERVED
10958 instr[12] = scaled
10959 instr[11,10] = 10
10960 instr[9,5] = rn
10961 instr[4,0] = rt. */
10962
ef0d8ffc
NC
10963 uint32_t V = INSTR (26, 26);
10964 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10965 Scaling scale = INSTR (12, 12);
10966 Extension extensionType = INSTR (15, 13);
2e8cf49e
NC
10967
10968 /* Check for illegal extension types. */
10969 if (uimm (extensionType, 1, 1) == 0)
10970 HALT_UNALLOC;
10971
10972 if (extensionType == UXTX || extensionType == SXTX)
10973 extensionType = NoExtension;
10974
10975 if (!V)
10976 {
10977 /* GReg operations. */
10978 switch (dispatch)
10979 {
10980 case 0: strb_scale_ext (cpu, scale, extensionType); return;
10981 case 1: ldrb32_scale_ext (cpu, scale, extensionType); return;
10982 case 2: ldrsb_scale_ext (cpu, scale, extensionType); return;
10983 case 3: ldrsb32_scale_ext (cpu, scale, extensionType); return;
10984 case 4: strh_scale_ext (cpu, scale, extensionType); return;
10985 case 5: ldrh32_scale_ext (cpu, scale, extensionType); return;
10986 case 6: ldrsh_scale_ext (cpu, scale, extensionType); return;
10987 case 7: ldrsh32_scale_ext (cpu, scale, extensionType); return;
10988 case 8: str32_scale_ext (cpu, scale, extensionType); return;
10989 case 9: ldr32_scale_ext (cpu, scale, extensionType); return;
10990 case 10: ldrsw_scale_ext (cpu, scale, extensionType); return;
10991 case 12: str_scale_ext (cpu, scale, extensionType); return;
10992 case 13: ldr_scale_ext (cpu, scale, extensionType); return;
10993 case 14: prfm_scale_ext (cpu, scale, extensionType); return;
10994
10995 default:
10996 case 11:
10997 case 15:
10998 HALT_UNALLOC;
10999 }
11000 }
11001
11002 /* FReg operations. */
11003 switch (dispatch)
11004 {
11005 case 1: /* LDUR 8 bit FP. */
11006 HALT_NYI;
11007 case 3: fldrq_scale_ext (cpu, scale, extensionType); return;
11008 case 5: /* LDUR 8 bit FP. */
11009 HALT_NYI;
11010 case 9: fldrs_scale_ext (cpu, scale, extensionType); return;
11011 case 13: fldrd_scale_ext (cpu, scale, extensionType); return;
11012
11013 case 0: fstrb_scale_ext (cpu, scale, extensionType); return;
11014 case 2: fstrq_scale_ext (cpu, scale, extensionType); return;
11015 case 4: fstrh_scale_ext (cpu, scale, extensionType); return;
11016 case 8: fstrs_scale_ext (cpu, scale, extensionType); return;
11017 case 12: fstrd_scale_ext (cpu, scale, extensionType); return;
11018
11019 default:
11020 case 6:
11021 case 7:
11022 case 10:
11023 case 11:
11024 case 14:
11025 case 15:
11026 HALT_UNALLOC;
11027 }
11028}
11029
11030static void
11031dexLoadUnsignedImmediate (sim_cpu *cpu)
11032{
5ab6d79e 11033 /* instr[29,24] == 111_01
2e8cf49e 11034 instr[31,30] = size
5ab6d79e 11035 instr[26] = V
2e8cf49e
NC
11036 instr[23,22] = opc
11037 instr[21,10] = uimm12 : unsigned immediate offset
5ab6d79e
NC
11038 instr[9,5] = rn may be SP.
11039 instr[4,0] = rt. */
ef0d8ffc
NC
11040
11041 uint32_t V = INSTR (26,26);
7517e550 11042 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
ef0d8ffc 11043 uint32_t imm = INSTR (21, 10);
2e8cf49e
NC
11044
11045 if (!V)
11046 {
11047 /* GReg operations. */
11048 switch (dispatch)
11049 {
11050 case 0: strb_abs (cpu, imm); return;
11051 case 1: ldrb32_abs (cpu, imm); return;
11052 case 2: ldrsb_abs (cpu, imm); return;
11053 case 3: ldrsb32_abs (cpu, imm); return;
11054 case 4: strh_abs (cpu, imm); return;
11055 case 5: ldrh32_abs (cpu, imm); return;
11056 case 6: ldrsh_abs (cpu, imm); return;
11057 case 7: ldrsh32_abs (cpu, imm); return;
11058 case 8: str32_abs (cpu, imm); return;
11059 case 9: ldr32_abs (cpu, imm); return;
11060 case 10: ldrsw_abs (cpu, imm); return;
11061 case 12: str_abs (cpu, imm); return;
11062 case 13: ldr_abs (cpu, imm); return;
11063 case 14: prfm_abs (cpu, imm); return;
11064
11065 default:
11066 case 11:
11067 case 15:
11068 HALT_UNALLOC;
11069 }
11070 }
11071
11072 /* FReg operations. */
11073 switch (dispatch)
11074 {
2e8cf49e 11075 case 0: fstrb_abs (cpu, imm); return;
2e8cf49e
NC
11076 case 4: fstrh_abs (cpu, imm); return;
11077 case 8: fstrs_abs (cpu, imm); return;
11078 case 12: fstrd_abs (cpu, imm); return;
5ab6d79e 11079 case 2: fstrq_abs (cpu, imm); return;
2e8cf49e 11080
5ab6d79e
NC
11081 case 1: fldrb_abs (cpu, imm); return;
11082 case 5: fldrh_abs (cpu, imm); return;
11083 case 9: fldrs_abs (cpu, imm); return;
11084 case 13: fldrd_abs (cpu, imm); return;
11085 case 3: fldrq_abs (cpu, imm); return;
2e8cf49e
NC
11086
11087 default:
11088 case 6:
11089 case 7:
11090 case 10:
11091 case 11:
11092 case 14:
11093 case 15:
11094 HALT_UNALLOC;
11095 }
11096}
11097
11098static void
11099dexLoadExclusive (sim_cpu *cpu)
11100{
11101 /* assert instr[29:24] = 001000;
11102 instr[31,30] = size
11103 instr[23] = 0 if exclusive
11104 instr[22] = L : 1 if load, 0 if store
11105 instr[21] = 1 if pair
11106 instr[20,16] = Rs
11107 instr[15] = o0 : 1 if ordered
11108 instr[14,10] = Rt2
11109 instr[9,5] = Rn
11110 instr[4.0] = Rt. */
11111
ef0d8ffc 11112 switch (INSTR (22, 21))
2e8cf49e
NC
11113 {
11114 case 2: ldxr (cpu); return;
11115 case 0: stxr (cpu); return;
11116 default: HALT_NYI;
11117 }
11118}
11119
11120static void
11121dexLoadOther (sim_cpu *cpu)
11122{
11123 uint32_t dispatch;
11124
11125 /* instr[29,25] = 111_0
11126 instr[24] == 0 ==> dispatch, 1 ==> ldst reg unsigned immediate
11127 instr[21:11,10] is the secondary dispatch. */
ef0d8ffc 11128 if (INSTR (24, 24))
2e8cf49e
NC
11129 {
11130 dexLoadUnsignedImmediate (cpu);
11131 return;
11132 }
11133
7517e550 11134 dispatch = ((INSTR (21, 21) << 2) | INSTR (11, 10));
2e8cf49e
NC
11135 switch (dispatch)
11136 {
11137 case 0: dexLoadUnscaledImmediate (cpu); return;
11138 case 1: dexLoadImmediatePrePost (cpu); return;
11139 case 3: dexLoadImmediatePrePost (cpu); return;
11140 case 6: dexLoadRegisterOffset (cpu); return;
11141
11142 default:
11143 case 2:
11144 case 4:
11145 case 5:
11146 case 7:
11147 HALT_NYI;
11148 }
11149}
11150
11151static void
11152store_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
11153{
ef0d8ffc
NC
11154 unsigned rn = INSTR (14, 10);
11155 unsigned rd = INSTR (9, 5);
11156 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11157 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11158
11159 if ((rn == rd || rm == rd) && wb != NoWriteBack)
11160 HALT_UNALLOC; /* ??? */
11161
11162 offset <<= 2;
11163
11164 if (wb != Post)
11165 address += offset;
11166
11167 aarch64_set_mem_u32 (cpu, address,
11168 aarch64_get_reg_u32 (cpu, rm, NO_SP));
11169 aarch64_set_mem_u32 (cpu, address + 4,
11170 aarch64_get_reg_u32 (cpu, rn, NO_SP));
11171
11172 if (wb == Post)
11173 address += offset;
11174
11175 if (wb != NoWriteBack)
11176 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11177}
11178
11179static void
11180store_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
11181{
ef0d8ffc
NC
11182 unsigned rn = INSTR (14, 10);
11183 unsigned rd = INSTR (9, 5);
11184 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11185 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11186
11187 if ((rn == rd || rm == rd) && wb != NoWriteBack)
11188 HALT_UNALLOC; /* ??? */
11189
11190 offset <<= 3;
11191
11192 if (wb != Post)
11193 address += offset;
11194
11195 aarch64_set_mem_u64 (cpu, address,
7517e550 11196 aarch64_get_reg_u64 (cpu, rm, NO_SP));
2e8cf49e 11197 aarch64_set_mem_u64 (cpu, address + 8,
7517e550 11198 aarch64_get_reg_u64 (cpu, rn, NO_SP));
2e8cf49e
NC
11199
11200 if (wb == Post)
11201 address += offset;
11202
11203 if (wb != NoWriteBack)
11204 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11205}
11206
11207static void
11208load_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
11209{
ef0d8ffc
NC
11210 unsigned rn = INSTR (14, 10);
11211 unsigned rd = INSTR (9, 5);
11212 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11213 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11214
7517e550 11215 /* Treat this as unalloc to make sure we don't do it. */
2e8cf49e
NC
11216 if (rn == rm)
11217 HALT_UNALLOC;
11218
11219 offset <<= 2;
11220
11221 if (wb != Post)
11222 address += offset;
11223
11224 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u32 (cpu, address));
11225 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u32 (cpu, address + 4));
11226
11227 if (wb == Post)
11228 address += offset;
11229
11230 if (wb != NoWriteBack)
11231 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11232}
11233
11234static void
11235load_pair_s32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
11236{
ef0d8ffc
NC
11237 unsigned rn = INSTR (14, 10);
11238 unsigned rd = INSTR (9, 5);
11239 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11240 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11241
11242 /* Treat this as unalloc to make sure we don't do it. */
11243 if (rn == rm)
11244 HALT_UNALLOC;
11245
11246 offset <<= 2;
11247
11248 if (wb != Post)
11249 address += offset;
11250
11251 aarch64_set_reg_s64 (cpu, rm, SP_OK, aarch64_get_mem_s32 (cpu, address));
11252 aarch64_set_reg_s64 (cpu, rn, SP_OK, aarch64_get_mem_s32 (cpu, address + 4));
11253
11254 if (wb == Post)
11255 address += offset;
11256
11257 if (wb != NoWriteBack)
11258 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11259}
11260
11261static void
11262load_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
11263{
ef0d8ffc
NC
11264 unsigned rn = INSTR (14, 10);
11265 unsigned rd = INSTR (9, 5);
11266 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11267 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11268
11269 /* Treat this as unalloc to make sure we don't do it. */
11270 if (rn == rm)
11271 HALT_UNALLOC;
11272
11273 offset <<= 3;
11274
11275 if (wb != Post)
11276 address += offset;
11277
11278 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u64 (cpu, address));
11279 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u64 (cpu, address + 8));
11280
11281 if (wb == Post)
11282 address += offset;
11283
11284 if (wb != NoWriteBack)
11285 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11286}
11287
11288static void
11289dex_load_store_pair_gr (sim_cpu *cpu)
11290{
11291 /* instr[31,30] = size (10=> 64-bit, 01=> signed 32-bit, 00=> 32-bit)
11292 instr[29,25] = instruction encoding: 101_0
11293 instr[26] = V : 1 if fp 0 if gp
11294 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
11295 instr[22] = load/store (1=> load)
11296 instr[21,15] = signed, scaled, offset
11297 instr[14,10] = Rn
11298 instr[ 9, 5] = Rd
11299 instr[ 4, 0] = Rm. */
11300
7517e550 11301 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
11302 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
11303
11304 switch (dispatch)
11305 {
11306 case 2: store_pair_u32 (cpu, offset, Post); return;
11307 case 3: load_pair_u32 (cpu, offset, Post); return;
11308 case 4: store_pair_u32 (cpu, offset, NoWriteBack); return;
11309 case 5: load_pair_u32 (cpu, offset, NoWriteBack); return;
11310 case 6: store_pair_u32 (cpu, offset, Pre); return;
11311 case 7: load_pair_u32 (cpu, offset, Pre); return;
11312
11313 case 11: load_pair_s32 (cpu, offset, Post); return;
11314 case 13: load_pair_s32 (cpu, offset, NoWriteBack); return;
11315 case 15: load_pair_s32 (cpu, offset, Pre); return;
11316
11317 case 18: store_pair_u64 (cpu, offset, Post); return;
11318 case 19: load_pair_u64 (cpu, offset, Post); return;
11319 case 20: store_pair_u64 (cpu, offset, NoWriteBack); return;
11320 case 21: load_pair_u64 (cpu, offset, NoWriteBack); return;
11321 case 22: store_pair_u64 (cpu, offset, Pre); return;
11322 case 23: load_pair_u64 (cpu, offset, Pre); return;
11323
11324 default:
11325 HALT_UNALLOC;
11326 }
11327}
11328
11329static void
11330store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
11331{
ef0d8ffc
NC
11332 unsigned rn = INSTR (14, 10);
11333 unsigned rd = INSTR (9, 5);
11334 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11335 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11336
11337 offset <<= 2;
11338
11339 if (wb != Post)
11340 address += offset;
11341
e101a78b
NC
11342 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, rm, 0));
11343 aarch64_set_mem_u32 (cpu, address + 4, aarch64_get_vec_u32 (cpu, rn, 0));
2e8cf49e
NC
11344
11345 if (wb == Post)
11346 address += offset;
11347
11348 if (wb != NoWriteBack)
11349 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11350}
11351
11352static void
11353store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11354{
ef0d8ffc
NC
11355 unsigned rn = INSTR (14, 10);
11356 unsigned rd = INSTR (9, 5);
11357 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11358 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11359
11360 offset <<= 3;
11361
11362 if (wb != Post)
11363 address += offset;
11364
e101a78b
NC
11365 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, rm, 0));
11366 aarch64_set_mem_u64 (cpu, address + 8, aarch64_get_vec_u64 (cpu, rn, 0));
2e8cf49e
NC
11367
11368 if (wb == Post)
11369 address += offset;
11370
11371 if (wb != NoWriteBack)
11372 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11373}
11374
11375static void
11376store_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11377{
11378 FRegister a;
ef0d8ffc
NC
11379 unsigned rn = INSTR (14, 10);
11380 unsigned rd = INSTR (9, 5);
11381 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11382 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11383
11384 offset <<= 4;
11385
11386 if (wb != Post)
11387 address += offset;
11388
11389 aarch64_get_FP_long_double (cpu, rm, & a);
11390 aarch64_set_mem_long_double (cpu, address, a);
11391 aarch64_get_FP_long_double (cpu, rn, & a);
11392 aarch64_set_mem_long_double (cpu, address + 16, a);
11393
11394 if (wb == Post)
11395 address += offset;
11396
11397 if (wb != NoWriteBack)
11398 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11399}
11400
11401static void
11402load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
11403{
ef0d8ffc
NC
11404 unsigned rn = INSTR (14, 10);
11405 unsigned rd = INSTR (9, 5);
11406 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11407 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11408
11409 if (rm == rn)
11410 HALT_UNALLOC;
11411
11412 offset <<= 2;
11413
11414 if (wb != Post)
11415 address += offset;
11416
e101a78b
NC
11417 aarch64_set_vec_u32 (cpu, rm, 0, aarch64_get_mem_u32 (cpu, address));
11418 aarch64_set_vec_u32 (cpu, rn, 0, aarch64_get_mem_u32 (cpu, address + 4));
2e8cf49e
NC
11419
11420 if (wb == Post)
11421 address += offset;
11422
11423 if (wb != NoWriteBack)
11424 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11425}
11426
11427static void
11428load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11429{
ef0d8ffc
NC
11430 unsigned rn = INSTR (14, 10);
11431 unsigned rd = INSTR (9, 5);
11432 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11433 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11434
11435 if (rm == rn)
11436 HALT_UNALLOC;
11437
11438 offset <<= 3;
11439
11440 if (wb != Post)
11441 address += offset;
11442
e101a78b
NC
11443 aarch64_set_vec_u64 (cpu, rm, 0, aarch64_get_mem_u64 (cpu, address));
11444 aarch64_set_vec_u64 (cpu, rn, 0, aarch64_get_mem_u64 (cpu, address + 8));
2e8cf49e
NC
11445
11446 if (wb == Post)
11447 address += offset;
11448
11449 if (wb != NoWriteBack)
11450 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11451}
11452
11453static void
11454load_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
11455{
11456 FRegister a;
ef0d8ffc
NC
11457 unsigned rn = INSTR (14, 10);
11458 unsigned rd = INSTR (9, 5);
11459 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
11460 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
11461
11462 if (rm == rn)
11463 HALT_UNALLOC;
11464
11465 offset <<= 4;
11466
11467 if (wb != Post)
11468 address += offset;
11469
11470 aarch64_get_mem_long_double (cpu, address, & a);
11471 aarch64_set_FP_long_double (cpu, rm, a);
11472 aarch64_get_mem_long_double (cpu, address + 16, & a);
11473 aarch64_set_FP_long_double (cpu, rn, a);
11474
11475 if (wb == Post)
11476 address += offset;
11477
11478 if (wb != NoWriteBack)
11479 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
11480}
11481
11482static void
11483dex_load_store_pair_fp (sim_cpu *cpu)
11484{
11485 /* instr[31,30] = size (10=> 128-bit, 01=> 64-bit, 00=> 32-bit)
11486 instr[29,25] = instruction encoding
11487 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
11488 instr[22] = load/store (1=> load)
11489 instr[21,15] = signed, scaled, offset
11490 instr[14,10] = Rn
11491 instr[ 9, 5] = Rd
11492 instr[ 4, 0] = Rm */
11493
7517e550 11494 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
11495 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
11496
11497 switch (dispatch)
11498 {
11499 case 2: store_pair_float (cpu, offset, Post); return;
11500 case 3: load_pair_float (cpu, offset, Post); return;
11501 case 4: store_pair_float (cpu, offset, NoWriteBack); return;
11502 case 5: load_pair_float (cpu, offset, NoWriteBack); return;
11503 case 6: store_pair_float (cpu, offset, Pre); return;
11504 case 7: load_pair_float (cpu, offset, Pre); return;
11505
11506 case 10: store_pair_double (cpu, offset, Post); return;
11507 case 11: load_pair_double (cpu, offset, Post); return;
11508 case 12: store_pair_double (cpu, offset, NoWriteBack); return;
11509 case 13: load_pair_double (cpu, offset, NoWriteBack); return;
11510 case 14: store_pair_double (cpu, offset, Pre); return;
11511 case 15: load_pair_double (cpu, offset, Pre); return;
11512
11513 case 18: store_pair_long_double (cpu, offset, Post); return;
11514 case 19: load_pair_long_double (cpu, offset, Post); return;
11515 case 20: store_pair_long_double (cpu, offset, NoWriteBack); return;
11516 case 21: load_pair_long_double (cpu, offset, NoWriteBack); return;
11517 case 22: store_pair_long_double (cpu, offset, Pre); return;
11518 case 23: load_pair_long_double (cpu, offset, Pre); return;
11519
11520 default:
11521 HALT_UNALLOC;
11522 }
11523}
11524
11525static inline unsigned
11526vec_reg (unsigned v, unsigned o)
11527{
11528 return (v + o) & 0x3F;
11529}
11530
bf155438 11531/* Load multiple N-element structures to M consecutive registers. */
2e8cf49e 11532static void
bf155438 11533vec_load (sim_cpu *cpu, uint64_t address, unsigned N, unsigned M)
2e8cf49e 11534{
ef0d8ffc
NC
11535 int all = INSTR (30, 30);
11536 unsigned size = INSTR (11, 10);
11537 unsigned vd = INSTR (4, 0);
bf155438
JW
11538 unsigned rpt = (N == M) ? 1 : M;
11539 unsigned selem = N;
11540 unsigned i, j, k;
2e8cf49e
NC
11541
11542 switch (size)
11543 {
11544 case 0: /* 8-bit operations. */
bf155438
JW
11545 for (i = 0; i < rpt; i++)
11546 for (j = 0; j < (8 + (8 * all)); j++)
11547 for (k = 0; k < selem; k++)
11548 {
11549 aarch64_set_vec_u8 (cpu, vec_reg (vd, i + k), j,
11550 aarch64_get_mem_u8 (cpu, address));
11551 address += 1;
11552 }
2e8cf49e
NC
11553 return;
11554
11555 case 1: /* 16-bit operations. */
bf155438
JW
11556 for (i = 0; i < rpt; i++)
11557 for (j = 0; j < (4 + (4 * all)); j++)
11558 for (k = 0; k < selem; k++)
11559 {
11560 aarch64_set_vec_u16 (cpu, vec_reg (vd, i + k), j,
11561 aarch64_get_mem_u16 (cpu, address));
11562 address += 2;
11563 }
2e8cf49e
NC
11564 return;
11565
11566 case 2: /* 32-bit operations. */
bf155438
JW
11567 for (i = 0; i < rpt; i++)
11568 for (j = 0; j < (2 + (2 * all)); j++)
11569 for (k = 0; k < selem; k++)
11570 {
11571 aarch64_set_vec_u32 (cpu, vec_reg (vd, i + k), j,
11572 aarch64_get_mem_u32 (cpu, address));
11573 address += 4;
11574 }
2e8cf49e
NC
11575 return;
11576
11577 case 3: /* 64-bit operations. */
bf155438
JW
11578 for (i = 0; i < rpt; i++)
11579 for (j = 0; j < (1 + all); j++)
11580 for (k = 0; k < selem; k++)
11581 {
11582 aarch64_set_vec_u64 (cpu, vec_reg (vd, i + k), j,
11583 aarch64_get_mem_u64 (cpu, address));
11584 address += 8;
11585 }
2e8cf49e 11586 return;
2e8cf49e
NC
11587 }
11588}
11589
bf155438 11590/* Load multiple 4-element structures into four consecutive registers. */
2e8cf49e
NC
11591static void
11592LD4 (sim_cpu *cpu, uint64_t address)
11593{
bf155438 11594 vec_load (cpu, address, 4, 4);
2e8cf49e
NC
11595}
11596
bf155438 11597/* Load multiple 3-element structures into three consecutive registers. */
2e8cf49e
NC
11598static void
11599LD3 (sim_cpu *cpu, uint64_t address)
11600{
bf155438 11601 vec_load (cpu, address, 3, 3);
2e8cf49e
NC
11602}
11603
bf155438 11604/* Load multiple 2-element structures into two consecutive registers. */
2e8cf49e
NC
11605static void
11606LD2 (sim_cpu *cpu, uint64_t address)
11607{
bf155438 11608 vec_load (cpu, address, 2, 2);
2e8cf49e
NC
11609}
11610
11611/* Load multiple 1-element structures into one register. */
11612static void
11613LD1_1 (sim_cpu *cpu, uint64_t address)
11614{
bf155438 11615 vec_load (cpu, address, 1, 1);
2e8cf49e
NC
11616}
11617
11618/* Load multiple 1-element structures into two registers. */
11619static void
11620LD1_2 (sim_cpu *cpu, uint64_t address)
11621{
bf155438 11622 vec_load (cpu, address, 1, 2);
2e8cf49e
NC
11623}
11624
11625/* Load multiple 1-element structures into three registers. */
11626static void
11627LD1_3 (sim_cpu *cpu, uint64_t address)
11628{
bf155438 11629 vec_load (cpu, address, 1, 3);
2e8cf49e
NC
11630}
11631
11632/* Load multiple 1-element structures into four registers. */
11633static void
11634LD1_4 (sim_cpu *cpu, uint64_t address)
11635{
bf155438 11636 vec_load (cpu, address, 1, 4);
2e8cf49e
NC
11637}
11638
bf155438 11639/* Store multiple N-element structures from M consecutive registers. */
2e8cf49e 11640static void
bf155438 11641vec_store (sim_cpu *cpu, uint64_t address, unsigned N, unsigned M)
2e8cf49e 11642{
ef0d8ffc
NC
11643 int all = INSTR (30, 30);
11644 unsigned size = INSTR (11, 10);
11645 unsigned vd = INSTR (4, 0);
bf155438
JW
11646 unsigned rpt = (N == M) ? 1 : M;
11647 unsigned selem = N;
11648 unsigned i, j, k;
2e8cf49e
NC
11649
11650 switch (size)
11651 {
11652 case 0: /* 8-bit operations. */
bf155438
JW
11653 for (i = 0; i < rpt; i++)
11654 for (j = 0; j < (8 + (8 * all)); j++)
11655 for (k = 0; k < selem; k++)
11656 {
11657 aarch64_set_mem_u8
11658 (cpu, address,
11659 aarch64_get_vec_u8 (cpu, vec_reg (vd, i + k), j));
11660 address += 1;
11661 }
2e8cf49e
NC
11662 return;
11663
11664 case 1: /* 16-bit operations. */
bf155438
JW
11665 for (i = 0; i < rpt; i++)
11666 for (j = 0; j < (4 + (4 * all)); j++)
11667 for (k = 0; k < selem; k++)
11668 {
11669 aarch64_set_mem_u16
11670 (cpu, address,
11671 aarch64_get_vec_u16 (cpu, vec_reg (vd, i + k), j));
11672 address += 2;
11673 }
2e8cf49e
NC
11674 return;
11675
11676 case 2: /* 32-bit operations. */
bf155438
JW
11677 for (i = 0; i < rpt; i++)
11678 for (j = 0; j < (2 + (2 * all)); j++)
11679 for (k = 0; k < selem; k++)
11680 {
11681 aarch64_set_mem_u32
11682 (cpu, address,
11683 aarch64_get_vec_u32 (cpu, vec_reg (vd, i + k), j));
11684 address += 4;
11685 }
2e8cf49e
NC
11686 return;
11687
11688 case 3: /* 64-bit operations. */
bf155438
JW
11689 for (i = 0; i < rpt; i++)
11690 for (j = 0; j < (1 + all); j++)
11691 for (k = 0; k < selem; k++)
11692 {
11693 aarch64_set_mem_u64
11694 (cpu, address,
11695 aarch64_get_vec_u64 (cpu, vec_reg (vd, i + k), j));
11696 address += 8;
11697 }
2e8cf49e 11698 return;
2e8cf49e
NC
11699 }
11700}
11701
bf155438 11702/* Store multiple 4-element structure from four consecutive registers. */
2e8cf49e
NC
11703static void
11704ST4 (sim_cpu *cpu, uint64_t address)
11705{
bf155438 11706 vec_store (cpu, address, 4, 4);
2e8cf49e
NC
11707}
11708
bf155438 11709/* Store multiple 3-element structures from three consecutive registers. */
2e8cf49e
NC
11710static void
11711ST3 (sim_cpu *cpu, uint64_t address)
11712{
bf155438 11713 vec_store (cpu, address, 3, 3);
2e8cf49e
NC
11714}
11715
bf155438 11716/* Store multiple 2-element structures from two consecutive registers. */
2e8cf49e
NC
11717static void
11718ST2 (sim_cpu *cpu, uint64_t address)
11719{
bf155438 11720 vec_store (cpu, address, 2, 2);
2e8cf49e
NC
11721}
11722
bf155438 11723/* Store multiple 1-element structures from one register. */
2e8cf49e
NC
11724static void
11725ST1_1 (sim_cpu *cpu, uint64_t address)
11726{
bf155438 11727 vec_store (cpu, address, 1, 1);
2e8cf49e
NC
11728}
11729
bf155438 11730/* Store multiple 1-element structures from two registers. */
2e8cf49e
NC
11731static void
11732ST1_2 (sim_cpu *cpu, uint64_t address)
11733{
bf155438 11734 vec_store (cpu, address, 1, 2);
2e8cf49e
NC
11735}
11736
bf155438 11737/* Store multiple 1-element structures from three registers. */
2e8cf49e
NC
11738static void
11739ST1_3 (sim_cpu *cpu, uint64_t address)
11740{
bf155438 11741 vec_store (cpu, address, 1, 3);
2e8cf49e
NC
11742}
11743
bf155438 11744/* Store multiple 1-element structures from four registers. */
2e8cf49e
NC
11745static void
11746ST1_4 (sim_cpu *cpu, uint64_t address)
11747{
bf155438 11748 vec_store (cpu, address, 1, 4);
2e8cf49e
NC
11749}
11750
e8f42b5e
JW
11751#define LDn_STn_SINGLE_LANE_AND_SIZE() \
11752 do \
11753 { \
11754 switch (INSTR (15, 14)) \
11755 { \
11756 case 0: \
11757 lane = (full << 3) | (s << 2) | size; \
11758 size = 0; \
11759 break; \
11760 \
11761 case 1: \
11762 if ((size & 1) == 1) \
11763 HALT_UNALLOC; \
11764 lane = (full << 2) | (s << 1) | (size >> 1); \
11765 size = 1; \
11766 break; \
11767 \
11768 case 2: \
11769 if ((size & 2) == 2) \
11770 HALT_UNALLOC; \
11771 \
11772 if ((size & 1) == 0) \
11773 { \
11774 lane = (full << 1) | s; \
11775 size = 2; \
11776 } \
11777 else \
11778 { \
11779 if (s) \
11780 HALT_UNALLOC; \
11781 lane = full; \
11782 size = 3; \
11783 } \
11784 break; \
11785 \
11786 default: \
11787 HALT_UNALLOC; \
11788 } \
11789 } \
11790 while (0)
11791
11792/* Load single structure into one lane of N registers. */
2e8cf49e 11793static void
e8f42b5e 11794do_vec_LDn_single (sim_cpu *cpu, uint64_t address)
2e8cf49e
NC
11795{
11796 /* instr[31] = 0
11797 instr[30] = element selector 0=>half, 1=>all elements
11798 instr[29,24] = 00 1101
11799 instr[23] = 0=>simple, 1=>post
11800 instr[22] = 1
e8f42b5e 11801 instr[21] = width: LD1-or-LD3 (0) / LD2-or-LD4 (1)
2e8cf49e
NC
11802 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
11803 11111 (immediate post inc)
e8f42b5e
JW
11804 instr[15,13] = opcode
11805 instr[12] = S, used for lane number
11806 instr[11,10] = size, also used for lane number
2e8cf49e
NC
11807 instr[9,5] = address
11808 instr[4,0] = Vd */
11809
ef0d8ffc
NC
11810 unsigned full = INSTR (30, 30);
11811 unsigned vd = INSTR (4, 0);
11812 unsigned size = INSTR (11, 10);
e8f42b5e
JW
11813 unsigned s = INSTR (12, 12);
11814 int nregs = ((INSTR (13, 13) << 1) | INSTR (21, 21)) + 1;
11815 int lane = 0;
2e8cf49e
NC
11816 int i;
11817
11818 NYI_assert (29, 24, 0x0D);
11819 NYI_assert (22, 22, 1);
2e8cf49e 11820
e8f42b5e
JW
11821 /* Compute the lane number first (using size), and then compute size. */
11822 LDn_STn_SINGLE_LANE_AND_SIZE ();
2e8cf49e 11823
e8f42b5e
JW
11824 for (i = 0; i < nregs; i++)
11825 switch (size)
11826 {
11827 case 0:
11828 {
11829 uint8_t val = aarch64_get_mem_u8 (cpu, address + i);
11830 aarch64_set_vec_u8 (cpu, vd + i, lane, val);
11831 break;
2e8cf49e 11832 }
2e8cf49e 11833
e8f42b5e 11834 case 1:
2e8cf49e 11835 {
e8f42b5e
JW
11836 uint16_t val = aarch64_get_mem_u16 (cpu, address + (i * 2));
11837 aarch64_set_vec_u16 (cpu, vd + i, lane, val);
11838 break;
11839 }
2e8cf49e 11840
e8f42b5e
JW
11841 case 2:
11842 {
11843 uint32_t val = aarch64_get_mem_u32 (cpu, address + (i * 4));
11844 aarch64_set_vec_u32 (cpu, vd + i, lane, val);
11845 break;
11846 }
2e8cf49e 11847
e8f42b5e
JW
11848 case 3:
11849 {
11850 uint64_t val = aarch64_get_mem_u64 (cpu, address + (i * 8));
11851 aarch64_set_vec_u64 (cpu, vd + i, lane, val);
11852 break;
11853 }
11854 }
11855}
2e8cf49e 11856
e8f42b5e
JW
11857/* Store single structure from one lane from N registers. */
11858static void
11859do_vec_STn_single (sim_cpu *cpu, uint64_t address)
11860{
11861 /* instr[31] = 0
11862 instr[30] = element selector 0=>half, 1=>all elements
11863 instr[29,24] = 00 1101
11864 instr[23] = 0=>simple, 1=>post
11865 instr[22] = 0
11866 instr[21] = width: LD1-or-LD3 (0) / LD2-or-LD4 (1)
11867 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
11868 11111 (immediate post inc)
11869 instr[15,13] = opcode
11870 instr[12] = S, used for lane number
11871 instr[11,10] = size, also used for lane number
11872 instr[9,5] = address
11873 instr[4,0] = Vd */
2e8cf49e 11874
e8f42b5e
JW
11875 unsigned full = INSTR (30, 30);
11876 unsigned vd = INSTR (4, 0);
11877 unsigned size = INSTR (11, 10);
11878 unsigned s = INSTR (12, 12);
11879 int nregs = ((INSTR (13, 13) << 1) | INSTR (21, 21)) + 1;
11880 int lane = 0;
11881 int i;
2e8cf49e 11882
e8f42b5e
JW
11883 NYI_assert (29, 24, 0x0D);
11884 NYI_assert (22, 22, 0);
2e8cf49e 11885
e8f42b5e
JW
11886 /* Compute the lane number first (using size), and then compute size. */
11887 LDn_STn_SINGLE_LANE_AND_SIZE ();
2e8cf49e 11888
e8f42b5e
JW
11889 for (i = 0; i < nregs; i++)
11890 switch (size)
11891 {
11892 case 0:
11893 {
11894 uint8_t val = aarch64_get_vec_u8 (cpu, vd + i, lane);
11895 aarch64_set_mem_u8 (cpu, address + i, val);
11896 break;
2e8cf49e 11897 }
2e8cf49e 11898
e8f42b5e 11899 case 1:
2e8cf49e 11900 {
e8f42b5e
JW
11901 uint16_t val = aarch64_get_vec_u16 (cpu, vd + i, lane);
11902 aarch64_set_mem_u16 (cpu, address + (i * 2), val);
2e8cf49e 11903 break;
e8f42b5e 11904 }
2e8cf49e 11905
e8f42b5e
JW
11906 case 2:
11907 {
11908 uint32_t val = aarch64_get_vec_u32 (cpu, vd + i, lane);
11909 aarch64_set_mem_u32 (cpu, address + (i * 4), val);
2e8cf49e 11910 break;
e8f42b5e 11911 }
2e8cf49e 11912
e8f42b5e
JW
11913 case 3:
11914 {
11915 uint64_t val = aarch64_get_vec_u64 (cpu, vd + i, lane);
11916 aarch64_set_mem_u64 (cpu, address + (i * 8), val);
2e8cf49e 11917 break;
e8f42b5e
JW
11918 }
11919 }
11920}
2e8cf49e 11921
e8f42b5e
JW
11922/* Load single structure into all lanes of N registers. */
11923static void
11924do_vec_LDnR (sim_cpu *cpu, uint64_t address)
11925{
11926 /* instr[31] = 0
11927 instr[30] = element selector 0=>half, 1=>all elements
11928 instr[29,24] = 00 1101
11929 instr[23] = 0=>simple, 1=>post
11930 instr[22] = 1
11931 instr[21] = width: LD1R-or-LD3R (0) / LD2R-or-LD4R (1)
11932 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
11933 11111 (immediate post inc)
11934 instr[15,14] = 11
11935 instr[13] = width: LD1R-or-LD2R (0) / LD3R-or-LD4R (1)
11936 instr[12] = 0
11937 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11938 10=> word(s), 11=> double(d)
11939 instr[9,5] = address
11940 instr[4,0] = Vd */
2e8cf49e 11941
e8f42b5e
JW
11942 unsigned full = INSTR (30, 30);
11943 unsigned vd = INSTR (4, 0);
11944 unsigned size = INSTR (11, 10);
11945 int nregs = ((INSTR (13, 13) << 1) | INSTR (21, 21)) + 1;
11946 int i, n;
2e8cf49e 11947
e8f42b5e
JW
11948 NYI_assert (29, 24, 0x0D);
11949 NYI_assert (22, 22, 1);
11950 NYI_assert (15, 14, 3);
11951 NYI_assert (12, 12, 0);
2e8cf49e 11952
e8f42b5e
JW
11953 for (n = 0; n < nregs; n++)
11954 switch (size)
11955 {
11956 case 0:
2e8cf49e 11957 {
e8f42b5e
JW
11958 uint8_t val = aarch64_get_mem_u8 (cpu, address + n);
11959 for (i = 0; i < (full ? 16 : 8); i++)
11960 aarch64_set_vec_u8 (cpu, vd + n, i, val);
2e8cf49e 11961 break;
e8f42b5e 11962 }
2e8cf49e 11963
e8f42b5e
JW
11964 case 1:
11965 {
11966 uint16_t val = aarch64_get_mem_u16 (cpu, address + (n * 2));
11967 for (i = 0; i < (full ? 8 : 4); i++)
11968 aarch64_set_vec_u16 (cpu, vd + n, i, val);
2e8cf49e 11969 break;
e8f42b5e 11970 }
2e8cf49e 11971
e8f42b5e
JW
11972 case 2:
11973 {
11974 uint32_t val = aarch64_get_mem_u32 (cpu, address + (n * 4));
11975 for (i = 0; i < (full ? 4 : 2); i++)
11976 aarch64_set_vec_u32 (cpu, vd + n, i, val);
2e8cf49e 11977 break;
e8f42b5e 11978 }
2e8cf49e 11979
e8f42b5e
JW
11980 case 3:
11981 {
11982 uint64_t val = aarch64_get_mem_u64 (cpu, address + (n * 8));
11983 for (i = 0; i < (full ? 2 : 1); i++)
11984 aarch64_set_vec_u64 (cpu, vd + n, i, val);
2e8cf49e 11985 break;
2e8cf49e 11986 }
2e8cf49e 11987
e8f42b5e
JW
11988 default:
11989 HALT_UNALLOC;
11990 }
2e8cf49e
NC
11991}
11992
11993static void
11994do_vec_load_store (sim_cpu *cpu)
11995{
11996 /* {LD|ST}<N> {Vd..Vd+N}, vaddr
11997
11998 instr[31] = 0
11999 instr[30] = element selector 0=>half, 1=>all elements
12000 instr[29,25] = 00110
e8f42b5e 12001 instr[24] = 0=>multiple struct, 1=>single struct
2e8cf49e
NC
12002 instr[23] = 0=>simple, 1=>post
12003 instr[22] = 0=>store, 1=>load
12004 instr[21] = 0 (LDn) / small(0)-large(1) selector (LDnR)
12005 instr[20,16] = 00000 (simple), Vinc (reg-post-inc, no SP),
12006 11111 (immediate post inc)
12007 instr[15,12] = elements and destinations. eg for load:
12008 0000=>LD4 => load multiple 4-element to
12009 four consecutive registers
12010 0100=>LD3 => load multiple 3-element to
12011 three consecutive registers
12012 1000=>LD2 => load multiple 2-element to
12013 two consecutive registers
12014 0010=>LD1 => load multiple 1-element to
12015 four consecutive registers
12016 0110=>LD1 => load multiple 1-element to
12017 three consecutive registers
12018 1010=>LD1 => load multiple 1-element to
12019 two consecutive registers
12020 0111=>LD1 => load multiple 1-element to
12021 one register
12022 1100=>LDR1,LDR2
12023 1110=>LDR3,LDR4
12024 instr[11,10] = element size 00=> byte(b), 01=> half(h),
12025 10=> word(s), 11=> double(d)
12026 instr[9,5] = Vn, can be SP
12027 instr[4,0] = Vd */
12028
e8f42b5e 12029 int single;
2e8cf49e
NC
12030 int post;
12031 int load;
12032 unsigned vn;
12033 uint64_t address;
12034 int type;
12035
7517e550 12036 if (INSTR (31, 31) != 0 || INSTR (29, 25) != 0x06)
2e8cf49e
NC
12037 HALT_NYI;
12038
e8f42b5e 12039 single = INSTR (24, 24);
ef0d8ffc
NC
12040 post = INSTR (23, 23);
12041 load = INSTR (22, 22);
e8f42b5e 12042 type = INSTR (15, 12);
ef0d8ffc 12043 vn = INSTR (9, 5);
2e8cf49e
NC
12044 address = aarch64_get_reg_u64 (cpu, vn, SP_OK);
12045
e8f42b5e
JW
12046 if (! single && INSTR (21, 21) != 0)
12047 HALT_UNALLOC;
12048
2e8cf49e
NC
12049 if (post)
12050 {
ef0d8ffc 12051 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
12052
12053 if (vm == R31)
12054 {
12055 unsigned sizeof_operation;
12056
e8f42b5e 12057 if (single)
2e8cf49e 12058 {
e8f42b5e
JW
12059 if ((type >= 0) && (type <= 11))
12060 {
12061 int nregs = ((INSTR (13, 13) << 1) | INSTR (21, 21)) + 1;
12062 switch (INSTR (15, 14))
12063 {
12064 case 0:
12065 sizeof_operation = nregs * 1;
12066 break;
12067 case 1:
12068 sizeof_operation = nregs * 2;
12069 break;
12070 case 2:
12071 if (INSTR (10, 10) == 0)
12072 sizeof_operation = nregs * 4;
12073 else
12074 sizeof_operation = nregs * 8;
12075 break;
12076 default:
12077 HALT_UNALLOC;
12078 }
12079 }
12080 else if (type == 0xC)
12081 {
12082 sizeof_operation = INSTR (21, 21) ? 2 : 1;
12083 sizeof_operation <<= INSTR (11, 10);
12084 }
12085 else if (type == 0xE)
12086 {
12087 sizeof_operation = INSTR (21, 21) ? 4 : 3;
12088 sizeof_operation <<= INSTR (11, 10);
12089 }
12090 else
12091 HALT_UNALLOC;
12092 }
12093 else
12094 {
12095 switch (type)
12096 {
12097 case 0: sizeof_operation = 32; break;
12098 case 4: sizeof_operation = 24; break;
12099 case 8: sizeof_operation = 16; break;
2e8cf49e 12100
e8f42b5e
JW
12101 case 7:
12102 /* One register, immediate offset variant. */
12103 sizeof_operation = 8;
12104 break;
2e8cf49e 12105
e8f42b5e
JW
12106 case 10:
12107 /* Two registers, immediate offset variant. */
12108 sizeof_operation = 16;
12109 break;
ef0d8ffc 12110
e8f42b5e
JW
12111 case 6:
12112 /* Three registers, immediate offset variant. */
12113 sizeof_operation = 24;
12114 break;
57aa1742 12115
e8f42b5e
JW
12116 case 2:
12117 /* Four registers, immediate offset variant. */
12118 sizeof_operation = 32;
12119 break;
57aa1742 12120
e8f42b5e
JW
12121 default:
12122 HALT_UNALLOC;
12123 }
2e8cf49e 12124
e8f42b5e
JW
12125 if (INSTR (30, 30))
12126 sizeof_operation *= 2;
2e8cf49e
NC
12127 }
12128
2e8cf49e
NC
12129 aarch64_set_reg_u64 (cpu, vn, SP_OK, address + sizeof_operation);
12130 }
12131 else
12132 aarch64_set_reg_u64 (cpu, vn, SP_OK,
12133 address + aarch64_get_reg_u64 (cpu, vm, NO_SP));
12134 }
12135 else
12136 {
12137 NYI_assert (20, 16, 0);
12138 }
12139
e8f42b5e
JW
12140 if (single)
12141 {
12142 if (load)
12143 {
12144 if ((type >= 0) && (type <= 11))
12145 do_vec_LDn_single (cpu, address);
12146 else if ((type == 0xC) || (type == 0xE))
12147 do_vec_LDnR (cpu, address);
12148 else
12149 HALT_UNALLOC;
12150 return;
12151 }
12152
12153 /* Stores. */
12154 if ((type >= 0) && (type <= 11))
12155 {
12156 do_vec_STn_single (cpu, address);
12157 return;
12158 }
12159
12160 HALT_UNALLOC;
12161 }
12162
2e8cf49e
NC
12163 if (load)
12164 {
12165 switch (type)
12166 {
12167 case 0: LD4 (cpu, address); return;
12168 case 4: LD3 (cpu, address); return;
12169 case 8: LD2 (cpu, address); return;
12170 case 2: LD1_4 (cpu, address); return;
12171 case 6: LD1_3 (cpu, address); return;
12172 case 10: LD1_2 (cpu, address); return;
12173 case 7: LD1_1 (cpu, address); return;
12174
2e8cf49e 12175 default:
e8f42b5e 12176 HALT_UNALLOC;
2e8cf49e
NC
12177 }
12178 }
12179
12180 /* Stores. */
12181 switch (type)
12182 {
12183 case 0: ST4 (cpu, address); return;
12184 case 4: ST3 (cpu, address); return;
12185 case 8: ST2 (cpu, address); return;
12186 case 2: ST1_4 (cpu, address); return;
12187 case 6: ST1_3 (cpu, address); return;
12188 case 10: ST1_2 (cpu, address); return;
12189 case 7: ST1_1 (cpu, address); return;
12190 default:
e8f42b5e 12191 HALT_UNALLOC;
2e8cf49e
NC
12192 }
12193}
12194
12195static void
12196dexLdSt (sim_cpu *cpu)
12197{
12198 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12199 assert group == GROUP_LDST_0100 || group == GROUP_LDST_0110 ||
12200 group == GROUP_LDST_1100 || group == GROUP_LDST_1110
12201 bits [29,28:26] of a LS are the secondary dispatch vector. */
12202 uint32_t group2 = dispatchLS (aarch64_get_instr (cpu));
12203
12204 switch (group2)
12205 {
12206 case LS_EXCL_000:
12207 dexLoadExclusive (cpu); return;
12208
12209 case LS_LIT_010:
12210 case LS_LIT_011:
12211 dexLoadLiteral (cpu); return;
12212
12213 case LS_OTHER_110:
12214 case LS_OTHER_111:
12215 dexLoadOther (cpu); return;
12216
12217 case LS_ADVSIMD_001:
12218 do_vec_load_store (cpu); return;
12219
12220 case LS_PAIR_100:
12221 dex_load_store_pair_gr (cpu); return;
12222
12223 case LS_PAIR_101:
12224 dex_load_store_pair_fp (cpu); return;
12225
12226 default:
12227 /* Should never reach here. */
12228 HALT_NYI;
12229 }
12230}
12231
12232/* Specific decode and execute for group Data Processing Register. */
12233
12234static void
12235dexLogicalShiftedRegister (sim_cpu *cpu)
12236{
ef0d8ffc
NC
12237 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12238 instr[30,29] = op
12239 instr[28:24] = 01010
2e8cf49e 12240 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> ROR
ef0d8ffc
NC
12241 instr[21] = N
12242 instr[20,16] = Rm
2e8cf49e 12243 instr[15,10] = count : must be 0xxxxx for 32 bit
ef0d8ffc
NC
12244 instr[9,5] = Rn
12245 instr[4,0] = Rd */
2e8cf49e 12246
ef0d8ffc
NC
12247 uint32_t size = INSTR (31, 31);
12248 Shift shiftType = INSTR (23, 22);
12249 uint32_t count = INSTR (15, 10);
2e8cf49e 12250
ef0d8ffc
NC
12251 /* 32 bit operations must have count[5] = 0.
12252 or else we have an UNALLOC. */
12253 if (size == 0 && uimm (count, 5, 5))
2e8cf49e
NC
12254 HALT_UNALLOC;
12255
ef0d8ffc
NC
12256 /* Dispatch on size:op:N. */
12257 switch ((INSTR (31, 29) << 1) | INSTR (21, 21))
2e8cf49e
NC
12258 {
12259 case 0: and32_shift (cpu, shiftType, count); return;
12260 case 1: bic32_shift (cpu, shiftType, count); return;
12261 case 2: orr32_shift (cpu, shiftType, count); return;
12262 case 3: orn32_shift (cpu, shiftType, count); return;
12263 case 4: eor32_shift (cpu, shiftType, count); return;
12264 case 5: eon32_shift (cpu, shiftType, count); return;
12265 case 6: ands32_shift (cpu, shiftType, count); return;
12266 case 7: bics32_shift (cpu, shiftType, count); return;
12267 case 8: and64_shift (cpu, shiftType, count); return;
12268 case 9: bic64_shift (cpu, shiftType, count); return;
12269 case 10:orr64_shift (cpu, shiftType, count); return;
12270 case 11:orn64_shift (cpu, shiftType, count); return;
12271 case 12:eor64_shift (cpu, shiftType, count); return;
12272 case 13:eon64_shift (cpu, shiftType, count); return;
12273 case 14:ands64_shift (cpu, shiftType, count); return;
12274 case 15:bics64_shift (cpu, shiftType, count); return;
2e8cf49e
NC
12275 }
12276}
12277
12278/* 32 bit conditional select. */
12279static void
12280csel32 (sim_cpu *cpu, CondCode cc)
12281{
ef0d8ffc
NC
12282 unsigned rm = INSTR (20, 16);
12283 unsigned rn = INSTR (9, 5);
12284 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12285
12286 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12287 testConditionCode (cpu, cc)
12288 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12289 : aarch64_get_reg_u32 (cpu, rm, NO_SP));
12290}
12291
12292/* 64 bit conditional select. */
12293static void
12294csel64 (sim_cpu *cpu, CondCode cc)
12295{
ef0d8ffc
NC
12296 unsigned rm = INSTR (20, 16);
12297 unsigned rn = INSTR (9, 5);
12298 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12299
12300 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12301 testConditionCode (cpu, cc)
12302 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12303 : aarch64_get_reg_u64 (cpu, rm, NO_SP));
12304}
12305
12306/* 32 bit conditional increment. */
12307static void
12308csinc32 (sim_cpu *cpu, CondCode cc)
12309{
ef0d8ffc
NC
12310 unsigned rm = INSTR (20, 16);
12311 unsigned rn = INSTR (9, 5);
12312 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12313
12314 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12315 testConditionCode (cpu, cc)
12316 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12317 : aarch64_get_reg_u32 (cpu, rm, NO_SP) + 1);
12318}
12319
12320/* 64 bit conditional increment. */
12321static void
12322csinc64 (sim_cpu *cpu, CondCode cc)
12323{
ef0d8ffc
NC
12324 unsigned rm = INSTR (20, 16);
12325 unsigned rn = INSTR (9, 5);
12326 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12327
12328 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12329 testConditionCode (cpu, cc)
12330 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12331 : aarch64_get_reg_u64 (cpu, rm, NO_SP) + 1);
12332}
12333
12334/* 32 bit conditional invert. */
12335static void
12336csinv32 (sim_cpu *cpu, CondCode cc)
12337{
ef0d8ffc
NC
12338 unsigned rm = INSTR (20, 16);
12339 unsigned rn = INSTR (9, 5);
12340 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12341
12342 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12343 testConditionCode (cpu, cc)
12344 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12345 : ~ aarch64_get_reg_u32 (cpu, rm, NO_SP));
12346}
12347
12348/* 64 bit conditional invert. */
12349static void
12350csinv64 (sim_cpu *cpu, CondCode cc)
12351{
ef0d8ffc
NC
12352 unsigned rm = INSTR (20, 16);
12353 unsigned rn = INSTR (9, 5);
12354 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12355
12356 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12357 testConditionCode (cpu, cc)
12358 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12359 : ~ aarch64_get_reg_u64 (cpu, rm, NO_SP));
12360}
12361
12362/* 32 bit conditional negate. */
12363static void
12364csneg32 (sim_cpu *cpu, CondCode cc)
12365{
ef0d8ffc
NC
12366 unsigned rm = INSTR (20, 16);
12367 unsigned rn = INSTR (9, 5);
12368 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12369
12370 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12371 testConditionCode (cpu, cc)
12372 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
12373 : - aarch64_get_reg_u32 (cpu, rm, NO_SP));
12374}
12375
12376/* 64 bit conditional negate. */
12377static void
12378csneg64 (sim_cpu *cpu, CondCode cc)
12379{
ef0d8ffc
NC
12380 unsigned rm = INSTR (20, 16);
12381 unsigned rn = INSTR (9, 5);
12382 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12383
12384 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12385 testConditionCode (cpu, cc)
12386 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
12387 : - aarch64_get_reg_u64 (cpu, rm, NO_SP));
12388}
12389
12390static void
12391dexCondSelect (sim_cpu *cpu)
12392{
ef0d8ffc
NC
12393 /* instr[28,21] = 11011011
12394 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2e8cf49e
NC
12395 instr[30:11,10] = op : 000 ==> CSEL, 001 ==> CSINC,
12396 100 ==> CSINV, 101 ==> CSNEG,
12397 _1_ ==> UNALLOC
12398 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
12399 instr[15,12] = cond
12400 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC */
12401
ef0d8ffc
NC
12402 CondCode cc = INSTR (15, 12);
12403 uint32_t S = INSTR (29, 29);
12404 uint32_t op2 = INSTR (11, 10);
2e8cf49e
NC
12405
12406 if (S == 1)
12407 HALT_UNALLOC;
12408
12409 if (op2 & 0x2)
12410 HALT_UNALLOC;
12411
ef0d8ffc 12412 switch ((INSTR (31, 30) << 1) | op2)
2e8cf49e
NC
12413 {
12414 case 0: csel32 (cpu, cc); return;
12415 case 1: csinc32 (cpu, cc); return;
12416 case 2: csinv32 (cpu, cc); return;
12417 case 3: csneg32 (cpu, cc); return;
12418 case 4: csel64 (cpu, cc); return;
12419 case 5: csinc64 (cpu, cc); return;
12420 case 6: csinv64 (cpu, cc); return;
12421 case 7: csneg64 (cpu, cc); return;
2e8cf49e
NC
12422 }
12423}
12424
12425/* Some helpers for counting leading 1 or 0 bits. */
12426
12427/* Counts the number of leading bits which are the same
12428 in a 32 bit value in the range 1 to 32. */
12429static uint32_t
12430leading32 (uint32_t value)
12431{
12432 int32_t mask= 0xffff0000;
12433 uint32_t count= 16; /* Counts number of bits set in mask. */
12434 uint32_t lo = 1; /* Lower bound for number of sign bits. */
12435 uint32_t hi = 32; /* Upper bound for number of sign bits. */
12436
12437 while (lo + 1 < hi)
12438 {
12439 int32_t test = (value & mask);
12440
12441 if (test == 0 || test == mask)
12442 {
12443 lo = count;
12444 count = (lo + hi) / 2;
12445 mask >>= (count - lo);
12446 }
12447 else
12448 {
12449 hi = count;
12450 count = (lo + hi) / 2;
12451 mask <<= hi - count;
12452 }
12453 }
12454
12455 if (lo != hi)
12456 {
12457 int32_t test;
12458
12459 mask >>= 1;
12460 test = (value & mask);
12461
12462 if (test == 0 || test == mask)
12463 count = hi;
12464 else
12465 count = lo;
12466 }
12467
12468 return count;
12469}
12470
12471/* Counts the number of leading bits which are the same
12472 in a 64 bit value in the range 1 to 64. */
12473static uint64_t
12474leading64 (uint64_t value)
12475{
12476 int64_t mask= 0xffffffff00000000LL;
12477 uint64_t count = 32; /* Counts number of bits set in mask. */
12478 uint64_t lo = 1; /* Lower bound for number of sign bits. */
12479 uint64_t hi = 64; /* Upper bound for number of sign bits. */
12480
12481 while (lo + 1 < hi)
12482 {
12483 int64_t test = (value & mask);
12484
12485 if (test == 0 || test == mask)
12486 {
12487 lo = count;
12488 count = (lo + hi) / 2;
12489 mask >>= (count - lo);
12490 }
12491 else
12492 {
12493 hi = count;
12494 count = (lo + hi) / 2;
12495 mask <<= hi - count;
12496 }
12497 }
12498
12499 if (lo != hi)
12500 {
12501 int64_t test;
12502
12503 mask >>= 1;
12504 test = (value & mask);
12505
12506 if (test == 0 || test == mask)
12507 count = hi;
12508 else
12509 count = lo;
12510 }
12511
12512 return count;
12513}
12514
12515/* Bit operations. */
12516/* N.B register args may not be SP. */
12517
12518/* 32 bit count leading sign bits. */
12519static void
12520cls32 (sim_cpu *cpu)
12521{
ef0d8ffc
NC
12522 unsigned rn = INSTR (9, 5);
12523 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12524
12525 /* N.B. the result needs to exclude the leading bit. */
12526 aarch64_set_reg_u64
12527 (cpu, rd, NO_SP, leading32 (aarch64_get_reg_u32 (cpu, rn, NO_SP)) - 1);
12528}
12529
12530/* 64 bit count leading sign bits. */
12531static void
12532cls64 (sim_cpu *cpu)
12533{
ef0d8ffc
NC
12534 unsigned rn = INSTR (9, 5);
12535 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12536
12537 /* N.B. the result needs to exclude the leading bit. */
12538 aarch64_set_reg_u64
12539 (cpu, rd, NO_SP, leading64 (aarch64_get_reg_u64 (cpu, rn, NO_SP)) - 1);
12540}
12541
12542/* 32 bit count leading zero bits. */
12543static void
12544clz32 (sim_cpu *cpu)
12545{
ef0d8ffc
NC
12546 unsigned rn = INSTR (9, 5);
12547 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12548 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12549
12550 /* if the sign (top) bit is set then the count is 0. */
12551 if (pick32 (value, 31, 31))
12552 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
12553 else
12554 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading32 (value));
12555}
12556
12557/* 64 bit count leading zero bits. */
12558static void
12559clz64 (sim_cpu *cpu)
12560{
ef0d8ffc
NC
12561 unsigned rn = INSTR (9, 5);
12562 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12563 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12564
12565 /* if the sign (top) bit is set then the count is 0. */
12566 if (pick64 (value, 63, 63))
12567 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
12568 else
12569 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading64 (value));
12570}
12571
12572/* 32 bit reverse bits. */
12573static void
12574rbit32 (sim_cpu *cpu)
12575{
ef0d8ffc
NC
12576 unsigned rn = INSTR (9, 5);
12577 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12578 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12579 uint32_t result = 0;
12580 int i;
12581
12582 for (i = 0; i < 32; i++)
12583 {
12584 result <<= 1;
12585 result |= (value & 1);
12586 value >>= 1;
12587 }
12588 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12589}
12590
12591/* 64 bit reverse bits. */
12592static void
12593rbit64 (sim_cpu *cpu)
12594{
ef0d8ffc
NC
12595 unsigned rn = INSTR (9, 5);
12596 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12597 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12598 uint64_t result = 0;
12599 int i;
12600
12601 for (i = 0; i < 64; i++)
12602 {
12603 result <<= 1;
57aa1742 12604 result |= (value & 1UL);
2e8cf49e
NC
12605 value >>= 1;
12606 }
12607 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12608}
12609
12610/* 32 bit reverse bytes. */
12611static void
12612rev32 (sim_cpu *cpu)
12613{
ef0d8ffc
NC
12614 unsigned rn = INSTR (9, 5);
12615 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12616 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12617 uint32_t result = 0;
12618 int i;
12619
12620 for (i = 0; i < 4; i++)
12621 {
12622 result <<= 8;
12623 result |= (value & 0xff);
12624 value >>= 8;
12625 }
12626 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12627}
12628
12629/* 64 bit reverse bytes. */
12630static void
12631rev64 (sim_cpu *cpu)
12632{
ef0d8ffc
NC
12633 unsigned rn = INSTR (9, 5);
12634 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12635 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12636 uint64_t result = 0;
12637 int i;
12638
12639 for (i = 0; i < 8; i++)
12640 {
12641 result <<= 8;
12642 result |= (value & 0xffULL);
12643 value >>= 8;
12644 }
12645 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12646}
12647
12648/* 32 bit reverse shorts. */
12649/* N.B.this reverses the order of the bytes in each half word. */
12650static void
12651revh32 (sim_cpu *cpu)
12652{
ef0d8ffc
NC
12653 unsigned rn = INSTR (9, 5);
12654 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12655 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12656 uint32_t result = 0;
12657 int i;
12658
12659 for (i = 0; i < 2; i++)
12660 {
12661 result <<= 8;
12662 result |= (value & 0x00ff00ff);
12663 value >>= 8;
12664 }
12665 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12666}
12667
12668/* 64 bit reverse shorts. */
12669/* N.B.this reverses the order of the bytes in each half word. */
12670static void
12671revh64 (sim_cpu *cpu)
12672{
ef0d8ffc
NC
12673 unsigned rn = INSTR (9, 5);
12674 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12675 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12676 uint64_t result = 0;
12677 int i;
12678
12679 for (i = 0; i < 2; i++)
12680 {
12681 result <<= 8;
12682 result |= (value & 0x00ff00ff00ff00ffULL);
12683 value >>= 8;
12684 }
12685 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12686}
12687
12688static void
12689dexDataProc1Source (sim_cpu *cpu)
12690{
ef0d8ffc
NC
12691 /* instr[30] = 1
12692 instr[28,21] = 111010110
12693 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12694 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
2e8cf49e
NC
12695 instr[20,16] = opcode2 : 00000 ==> ok, ow ==> UNALLOC
12696 instr[15,10] = opcode : 000000 ==> RBIT, 000001 ==> REV16,
12697 000010 ==> REV, 000011 ==> UNALLOC
12698 000100 ==> CLZ, 000101 ==> CLS
12699 ow ==> UNALLOC
ef0d8ffc
NC
12700 instr[9,5] = rn : may not be SP
12701 instr[4,0] = rd : may not be SP. */
2e8cf49e 12702
ef0d8ffc
NC
12703 uint32_t S = INSTR (29, 29);
12704 uint32_t opcode2 = INSTR (20, 16);
12705 uint32_t opcode = INSTR (15, 10);
12706 uint32_t dispatch = ((INSTR (31, 31) << 3) | opcode);
2e8cf49e
NC
12707
12708 if (S == 1)
12709 HALT_UNALLOC;
12710
12711 if (opcode2 != 0)
12712 HALT_UNALLOC;
12713
12714 if (opcode & 0x38)
12715 HALT_UNALLOC;
12716
12717 switch (dispatch)
12718 {
12719 case 0: rbit32 (cpu); return;
12720 case 1: revh32 (cpu); return;
12721 case 2: rev32 (cpu); return;
12722 case 4: clz32 (cpu); return;
12723 case 5: cls32 (cpu); return;
12724 case 8: rbit64 (cpu); return;
12725 case 9: revh64 (cpu); return;
12726 case 10:rev32 (cpu); return;
12727 case 11:rev64 (cpu); return;
12728 case 12:clz64 (cpu); return;
12729 case 13:cls64 (cpu); return;
12730 default: HALT_UNALLOC;
12731 }
12732}
12733
12734/* Variable shift.
12735 Shifts by count supplied in register.
12736 N.B register args may not be SP.
12737 These all use the shifted auxiliary function for
12738 simplicity and clarity. Writing the actual shift
12739 inline would avoid a branch and so be faster but
12740 would also necessitate getting signs right. */
12741
12742/* 32 bit arithmetic shift right. */
12743static void
12744asrv32 (sim_cpu *cpu)
12745{
ef0d8ffc
NC
12746 unsigned rm = INSTR (20, 16);
12747 unsigned rn = INSTR (9, 5);
12748 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12749
12750 aarch64_set_reg_u64
12751 (cpu, rd, NO_SP,
12752 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ASR,
12753 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12754}
12755
12756/* 64 bit arithmetic shift right. */
12757static void
12758asrv64 (sim_cpu *cpu)
12759{
ef0d8ffc
NC
12760 unsigned rm = INSTR (20, 16);
12761 unsigned rn = INSTR (9, 5);
12762 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12763
12764 aarch64_set_reg_u64
12765 (cpu, rd, NO_SP,
12766 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ASR,
12767 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12768}
12769
12770/* 32 bit logical shift left. */
12771static void
12772lslv32 (sim_cpu *cpu)
12773{
ef0d8ffc
NC
12774 unsigned rm = INSTR (20, 16);
12775 unsigned rn = INSTR (9, 5);
12776 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12777
12778 aarch64_set_reg_u64
12779 (cpu, rd, NO_SP,
12780 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSL,
12781 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12782}
12783
12784/* 64 bit arithmetic shift left. */
12785static void
12786lslv64 (sim_cpu *cpu)
12787{
ef0d8ffc
NC
12788 unsigned rm = INSTR (20, 16);
12789 unsigned rn = INSTR (9, 5);
12790 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12791
12792 aarch64_set_reg_u64
12793 (cpu, rd, NO_SP,
12794 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSL,
12795 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12796}
12797
12798/* 32 bit logical shift right. */
12799static void
12800lsrv32 (sim_cpu *cpu)
12801{
ef0d8ffc
NC
12802 unsigned rm = INSTR (20, 16);
12803 unsigned rn = INSTR (9, 5);
12804 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12805
12806 aarch64_set_reg_u64
12807 (cpu, rd, NO_SP,
12808 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSR,
12809 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12810}
12811
12812/* 64 bit logical shift right. */
12813static void
12814lsrv64 (sim_cpu *cpu)
12815{
ef0d8ffc
NC
12816 unsigned rm = INSTR (20, 16);
12817 unsigned rn = INSTR (9, 5);
12818 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12819
12820 aarch64_set_reg_u64
12821 (cpu, rd, NO_SP,
12822 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSR,
12823 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12824}
12825
12826/* 32 bit rotate right. */
12827static void
12828rorv32 (sim_cpu *cpu)
12829{
ef0d8ffc
NC
12830 unsigned rm = INSTR (20, 16);
12831 unsigned rn = INSTR (9, 5);
12832 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12833
12834 aarch64_set_reg_u64
12835 (cpu, rd, NO_SP,
12836 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ROR,
12837 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12838}
12839
12840/* 64 bit rotate right. */
12841static void
12842rorv64 (sim_cpu *cpu)
12843{
ef0d8ffc
NC
12844 unsigned rm = INSTR (20, 16);
12845 unsigned rn = INSTR (9, 5);
12846 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12847
12848 aarch64_set_reg_u64
12849 (cpu, rd, NO_SP,
12850 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ROR,
12851 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12852}
12853
12854
12855/* divide. */
12856
12857/* 32 bit signed divide. */
12858static void
12859cpuiv32 (sim_cpu *cpu)
12860{
ef0d8ffc
NC
12861 unsigned rm = INSTR (20, 16);
12862 unsigned rn = INSTR (9, 5);
12863 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12864 /* N.B. the pseudo-code does the divide using 64 bit data. */
12865 /* TODO : check that this rounds towards zero as required. */
12866 int64_t dividend = aarch64_get_reg_s32 (cpu, rn, NO_SP);
12867 int64_t divisor = aarch64_get_reg_s32 (cpu, rm, NO_SP);
12868
12869 aarch64_set_reg_s64 (cpu, rd, NO_SP,
12870 divisor ? ((int32_t) (dividend / divisor)) : 0);
12871}
12872
12873/* 64 bit signed divide. */
12874static void
12875cpuiv64 (sim_cpu *cpu)
12876{
ef0d8ffc
NC
12877 unsigned rm = INSTR (20, 16);
12878 unsigned rn = INSTR (9, 5);
12879 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12880
12881 /* TODO : check that this rounds towards zero as required. */
12882 int64_t divisor = aarch64_get_reg_s64 (cpu, rm, NO_SP);
12883
12884 aarch64_set_reg_s64
12885 (cpu, rd, NO_SP,
12886 divisor ? (aarch64_get_reg_s64 (cpu, rn, NO_SP) / divisor) : 0);
12887}
12888
12889/* 32 bit unsigned divide. */
12890static void
12891udiv32 (sim_cpu *cpu)
12892{
ef0d8ffc
NC
12893 unsigned rm = INSTR (20, 16);
12894 unsigned rn = INSTR (9, 5);
12895 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12896
12897 /* N.B. the pseudo-code does the divide using 64 bit data. */
12898 uint64_t dividend = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12899 uint64_t divisor = aarch64_get_reg_u32 (cpu, rm, NO_SP);
12900
12901 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12902 divisor ? (uint32_t) (dividend / divisor) : 0);
12903}
12904
12905/* 64 bit unsigned divide. */
12906static void
12907udiv64 (sim_cpu *cpu)
12908{
ef0d8ffc
NC
12909 unsigned rm = INSTR (20, 16);
12910 unsigned rn = INSTR (9, 5);
12911 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12912
12913 /* TODO : check that this rounds towards zero as required. */
12914 uint64_t divisor = aarch64_get_reg_u64 (cpu, rm, NO_SP);
12915
12916 aarch64_set_reg_u64
12917 (cpu, rd, NO_SP,
12918 divisor ? (aarch64_get_reg_u64 (cpu, rn, NO_SP) / divisor) : 0);
12919}
12920
12921static void
12922dexDataProc2Source (sim_cpu *cpu)
12923{
12924 /* assert instr[30] == 0
12925 instr[28,21] == 11010110
12926 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12927 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
12928 instr[15,10] = opcode : 000010 ==> UDIV, 000011 ==> CPUIV,
12929 001000 ==> LSLV, 001001 ==> LSRV
12930 001010 ==> ASRV, 001011 ==> RORV
12931 ow ==> UNALLOC. */
12932
12933 uint32_t dispatch;
ef0d8ffc
NC
12934 uint32_t S = INSTR (29, 29);
12935 uint32_t opcode = INSTR (15, 10);
2e8cf49e
NC
12936
12937 if (S == 1)
12938 HALT_UNALLOC;
12939
12940 if (opcode & 0x34)
12941 HALT_UNALLOC;
12942
ef0d8ffc 12943 dispatch = ( (INSTR (31, 31) << 3)
2e8cf49e
NC
12944 | (uimm (opcode, 3, 3) << 2)
12945 | uimm (opcode, 1, 0));
12946 switch (dispatch)
12947 {
12948 case 2: udiv32 (cpu); return;
12949 case 3: cpuiv32 (cpu); return;
12950 case 4: lslv32 (cpu); return;
12951 case 5: lsrv32 (cpu); return;
12952 case 6: asrv32 (cpu); return;
12953 case 7: rorv32 (cpu); return;
12954 case 10: udiv64 (cpu); return;
12955 case 11: cpuiv64 (cpu); return;
12956 case 12: lslv64 (cpu); return;
12957 case 13: lsrv64 (cpu); return;
12958 case 14: asrv64 (cpu); return;
12959 case 15: rorv64 (cpu); return;
12960 default: HALT_UNALLOC;
12961 }
12962}
12963
12964
12965/* Multiply. */
12966
12967/* 32 bit multiply and add. */
12968static void
12969madd32 (sim_cpu *cpu)
12970{
ef0d8ffc
NC
12971 unsigned rm = INSTR (20, 16);
12972 unsigned ra = INSTR (14, 10);
12973 unsigned rn = INSTR (9, 5);
12974 unsigned rd = INSTR (4, 0);
2e8cf49e 12975
2cdad34c 12976 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12977 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12978 aarch64_get_reg_u32 (cpu, ra, NO_SP)
12979 + aarch64_get_reg_u32 (cpu, rn, NO_SP)
12980 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
12981}
12982
12983/* 64 bit multiply and add. */
12984static void
12985madd64 (sim_cpu *cpu)
12986{
ef0d8ffc
NC
12987 unsigned rm = INSTR (20, 16);
12988 unsigned ra = INSTR (14, 10);
12989 unsigned rn = INSTR (9, 5);
12990 unsigned rd = INSTR (4, 0);
2e8cf49e 12991
2cdad34c 12992 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
12993 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12994 aarch64_get_reg_u64 (cpu, ra, NO_SP)
2cdad34c
NC
12995 + (aarch64_get_reg_u64 (cpu, rn, NO_SP)
12996 * aarch64_get_reg_u64 (cpu, rm, NO_SP)));
2e8cf49e
NC
12997}
12998
12999/* 32 bit multiply and sub. */
13000static void
13001msub32 (sim_cpu *cpu)
13002{
ef0d8ffc
NC
13003 unsigned rm = INSTR (20, 16);
13004 unsigned ra = INSTR (14, 10);
13005 unsigned rn = INSTR (9, 5);
13006 unsigned rd = INSTR (4, 0);
2e8cf49e 13007
2cdad34c 13008 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13009 aarch64_set_reg_u64 (cpu, rd, NO_SP,
13010 aarch64_get_reg_u32 (cpu, ra, NO_SP)
13011 - aarch64_get_reg_u32 (cpu, rn, NO_SP)
13012 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
13013}
13014
13015/* 64 bit multiply and sub. */
13016static void
13017msub64 (sim_cpu *cpu)
13018{
ef0d8ffc
NC
13019 unsigned rm = INSTR (20, 16);
13020 unsigned ra = INSTR (14, 10);
13021 unsigned rn = INSTR (9, 5);
13022 unsigned rd = INSTR (4, 0);
2e8cf49e 13023
2cdad34c 13024 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13025 aarch64_set_reg_u64 (cpu, rd, NO_SP,
13026 aarch64_get_reg_u64 (cpu, ra, NO_SP)
13027 - aarch64_get_reg_u64 (cpu, rn, NO_SP)
13028 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
13029}
13030
13031/* Signed multiply add long -- source, source2 : 32 bit, source3 : 64 bit. */
13032static void
13033smaddl (sim_cpu *cpu)
13034{
ef0d8ffc
NC
13035 unsigned rm = INSTR (20, 16);
13036 unsigned ra = INSTR (14, 10);
13037 unsigned rn = INSTR (9, 5);
13038 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
13039
13040 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
13041 obtain a 64 bit product. */
13042 aarch64_set_reg_s64
13043 (cpu, rd, NO_SP,
13044 aarch64_get_reg_s64 (cpu, ra, NO_SP)
13045 + ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
13046 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
13047}
13048
13049/* Signed multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
13050static void
13051smsubl (sim_cpu *cpu)
13052{
ef0d8ffc
NC
13053 unsigned rm = INSTR (20, 16);
13054 unsigned ra = INSTR (14, 10);
13055 unsigned rn = INSTR (9, 5);
13056 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
13057
13058 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
13059 obtain a 64 bit product. */
13060 aarch64_set_reg_s64
13061 (cpu, rd, NO_SP,
13062 aarch64_get_reg_s64 (cpu, ra, NO_SP)
13063 - ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
13064 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
13065}
13066
13067/* Integer Multiply/Divide. */
13068
13069/* First some macros and a helper function. */
13070/* Macros to test or access elements of 64 bit words. */
13071
13072/* Mask used to access lo 32 bits of 64 bit unsigned int. */
13073#define LOW_WORD_MASK ((1ULL << 32) - 1)
13074/* Return the lo 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
13075#define lowWordToU64(_value_u64) ((_value_u64) & LOW_WORD_MASK)
13076/* Return the hi 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
13077#define highWordToU64(_value_u64) ((_value_u64) >> 32)
13078
13079/* Offset of sign bit in 64 bit signed integger. */
13080#define SIGN_SHIFT_U64 63
13081/* The sign bit itself -- also identifies the minimum negative int value. */
13082#define SIGN_BIT_U64 (1UL << SIGN_SHIFT_U64)
13083/* Return true if a 64 bit signed int presented as an unsigned int is the
13084 most negative value. */
13085#define isMinimumU64(_value_u64) ((_value_u64) == SIGN_BIT_U64)
13086/* Return true (non-zero) if a 64 bit signed int presented as an unsigned
13087 int has its sign bit set to false. */
13088#define isSignSetU64(_value_u64) ((_value_u64) & SIGN_BIT_U64)
13089/* Return 1L or -1L according to whether a 64 bit signed int presented as
13090 an unsigned int has its sign bit set or not. */
13091#define signOfU64(_value_u64) (1L + (((value_u64) >> SIGN_SHIFT_U64) * -2L)
13092/* Clear the sign bit of a 64 bit signed int presented as an unsigned int. */
13093#define clearSignU64(_value_u64) ((_value_u64) &= ~SIGN_BIT_U64)
13094
13095/* Multiply two 64 bit ints and return.
13096 the hi 64 bits of the 128 bit product. */
13097
13098static uint64_t
13099mul64hi (uint64_t value1, uint64_t value2)
13100{
13101 uint64_t resultmid1;
13102 uint64_t result;
13103 uint64_t value1_lo = lowWordToU64 (value1);
13104 uint64_t value1_hi = highWordToU64 (value1) ;
13105 uint64_t value2_lo = lowWordToU64 (value2);
13106 uint64_t value2_hi = highWordToU64 (value2);
13107
13108 /* Cross-multiply and collect results. */
2e8cf49e
NC
13109 uint64_t xproductlo = value1_lo * value2_lo;
13110 uint64_t xproductmid1 = value1_lo * value2_hi;
13111 uint64_t xproductmid2 = value1_hi * value2_lo;
13112 uint64_t xproducthi = value1_hi * value2_hi;
13113 uint64_t carry = 0;
13114 /* Start accumulating 64 bit results. */
13115 /* Drop bottom half of lowest cross-product. */
13116 uint64_t resultmid = xproductlo >> 32;
13117 /* Add in middle products. */
13118 resultmid = resultmid + xproductmid1;
13119
13120 /* Check for overflow. */
13121 if (resultmid < xproductmid1)
13122 /* Carry over 1 into top cross-product. */
13123 carry++;
13124
13125 resultmid1 = resultmid + xproductmid2;
13126
13127 /* Check for overflow. */
13128 if (resultmid1 < xproductmid2)
13129 /* Carry over 1 into top cross-product. */
13130 carry++;
13131
13132 /* Drop lowest 32 bits of middle cross-product. */
13133 result = resultmid1 >> 32;
8ecbe595
JW
13134 /* Move carry bit to just above middle cross-product highest bit. */
13135 carry = carry << 32;
2e8cf49e
NC
13136
13137 /* Add top cross-product plus and any carry. */
13138 result += xproducthi + carry;
13139
13140 return result;
13141}
13142
13143/* Signed multiply high, source, source2 :
13144 64 bit, dest <-- high 64-bit of result. */
13145static void
13146smulh (sim_cpu *cpu)
13147{
13148 uint64_t uresult;
ef0d8ffc
NC
13149 int64_t result;
13150 unsigned rm = INSTR (20, 16);
13151 unsigned rn = INSTR (9, 5);
13152 unsigned rd = INSTR (4, 0);
13153 GReg ra = INSTR (14, 10);
13154 int64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
13155 int64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2e8cf49e
NC
13156 uint64_t uvalue1;
13157 uint64_t uvalue2;
8ecbe595 13158 int negate = 0;
2e8cf49e
NC
13159
13160 if (ra != R31)
13161 HALT_UNALLOC;
13162
13163 /* Convert to unsigned and use the unsigned mul64hi routine
13164 the fix the sign up afterwards. */
13165 if (value1 < 0)
13166 {
8ecbe595 13167 negate = !negate;
2e8cf49e
NC
13168 uvalue1 = -value1;
13169 }
13170 else
13171 {
13172 uvalue1 = value1;
13173 }
13174
13175 if (value2 < 0)
13176 {
8ecbe595 13177 negate = !negate;
2e8cf49e
NC
13178 uvalue2 = -value2;
13179 }
13180 else
13181 {
13182 uvalue2 = value2;
13183 }
13184
2cdad34c 13185 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
8ecbe595 13186
2e8cf49e
NC
13187 uresult = mul64hi (uvalue1, uvalue2);
13188 result = uresult;
8ecbe595
JW
13189
13190 if (negate)
13191 {
13192 /* Multiply 128-bit result by -1, which means highpart gets inverted,
13193 and has carry in added only if low part is 0. */
13194 result = ~result;
13195 if ((uvalue1 * uvalue2) == 0)
13196 result += 1;
13197 }
2e8cf49e
NC
13198
13199 aarch64_set_reg_s64 (cpu, rd, NO_SP, result);
13200}
13201
13202/* Unsigned multiply add long -- source, source2 :
13203 32 bit, source3 : 64 bit. */
13204static void
13205umaddl (sim_cpu *cpu)
13206{
ef0d8ffc
NC
13207 unsigned rm = INSTR (20, 16);
13208 unsigned ra = INSTR (14, 10);
13209 unsigned rn = INSTR (9, 5);
13210 unsigned rd = INSTR (4, 0);
2e8cf49e 13211
2cdad34c 13212 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13213 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
13214 obtain a 64 bit product. */
13215 aarch64_set_reg_u64
13216 (cpu, rd, NO_SP,
13217 aarch64_get_reg_u64 (cpu, ra, NO_SP)
13218 + ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
13219 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
13220}
13221
13222/* Unsigned multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
13223static void
13224umsubl (sim_cpu *cpu)
13225{
ef0d8ffc
NC
13226 unsigned rm = INSTR (20, 16);
13227 unsigned ra = INSTR (14, 10);
13228 unsigned rn = INSTR (9, 5);
13229 unsigned rd = INSTR (4, 0);
2e8cf49e 13230
2cdad34c 13231 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13232 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
13233 obtain a 64 bit product. */
13234 aarch64_set_reg_u64
13235 (cpu, rd, NO_SP,
13236 aarch64_get_reg_u64 (cpu, ra, NO_SP)
13237 - ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
13238 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
13239}
13240
13241/* Unsigned multiply high, source, source2 :
13242 64 bit, dest <-- high 64-bit of result. */
13243static void
13244umulh (sim_cpu *cpu)
13245{
ef0d8ffc
NC
13246 unsigned rm = INSTR (20, 16);
13247 unsigned rn = INSTR (9, 5);
13248 unsigned rd = INSTR (4, 0);
13249 GReg ra = INSTR (14, 10);
2e8cf49e
NC
13250
13251 if (ra != R31)
13252 HALT_UNALLOC;
13253
2cdad34c 13254 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13255 aarch64_set_reg_u64 (cpu, rd, NO_SP,
13256 mul64hi (aarch64_get_reg_u64 (cpu, rn, NO_SP),
13257 aarch64_get_reg_u64 (cpu, rm, NO_SP)));
13258}
13259
13260static void
13261dexDataProc3Source (sim_cpu *cpu)
13262{
13263 /* assert instr[28,24] == 11011. */
13264 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit (for rd at least)
13265 instr[30,29] = op54 : 00 ==> ok, ow ==> UNALLOC
13266 instr[23,21] = op31 : 111 ==> UNALLOC, o2 ==> ok
13267 instr[15] = o0 : 0/1 ==> ok
13268 instr[23,21:15] ==> op : 0000 ==> MADD, 0001 ==> MSUB, (32/64 bit)
13269 0010 ==> SMADDL, 0011 ==> SMSUBL, (64 bit only)
13270 0100 ==> SMULH, (64 bit only)
13271 1010 ==> UMADDL, 1011 ==> UNSUBL, (64 bit only)
13272 1100 ==> UMULH (64 bit only)
13273 ow ==> UNALLOC. */
13274
13275 uint32_t dispatch;
ef0d8ffc
NC
13276 uint32_t size = INSTR (31, 31);
13277 uint32_t op54 = INSTR (30, 29);
13278 uint32_t op31 = INSTR (23, 21);
13279 uint32_t o0 = INSTR (15, 15);
2e8cf49e
NC
13280
13281 if (op54 != 0)
13282 HALT_UNALLOC;
13283
13284 if (size == 0)
13285 {
13286 if (op31 != 0)
13287 HALT_UNALLOC;
13288
13289 if (o0 == 0)
13290 madd32 (cpu);
13291 else
13292 msub32 (cpu);
13293 return;
13294 }
13295
13296 dispatch = (op31 << 1) | o0;
13297
13298 switch (dispatch)
13299 {
13300 case 0: madd64 (cpu); return;
13301 case 1: msub64 (cpu); return;
13302 case 2: smaddl (cpu); return;
13303 case 3: smsubl (cpu); return;
13304 case 4: smulh (cpu); return;
13305 case 10: umaddl (cpu); return;
13306 case 11: umsubl (cpu); return;
13307 case 12: umulh (cpu); return;
13308 default: HALT_UNALLOC;
13309 }
13310}
13311
13312static void
13313dexDPReg (sim_cpu *cpu)
13314{
13315 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
13316 assert group == GROUP_DPREG_0101 || group == GROUP_DPREG_1101
13317 bits [28:24:21] of a DPReg are the secondary dispatch vector. */
13318 uint32_t group2 = dispatchDPReg (aarch64_get_instr (cpu));
13319
13320 switch (group2)
13321 {
13322 case DPREG_LOG_000:
13323 case DPREG_LOG_001:
13324 dexLogicalShiftedRegister (cpu); return;
13325
13326 case DPREG_ADDSHF_010:
13327 dexAddSubtractShiftedRegister (cpu); return;
13328
13329 case DPREG_ADDEXT_011:
13330 dexAddSubtractExtendedRegister (cpu); return;
13331
13332 case DPREG_ADDCOND_100:
13333 {
13334 /* This set bundles a variety of different operations. */
13335 /* Check for. */
13336 /* 1) add/sub w carry. */
13337 uint32_t mask1 = 0x1FE00000U;
13338 uint32_t val1 = 0x1A000000U;
13339 /* 2) cond compare register/immediate. */
13340 uint32_t mask2 = 0x1FE00000U;
13341 uint32_t val2 = 0x1A400000U;
13342 /* 3) cond select. */
13343 uint32_t mask3 = 0x1FE00000U;
13344 uint32_t val3 = 0x1A800000U;
13345 /* 4) data proc 1/2 source. */
13346 uint32_t mask4 = 0x1FE00000U;
13347 uint32_t val4 = 0x1AC00000U;
13348
13349 if ((aarch64_get_instr (cpu) & mask1) == val1)
13350 dexAddSubtractWithCarry (cpu);
13351
13352 else if ((aarch64_get_instr (cpu) & mask2) == val2)
13353 CondCompare (cpu);
13354
13355 else if ((aarch64_get_instr (cpu) & mask3) == val3)
13356 dexCondSelect (cpu);
13357
13358 else if ((aarch64_get_instr (cpu) & mask4) == val4)
13359 {
13360 /* Bit 30 is clear for data proc 2 source
13361 and set for data proc 1 source. */
13362 if (aarch64_get_instr (cpu) & (1U << 30))
13363 dexDataProc1Source (cpu);
13364 else
13365 dexDataProc2Source (cpu);
13366 }
13367
13368 else
13369 /* Should not reach here. */
13370 HALT_NYI;
13371
13372 return;
13373 }
13374
13375 case DPREG_3SRC_110:
13376 dexDataProc3Source (cpu); return;
13377
13378 case DPREG_UNALLOC_101:
13379 HALT_UNALLOC;
13380
13381 case DPREG_3SRC_111:
13382 dexDataProc3Source (cpu); return;
13383
13384 default:
13385 /* Should never reach here. */
13386 HALT_NYI;
13387 }
13388}
13389
13390/* Unconditional Branch immediate.
13391 Offset is a PC-relative byte offset in the range +/- 128MiB.
13392 The offset is assumed to be raw from the decode i.e. the
13393 simulator is expected to scale them from word offsets to byte. */
13394
13395/* Unconditional branch. */
13396static void
13397buc (sim_cpu *cpu, int32_t offset)
13398{
13399 aarch64_set_next_PC_by_offset (cpu, offset);
13400}
13401
13402static unsigned stack_depth = 0;
13403
13404/* Unconditional branch and link -- writes return PC to LR. */
13405static void
13406bl (sim_cpu *cpu, int32_t offset)
13407{
2cdad34c 13408 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13409 aarch64_save_LR (cpu);
13410 aarch64_set_next_PC_by_offset (cpu, offset);
13411
13412 if (TRACE_BRANCH_P (cpu))
13413 {
13414 ++ stack_depth;
13415 TRACE_BRANCH (cpu,
13416 " %*scall %" PRIx64 " [%s]"
13417 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
13418 stack_depth, " ", aarch64_get_next_PC (cpu),
5357150c
MF
13419 aarch64_get_func (CPU_STATE (cpu),
13420 aarch64_get_next_PC (cpu)),
2e8cf49e
NC
13421 aarch64_get_reg_u64 (cpu, 0, NO_SP),
13422 aarch64_get_reg_u64 (cpu, 1, NO_SP),
13423 aarch64_get_reg_u64 (cpu, 2, NO_SP)
13424 );
13425 }
13426}
13427
13428/* Unconditional Branch register.
13429 Branch/return address is in source register. */
13430
13431/* Unconditional branch. */
13432static void
13433br (sim_cpu *cpu)
13434{
ef0d8ffc 13435 unsigned rn = INSTR (9, 5);
2cdad34c 13436 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13437 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13438}
13439
13440/* Unconditional branch and link -- writes return PC to LR. */
13441static void
13442blr (sim_cpu *cpu)
13443{
69b1ffdb
CB
13444 /* Ensure we read the destination before we write LR. */
13445 uint64_t target = aarch64_get_reg_u64 (cpu, INSTR (9, 5), NO_SP);
2e8cf49e 13446
2cdad34c 13447 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e 13448 aarch64_save_LR (cpu);
69b1ffdb 13449 aarch64_set_next_PC (cpu, target);
2e8cf49e
NC
13450
13451 if (TRACE_BRANCH_P (cpu))
13452 {
13453 ++ stack_depth;
13454 TRACE_BRANCH (cpu,
13455 " %*scall %" PRIx64 " [%s]"
13456 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
13457 stack_depth, " ", aarch64_get_next_PC (cpu),
5357150c
MF
13458 aarch64_get_func (CPU_STATE (cpu),
13459 aarch64_get_next_PC (cpu)),
2e8cf49e
NC
13460 aarch64_get_reg_u64 (cpu, 0, NO_SP),
13461 aarch64_get_reg_u64 (cpu, 1, NO_SP),
13462 aarch64_get_reg_u64 (cpu, 2, NO_SP)
13463 );
13464 }
13465}
13466
13467/* Return -- assembler will default source to LR this is functionally
13468 equivalent to br but, presumably, unlike br it side effects the
13469 branch predictor. */
13470static void
13471ret (sim_cpu *cpu)
13472{
ef0d8ffc 13473 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
13474 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
13475
2cdad34c 13476 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13477 if (TRACE_BRANCH_P (cpu))
13478 {
13479 TRACE_BRANCH (cpu,
13480 " %*sreturn [result: %" PRIx64 "]",
13481 stack_depth, " ", aarch64_get_reg_u64 (cpu, 0, NO_SP));
13482 -- stack_depth;
13483 }
13484}
13485
13486/* NOP -- we implement this and call it from the decode in case we
13487 want to intercept it later. */
13488
13489static void
13490nop (sim_cpu *cpu)
13491{
2cdad34c 13492 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13493}
13494
13495/* Data synchronization barrier. */
13496
13497static void
13498dsb (sim_cpu *cpu)
13499{
2cdad34c 13500 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13501}
13502
13503/* Data memory barrier. */
13504
13505static void
13506dmb (sim_cpu *cpu)
13507{
2cdad34c 13508 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13509}
13510
13511/* Instruction synchronization barrier. */
13512
13513static void
13514isb (sim_cpu *cpu)
13515{
2cdad34c 13516 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13517}
13518
13519static void
13520dexBranchImmediate (sim_cpu *cpu)
13521{
13522 /* assert instr[30,26] == 00101
13523 instr[31] ==> 0 == B, 1 == BL
13524 instr[25,0] == imm26 branch offset counted in words. */
13525
ef0d8ffc 13526 uint32_t top = INSTR (31, 31);
2e8cf49e
NC
13527 /* We have a 26 byte signed word offset which we need to pass to the
13528 execute routine as a signed byte offset. */
13529 int32_t offset = simm32 (aarch64_get_instr (cpu), 25, 0) << 2;
13530
13531 if (top)
13532 bl (cpu, offset);
13533 else
13534 buc (cpu, offset);
13535}
13536
13537/* Control Flow. */
13538
13539/* Conditional branch
13540
13541 Offset is a PC-relative byte offset in the range +/- 1MiB pos is
13542 a bit position in the range 0 .. 63
13543
13544 cc is a CondCode enum value as pulled out of the decode
13545
13546 N.B. any offset register (source) can only be Xn or Wn. */
13547
13548static void
13549bcc (sim_cpu *cpu, int32_t offset, CondCode cc)
13550{
2cdad34c
NC
13551 /* The test returns TRUE if CC is met. */
13552 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13553 if (testConditionCode (cpu, cc))
13554 aarch64_set_next_PC_by_offset (cpu, offset);
13555}
13556
13557/* 32 bit branch on register non-zero. */
13558static void
13559cbnz32 (sim_cpu *cpu, int32_t offset)
13560{
ef0d8ffc 13561 unsigned rt = INSTR (4, 0);
2e8cf49e 13562
2cdad34c 13563 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13564 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) != 0)
13565 aarch64_set_next_PC_by_offset (cpu, offset);
13566}
13567
13568/* 64 bit branch on register zero. */
13569static void
13570cbnz (sim_cpu *cpu, int32_t offset)
13571{
ef0d8ffc 13572 unsigned rt = INSTR (4, 0);
2e8cf49e 13573
2cdad34c 13574 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13575 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) != 0)
13576 aarch64_set_next_PC_by_offset (cpu, offset);
13577}
13578
13579/* 32 bit branch on register non-zero. */
13580static void
13581cbz32 (sim_cpu *cpu, int32_t offset)
13582{
ef0d8ffc 13583 unsigned rt = INSTR (4, 0);
2e8cf49e 13584
2cdad34c 13585 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13586 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) == 0)
13587 aarch64_set_next_PC_by_offset (cpu, offset);
13588}
13589
13590/* 64 bit branch on register zero. */
13591static void
13592cbz (sim_cpu *cpu, int32_t offset)
13593{
ef0d8ffc 13594 unsigned rt = INSTR (4, 0);
2e8cf49e 13595
2cdad34c 13596 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13597 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) == 0)
13598 aarch64_set_next_PC_by_offset (cpu, offset);
13599}
13600
13601/* Branch on register bit test non-zero -- one size fits all. */
13602static void
13603tbnz (sim_cpu *cpu, uint32_t pos, int32_t offset)
13604{
ef0d8ffc 13605 unsigned rt = INSTR (4, 0);
2e8cf49e 13606
2cdad34c 13607 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
668650d5 13608 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) & (((uint64_t) 1) << pos))
2e8cf49e
NC
13609 aarch64_set_next_PC_by_offset (cpu, offset);
13610}
13611
2cdad34c 13612/* Branch on register bit test zero -- one size fits all. */
2e8cf49e
NC
13613static void
13614tbz (sim_cpu *cpu, uint32_t pos, int32_t offset)
13615{
ef0d8ffc 13616 unsigned rt = INSTR (4, 0);
2e8cf49e 13617
2cdad34c 13618 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
668650d5 13619 if (!(aarch64_get_reg_u64 (cpu, rt, NO_SP) & (((uint64_t) 1) << pos)))
2e8cf49e
NC
13620 aarch64_set_next_PC_by_offset (cpu, offset);
13621}
13622
13623static void
13624dexCompareBranchImmediate (sim_cpu *cpu)
13625{
13626 /* instr[30,25] = 01 1010
13627 instr[31] = size : 0 ==> 32, 1 ==> 64
13628 instr[24] = op : 0 ==> CBZ, 1 ==> CBNZ
13629 instr[23,5] = simm19 branch offset counted in words
13630 instr[4,0] = rt */
13631
ef0d8ffc
NC
13632 uint32_t size = INSTR (31, 31);
13633 uint32_t op = INSTR (24, 24);
2e8cf49e
NC
13634 int32_t offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
13635
13636 if (size == 0)
13637 {
13638 if (op == 0)
13639 cbz32 (cpu, offset);
13640 else
13641 cbnz32 (cpu, offset);
13642 }
13643 else
13644 {
13645 if (op == 0)
13646 cbz (cpu, offset);
13647 else
13648 cbnz (cpu, offset);
13649 }
13650}
13651
13652static void
13653dexTestBranchImmediate (sim_cpu *cpu)
13654{
13655 /* instr[31] = b5 : bit 5 of test bit idx
13656 instr[30,25] = 01 1011
13657 instr[24] = op : 0 ==> TBZ, 1 == TBNZ
13658 instr[23,19] = b40 : bits 4 to 0 of test bit idx
13659 instr[18,5] = simm14 : signed offset counted in words
13660 instr[4,0] = uimm5 */
13661
668650d5 13662 uint32_t pos = ((INSTR (31, 31) << 5) | INSTR (23, 19));
2e8cf49e
NC
13663 int32_t offset = simm32 (aarch64_get_instr (cpu), 18, 5) << 2;
13664
13665 NYI_assert (30, 25, 0x1b);
13666
ef0d8ffc 13667 if (INSTR (24, 24) == 0)
2e8cf49e
NC
13668 tbz (cpu, pos, offset);
13669 else
13670 tbnz (cpu, pos, offset);
13671}
13672
13673static void
13674dexCondBranchImmediate (sim_cpu *cpu)
13675{
13676 /* instr[31,25] = 010 1010
13677 instr[24] = op1; op => 00 ==> B.cond
13678 instr[23,5] = simm19 : signed offset counted in words
13679 instr[4] = op0
13680 instr[3,0] = cond */
13681
13682 int32_t offset;
ef0d8ffc 13683 uint32_t op = ((INSTR (24, 24) << 1) | INSTR (4, 4));
2e8cf49e
NC
13684
13685 NYI_assert (31, 25, 0x2a);
13686
13687 if (op != 0)
13688 HALT_UNALLOC;
13689
13690 offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
2e8cf49e 13691
ef0d8ffc 13692 bcc (cpu, offset, INSTR (3, 0));
2e8cf49e
NC
13693}
13694
13695static void
13696dexBranchRegister (sim_cpu *cpu)
13697{
13698 /* instr[31,25] = 110 1011
13699 instr[24,21] = op : 0 ==> BR, 1 => BLR, 2 => RET, 3 => ERET, 4 => DRPS
13700 instr[20,16] = op2 : must be 11111
13701 instr[15,10] = op3 : must be 000000
13702 instr[4,0] = op2 : must be 11111. */
13703
ef0d8ffc
NC
13704 uint32_t op = INSTR (24, 21);
13705 uint32_t op2 = INSTR (20, 16);
13706 uint32_t op3 = INSTR (15, 10);
13707 uint32_t op4 = INSTR (4, 0);
2e8cf49e
NC
13708
13709 NYI_assert (31, 25, 0x6b);
13710
13711 if (op2 != 0x1F || op3 != 0 || op4 != 0)
13712 HALT_UNALLOC;
13713
13714 if (op == 0)
13715 br (cpu);
13716
13717 else if (op == 1)
13718 blr (cpu);
13719
13720 else if (op == 2)
13721 ret (cpu);
13722
13723 else
13724 {
ef0d8ffc 13725 /* ERET and DRPS accept 0b11111 for rn = instr [4,0]. */
2e8cf49e 13726 /* anything else is unallocated. */
ef0d8ffc 13727 uint32_t rn = INSTR (4, 0);
2e8cf49e
NC
13728
13729 if (rn != 0x1f)
13730 HALT_UNALLOC;
13731
13732 if (op == 4 || op == 5)
13733 HALT_NYI;
13734
13735 HALT_UNALLOC;
13736 }
13737}
13738
13739/* FIXME: We should get the Angel SWI values from ../../libgloss/aarch64/svc.h
13740 but this may not be available. So instead we define the values we need
13741 here. */
13742#define AngelSVC_Reason_Open 0x01
13743#define AngelSVC_Reason_Close 0x02
13744#define AngelSVC_Reason_Write 0x05
13745#define AngelSVC_Reason_Read 0x06
13746#define AngelSVC_Reason_IsTTY 0x09
13747#define AngelSVC_Reason_Seek 0x0A
13748#define AngelSVC_Reason_FLen 0x0C
13749#define AngelSVC_Reason_Remove 0x0E
13750#define AngelSVC_Reason_Rename 0x0F
13751#define AngelSVC_Reason_Clock 0x10
13752#define AngelSVC_Reason_Time 0x11
13753#define AngelSVC_Reason_System 0x12
13754#define AngelSVC_Reason_Errno 0x13
13755#define AngelSVC_Reason_GetCmdLine 0x15
13756#define AngelSVC_Reason_HeapInfo 0x16
13757#define AngelSVC_Reason_ReportException 0x18
13758#define AngelSVC_Reason_Elapsed 0x30
13759
13760
13761static void
13762handle_halt (sim_cpu *cpu, uint32_t val)
13763{
13764 uint64_t result = 0;
13765
2cdad34c 13766 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
2e8cf49e
NC
13767 if (val != 0xf000)
13768 {
13769 TRACE_SYSCALL (cpu, " HLT [0x%x]", val);
13770 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13771 sim_stopped, SIM_SIGTRAP);
13772 }
13773
13774 /* We have encountered an Angel SVC call. See if we can process it. */
13775 switch (aarch64_get_reg_u32 (cpu, 0, NO_SP))
13776 {
13777 case AngelSVC_Reason_HeapInfo:
13778 {
13779 /* Get the values. */
13780 uint64_t stack_top = aarch64_get_stack_start (cpu);
13781 uint64_t heap_base = aarch64_get_heap_start (cpu);
13782
13783 /* Get the pointer */
13784 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13785 ptr = aarch64_get_mem_u64 (cpu, ptr);
13786
13787 /* Fill in the memory block. */
13788 /* Start addr of heap. */
13789 aarch64_set_mem_u64 (cpu, ptr + 0, heap_base);
13790 /* End addr of heap. */
13791 aarch64_set_mem_u64 (cpu, ptr + 8, stack_top);
13792 /* Lowest stack addr. */
13793 aarch64_set_mem_u64 (cpu, ptr + 16, heap_base);
13794 /* Initial stack addr. */
13795 aarch64_set_mem_u64 (cpu, ptr + 24, stack_top);
13796
13797 TRACE_SYSCALL (cpu, " AngelSVC: Get Heap Info");
13798 }
13799 break;
13800
13801 case AngelSVC_Reason_Open:
13802 {
13803 /* Get the pointer */
13804 /* uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);. */
13805 /* FIXME: For now we just assume that we will only be asked
13806 to open the standard file descriptors. */
13807 static int fd = 0;
13808 result = fd ++;
13809
13810 TRACE_SYSCALL (cpu, " AngelSVC: Open file %d", fd - 1);
13811 }
13812 break;
13813
13814 case AngelSVC_Reason_Close:
13815 {
13816 uint64_t fh = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13817 TRACE_SYSCALL (cpu, " AngelSVC: Close file %d", (int) fh);
13818 result = 0;
13819 }
13820 break;
13821
13822 case AngelSVC_Reason_Errno:
13823 result = 0;
13824 TRACE_SYSCALL (cpu, " AngelSVC: Get Errno");
13825 break;
13826
13827 case AngelSVC_Reason_Clock:
13828 result =
13829#ifdef CLOCKS_PER_SEC
13830 (CLOCKS_PER_SEC >= 100)
13831 ? (clock () / (CLOCKS_PER_SEC / 100))
13832 : ((clock () * 100) / CLOCKS_PER_SEC)
13833#else
13834 /* Presume unix... clock() returns microseconds. */
13835 (clock () / 10000)
13836#endif
13837 ;
13838 TRACE_SYSCALL (cpu, " AngelSVC: Get Clock");
13839 break;
13840
13841 case AngelSVC_Reason_GetCmdLine:
13842 {
13843 /* Get the pointer */
13844 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13845 ptr = aarch64_get_mem_u64 (cpu, ptr);
13846
13847 /* FIXME: No command line for now. */
13848 aarch64_set_mem_u64 (cpu, ptr, 0);
13849 TRACE_SYSCALL (cpu, " AngelSVC: Get Command Line");
13850 }
13851 break;
13852
13853 case AngelSVC_Reason_IsTTY:
13854 result = 1;
13855 TRACE_SYSCALL (cpu, " AngelSVC: IsTTY ?");
13856 break;
13857
13858 case AngelSVC_Reason_Write:
13859 {
13860 /* Get the pointer */
13861 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13862 /* Get the write control block. */
13863 uint64_t fd = aarch64_get_mem_u64 (cpu, ptr);
13864 uint64_t buf = aarch64_get_mem_u64 (cpu, ptr + 8);
13865 uint64_t len = aarch64_get_mem_u64 (cpu, ptr + 16);
13866
13867 TRACE_SYSCALL (cpu, "write of %" PRIx64 " bytes from %"
13868 PRIx64 " on descriptor %" PRIx64,
13869 len, buf, fd);
13870
13871 if (len > 1280)
13872 {
13873 TRACE_SYSCALL (cpu,
13874 " AngelSVC: Write: Suspiciously long write: %ld",
13875 (long) len);
13876 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13877 sim_stopped, SIM_SIGBUS);
13878 }
13879 else if (fd == 1)
13880 {
13881 printf ("%.*s", (int) len, aarch64_get_mem_ptr (cpu, buf));
2e8cf49e
NC
13882 }
13883 else if (fd == 2)
13884 {
13885 TRACE (cpu, 0, "\n");
13886 sim_io_eprintf (CPU_STATE (cpu), "%.*s",
13887 (int) len, aarch64_get_mem_ptr (cpu, buf));
13888 TRACE (cpu, 0, "\n");
13889 }
13890 else
13891 {
13892 TRACE_SYSCALL (cpu,
13893 " AngelSVC: Write: Unexpected file handle: %d",
13894 (int) fd);
13895 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13896 sim_stopped, SIM_SIGABRT);
13897 }
13898 }
13899 break;
13900
13901 case AngelSVC_Reason_ReportException:
13902 {
13903 /* Get the pointer */
13904 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13905 /*ptr = aarch64_get_mem_u64 (cpu, ptr);. */
13906 uint64_t type = aarch64_get_mem_u64 (cpu, ptr);
13907 uint64_t state = aarch64_get_mem_u64 (cpu, ptr + 8);
13908
13909 TRACE_SYSCALL (cpu,
13910 "Angel Exception: type 0x%" PRIx64 " state %" PRIx64,
13911 type, state);
13912
13913 if (type == 0x20026)
13914 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13915 sim_exited, state);
13916 else
13917 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13918 sim_stopped, SIM_SIGINT);
13919 }
13920 break;
13921
13922 case AngelSVC_Reason_Read:
13923 case AngelSVC_Reason_FLen:
13924 case AngelSVC_Reason_Seek:
13925 case AngelSVC_Reason_Remove:
13926 case AngelSVC_Reason_Time:
13927 case AngelSVC_Reason_System:
13928 case AngelSVC_Reason_Rename:
13929 case AngelSVC_Reason_Elapsed:
13930 default:
13931 TRACE_SYSCALL (cpu, " HLT [Unknown angel %x]",
13932 aarch64_get_reg_u32 (cpu, 0, NO_SP));
13933 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13934 sim_stopped, SIM_SIGTRAP);
13935 }
13936
13937 aarch64_set_reg_u64 (cpu, 0, NO_SP, result);
13938}
13939
13940static void
13941dexExcpnGen (sim_cpu *cpu)
13942{
13943 /* instr[31:24] = 11010100
13944 instr[23,21] = opc : 000 ==> GEN EXCPN, 001 ==> BRK
13945 010 ==> HLT, 101 ==> DBG GEN EXCPN
13946 instr[20,5] = imm16
13947 instr[4,2] = opc2 000 ==> OK, ow ==> UNALLOC
13948 instr[1,0] = LL : discriminates opc */
13949
ef0d8ffc
NC
13950 uint32_t opc = INSTR (23, 21);
13951 uint32_t imm16 = INSTR (20, 5);
13952 uint32_t opc2 = INSTR (4, 2);
2e8cf49e
NC
13953 uint32_t LL;
13954
13955 NYI_assert (31, 24, 0xd4);
13956
13957 if (opc2 != 0)
13958 HALT_UNALLOC;
13959
ef0d8ffc 13960 LL = INSTR (1, 0);
2e8cf49e
NC
13961
13962 /* We only implement HLT and BRK for now. */
13963 if (opc == 1 && LL == 0)
13964 {
13965 TRACE_EVENTS (cpu, " BRK [0x%x]", imm16);
13966 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13967 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13968 }
13969
13970 if (opc == 2 && LL == 0)
13971 handle_halt (cpu, imm16);
13972
13973 else if (opc == 0 || opc == 5)
13974 HALT_NYI;
13975
13976 else
13977 HALT_UNALLOC;
13978}
13979
5ab6d79e 13980/* Stub for accessing system registers. */
caa8d700
NC
13981
13982static uint64_t
13983system_get (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
13984 unsigned crm, unsigned op2)
13985{
13986 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 7)
13987 /* DCZID_EL0 - the Data Cache Zero ID register.
13988 We do not support DC ZVA at the moment, so
5ab6d79e
NC
13989 we return a value with the disable bit set.
13990 We implement support for the DCZID register since
13991 it is used by the C library's memset function. */
caa8d700
NC
13992 return ((uint64_t) 1) << 4;
13993
5ab6d79e
NC
13994 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 1)
13995 /* Cache Type Register. */
13996 return 0x80008000UL;
13997
13998 if (crn == 13 && op1 == 3 && crm == 0 && op2 == 2)
13999 /* TPIDR_EL0 - thread pointer id. */
14000 return aarch64_get_thread_id (cpu);
14001
14002 if (op1 == 3 && crm == 4 && op2 == 0)
14003 return aarch64_get_FPCR (cpu);
14004
14005 if (op1 == 3 && crm == 4 && op2 == 1)
14006 return aarch64_get_FPSR (cpu);
14007
14008 else if (op1 == 3 && crm == 2 && op2 == 0)
14009 return aarch64_get_CPSR (cpu);
14010
caa8d700
NC
14011 HALT_NYI;
14012}
14013
5ab6d79e
NC
14014static void
14015system_set (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
14016 unsigned crm, unsigned op2, uint64_t val)
14017{
14018 if (op1 == 3 && crm == 4 && op2 == 0)
14019 aarch64_set_FPCR (cpu, val);
14020
14021 else if (op1 == 3 && crm == 4 && op2 == 1)
14022 aarch64_set_FPSR (cpu, val);
14023
14024 else if (op1 == 3 && crm == 2 && op2 == 0)
14025 aarch64_set_CPSR (cpu, val);
14026
14027 else
14028 HALT_NYI;
14029}
ef0d8ffc 14030
caa8d700
NC
14031static void
14032do_mrs (sim_cpu *cpu)
14033{
5ab6d79e 14034 /* instr[31:20] = 1101 0101 0001 1
caa8d700
NC
14035 instr[19] = op0
14036 instr[18,16] = op1
14037 instr[15,12] = CRn
14038 instr[11,8] = CRm
14039 instr[7,5] = op2
14040 instr[4,0] = Rt */
ef0d8ffc
NC
14041 unsigned sys_op0 = INSTR (19, 19) + 2;
14042 unsigned sys_op1 = INSTR (18, 16);
14043 unsigned sys_crn = INSTR (15, 12);
14044 unsigned sys_crm = INSTR (11, 8);
14045 unsigned sys_op2 = INSTR (7, 5);
14046 unsigned rt = INSTR (4, 0);
caa8d700 14047
2cdad34c 14048 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
caa8d700
NC
14049 aarch64_set_reg_u64 (cpu, rt, NO_SP,
14050 system_get (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2));
14051}
14052
5ab6d79e
NC
14053static void
14054do_MSR_immediate (sim_cpu *cpu)
14055{
14056 /* instr[31:19] = 1101 0101 0000 0
14057 instr[18,16] = op1
14058 instr[15,12] = 0100
14059 instr[11,8] = CRm
14060 instr[7,5] = op2
14061 instr[4,0] = 1 1111 */
14062
ef0d8ffc
NC
14063 unsigned op1 = INSTR (18, 16);
14064 /*unsigned crm = INSTR (11, 8);*/
14065 unsigned op2 = INSTR (7, 5);
5ab6d79e
NC
14066
14067 NYI_assert (31, 19, 0x1AA0);
14068 NYI_assert (15, 12, 0x4);
14069 NYI_assert (4, 0, 0x1F);
14070
14071 if (op1 == 0)
14072 {
14073 if (op2 == 5)
14074 HALT_NYI; /* set SPSel. */
14075 else
14076 HALT_UNALLOC;
14077 }
14078 else if (op1 == 3)
14079 {
14080 if (op2 == 6)
14081 HALT_NYI; /* set DAIFset. */
14082 else if (op2 == 7)
14083 HALT_NYI; /* set DAIFclr. */
14084 else
14085 HALT_UNALLOC;
14086 }
14087 else
14088 HALT_UNALLOC;
14089}
14090
14091static void
14092do_MSR_reg (sim_cpu *cpu)
14093{
14094 /* instr[31:20] = 1101 0101 0001
14095 instr[19] = op0
14096 instr[18,16] = op1
14097 instr[15,12] = CRn
14098 instr[11,8] = CRm
14099 instr[7,5] = op2
14100 instr[4,0] = Rt */
14101
ef0d8ffc
NC
14102 unsigned sys_op0 = INSTR (19, 19) + 2;
14103 unsigned sys_op1 = INSTR (18, 16);
14104 unsigned sys_crn = INSTR (15, 12);
14105 unsigned sys_crm = INSTR (11, 8);
14106 unsigned sys_op2 = INSTR (7, 5);
14107 unsigned rt = INSTR (4, 0);
5ab6d79e
NC
14108
14109 NYI_assert (31, 20, 0xD51);
ef0d8ffc 14110
2cdad34c 14111 TRACE_DECODE (cpu, "emulated at line %d", __LINE__);
5ab6d79e
NC
14112 system_set (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2,
14113 aarch64_get_reg_u64 (cpu, rt, NO_SP));
14114}
14115
14116static void
ef0d8ffc 14117do_SYS (sim_cpu *cpu)
5ab6d79e
NC
14118{
14119 /* instr[31,19] = 1101 0101 0000 1
14120 instr[18,16] = op1
14121 instr[15,12] = CRn
14122 instr[11,8] = CRm
14123 instr[7,5] = op2
14124 instr[4,0] = Rt */
14125 NYI_assert (31, 19, 0x1AA1);
14126
14127 /* FIXME: For now we just silently accept system ops. */
14128}
ef0d8ffc 14129
2e8cf49e
NC
14130static void
14131dexSystem (sim_cpu *cpu)
14132{
14133 /* instr[31:22] = 1101 01010 0
14134 instr[21] = L
14135 instr[20,19] = op0
14136 instr[18,16] = op1
14137 instr[15,12] = CRn
14138 instr[11,8] = CRm
14139 instr[7,5] = op2
14140 instr[4,0] = uimm5 */
14141
14142 /* We are interested in HINT, DSB, DMB and ISB
14143
14144 Hint #0 encodes NOOP (this is the only hint we care about)
14145 L == 0, op0 == 0, op1 = 011, CRn = 0010, Rt = 11111,
14146 CRm op2 != 0000 000 OR CRm op2 == 0000 000 || CRm op > 0000 101
14147
14148 DSB, DMB, ISB are data store barrier, data memory barrier and
14149 instruction store barrier, respectively, where
14150
14151 L == 0, op0 == 0, op1 = 011, CRn = 0011, Rt = 11111,
14152 op2 : DSB ==> 100, DMB ==> 101, ISB ==> 110
14153 CRm<3:2> ==> domain, CRm<1:0> ==> types,
14154 domain : 00 ==> OuterShareable, 01 ==> Nonshareable,
14155 10 ==> InerShareable, 11 ==> FullSystem
14156 types : 01 ==> Reads, 10 ==> Writes,
14157 11 ==> All, 00 ==> All (domain == FullSystem). */
14158
ef0d8ffc 14159 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
14160
14161 NYI_assert (31, 22, 0x354);
14162
5ab6d79e 14163 switch (INSTR (21, 12))
2e8cf49e
NC
14164 {
14165 case 0x032:
14166 if (rt == 0x1F)
14167 {
14168 /* NOP has CRm != 0000 OR. */
14169 /* (CRm == 0000 AND (op2 == 000 OR op2 > 101)). */
ef0d8ffc
NC
14170 uint32_t crm = INSTR (11, 8);
14171 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
14172
14173 if (crm != 0 || (op2 == 0 || op2 > 5))
14174 {
14175 /* Actually call nop method so we can reimplement it later. */
14176 nop (cpu);
14177 return;
14178 }
14179 }
14180 HALT_NYI;
14181
14182 case 0x033:
14183 {
ef0d8ffc 14184 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
14185
14186 switch (op2)
14187 {
caa8d700 14188 case 2: HALT_NYI;
2e8cf49e
NC
14189 case 4: dsb (cpu); return;
14190 case 5: dmb (cpu); return;
14191 case 6: isb (cpu); return;
2e8cf49e
NC
14192 default: HALT_UNALLOC;
14193 }
14194 }
14195
14196 case 0x3B0:
2e8cf49e
NC
14197 case 0x3B4:
14198 case 0x3BD:
caa8d700 14199 do_mrs (cpu);
2e8cf49e
NC
14200 return;
14201
14202 case 0x0B7:
5ab6d79e 14203 do_SYS (cpu); /* DC is an alias of SYS. */
2e8cf49e
NC
14204 return;
14205
14206 default:
ef0d8ffc 14207 if (INSTR (21, 20) == 0x1)
5ab6d79e
NC
14208 do_MSR_reg (cpu);
14209 else if (INSTR (21, 19) == 0 && INSTR (15, 12) == 0x4)
14210 do_MSR_immediate (cpu);
14211 else
14212 HALT_NYI;
caa8d700 14213 return;
2e8cf49e
NC
14214 }
14215}
14216
14217static void
14218dexBr (sim_cpu *cpu)
14219{
14220 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
14221 assert group == GROUP_BREXSYS_1010 || group == GROUP_BREXSYS_1011
14222 bits [31,29] of a BrExSys are the secondary dispatch vector. */
14223 uint32_t group2 = dispatchBrExSys (aarch64_get_instr (cpu));
14224
14225 switch (group2)
14226 {
14227 case BR_IMM_000:
14228 return dexBranchImmediate (cpu);
14229
14230 case BR_IMMCMP_001:
14231 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 14232 if (!INSTR (25, 25))
2e8cf49e
NC
14233 dexCompareBranchImmediate (cpu);
14234 else
14235 dexTestBranchImmediate (cpu);
14236 return;
14237
14238 case BR_IMMCOND_010:
14239 /* This is a conditional branch if bit 25 is clear otherwise
14240 unallocated. */
ef0d8ffc 14241 if (!INSTR (25, 25))
2e8cf49e
NC
14242 dexCondBranchImmediate (cpu);
14243 else
14244 HALT_UNALLOC;
14245 return;
14246
14247 case BR_UNALLOC_011:
14248 HALT_UNALLOC;
14249
14250 case BR_IMM_100:
14251 dexBranchImmediate (cpu);
14252 return;
14253
14254 case BR_IMMCMP_101:
14255 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 14256 if (!INSTR (25, 25))
2e8cf49e
NC
14257 dexCompareBranchImmediate (cpu);
14258 else
14259 dexTestBranchImmediate (cpu);
14260 return;
14261
14262 case BR_REG_110:
14263 /* Unconditional branch reg has bit 25 set. */
ef0d8ffc 14264 if (INSTR (25, 25))
2e8cf49e
NC
14265 dexBranchRegister (cpu);
14266
14267 /* This includes both Excpn Gen, System and unalloc operations.
14268 We need to decode the Excpn Gen operation BRK so we can plant
14269 debugger entry points.
ef0d8ffc 14270 Excpn Gen operations have instr [24] = 0.
2e8cf49e
NC
14271 we need to decode at least one of the System operations NOP
14272 which is an alias for HINT #0.
ef0d8ffc
NC
14273 System operations have instr [24,22] = 100. */
14274 else if (INSTR (24, 24) == 0)
2e8cf49e
NC
14275 dexExcpnGen (cpu);
14276
ef0d8ffc 14277 else if (INSTR (24, 22) == 4)
2e8cf49e
NC
14278 dexSystem (cpu);
14279
14280 else
14281 HALT_UNALLOC;
14282
14283 return;
14284
14285 case BR_UNALLOC_111:
14286 HALT_UNALLOC;
14287
14288 default:
14289 /* Should never reach here. */
14290 HALT_NYI;
14291 }
14292}
14293
14294static void
14295aarch64_decode_and_execute (sim_cpu *cpu, uint64_t pc)
14296{
14297 /* We need to check if gdb wants an in here. */
14298 /* checkBreak (cpu);. */
14299
14300 uint64_t group = dispatchGroup (aarch64_get_instr (cpu));
14301
14302 switch (group)
14303 {
14304 case GROUP_PSEUDO_0000: dexPseudo (cpu); break;
14305 case GROUP_LDST_0100: dexLdSt (cpu); break;
14306 case GROUP_DPREG_0101: dexDPReg (cpu); break;
14307 case GROUP_LDST_0110: dexLdSt (cpu); break;
14308 case GROUP_ADVSIMD_0111: dexAdvSIMD0 (cpu); break;
14309 case GROUP_DPIMM_1000: dexDPImm (cpu); break;
14310 case GROUP_DPIMM_1001: dexDPImm (cpu); break;
14311 case GROUP_BREXSYS_1010: dexBr (cpu); break;
14312 case GROUP_BREXSYS_1011: dexBr (cpu); break;
14313 case GROUP_LDST_1100: dexLdSt (cpu); break;
14314 case GROUP_DPREG_1101: dexDPReg (cpu); break;
14315 case GROUP_LDST_1110: dexLdSt (cpu); break;
14316 case GROUP_ADVSIMD_1111: dexAdvSIMD1 (cpu); break;
14317
14318 case GROUP_UNALLOC_0001:
14319 case GROUP_UNALLOC_0010:
14320 case GROUP_UNALLOC_0011:
14321 HALT_UNALLOC;
14322
14323 default:
14324 /* Should never reach here. */
14325 HALT_NYI;
14326 }
14327}
14328
b14bdb3b 14329static bfd_boolean
2e8cf49e
NC
14330aarch64_step (sim_cpu *cpu)
14331{
14332 uint64_t pc = aarch64_get_PC (cpu);
14333
14334 if (pc == TOP_LEVEL_RETURN_PC)
14335 return FALSE;
14336
14337 aarch64_set_next_PC (cpu, pc + 4);
c7be4414
JW
14338
14339 /* Code is always little-endian. */
14340 sim_core_read_buffer (CPU_STATE (cpu), cpu, read_map,
14341 & aarch64_get_instr (cpu), pc, 4);
14342 aarch64_get_instr (cpu) = endian_le2h_4 (aarch64_get_instr (cpu));
2e8cf49e 14343
57aa1742 14344 TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %08x", pc,
1a846c62
MF
14345 aarch64_get_instr (cpu));
14346 TRACE_DISASM (cpu, pc);
2e8cf49e
NC
14347
14348 aarch64_decode_and_execute (cpu, pc);
14349
14350 return TRUE;
14351}
14352
14353void
14354aarch64_run (SIM_DESC sd)
14355{
14356 sim_cpu *cpu = STATE_CPU (sd, 0);
14357
14358 while (aarch64_step (cpu))
b14bdb3b
NC
14359 {
14360 aarch64_update_PC (cpu);
14361
14362 if (sim_events_tick (sd))
14363 sim_events_process (sd);
14364 }
2e8cf49e 14365
b14bdb3b
NC
14366 sim_engine_halt (sd, cpu, NULL, aarch64_get_PC (cpu),
14367 sim_exited, aarch64_get_reg_s32 (cpu, R0, NO_SP));
2e8cf49e
NC
14368}
14369
14370void
14371aarch64_init (sim_cpu *cpu, uint64_t pc)
14372{
14373 uint64_t sp = aarch64_get_stack_start (cpu);
14374
14375 /* Install SP, FP and PC and set LR to -20
14376 so we can detect a top-level return. */
14377 aarch64_set_reg_u64 (cpu, SP, SP_OK, sp);
14378 aarch64_set_reg_u64 (cpu, FP, SP_OK, sp);
14379 aarch64_set_reg_u64 (cpu, LR, SP_OK, TOP_LEVEL_RETURN_PC);
14380 aarch64_set_next_PC (cpu, pc);
14381 aarch64_update_PC (cpu);
14382 aarch64_init_LIT_table ();
14383}
This page took 1.156896 seconds and 4 git commands to generate.