[AArch64] Support RAS extension for ARMv8 onwards.
[deliverable/binutils-gdb.git] / sim / aarch64 / simulator.c
CommitLineData
2e8cf49e
NC
1/* simulator.c -- Interface for the AArch64 simulator.
2
618f726f 3 Copyright (C) 2015-2016 Free Software Foundation, Inc.
2e8cf49e
NC
4
5 Contributed by Red Hat.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22#include "config.h"
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <sys/types.h>
2e8cf49e
NC
27#include <math.h>
28#include <time.h>
29#include <limits.h>
30
2e8cf49e
NC
31#include "simulator.h"
32#include "cpustate.h"
33#include "memory.h"
34
35#define NO_SP 0
36#define SP_OK 1
37
2e8cf49e 38#define TST(_flag) (aarch64_test_CPSR_bit (cpu, _flag))
e101a78b
NC
39#define IS_SET(_X) (TST (( _X )) ? 1 : 0)
40#define IS_CLEAR(_X) (TST (( _X )) ? 0 : 1)
2e8cf49e 41
ef0d8ffc
NC
42/* Space saver macro. */
43#define INSTR(HIGH, LOW) uimm (aarch64_get_instr (cpu), (HIGH), (LOW))
44
2e8cf49e
NC
45#define HALT_UNALLOC \
46 do \
47 { \
1a846c62
MF
48 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
49 TRACE_INSN (cpu, \
50 "Unallocated instruction detected at sim line %d," \
51 " exe addr %" PRIx64, \
52 __LINE__, aarch64_get_PC (cpu)); \
2e8cf49e
NC
53 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
54 sim_stopped, SIM_SIGILL); \
55 } \
56 while (0)
57
58#define HALT_NYI \
59 do \
60 { \
1a846c62
MF
61 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
62 TRACE_INSN (cpu, \
63 "Unimplemented instruction detected at sim line %d," \
64 " exe addr %" PRIx64, \
65 __LINE__, aarch64_get_PC (cpu)); \
5ab6d79e
NC
66 if (! TRACE_ANY_P (cpu)) \
67 { \
ef0d8ffc 68 sim_io_eprintf (CPU_STATE (cpu), "SIM Error: Unimplemented instruction: "); \
5ab6d79e
NC
69 trace_disasm (CPU_STATE (cpu), cpu, aarch64_get_PC (cpu)); \
70 } \
2e8cf49e
NC
71 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
72 sim_stopped, SIM_SIGABRT); \
73 } \
74 while (0)
75
76#define NYI_assert(HI, LO, EXPECTED) \
77 do \
78 { \
ef0d8ffc 79 if (INSTR ((HI), (LO)) != (EXPECTED)) \
2e8cf49e
NC
80 HALT_NYI; \
81 } \
82 while (0)
83
2e8cf49e
NC
84/* Helper functions used by expandLogicalImmediate. */
85
86/* for i = 1, ... N result<i-1> = 1 other bits are zero */
87static inline uint64_t
88ones (int N)
89{
90 return (N == 64 ? (uint64_t)-1UL : ((1UL << N) - 1));
91}
92
93/* result<0> to val<N> */
94static inline uint64_t
95pickbit (uint64_t val, int N)
96{
97 return pickbits64 (val, N, N);
98}
99
100static uint64_t
101expand_logical_immediate (uint32_t S, uint32_t R, uint32_t N)
102{
103 uint64_t mask;
104 uint64_t imm;
105 unsigned simd_size;
106
107 /* The immediate value is S+1 bits to 1, left rotated by SIMDsize - R
108 (in other words, right rotated by R), then replicated. */
109 if (N != 0)
110 {
111 simd_size = 64;
112 mask = 0xffffffffffffffffull;
113 }
114 else
115 {
116 switch (S)
117 {
118 case 0x00 ... 0x1f: /* 0xxxxx */ simd_size = 32; break;
119 case 0x20 ... 0x2f: /* 10xxxx */ simd_size = 16; S &= 0xf; break;
120 case 0x30 ... 0x37: /* 110xxx */ simd_size = 8; S &= 0x7; break;
121 case 0x38 ... 0x3b: /* 1110xx */ simd_size = 4; S &= 0x3; break;
122 case 0x3c ... 0x3d: /* 11110x */ simd_size = 2; S &= 0x1; break;
123 default: return 0;
124 }
125 mask = (1ull << simd_size) - 1;
126 /* Top bits are IGNORED. */
127 R &= simd_size - 1;
128 }
129
130 /* NOTE: if S = simd_size - 1 we get 0xf..f which is rejected. */
131 if (S == simd_size - 1)
132 return 0;
133
134 /* S+1 consecutive bits to 1. */
135 /* NOTE: S can't be 63 due to detection above. */
136 imm = (1ull << (S + 1)) - 1;
137
138 /* Rotate to the left by simd_size - R. */
139 if (R != 0)
140 imm = ((imm << (simd_size - R)) & mask) | (imm >> R);
141
142 /* Replicate the value according to SIMD size. */
143 switch (simd_size)
144 {
145 case 2: imm = (imm << 2) | imm;
146 case 4: imm = (imm << 4) | imm;
147 case 8: imm = (imm << 8) | imm;
148 case 16: imm = (imm << 16) | imm;
149 case 32: imm = (imm << 32) | imm;
150 case 64: break;
151 default: return 0;
152 }
153
154 return imm;
155}
156
157/* Instr[22,10] encodes N immr and imms. we want a lookup table
158 for each possible combination i.e. 13 bits worth of int entries. */
159#define LI_TABLE_SIZE (1 << 13)
160static uint64_t LITable[LI_TABLE_SIZE];
161
162void
163aarch64_init_LIT_table (void)
164{
165 unsigned index;
166
167 for (index = 0; index < LI_TABLE_SIZE; index++)
168 {
169 uint32_t N = uimm (index, 12, 12);
170 uint32_t immr = uimm (index, 11, 6);
171 uint32_t imms = uimm (index, 5, 0);
172
173 LITable [index] = expand_logical_immediate (imms, immr, N);
174 }
175}
176
177static void
178dexNotify (sim_cpu *cpu)
179{
180 /* instr[14,0] == type : 0 ==> method entry, 1 ==> method reentry
181 2 ==> exit Java, 3 ==> start next bytecode. */
ef0d8ffc 182 uint32_t type = INSTR (14, 0);
2e8cf49e
NC
183
184 TRACE_EVENTS (cpu, "Notify Insn encountered, type = 0x%x", type);
185
186 switch (type)
187 {
188 case 0:
189 /* aarch64_notifyMethodEntry (aarch64_get_reg_u64 (cpu, R23, 0),
190 aarch64_get_reg_u64 (cpu, R22, 0)); */
191 break;
192 case 1:
193 /* aarch64_notifyMethodReentry (aarch64_get_reg_u64 (cpu, R23, 0),
194 aarch64_get_reg_u64 (cpu, R22, 0)); */
195 break;
196 case 2:
197 /* aarch64_notifyMethodExit (); */
198 break;
199 case 3:
200 /* aarch64_notifyBCStart (aarch64_get_reg_u64 (cpu, R23, 0),
201 aarch64_get_reg_u64 (cpu, R22, 0)); */
202 break;
203 }
204}
205
206/* secondary decode within top level groups */
207
208static void
209dexPseudo (sim_cpu *cpu)
210{
211 /* assert instr[28,27] = 00
212
213 We provide 2 pseudo instructions:
214
215 HALT stops execution of the simulator causing an immediate
216 return to the x86 code which entered it.
217
218 CALLOUT initiates recursive entry into x86 code. A register
219 argument holds the address of the x86 routine. Immediate
220 values in the instruction identify the number of general
221 purpose and floating point register arguments to be passed
222 and the type of any value to be returned. */
223
224 uint32_t PSEUDO_HALT = 0xE0000000U;
225 uint32_t PSEUDO_CALLOUT = 0x00018000U;
226 uint32_t PSEUDO_CALLOUTR = 0x00018001U;
227 uint32_t PSEUDO_NOTIFY = 0x00014000U;
228 uint32_t dispatch;
229
230 if (aarch64_get_instr (cpu) == PSEUDO_HALT)
231 {
232 TRACE_EVENTS (cpu, " Pseudo Halt Instruction");
233 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
234 sim_stopped, SIM_SIGTRAP);
235 }
236
ef0d8ffc 237 dispatch = INSTR (31, 15);
2e8cf49e
NC
238
239 /* We do not handle callouts at the moment. */
240 if (dispatch == PSEUDO_CALLOUT || dispatch == PSEUDO_CALLOUTR)
241 {
242 TRACE_EVENTS (cpu, " Callout");
243 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
244 sim_stopped, SIM_SIGABRT);
245 }
246
247 else if (dispatch == PSEUDO_NOTIFY)
248 dexNotify (cpu);
249
250 else
251 HALT_UNALLOC;
252}
253
254/* Load-store single register (unscaled offset)
255 These instructions employ a base register plus an unscaled signed
256 9 bit offset.
257
258 N.B. the base register (source) can be Xn or SP. all other
259 registers may not be SP. */
260
261/* 32 bit load 32 bit unscaled signed 9 bit. */
262static void
263ldur32 (sim_cpu *cpu, int32_t offset)
264{
ef0d8ffc
NC
265 unsigned rn = INSTR (9, 5);
266 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
267
268 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
269 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
270 + offset));
271}
272
273/* 64 bit load 64 bit unscaled signed 9 bit. */
274static void
275ldur64 (sim_cpu *cpu, int32_t offset)
276{
ef0d8ffc
NC
277 unsigned rn = INSTR (9, 5);
278 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
279
280 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
281 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
282 + offset));
283}
284
285/* 32 bit load zero-extended byte unscaled signed 9 bit. */
286static void
287ldurb32 (sim_cpu *cpu, int32_t offset)
288{
ef0d8ffc
NC
289 unsigned rn = INSTR (9, 5);
290 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
291
292 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8
293 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
294 + offset));
295}
296
297/* 32 bit load sign-extended byte unscaled signed 9 bit. */
298static void
299ldursb32 (sim_cpu *cpu, int32_t offset)
300{
ef0d8ffc
NC
301 unsigned rn = INSTR (9, 5);
302 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
303
304 aarch64_set_reg_u64 (cpu, rt, NO_SP, (uint32_t) aarch64_get_mem_s8
305 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
306 + offset));
307}
308
309/* 64 bit load sign-extended byte unscaled signed 9 bit. */
310static void
311ldursb64 (sim_cpu *cpu, int32_t offset)
312{
ef0d8ffc
NC
313 unsigned rn = INSTR (9, 5);
314 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
315
316 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s8
317 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
318 + offset));
319}
320
321/* 32 bit load zero-extended short unscaled signed 9 bit */
322static void
323ldurh32 (sim_cpu *cpu, int32_t offset)
324{
ef0d8ffc
NC
325 unsigned rn = INSTR (9, 5);
326 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
327
328 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_mem_u16
329 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
330 + offset));
331}
332
333/* 32 bit load sign-extended short unscaled signed 9 bit */
334static void
335ldursh32 (sim_cpu *cpu, int32_t offset)
336{
ef0d8ffc
NC
337 unsigned rn = INSTR (9, 5);
338 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
339
340 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s16
341 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
342 + offset));
343}
344
345/* 64 bit load sign-extended short unscaled signed 9 bit */
346static void
347ldursh64 (sim_cpu *cpu, int32_t offset)
348{
ef0d8ffc
NC
349 unsigned rn = INSTR (9, 5);
350 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
351
352 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s16
353 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
354 + offset));
355}
356
357/* 64 bit load sign-extended word unscaled signed 9 bit */
358static void
359ldursw (sim_cpu *cpu, int32_t offset)
360{
ef0d8ffc
NC
361 unsigned rn = INSTR (9, 5);
362 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
363
364 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s32
365 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
366 + offset));
367}
368
369/* N.B. with stores the value in source is written to the address
370 identified by source2 modified by offset. */
371
372/* 32 bit store 32 bit unscaled signed 9 bit. */
373static void
374stur32 (sim_cpu *cpu, int32_t offset)
375{
ef0d8ffc
NC
376 unsigned rn = INSTR (9, 5);
377 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
378
379 aarch64_set_mem_u32 (cpu,
380 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
381 aarch64_get_reg_u32 (cpu, rd, NO_SP));
382}
383
384/* 64 bit store 64 bit unscaled signed 9 bit */
385static void
386stur64 (sim_cpu *cpu, int32_t offset)
387{
ef0d8ffc
NC
388 unsigned rn = INSTR (9, 5);
389 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
390
391 aarch64_set_mem_u64 (cpu,
392 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
393 aarch64_get_reg_u64 (cpu, rd, NO_SP));
394}
395
396/* 32 bit store byte unscaled signed 9 bit */
397static void
398sturb (sim_cpu *cpu, int32_t offset)
399{
ef0d8ffc
NC
400 unsigned rn = INSTR (9, 5);
401 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
402
403 aarch64_set_mem_u8 (cpu,
404 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
405 aarch64_get_reg_u8 (cpu, rd, NO_SP));
406}
407
408/* 32 bit store short unscaled signed 9 bit */
409static void
410sturh (sim_cpu *cpu, int32_t offset)
411{
ef0d8ffc
NC
412 unsigned rn = INSTR (9, 5);
413 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
414
415 aarch64_set_mem_u16 (cpu,
416 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
417 aarch64_get_reg_u16 (cpu, rd, NO_SP));
418}
419
420/* Load single register pc-relative label
421 Offset is a signed 19 bit immediate count in words
422 rt may not be SP. */
423
424/* 32 bit pc-relative load */
425static void
426ldr32_pcrel (sim_cpu *cpu, int32_t offset)
427{
ef0d8ffc 428 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
429
430 aarch64_set_reg_u64 (cpu, rd, NO_SP,
431 aarch64_get_mem_u32
432 (cpu, aarch64_get_PC (cpu) + offset * 4));
433}
434
435/* 64 bit pc-relative load */
436static void
437ldr_pcrel (sim_cpu *cpu, int32_t offset)
438{
ef0d8ffc 439 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
440
441 aarch64_set_reg_u64 (cpu, rd, NO_SP,
442 aarch64_get_mem_u64
443 (cpu, aarch64_get_PC (cpu) + offset * 4));
444}
445
446/* sign extended 32 bit pc-relative load */
447static void
448ldrsw_pcrel (sim_cpu *cpu, int32_t offset)
449{
ef0d8ffc 450 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
451
452 aarch64_set_reg_u64 (cpu, rd, NO_SP,
453 aarch64_get_mem_s32
454 (cpu, aarch64_get_PC (cpu) + offset * 4));
455}
456
457/* float pc-relative load */
458static void
459fldrs_pcrel (sim_cpu *cpu, int32_t offset)
460{
ef0d8ffc 461 unsigned int rd = INSTR (4, 0);
2e8cf49e 462
e101a78b
NC
463 aarch64_set_vec_u32 (cpu, rd, 0,
464 aarch64_get_mem_u32
465 (cpu, aarch64_get_PC (cpu) + offset * 4));
2e8cf49e
NC
466}
467
468/* double pc-relative load */
469static void
470fldrd_pcrel (sim_cpu *cpu, int32_t offset)
471{
ef0d8ffc 472 unsigned int st = INSTR (4, 0);
2e8cf49e 473
e101a78b
NC
474 aarch64_set_vec_u64 (cpu, st, 0,
475 aarch64_get_mem_u64
476 (cpu, aarch64_get_PC (cpu) + offset * 4));
2e8cf49e
NC
477}
478
479/* long double pc-relative load. */
480static void
481fldrq_pcrel (sim_cpu *cpu, int32_t offset)
482{
ef0d8ffc 483 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
484 uint64_t addr = aarch64_get_PC (cpu) + offset * 4;
485 FRegister a;
486
487 aarch64_get_mem_long_double (cpu, addr, & a);
488 aarch64_set_FP_long_double (cpu, st, a);
489}
490
491/* This can be used to scale an offset by applying
492 the requisite shift. the second argument is either
493 16, 32 or 64. */
494
495#define SCALE(_offset, _elementSize) \
496 ((_offset) << ScaleShift ## _elementSize)
497
498/* This can be used to optionally scale a register derived offset
499 by applying the requisite shift as indicated by the Scaling
7517e550 500 argument. The second argument is either Byte, Short, Word
2e8cf49e
NC
501 or Long. The third argument is either Scaled or Unscaled.
502 N.B. when _Scaling is Scaled the shift gets ANDed with
503 all 1s while when it is Unscaled it gets ANDed with 0. */
504
505#define OPT_SCALE(_offset, _elementType, _Scaling) \
506 ((_offset) << (_Scaling ? ScaleShift ## _elementType : 0))
507
508/* This can be used to zero or sign extend a 32 bit register derived
509 value to a 64 bit value. the first argument must be the value as
510 a uint32_t and the second must be either UXTW or SXTW. The result
511 is returned as an int64_t. */
512
513static inline int64_t
514extend (uint32_t value, Extension extension)
515{
516 union
517 {
518 uint32_t u;
519 int32_t n;
520 } x;
521
522 /* A branchless variant of this ought to be possible. */
523 if (extension == UXTW || extension == NoExtension)
524 return value;
525
526 x.u = value;
527 return x.n;
528}
529
530/* Scalar Floating Point
531
532 FP load/store single register (4 addressing modes)
533
534 N.B. the base register (source) can be the stack pointer.
535 The secondary source register (source2) can only be an Xn register. */
536
537/* Load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
538static void
539fldrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
540{
ef0d8ffc
NC
541 unsigned rn = INSTR (9, 5);
542 unsigned st = INSTR (4, 0);
2e8cf49e
NC
543 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
544
545 if (wb != Post)
546 address += offset;
547
e101a78b 548 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32 (cpu, address));
2e8cf49e
NC
549 if (wb == Post)
550 address += offset;
551
552 if (wb != NoWriteBack)
553 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
554}
555
5ab6d79e
NC
556/* Load 8 bit with unsigned 12 bit offset. */
557static void
558fldrb_abs (sim_cpu *cpu, uint32_t offset)
559{
ef0d8ffc
NC
560 unsigned rd = INSTR (4, 0);
561 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
562 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
563
564 aarch64_set_vec_u8 (cpu, rd, 0, aarch64_get_mem_u32 (cpu, addr));
565}
566
567/* Load 16 bit scaled unsigned 12 bit. */
568static void
569fldrh_abs (sim_cpu *cpu, uint32_t offset)
570{
ef0d8ffc
NC
571 unsigned rd = INSTR (4, 0);
572 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
573 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16);
574
575 aarch64_set_vec_u16 (cpu, rd, 0, aarch64_get_mem_u16 (cpu, addr));
576}
577
2e8cf49e
NC
578/* Load 32 bit scaled unsigned 12 bit. */
579static void
580fldrs_abs (sim_cpu *cpu, uint32_t offset)
581{
ef0d8ffc
NC
582 unsigned rd = INSTR (4, 0);
583 unsigned rn = INSTR (9, 5);
5ab6d79e 584 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32);
2e8cf49e 585
5ab6d79e
NC
586 aarch64_set_vec_u32 (cpu, rd, 0, aarch64_get_mem_u32 (cpu, addr));
587}
588
589/* Load 64 bit scaled unsigned 12 bit. */
590static void
591fldrd_abs (sim_cpu *cpu, uint32_t offset)
592{
ef0d8ffc
NC
593 unsigned rd = INSTR (4, 0);
594 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
595 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64);
596
597 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_mem_u64 (cpu, addr));
598}
599
600/* Load 128 bit scaled unsigned 12 bit. */
601static void
602fldrq_abs (sim_cpu *cpu, uint32_t offset)
603{
ef0d8ffc
NC
604 unsigned rd = INSTR (4, 0);
605 unsigned rn = INSTR (9, 5);
5ab6d79e
NC
606 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
607
608 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_mem_u64 (cpu, addr));
609 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_mem_u64 (cpu, addr + 8));
2e8cf49e
NC
610}
611
612/* Load 32 bit scaled or unscaled zero- or sign-extended
613 32-bit register offset. */
614static void
615fldrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
616{
ef0d8ffc
NC
617 unsigned rm = INSTR (20, 16);
618 unsigned rn = INSTR (9, 5);
619 unsigned st = INSTR (4, 0);
2e8cf49e
NC
620 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
621 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
622 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
623
e101a78b
NC
624 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
625 (cpu, address + displacement));
2e8cf49e
NC
626}
627
628/* Load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
629static void
630fldrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
631{
ef0d8ffc
NC
632 unsigned rn = INSTR (9, 5);
633 unsigned st = INSTR (4, 0);
2e8cf49e
NC
634 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
635
636 if (wb != Post)
637 address += offset;
638
e101a78b 639 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64 (cpu, address));
2e8cf49e
NC
640
641 if (wb == Post)
642 address += offset;
643
644 if (wb != NoWriteBack)
645 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
646}
647
2e8cf49e
NC
648/* Load 64 bit scaled or unscaled zero- or sign-extended 32-bit register offset. */
649static void
650fldrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
651{
ef0d8ffc 652 unsigned rm = INSTR (20, 16);
2e8cf49e
NC
653 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
654 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
655
656 fldrd_wb (cpu, displacement, NoWriteBack);
657}
658
659/* Load 128 bit unscaled signed 9 bit with pre- or post-writeback. */
660static void
661fldrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
662{
663 FRegister a;
ef0d8ffc
NC
664 unsigned rn = INSTR (9, 5);
665 unsigned st = INSTR (4, 0);
2e8cf49e
NC
666 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
667
668 if (wb != Post)
669 address += offset;
670
671 aarch64_get_mem_long_double (cpu, address, & a);
672 aarch64_set_FP_long_double (cpu, st, a);
673
674 if (wb == Post)
675 address += offset;
676
677 if (wb != NoWriteBack)
678 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
679}
680
2e8cf49e
NC
681/* Load 128 bit scaled or unscaled zero- or sign-extended 32-bit register offset */
682static void
683fldrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
684{
ef0d8ffc 685 unsigned rm = INSTR (20, 16);
2e8cf49e
NC
686 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
687 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
688
689 fldrq_wb (cpu, displacement, NoWriteBack);
690}
691
692/* Memory Access
693
694 load-store single register
695 There are four addressing modes available here which all employ a
696 64 bit source (base) register.
697
698 N.B. the base register (source) can be the stack pointer.
699 The secondary source register (source2)can only be an Xn register.
700
701 Scaled, 12-bit, unsigned immediate offset, without pre- and
702 post-index options.
703 Unscaled, 9-bit, signed immediate offset with pre- or post-index
704 writeback.
705 scaled or unscaled 64-bit register offset.
706 scaled or unscaled 32-bit extended register offset.
707
708 All offsets are assumed to be raw from the decode i.e. the
709 simulator is expected to adjust scaled offsets based on the
710 accessed data size with register or extended register offset
711 versions the same applies except that in the latter case the
712 operation may also require a sign extend.
713
714 A separate method is provided for each possible addressing mode. */
715
716/* 32 bit load 32 bit scaled unsigned 12 bit */
717static void
718ldr32_abs (sim_cpu *cpu, uint32_t offset)
719{
ef0d8ffc
NC
720 unsigned rn = INSTR (9, 5);
721 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
722
723 /* The target register may not be SP but the source may be. */
724 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
725 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
726 + SCALE (offset, 32)));
727}
728
729/* 32 bit load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
730static void
731ldr32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
732{
ef0d8ffc
NC
733 unsigned rn = INSTR (9, 5);
734 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
735 uint64_t address;
736
737 if (rn == rt && wb != NoWriteBack)
738 HALT_UNALLOC;
739
740 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
741
742 if (wb != Post)
743 address += offset;
744
745 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
746
747 if (wb == Post)
748 address += offset;
749
750 if (wb != NoWriteBack)
751 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
752}
753
754/* 32 bit load 32 bit scaled or unscaled
755 zero- or sign-extended 32-bit register offset */
756static void
757ldr32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
758{
ef0d8ffc
NC
759 unsigned rm = INSTR (20, 16);
760 unsigned rn = INSTR (9, 5);
761 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
762 /* rn may reference SP, rm and rt must reference ZR */
763
764 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
765 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
766 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
767
768 aarch64_set_reg_u64 (cpu, rt, NO_SP,
769 aarch64_get_mem_u32 (cpu, address + displacement));
770}
771
772/* 64 bit load 64 bit scaled unsigned 12 bit */
773static void
774ldr_abs (sim_cpu *cpu, uint32_t offset)
775{
ef0d8ffc
NC
776 unsigned rn = INSTR (9, 5);
777 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
778
779 /* The target register may not be SP but the source may be. */
780 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
781 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
782 + SCALE (offset, 64)));
783}
784
785/* 64 bit load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
786static void
787ldr_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
788{
ef0d8ffc
NC
789 unsigned rn = INSTR (9, 5);
790 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
791 uint64_t address;
792
793 if (rn == rt && wb != NoWriteBack)
794 HALT_UNALLOC;
795
796 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
797
798 if (wb != Post)
799 address += offset;
800
801 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
802
803 if (wb == Post)
804 address += offset;
805
806 if (wb != NoWriteBack)
807 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
808}
809
810/* 64 bit load 64 bit scaled or unscaled zero-
811 or sign-extended 32-bit register offset. */
812static void
813ldr_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
814{
ef0d8ffc
NC
815 unsigned rm = INSTR (20, 16);
816 unsigned rn = INSTR (9, 5);
817 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
818 /* rn may reference SP, rm and rt must reference ZR */
819
820 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
821 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
822 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
823
824 aarch64_set_reg_u64 (cpu, rt, NO_SP,
825 aarch64_get_mem_u64 (cpu, address + displacement));
826}
827
828/* 32 bit load zero-extended byte scaled unsigned 12 bit. */
829static void
830ldrb32_abs (sim_cpu *cpu, uint32_t offset)
831{
ef0d8ffc
NC
832 unsigned rn = INSTR (9, 5);
833 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
834
835 /* The target register may not be SP but the source may be
836 there is no scaling required for a byte load. */
837 aarch64_set_reg_u64 (cpu, rt, NO_SP,
838 aarch64_get_mem_u8
839 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
840}
841
842/* 32 bit load zero-extended byte unscaled signed 9 bit with pre- or post-writeback. */
843static void
844ldrb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
845{
ef0d8ffc
NC
846 unsigned rn = INSTR (9, 5);
847 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
848 uint64_t address;
849
850 if (rn == rt && wb != NoWriteBack)
851 HALT_UNALLOC;
852
853 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
854
855 if (wb != Post)
856 address += offset;
857
858 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
859
860 if (wb == Post)
861 address += offset;
862
863 if (wb != NoWriteBack)
864 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
865}
866
867/* 32 bit load zero-extended byte scaled or unscaled zero-
868 or sign-extended 32-bit register offset. */
869static void
870ldrb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
871{
ef0d8ffc
NC
872 unsigned rm = INSTR (20, 16);
873 unsigned rn = INSTR (9, 5);
874 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
875 /* rn may reference SP, rm and rt must reference ZR */
876
877 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
878 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
879 extension);
880
881 /* There is no scaling required for a byte load. */
882 aarch64_set_reg_u64 (cpu, rt, NO_SP,
883 aarch64_get_mem_u8 (cpu, address + displacement));
884}
885
886/* 64 bit load sign-extended byte unscaled signed 9 bit
887 with pre- or post-writeback. */
888static void
889ldrsb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
890{
ef0d8ffc
NC
891 unsigned rn = INSTR (9, 5);
892 unsigned rt = INSTR (4, 0);
2e8cf49e 893 uint64_t address;
7517e550 894 int64_t val;
2e8cf49e
NC
895
896 if (rn == rt && wb != NoWriteBack)
897 HALT_UNALLOC;
898
899 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
900
901 if (wb != Post)
902 address += offset;
903
7517e550
NC
904 val = aarch64_get_mem_s8 (cpu, address);
905 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
906
907 if (wb == Post)
908 address += offset;
909
910 if (wb != NoWriteBack)
911 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
912}
913
914/* 64 bit load sign-extended byte scaled unsigned 12 bit. */
915static void
916ldrsb_abs (sim_cpu *cpu, uint32_t offset)
917{
918 ldrsb_wb (cpu, offset, NoWriteBack);
919}
920
921/* 64 bit load sign-extended byte scaled or unscaled zero-
922 or sign-extended 32-bit register offset. */
923static void
924ldrsb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
925{
ef0d8ffc
NC
926 unsigned rm = INSTR (20, 16);
927 unsigned rn = INSTR (9, 5);
928 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
929 /* rn may reference SP, rm and rt must reference ZR */
930
931 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
932 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
933 extension);
934 /* There is no scaling required for a byte load. */
7517e550 935 aarch64_set_reg_s64 (cpu, rt, NO_SP,
2e8cf49e
NC
936 aarch64_get_mem_s8 (cpu, address + displacement));
937}
938
939/* 32 bit load zero-extended short scaled unsigned 12 bit. */
940static void
941ldrh32_abs (sim_cpu *cpu, uint32_t offset)
942{
ef0d8ffc
NC
943 unsigned rn = INSTR (9, 5);
944 unsigned rt = INSTR (4, 0);
7517e550 945 uint32_t val;
2e8cf49e
NC
946
947 /* The target register may not be SP but the source may be. */
7517e550
NC
948 val = aarch64_get_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
949 + SCALE (offset, 16));
950 aarch64_set_reg_u32 (cpu, rt, NO_SP, val);
2e8cf49e
NC
951}
952
953/* 32 bit load zero-extended short unscaled signed 9 bit
954 with pre- or post-writeback. */
955static void
956ldrh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
957{
ef0d8ffc
NC
958 unsigned rn = INSTR (9, 5);
959 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
960 uint64_t address;
961
962 if (rn == rt && wb != NoWriteBack)
963 HALT_UNALLOC;
964
965 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
966
967 if (wb != Post)
968 address += offset;
969
7517e550 970 aarch64_set_reg_u32 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
2e8cf49e
NC
971
972 if (wb == Post)
973 address += offset;
974
975 if (wb != NoWriteBack)
976 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
977}
978
979/* 32 bit load zero-extended short scaled or unscaled zero-
980 or sign-extended 32-bit register offset. */
981static void
982ldrh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
983{
ef0d8ffc
NC
984 unsigned rm = INSTR (20, 16);
985 unsigned rn = INSTR (9, 5);
986 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
987 /* rn may reference SP, rm and rt must reference ZR */
988
989 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
990 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
991 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
992
7517e550 993 aarch64_set_reg_u32 (cpu, rt, NO_SP,
2e8cf49e
NC
994 aarch64_get_mem_u16 (cpu, address + displacement));
995}
996
997/* 32 bit load sign-extended short scaled unsigned 12 bit. */
998static void
999ldrsh32_abs (sim_cpu *cpu, uint32_t offset)
1000{
ef0d8ffc
NC
1001 unsigned rn = INSTR (9, 5);
1002 unsigned rt = INSTR (4, 0);
7517e550 1003 int32_t val;
2e8cf49e
NC
1004
1005 /* The target register may not be SP but the source may be. */
7517e550
NC
1006 val = aarch64_get_mem_s16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1007 + SCALE (offset, 16));
1008 aarch64_set_reg_s32 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1009}
1010
1011/* 32 bit load sign-extended short unscaled signed 9 bit
1012 with pre- or post-writeback. */
1013static void
1014ldrsh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1015{
ef0d8ffc
NC
1016 unsigned rn = INSTR (9, 5);
1017 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1018 uint64_t address;
1019
1020 if (rn == rt && wb != NoWriteBack)
1021 HALT_UNALLOC;
1022
1023 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1024
1025 if (wb != Post)
1026 address += offset;
1027
7517e550
NC
1028 aarch64_set_reg_s32 (cpu, rt, NO_SP,
1029 (int32_t) aarch64_get_mem_s16 (cpu, address));
2e8cf49e
NC
1030
1031 if (wb == Post)
1032 address += offset;
1033
1034 if (wb != NoWriteBack)
1035 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1036}
1037
1038/* 32 bit load sign-extended short scaled or unscaled zero-
1039 or sign-extended 32-bit register offset. */
1040static void
1041ldrsh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1042{
ef0d8ffc
NC
1043 unsigned rm = INSTR (20, 16);
1044 unsigned rn = INSTR (9, 5);
1045 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1046 /* rn may reference SP, rm and rt must reference ZR */
1047
1048 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1049 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1050 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1051
7517e550
NC
1052 aarch64_set_reg_s32 (cpu, rt, NO_SP,
1053 (int32_t) aarch64_get_mem_s16
2e8cf49e
NC
1054 (cpu, address + displacement));
1055}
1056
1057/* 64 bit load sign-extended short scaled unsigned 12 bit. */
1058static void
1059ldrsh_abs (sim_cpu *cpu, uint32_t offset)
1060{
ef0d8ffc
NC
1061 unsigned rn = INSTR (9, 5);
1062 unsigned rt = INSTR (4, 0);
7517e550 1063 int64_t val;
2e8cf49e
NC
1064
1065 /* The target register may not be SP but the source may be. */
7517e550
NC
1066 val = aarch64_get_mem_s16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1067 + SCALE (offset, 16));
1068 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1069}
1070
1071/* 64 bit load sign-extended short unscaled signed 9 bit
1072 with pre- or post-writeback. */
1073static void
1074ldrsh64_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1075{
ef0d8ffc
NC
1076 unsigned rn = INSTR (9, 5);
1077 unsigned rt = INSTR (4, 0);
2e8cf49e 1078 uint64_t address;
7517e550 1079 int64_t val;
2e8cf49e
NC
1080
1081 if (rn == rt && wb != NoWriteBack)
1082 HALT_UNALLOC;
1083
1084 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1085
1086 if (wb != Post)
1087 address += offset;
1088
7517e550
NC
1089 val = aarch64_get_mem_s16 (cpu, address);
1090 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1091
1092 if (wb == Post)
1093 address += offset;
1094
1095 if (wb != NoWriteBack)
1096 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1097}
1098
1099/* 64 bit load sign-extended short scaled or unscaled zero-
1100 or sign-extended 32-bit register offset. */
1101static void
1102ldrsh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1103{
ef0d8ffc
NC
1104 unsigned rm = INSTR (20, 16);
1105 unsigned rn = INSTR (9, 5);
1106 unsigned rt = INSTR (4, 0);
7517e550 1107
2e8cf49e
NC
1108 /* rn may reference SP, rm and rt must reference ZR */
1109
1110 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1111 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1112 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
7517e550 1113 int64_t val;
2e8cf49e 1114
7517e550
NC
1115 val = aarch64_get_mem_s16 (cpu, address + displacement);
1116 aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1117}
1118
1119/* 64 bit load sign-extended 32 bit scaled unsigned 12 bit. */
1120static void
1121ldrsw_abs (sim_cpu *cpu, uint32_t offset)
1122{
ef0d8ffc
NC
1123 unsigned rn = INSTR (9, 5);
1124 unsigned rt = INSTR (4, 0);
7517e550 1125 int64_t val;
2e8cf49e 1126
7517e550
NC
1127 val = aarch64_get_mem_s32 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1128 + SCALE (offset, 32));
2e8cf49e 1129 /* The target register may not be SP but the source may be. */
7517e550 1130 return aarch64_set_reg_s64 (cpu, rt, NO_SP, val);
2e8cf49e
NC
1131}
1132
1133/* 64 bit load sign-extended 32 bit unscaled signed 9 bit
1134 with pre- or post-writeback. */
1135static void
1136ldrsw_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1137{
ef0d8ffc
NC
1138 unsigned rn = INSTR (9, 5);
1139 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1140 uint64_t address;
1141
1142 if (rn == rt && wb != NoWriteBack)
1143 HALT_UNALLOC;
1144
1145 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1146
1147 if (wb != Post)
1148 address += offset;
1149
1150 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32 (cpu, address));
1151
1152 if (wb == Post)
1153 address += offset;
1154
1155 if (wb != NoWriteBack)
1156 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1157}
1158
1159/* 64 bit load sign-extended 32 bit scaled or unscaled zero-
1160 or sign-extended 32-bit register offset. */
1161static void
1162ldrsw_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1163{
ef0d8ffc
NC
1164 unsigned rm = INSTR (20, 16);
1165 unsigned rn = INSTR (9, 5);
1166 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1167 /* rn may reference SP, rm and rt must reference ZR */
1168
1169 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1170 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1171 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1172
1173 aarch64_set_reg_s64 (cpu, rt, NO_SP,
1174 aarch64_get_mem_s32 (cpu, address + displacement));
1175}
1176
1177/* N.B. with stores the value in source is written to the
1178 address identified by source2 modified by source3/offset. */
1179
1180/* 32 bit store scaled unsigned 12 bit. */
1181static void
1182str32_abs (sim_cpu *cpu, uint32_t offset)
1183{
ef0d8ffc
NC
1184 unsigned rn = INSTR (9, 5);
1185 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1186
1187 /* The target register may not be SP but the source may be. */
1188 aarch64_set_mem_u32 (cpu, (aarch64_get_reg_u64 (cpu, rn, SP_OK)
1189 + SCALE (offset, 32)),
1190 aarch64_get_reg_u32 (cpu, rt, NO_SP));
1191}
1192
1193/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
1194static void
1195str32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1196{
ef0d8ffc
NC
1197 unsigned rn = INSTR (9, 5);
1198 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1199 uint64_t address;
1200
1201 if (rn == rt && wb != NoWriteBack)
1202 HALT_UNALLOC;
1203
1204 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1205 if (wb != Post)
1206 address += offset;
1207
1208 aarch64_set_mem_u32 (cpu, address, aarch64_get_reg_u32 (cpu, rt, NO_SP));
1209
1210 if (wb == Post)
1211 address += offset;
1212
1213 if (wb != NoWriteBack)
1214 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1215}
1216
1217/* 32 bit store scaled or unscaled zero- or
1218 sign-extended 32-bit register offset. */
1219static void
1220str32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1221{
ef0d8ffc
NC
1222 unsigned rm = INSTR (20, 16);
1223 unsigned rn = INSTR (9, 5);
1224 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1225
1226 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1227 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1228 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1229
1230 aarch64_set_mem_u32 (cpu, address + displacement,
1231 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1232}
1233
1234/* 64 bit store scaled unsigned 12 bit. */
1235static void
1236str_abs (sim_cpu *cpu, uint32_t offset)
1237{
ef0d8ffc
NC
1238 unsigned rn = INSTR (9, 5);
1239 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1240
1241 aarch64_set_mem_u64 (cpu,
1242 aarch64_get_reg_u64 (cpu, rn, SP_OK)
1243 + SCALE (offset, 64),
1244 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1245}
1246
1247/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
1248static void
1249str_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
1260 if (wb != Post)
1261 address += offset;
1262
1263 aarch64_set_mem_u64 (cpu, address, aarch64_get_reg_u64 (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/* 64 bit store scaled or unscaled zero-
1273 or sign-extended 32-bit register offset. */
1274static void
1275str_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 /* rn may reference SP, rm and rt must reference ZR */
1281
1282 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1283 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1284 extension);
1285 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1286
1287 aarch64_set_mem_u64 (cpu, address + displacement,
1288 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1289}
1290
1291/* 32 bit store byte scaled unsigned 12 bit. */
1292static void
1293strb_abs (sim_cpu *cpu, uint32_t offset)
1294{
ef0d8ffc
NC
1295 unsigned rn = INSTR (9, 5);
1296 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1297
1298 /* The target register may not be SP but the source may be.
1299 There is no scaling required for a byte load. */
1300 aarch64_set_mem_u8 (cpu,
1301 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
1302 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1303}
1304
1305/* 32 bit store byte unscaled signed 9 bit with pre- or post-writeback. */
1306static void
1307strb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1308{
ef0d8ffc
NC
1309 unsigned rn = INSTR (9, 5);
1310 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1311 uint64_t address;
1312
1313 if (rn == rt && wb != NoWriteBack)
1314 HALT_UNALLOC;
1315
1316 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1317
1318 if (wb != Post)
1319 address += offset;
1320
1321 aarch64_set_mem_u8 (cpu, address, aarch64_get_reg_u8 (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/* 32 bit store byte scaled or unscaled zero-
1331 or sign-extended 32-bit register offset. */
1332static void
1333strb_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 displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1342 extension);
1343
1344 /* There is no scaling required for a byte load. */
1345 aarch64_set_mem_u8 (cpu, address + displacement,
1346 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1347}
1348
1349/* 32 bit store short scaled unsigned 12 bit. */
1350static void
1351strh_abs (sim_cpu *cpu, uint32_t offset)
1352{
ef0d8ffc
NC
1353 unsigned rn = INSTR (9, 5);
1354 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1355
1356 /* The target register may not be SP but the source may be. */
1357 aarch64_set_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1358 + SCALE (offset, 16),
1359 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1360}
1361
1362/* 32 bit store short unscaled signed 9 bit with pre- or post-writeback. */
1363static void
1364strh_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1365{
ef0d8ffc
NC
1366 unsigned rn = INSTR (9, 5);
1367 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1368 uint64_t address;
1369
1370 if (rn == rt && wb != NoWriteBack)
1371 HALT_UNALLOC;
1372
1373 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1374
1375 if (wb != Post)
1376 address += offset;
1377
1378 aarch64_set_mem_u16 (cpu, address, aarch64_get_reg_u16 (cpu, rt, NO_SP));
1379
1380 if (wb == Post)
1381 address += offset;
1382
1383 if (wb != NoWriteBack)
1384 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1385}
1386
1387/* 32 bit store short scaled or unscaled zero-
1388 or sign-extended 32-bit register offset. */
1389static void
1390strh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1391{
ef0d8ffc
NC
1392 unsigned rm = INSTR (20, 16);
1393 unsigned rn = INSTR (9, 5);
1394 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
1395 /* rn may reference SP, rm and rt must reference ZR */
1396
1397 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1398 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1399 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1400
1401 aarch64_set_mem_u16 (cpu, address + displacement,
1402 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1403}
1404
1405/* Prefetch unsigned 12 bit. */
1406static void
1407prfm_abs (sim_cpu *cpu, uint32_t offset)
1408{
1409 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1410 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1411 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1412 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1413 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1414 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1415 ow ==> UNALLOC
ef0d8ffc 1416 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1417 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK)
1418 + SCALE (offset, 64). */
1419
1420 /* TODO : implement prefetch of address. */
1421}
1422
1423/* Prefetch scaled or unscaled zero- or sign-extended 32-bit register offset. */
1424static void
1425prfm_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1426{
1427 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1428 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1429 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1430 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1431 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1432 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1433 ow ==> UNALLOC
1434 rn may reference SP, rm may only reference ZR
ef0d8ffc 1435 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1436 uint64_t base = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1437 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1438 extension);
1439 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1440 uint64_t address = base + displacement. */
1441
1442 /* TODO : implement prefetch of address */
1443}
1444
1445/* 64 bit pc-relative prefetch. */
1446static void
1447prfm_pcrel (sim_cpu *cpu, int32_t offset)
1448{
1449 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1450 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1451 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1452 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1453 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1454 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1455 ow ==> UNALLOC
ef0d8ffc 1456 PrfOp prfop = prfop (instr, 4, 0);
2e8cf49e
NC
1457 uint64_t address = aarch64_get_PC (cpu) + offset. */
1458
1459 /* TODO : implement this */
1460}
1461
1462/* Load-store exclusive. */
1463
1464static void
1465ldxr (sim_cpu *cpu)
1466{
ef0d8ffc
NC
1467 unsigned rn = INSTR (9, 5);
1468 unsigned rt = INSTR (4, 0);
2e8cf49e 1469 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
ef0d8ffc
NC
1470 int size = INSTR (31, 30);
1471 /* int ordered = INSTR (15, 15); */
1472 /* int exclusive = ! INSTR (23, 23); */
2e8cf49e
NC
1473
1474 switch (size)
1475 {
1476 case 0:
1477 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
1478 break;
1479 case 1:
1480 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
1481 break;
1482 case 2:
1483 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
1484 break;
1485 case 3:
1486 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
1487 break;
2e8cf49e
NC
1488 }
1489}
1490
1491static void
1492stxr (sim_cpu *cpu)
1493{
ef0d8ffc
NC
1494 unsigned rn = INSTR (9, 5);
1495 unsigned rt = INSTR (4, 0);
1496 unsigned rs = INSTR (20, 16);
2e8cf49e 1497 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
ef0d8ffc 1498 int size = INSTR (31, 30);
2e8cf49e
NC
1499 uint64_t data = aarch64_get_reg_u64 (cpu, rt, NO_SP);
1500
1501 switch (size)
1502 {
1503 case 0: aarch64_set_mem_u8 (cpu, address, data); break;
1504 case 1: aarch64_set_mem_u16 (cpu, address, data); break;
1505 case 2: aarch64_set_mem_u32 (cpu, address, data); break;
1506 case 3: aarch64_set_mem_u64 (cpu, address, data); break;
2e8cf49e
NC
1507 }
1508
1509 aarch64_set_reg_u64 (cpu, rs, NO_SP, 0); /* Always exclusive... */
1510}
1511
1512static void
1513dexLoadLiteral (sim_cpu *cpu)
1514{
1515 /* instr[29,27] == 011
1516 instr[25,24] == 00
1517 instr[31,30:26] = opc: 000 ==> LDRW, 001 ==> FLDRS
1518 010 ==> LDRX, 011 ==> FLDRD
1519 100 ==> LDRSW, 101 ==> FLDRQ
1520 110 ==> PRFM, 111 ==> UNALLOC
1521 instr[26] ==> V : 0 ==> GReg, 1 ==> FReg
1522 instr[23, 5] == simm19 */
1523
ef0d8ffc 1524 /* unsigned rt = INSTR (4, 0); */
7517e550 1525 uint32_t dispatch = (INSTR (31, 30) << 1) | INSTR (26, 26);
2e8cf49e
NC
1526 int32_t imm = simm32 (aarch64_get_instr (cpu), 23, 5);
1527
1528 switch (dispatch)
1529 {
1530 case 0: ldr32_pcrel (cpu, imm); break;
1531 case 1: fldrs_pcrel (cpu, imm); break;
1532 case 2: ldr_pcrel (cpu, imm); break;
1533 case 3: fldrd_pcrel (cpu, imm); break;
1534 case 4: ldrsw_pcrel (cpu, imm); break;
1535 case 5: fldrq_pcrel (cpu, imm); break;
1536 case 6: prfm_pcrel (cpu, imm); break;
1537 case 7:
1538 default:
1539 HALT_UNALLOC;
1540 }
1541}
1542
1543/* Immediate arithmetic
1544 The aimm argument is a 12 bit unsigned value or a 12 bit unsigned
1545 value left shifted by 12 bits (done at decode).
1546
1547 N.B. the register args (dest, source) can normally be Xn or SP.
1548 the exception occurs for flag setting instructions which may
1549 only use Xn for the output (dest). */
1550
1551/* 32 bit add immediate. */
1552static void
1553add32 (sim_cpu *cpu, uint32_t aimm)
1554{
ef0d8ffc
NC
1555 unsigned rn = INSTR (9, 5);
1556 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1557
1558 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1559 aarch64_get_reg_u32 (cpu, rn, SP_OK) + aimm);
1560}
1561
1562/* 64 bit add immediate. */
1563static void
1564add64 (sim_cpu *cpu, uint32_t aimm)
1565{
ef0d8ffc
NC
1566 unsigned rn = INSTR (9, 5);
1567 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1568
1569 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1570 aarch64_get_reg_u64 (cpu, rn, SP_OK) + aimm);
1571}
1572
1573static void
1574set_flags_for_add32 (sim_cpu *cpu, int32_t value1, int32_t value2)
1575{
1576 int32_t result = value1 + value2;
1577 int64_t sresult = (int64_t) value1 + (int64_t) value2;
1578 uint64_t uresult = (uint64_t)(uint32_t) value1
1579 + (uint64_t)(uint32_t) value2;
1580 uint32_t flags = 0;
1581
1582 if (result == 0)
1583 flags |= Z;
1584
1585 if (result & (1 << 31))
1586 flags |= N;
1587
1588 if (uresult != result)
1589 flags |= C;
1590
1591 if (sresult != result)
1592 flags |= V;
1593
1594 aarch64_set_CPSR (cpu, flags);
1595}
1596
1597static void
1598set_flags_for_add64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1599{
1600 int64_t sval1 = value1;
1601 int64_t sval2 = value2;
1602 uint64_t result = value1 + value2;
1603 int64_t sresult = sval1 + sval2;
1604 uint32_t flags = 0;
1605
1606 if (result == 0)
1607 flags |= Z;
1608
1609 if (result & (1ULL << 63))
1610 flags |= N;
1611
1612 if (sval1 < 0)
1613 {
1614 if (sval2 < 0)
1615 {
1616 /* Negative plus a negative. Overflow happens if
1617 the result is greater than either of the operands. */
1618 if (sresult > sval1 || sresult > sval2)
1619 flags |= V;
1620 }
1621 /* else Negative plus a positive. Overflow cannot happen. */
1622 }
1623 else /* value1 is +ve. */
1624 {
1625 if (sval2 < 0)
1626 {
1627 /* Overflow can only occur if we computed "0 - MININT". */
1628 if (sval1 == 0 && sval2 == (1LL << 63))
1629 flags |= V;
1630 }
1631 else
1632 {
1633 /* Postive plus positive - overflow has happened if the
1634 result is smaller than either of the operands. */
1635 if (result < value1 || result < value2)
1636 flags |= V | C;
1637 }
1638 }
1639
1640 aarch64_set_CPSR (cpu, flags);
1641}
1642
1643#define NEG(a) (((a) & signbit) == signbit)
1644#define POS(a) (((a) & signbit) == 0)
1645
1646static void
1647set_flags_for_sub32 (sim_cpu *cpu, uint32_t value1, uint32_t value2)
1648{
1649 uint32_t result = value1 - value2;
1650 uint32_t flags = 0;
57aa1742 1651 uint32_t signbit = 1U << 31;
2e8cf49e
NC
1652
1653 if (result == 0)
1654 flags |= Z;
1655
1656 if (NEG (result))
1657 flags |= N;
1658
1659 if ( (NEG (value1) && POS (value2))
1660 || (NEG (value1) && POS (result))
1661 || (POS (value2) && POS (result)))
1662 flags |= C;
1663
1664 if ( (NEG (value1) && POS (value2) && POS (result))
1665 || (POS (value1) && NEG (value2) && NEG (result)))
1666 flags |= V;
1667
1668 aarch64_set_CPSR (cpu, flags);
1669}
1670
1671static void
1672set_flags_for_sub64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1673{
1674 uint64_t result = value1 - value2;
1675 uint32_t flags = 0;
1676 uint64_t signbit = 1ULL << 63;
1677
1678 if (result == 0)
1679 flags |= Z;
1680
1681 if (NEG (result))
1682 flags |= N;
1683
1684 if ( (NEG (value1) && POS (value2))
1685 || (NEG (value1) && POS (result))
1686 || (POS (value2) && POS (result)))
1687 flags |= C;
1688
1689 if ( (NEG (value1) && POS (value2) && POS (result))
1690 || (POS (value1) && NEG (value2) && NEG (result)))
1691 flags |= V;
1692
1693 aarch64_set_CPSR (cpu, flags);
1694}
1695
1696static void
1697set_flags_for_binop32 (sim_cpu *cpu, uint32_t result)
1698{
1699 uint32_t flags = 0;
1700
1701 if (result == 0)
1702 flags |= Z;
1703 else
1704 flags &= ~ Z;
1705
1706 if (result & (1 << 31))
1707 flags |= N;
1708 else
1709 flags &= ~ N;
1710
1711 aarch64_set_CPSR (cpu, flags);
1712}
1713
1714static void
1715set_flags_for_binop64 (sim_cpu *cpu, uint64_t result)
1716{
1717 uint32_t flags = 0;
1718
1719 if (result == 0)
1720 flags |= Z;
1721 else
1722 flags &= ~ Z;
1723
1724 if (result & (1ULL << 63))
1725 flags |= N;
1726 else
1727 flags &= ~ N;
1728
1729 aarch64_set_CPSR (cpu, flags);
1730}
1731
1732/* 32 bit add immediate set flags. */
1733static void
1734adds32 (sim_cpu *cpu, uint32_t aimm)
1735{
ef0d8ffc
NC
1736 unsigned rn = INSTR (9, 5);
1737 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1738 /* TODO : do we need to worry about signs here? */
1739 int32_t value1 = aarch64_get_reg_s32 (cpu, rn, SP_OK);
1740
1741 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + aimm);
1742 set_flags_for_add32 (cpu, value1, aimm);
1743}
1744
1745/* 64 bit add immediate set flags. */
1746static void
1747adds64 (sim_cpu *cpu, uint32_t aimm)
1748{
ef0d8ffc
NC
1749 unsigned rn = INSTR (9, 5);
1750 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1751 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1752 uint64_t value2 = aimm;
1753
1754 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1755 set_flags_for_add64 (cpu, value1, value2);
1756}
1757
1758/* 32 bit sub immediate. */
1759static void
1760sub32 (sim_cpu *cpu, uint32_t aimm)
1761{
ef0d8ffc
NC
1762 unsigned rn = INSTR (9, 5);
1763 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1764
1765 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1766 aarch64_get_reg_u32 (cpu, rn, SP_OK) - aimm);
1767}
1768
1769/* 64 bit sub immediate. */
1770static void
1771sub64 (sim_cpu *cpu, uint32_t aimm)
1772{
ef0d8ffc
NC
1773 unsigned rn = INSTR (9, 5);
1774 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1775
1776 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1777 aarch64_get_reg_u64 (cpu, rn, SP_OK) - aimm);
1778}
1779
1780/* 32 bit sub immediate set flags. */
1781static void
1782subs32 (sim_cpu *cpu, uint32_t aimm)
1783{
ef0d8ffc
NC
1784 unsigned rn = INSTR (9, 5);
1785 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1786 uint32_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1787 uint32_t value2 = aimm;
1788
1789 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1790 set_flags_for_sub32 (cpu, value1, value2);
1791}
1792
1793/* 64 bit sub immediate set flags. */
1794static void
1795subs64 (sim_cpu *cpu, uint32_t aimm)
1796{
ef0d8ffc
NC
1797 unsigned rn = INSTR (9, 5);
1798 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1799 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1800 uint32_t value2 = aimm;
1801
1802 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1803 set_flags_for_sub64 (cpu, value1, value2);
1804}
1805
1806/* Data Processing Register. */
1807
1808/* First two helpers to perform the shift operations. */
1809
1810static inline uint32_t
1811shifted32 (uint32_t value, Shift shift, uint32_t count)
1812{
1813 switch (shift)
1814 {
1815 default:
1816 case LSL:
1817 return (value << count);
1818 case LSR:
1819 return (value >> count);
1820 case ASR:
1821 {
1822 int32_t svalue = value;
1823 return (svalue >> count);
1824 }
1825 case ROR:
1826 {
1827 uint32_t top = value >> count;
1828 uint32_t bottom = value << (32 - count);
1829 return (bottom | top);
1830 }
1831 }
1832}
1833
1834static inline uint64_t
1835shifted64 (uint64_t value, Shift shift, uint32_t count)
1836{
1837 switch (shift)
1838 {
1839 default:
1840 case LSL:
1841 return (value << count);
1842 case LSR:
1843 return (value >> count);
1844 case ASR:
1845 {
1846 int64_t svalue = value;
1847 return (svalue >> count);
1848 }
1849 case ROR:
1850 {
1851 uint64_t top = value >> count;
1852 uint64_t bottom = value << (64 - count);
1853 return (bottom | top);
1854 }
1855 }
1856}
1857
1858/* Arithmetic shifted register.
1859 These allow an optional LSL, ASR or LSR to the second source
1860 register with a count up to the register bit count.
1861
1862 N.B register args may not be SP. */
1863
1864/* 32 bit ADD shifted register. */
1865static void
1866add32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1867{
ef0d8ffc
NC
1868 unsigned rm = INSTR (20, 16);
1869 unsigned rn = INSTR (9, 5);
1870 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1871
1872 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1873 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1874 + shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1875 shift, count));
1876}
1877
1878/* 64 bit ADD shifted register. */
1879static void
1880add64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1881{
ef0d8ffc
NC
1882 unsigned rm = INSTR (20, 16);
1883 unsigned rn = INSTR (9, 5);
1884 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1885
1886 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1887 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1888 + shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1889 shift, count));
1890}
1891
1892/* 32 bit ADD shifted register setting flags. */
1893static void
1894adds32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1895{
ef0d8ffc
NC
1896 unsigned rm = INSTR (20, 16);
1897 unsigned rn = INSTR (9, 5);
1898 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1899
1900 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1901 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1902 shift, count);
1903
1904 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1905 set_flags_for_add32 (cpu, value1, value2);
1906}
1907
1908/* 64 bit ADD shifted register setting flags. */
1909static void
1910adds64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1911{
ef0d8ffc
NC
1912 unsigned rm = INSTR (20, 16);
1913 unsigned rn = INSTR (9, 5);
1914 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1915
1916 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1917 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1918 shift, count);
1919
1920 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1921 set_flags_for_add64 (cpu, value1, value2);
1922}
1923
1924/* 32 bit SUB shifted register. */
1925static void
1926sub32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1927{
ef0d8ffc
NC
1928 unsigned rm = INSTR (20, 16);
1929 unsigned rn = INSTR (9, 5);
1930 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1931
1932 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1933 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1934 - shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1935 shift, count));
1936}
1937
1938/* 64 bit SUB shifted register. */
1939static void
1940sub64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1941{
ef0d8ffc
NC
1942 unsigned rm = INSTR (20, 16);
1943 unsigned rn = INSTR (9, 5);
1944 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1945
1946 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1947 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1948 - shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1949 shift, count));
1950}
1951
1952/* 32 bit SUB shifted register setting flags. */
1953static void
1954subs32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1955{
ef0d8ffc
NC
1956 unsigned rm = INSTR (20, 16);
1957 unsigned rn = INSTR (9, 5);
1958 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1959
1960 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1961 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1962 shift, count);
1963
1964 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1965 set_flags_for_sub32 (cpu, value1, value2);
1966}
1967
1968/* 64 bit SUB shifted register setting flags. */
1969static void
1970subs64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1971{
ef0d8ffc
NC
1972 unsigned rm = INSTR (20, 16);
1973 unsigned rn = INSTR (9, 5);
1974 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
1975
1976 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1977 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1978 shift, count);
1979
1980 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1981 set_flags_for_sub64 (cpu, value1, value2);
1982}
1983
1984/* First a couple more helpers to fetch the
1985 relevant source register element either
1986 sign or zero extended as required by the
1987 extension value. */
1988
1989static uint32_t
1990extreg32 (sim_cpu *cpu, unsigned int lo, Extension extension)
1991{
1992 switch (extension)
1993 {
1994 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
1995 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
1996 case UXTW: /* Fall through. */
1997 case UXTX: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
1998 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
1999 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
2000 case SXTW: /* Fall through. */
2001 case SXTX: /* Fall through. */
2002 default: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
2003 }
2004}
2005
2006static uint64_t
2007extreg64 (sim_cpu *cpu, unsigned int lo, Extension extension)
2008{
2009 switch (extension)
2010 {
2011 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
2012 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
2013 case UXTW: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
2014 case UXTX: return aarch64_get_reg_u64 (cpu, lo, NO_SP);
2015 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
2016 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
2017 case SXTW: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
2018 case SXTX:
2019 default: return aarch64_get_reg_s64 (cpu, lo, NO_SP);
2020 }
2021}
2022
2023/* Arithmetic extending register
2024 These allow an optional sign extension of some portion of the
2025 second source register followed by an optional left shift of
2026 between 1 and 4 bits (i.e. a shift of 0-4 bits???)
2027
2028 N.B output (dest) and first input arg (source) may normally be Xn
2029 or SP. However, for flag setting operations dest can only be
2030 Xn. Second input registers are always Xn. */
2031
2032/* 32 bit ADD extending register. */
2033static void
2034add32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2035{
ef0d8ffc
NC
2036 unsigned rm = INSTR (20, 16);
2037 unsigned rn = INSTR (9, 5);
2038 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2039
2040 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2041 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2042 + (extreg32 (cpu, rm, extension) << shift));
2043}
2044
2045/* 64 bit ADD extending register.
2046 N.B. This subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2047static void
2048add64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2049{
ef0d8ffc
NC
2050 unsigned rm = INSTR (20, 16);
2051 unsigned rn = INSTR (9, 5);
2052 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2053
2054 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2055 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2056 + (extreg64 (cpu, rm, extension) << shift));
2057}
2058
2059/* 32 bit ADD extending register setting flags. */
2060static void
2061adds32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2062{
ef0d8ffc
NC
2063 unsigned rm = INSTR (20, 16);
2064 unsigned rn = INSTR (9, 5);
2065 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2066
2067 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2068 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2069
2070 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2071 set_flags_for_add32 (cpu, value1, value2);
2072}
2073
2074/* 64 bit ADD extending register setting flags */
2075/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2076static void
2077adds64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2078{
ef0d8ffc
NC
2079 unsigned rm = INSTR (20, 16);
2080 unsigned rn = INSTR (9, 5);
2081 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2082
2083 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2084 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2085
2086 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2087 set_flags_for_add64 (cpu, value1, value2);
2088}
2089
2090/* 32 bit SUB extending register. */
2091static void
2092sub32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2093{
ef0d8ffc
NC
2094 unsigned rm = INSTR (20, 16);
2095 unsigned rn = INSTR (9, 5);
2096 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2097
2098 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2099 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2100 - (extreg32 (cpu, rm, extension) << shift));
2101}
2102
2103/* 64 bit SUB extending register. */
2104/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2105static void
2106sub64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2107{
ef0d8ffc
NC
2108 unsigned rm = INSTR (20, 16);
2109 unsigned rn = INSTR (9, 5);
2110 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2111
2112 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2113 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2114 - (extreg64 (cpu, rm, extension) << shift));
2115}
2116
2117/* 32 bit SUB extending register setting flags. */
2118static void
2119subs32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2120{
ef0d8ffc
NC
2121 unsigned rm = INSTR (20, 16);
2122 unsigned rn = INSTR (9, 5);
2123 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2124
2125 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2126 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2127
2128 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2129 set_flags_for_sub32 (cpu, value1, value2);
2130}
2131
2132/* 64 bit SUB extending register setting flags */
2133/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2134static void
2135subs64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2136{
ef0d8ffc
NC
2137 unsigned rm = INSTR (20, 16);
2138 unsigned rn = INSTR (9, 5);
2139 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2140
2141 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2142 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2143
2144 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2145 set_flags_for_sub64 (cpu, value1, value2);
2146}
2147
2148static void
2149dexAddSubtractImmediate (sim_cpu *cpu)
2150{
2151 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2152 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2153 instr[29] = set : 0 ==> no flags, 1 ==> set flags
2154 instr[28,24] = 10001
2155 instr[23,22] = shift : 00 == LSL#0, 01 = LSL#12 1x = UNALLOC
2156 instr[21,10] = uimm12
2157 instr[9,5] = Rn
2158 instr[4,0] = Rd */
2159
2160 /* N.B. the shift is applied at decode before calling the add/sub routine. */
ef0d8ffc
NC
2161 uint32_t shift = INSTR (23, 22);
2162 uint32_t imm = INSTR (21, 10);
2163 uint32_t dispatch = INSTR (31, 29);
2e8cf49e
NC
2164
2165 NYI_assert (28, 24, 0x11);
2166
2167 if (shift > 1)
2168 HALT_UNALLOC;
2169
2170 if (shift)
2171 imm <<= 12;
2172
2173 switch (dispatch)
2174 {
2175 case 0: add32 (cpu, imm); break;
2176 case 1: adds32 (cpu, imm); break;
2177 case 2: sub32 (cpu, imm); break;
2178 case 3: subs32 (cpu, imm); break;
2179 case 4: add64 (cpu, imm); break;
2180 case 5: adds64 (cpu, imm); break;
2181 case 6: sub64 (cpu, imm); break;
2182 case 7: subs64 (cpu, imm); break;
2e8cf49e
NC
2183 }
2184}
2185
2186static void
2187dexAddSubtractShiftedRegister (sim_cpu *cpu)
2188{
2189 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2190 instr[30,29] = op : 00 ==> ADD, 01 ==> ADDS, 10 ==> SUB, 11 ==> SUBS
2191 instr[28,24] = 01011
2192 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> UNALLOC
2193 instr[21] = 0
2194 instr[20,16] = Rm
2195 instr[15,10] = count : must be 0xxxxx for 32 bit
2196 instr[9,5] = Rn
2197 instr[4,0] = Rd */
2198
ef0d8ffc
NC
2199 uint32_t size = INSTR (31, 31);
2200 uint32_t count = INSTR (15, 10);
2201 Shift shiftType = INSTR (23, 22);
2e8cf49e
NC
2202
2203 NYI_assert (28, 24, 0x0B);
2204 NYI_assert (21, 21, 0);
2205
ef0d8ffc 2206 /* Shift encoded as ROR is unallocated. */
2e8cf49e
NC
2207 if (shiftType == ROR)
2208 HALT_UNALLOC;
2209
ef0d8ffc
NC
2210 /* 32 bit operations must have count[5] = 0
2211 or else we have an UNALLOC. */
2212 if (size == 0 && uimm (count, 5, 5))
2e8cf49e
NC
2213 HALT_UNALLOC;
2214
ef0d8ffc
NC
2215 /* Dispatch on size:op i.e instr [31,29]. */
2216 switch (INSTR (31, 29))
2e8cf49e
NC
2217 {
2218 case 0: add32_shift (cpu, shiftType, count); break;
2219 case 1: adds32_shift (cpu, shiftType, count); break;
2220 case 2: sub32_shift (cpu, shiftType, count); break;
2221 case 3: subs32_shift (cpu, shiftType, count); break;
2222 case 4: add64_shift (cpu, shiftType, count); break;
2223 case 5: adds64_shift (cpu, shiftType, count); break;
2224 case 6: sub64_shift (cpu, shiftType, count); break;
2225 case 7: subs64_shift (cpu, shiftType, count); break;
2e8cf49e
NC
2226 }
2227}
2228
2229static void
2230dexAddSubtractExtendedRegister (sim_cpu *cpu)
2231{
2232 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2233 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2234 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2235 instr[28,24] = 01011
2236 instr[23,22] = opt : 0 ==> ok, 1,2,3 ==> UNALLOC
2237 instr[21] = 1
2238 instr[20,16] = Rm
2239 instr[15,13] = option : 000 ==> UXTB, 001 ==> UXTH,
2240 000 ==> LSL|UXTW, 001 ==> UXTZ,
2241 000 ==> SXTB, 001 ==> SXTH,
2242 000 ==> SXTW, 001 ==> SXTX,
2243 instr[12,10] = shift : 0,1,2,3,4 ==> ok, 5,6,7 ==> UNALLOC
2244 instr[9,5] = Rn
2245 instr[4,0] = Rd */
2246
ef0d8ffc
NC
2247 Extension extensionType = INSTR (15, 13);
2248 uint32_t shift = INSTR (12, 10);
2e8cf49e
NC
2249
2250 NYI_assert (28, 24, 0x0B);
2251 NYI_assert (21, 21, 1);
2252
2253 /* Shift may not exceed 4. */
2254 if (shift > 4)
2255 HALT_UNALLOC;
2256
ef0d8ffc
NC
2257 /* Dispatch on size:op:set?. */
2258 switch (INSTR (31, 29))
2e8cf49e
NC
2259 {
2260 case 0: add32_ext (cpu, extensionType, shift); break;
2261 case 1: adds32_ext (cpu, extensionType, shift); break;
2262 case 2: sub32_ext (cpu, extensionType, shift); break;
2263 case 3: subs32_ext (cpu, extensionType, shift); break;
2264 case 4: add64_ext (cpu, extensionType, shift); break;
2265 case 5: adds64_ext (cpu, extensionType, shift); break;
2266 case 6: sub64_ext (cpu, extensionType, shift); break;
2267 case 7: subs64_ext (cpu, extensionType, shift); break;
2e8cf49e
NC
2268 }
2269}
2270
2271/* Conditional data processing
2272 Condition register is implicit 3rd source. */
2273
2274/* 32 bit add with carry. */
2275/* N.B register args may not be SP. */
2276
2277static void
2278adc32 (sim_cpu *cpu)
2279{
ef0d8ffc
NC
2280 unsigned rm = INSTR (20, 16);
2281 unsigned rn = INSTR (9, 5);
2282 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2283
2284 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2285 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2286 + aarch64_get_reg_u32 (cpu, rm, NO_SP)
2287 + IS_SET (C));
2288}
2289
2290/* 64 bit add with carry */
2291static void
2292adc64 (sim_cpu *cpu)
2293{
ef0d8ffc
NC
2294 unsigned rm = INSTR (20, 16);
2295 unsigned rn = INSTR (9, 5);
2296 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2297
2298 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2299 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2300 + aarch64_get_reg_u64 (cpu, rm, NO_SP)
2301 + IS_SET (C));
2302}
2303
2304/* 32 bit add with carry setting flags. */
2305static void
2306adcs32 (sim_cpu *cpu)
2307{
ef0d8ffc
NC
2308 unsigned rm = INSTR (20, 16);
2309 unsigned rn = INSTR (9, 5);
2310 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2311
2312 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2313 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2314 uint32_t carry = IS_SET (C);
2315
2316 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2317 set_flags_for_add32 (cpu, value1, value2 + carry);
2318}
2319
2320/* 64 bit add with carry setting flags. */
2321static void
2322adcs64 (sim_cpu *cpu)
2323{
ef0d8ffc
NC
2324 unsigned rm = INSTR (20, 16);
2325 unsigned rn = INSTR (9, 5);
2326 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2327
2328 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2329 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2330 uint64_t carry = IS_SET (C);
2331
2332 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2333 set_flags_for_add64 (cpu, value1, value2 + carry);
2334}
2335
2336/* 32 bit sub with carry. */
2337static void
2338sbc32 (sim_cpu *cpu)
2339{
ef0d8ffc
NC
2340 unsigned rm = INSTR (20, 16);
2341 unsigned rn = INSTR (9, 5); /* ngc iff rn == 31. */
2342 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2343
2344 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2345 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2346 - aarch64_get_reg_u32 (cpu, rm, NO_SP)
2347 - 1 + IS_SET (C));
2348}
2349
2350/* 64 bit sub with carry */
2351static void
2352sbc64 (sim_cpu *cpu)
2353{
ef0d8ffc
NC
2354 unsigned rm = INSTR (20, 16);
2355 unsigned rn = INSTR (9, 5);
2356 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2357
2358 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2359 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2360 - aarch64_get_reg_u64 (cpu, rm, NO_SP)
2361 - 1 + IS_SET (C));
2362}
2363
2364/* 32 bit sub with carry setting flags */
2365static void
2366sbcs32 (sim_cpu *cpu)
2367{
ef0d8ffc
NC
2368 unsigned rm = INSTR (20, 16);
2369 unsigned rn = INSTR (9, 5);
2370 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2371
2372 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2373 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2374 uint32_t carry = IS_SET (C);
2375 uint32_t result = value1 - value2 + 1 - carry;
2376
2377 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2378 set_flags_for_sub32 (cpu, value1, value2 + 1 - carry);
2379}
2380
2381/* 64 bit sub with carry setting flags */
2382static void
2383sbcs64 (sim_cpu *cpu)
2384{
ef0d8ffc
NC
2385 unsigned rm = INSTR (20, 16);
2386 unsigned rn = INSTR (9, 5);
2387 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2388
2389 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2390 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2391 uint64_t carry = IS_SET (C);
2392 uint64_t result = value1 - value2 + 1 - carry;
2393
2394 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2395 set_flags_for_sub64 (cpu, value1, value2 + 1 - carry);
2396}
2397
2398static void
2399dexAddSubtractWithCarry (sim_cpu *cpu)
2400{
2401 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2402 instr[30] = op : 0 ==> ADC, 1 ==> SBC
2403 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2404 instr[28,21] = 1 1010 000
2405 instr[20,16] = Rm
2406 instr[15,10] = op2 : 00000 ==> ok, ow ==> UNALLOC
2407 instr[9,5] = Rn
2408 instr[4,0] = Rd */
2409
ef0d8ffc 2410 uint32_t op2 = INSTR (15, 10);
2e8cf49e
NC
2411
2412 NYI_assert (28, 21, 0xD0);
2413
2414 if (op2 != 0)
2415 HALT_UNALLOC;
2416
ef0d8ffc
NC
2417 /* Dispatch on size:op:set?. */
2418 switch (INSTR (31, 29))
2e8cf49e
NC
2419 {
2420 case 0: adc32 (cpu); break;
2421 case 1: adcs32 (cpu); break;
2422 case 2: sbc32 (cpu); break;
2423 case 3: sbcs32 (cpu); break;
2424 case 4: adc64 (cpu); break;
2425 case 5: adcs64 (cpu); break;
2426 case 6: sbc64 (cpu); break;
2427 case 7: sbcs64 (cpu); break;
2e8cf49e
NC
2428 }
2429}
2430
2431static uint32_t
2432testConditionCode (sim_cpu *cpu, CondCode cc)
2433{
2434 /* This should be reduceable to branchless logic
2435 by some careful testing of bits in CC followed
2436 by the requisite masking and combining of bits
2437 from the flag register.
2438
2439 For now we do it with a switch. */
2440 int res;
2441
2442 switch (cc)
2443 {
2444 case EQ: res = IS_SET (Z); break;
2445 case NE: res = IS_CLEAR (Z); break;
2446 case CS: res = IS_SET (C); break;
2447 case CC: res = IS_CLEAR (C); break;
2448 case MI: res = IS_SET (N); break;
2449 case PL: res = IS_CLEAR (N); break;
2450 case VS: res = IS_SET (V); break;
2451 case VC: res = IS_CLEAR (V); break;
2452 case HI: res = IS_SET (C) && IS_CLEAR (Z); break;
2453 case LS: res = IS_CLEAR (C) || IS_SET (Z); break;
2454 case GE: res = IS_SET (N) == IS_SET (V); break;
2455 case LT: res = IS_SET (N) != IS_SET (V); break;
2456 case GT: res = IS_CLEAR (Z) && (IS_SET (N) == IS_SET (V)); break;
2457 case LE: res = IS_SET (Z) || (IS_SET (N) != IS_SET (V)); break;
2458 case AL:
2459 case NV:
2460 default:
2461 res = 1;
2462 break;
2463 }
2464 return res;
2465}
2466
2467static void
2468CondCompare (sim_cpu *cpu) /* aka: ccmp and ccmn */
2469{
2470 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
57aa1742 2471 instr[30] = compare with positive (1) or negative value (0)
2e8cf49e
NC
2472 instr[29,21] = 1 1101 0010
2473 instr[20,16] = Rm or const
2474 instr[15,12] = cond
2475 instr[11] = compare reg (0) or const (1)
2476 instr[10] = 0
2477 instr[9,5] = Rn
2478 instr[4] = 0
2479 instr[3,0] = value for CPSR bits if the comparison does not take place. */
2480 signed int negate;
2481 unsigned rm;
2482 unsigned rn;
2483
2484 NYI_assert (29, 21, 0x1d2);
2485 NYI_assert (10, 10, 0);
2486 NYI_assert (4, 4, 0);
2487
ef0d8ffc 2488 if (! testConditionCode (cpu, INSTR (15, 12)))
2e8cf49e 2489 {
ef0d8ffc 2490 aarch64_set_CPSR (cpu, INSTR (3, 0));
2e8cf49e
NC
2491 return;
2492 }
2493
ef0d8ffc
NC
2494 negate = INSTR (30, 30) ? 1 : -1;
2495 rm = INSTR (20, 16);
2496 rn = INSTR ( 9, 5);
2e8cf49e 2497
ef0d8ffc 2498 if (INSTR (31, 31))
2e8cf49e 2499 {
ef0d8ffc 2500 if (INSTR (11, 11))
2e8cf49e
NC
2501 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2502 negate * (uint64_t) rm);
2503 else
2504 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2505 negate * aarch64_get_reg_u64 (cpu, rm, SP_OK));
2506 }
2507 else
2508 {
ef0d8ffc 2509 if (INSTR (11, 11))
2e8cf49e
NC
2510 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2511 negate * rm);
2512 else
2513 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2514 negate * aarch64_get_reg_u32 (cpu, rm, SP_OK));
2515 }
2516}
2517
2518static void
2519do_vec_MOV_whole_vector (sim_cpu *cpu)
2520{
2521 /* MOV Vd.T, Vs.T (alias for ORR Vd.T, Vn.T, Vm.T where Vn == Vm)
2522
2523 instr[31] = 0
2524 instr[30] = half(0)/full(1)
2525 instr[29,21] = 001110101
2526 instr[20,16] = Vs
2527 instr[15,10] = 000111
2528 instr[9,5] = Vs
2529 instr[4,0] = Vd */
2530
ef0d8ffc
NC
2531 unsigned vs = INSTR (9, 5);
2532 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2533
2534 NYI_assert (29, 21, 0x075);
2535 NYI_assert (15, 10, 0x07);
2536
ef0d8ffc 2537 if (INSTR (20, 16) != vs)
2e8cf49e
NC
2538 HALT_NYI;
2539
ef0d8ffc 2540 if (INSTR (30, 30))
2e8cf49e
NC
2541 aarch64_set_vec_u64 (cpu, vd, 1, aarch64_get_vec_u64 (cpu, vs, 1));
2542
2543 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vs, 0));
2544}
2545
2546static void
2547do_vec_MOV_into_scalar (sim_cpu *cpu)
2548{
2549 /* instr[31] = 0
2550 instr[30] = word(0)/long(1)
2551 instr[29,21] = 00 1110 000
2552 instr[20,18] = element size and index
2553 instr[17,10] = 00 0011 11
2554 instr[9,5] = V source
2555 instr[4,0] = R dest */
2556
ef0d8ffc
NC
2557 unsigned vs = INSTR (9, 5);
2558 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
2559
2560 NYI_assert (29, 21, 0x070);
2561 NYI_assert (17, 10, 0x0F);
2562
ef0d8ffc 2563 switch (INSTR (20, 18))
2e8cf49e
NC
2564 {
2565 case 0x2:
2566 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 0));
2567 break;
2568
2569 case 0x6:
2570 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 1));
2571 break;
2572
2573 case 0x1:
2574 case 0x3:
2575 case 0x5:
2576 case 0x7:
2577 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u32
ef0d8ffc 2578 (cpu, vs, INSTR (20, 19)));
2e8cf49e
NC
2579 break;
2580
2581 default:
2582 HALT_NYI;
2583 }
2584}
2585
2586static void
2587do_vec_INS (sim_cpu *cpu)
2588{
2589 /* instr[31,21] = 01001110000
2590 instr[20,16] = element size and index
2591 instr[15,10] = 000111
2592 instr[9,5] = W source
2593 instr[4,0] = V dest */
2594
2595 int index;
ef0d8ffc
NC
2596 unsigned rs = INSTR (9, 5);
2597 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2598
2599 NYI_assert (31, 21, 0x270);
2600 NYI_assert (15, 10, 0x07);
2601
ef0d8ffc 2602 if (INSTR (16, 16))
2e8cf49e 2603 {
ef0d8ffc 2604 index = INSTR (20, 17);
2e8cf49e
NC
2605 aarch64_set_vec_u8 (cpu, vd, index,
2606 aarch64_get_reg_u8 (cpu, rs, NO_SP));
2607 }
ef0d8ffc 2608 else if (INSTR (17, 17))
2e8cf49e 2609 {
ef0d8ffc 2610 index = INSTR (20, 18);
2e8cf49e
NC
2611 aarch64_set_vec_u16 (cpu, vd, index,
2612 aarch64_get_reg_u16 (cpu, rs, NO_SP));
2613 }
ef0d8ffc 2614 else if (INSTR (18, 18))
2e8cf49e 2615 {
ef0d8ffc 2616 index = INSTR (20, 19);
2e8cf49e
NC
2617 aarch64_set_vec_u32 (cpu, vd, index,
2618 aarch64_get_reg_u32 (cpu, rs, NO_SP));
2619 }
ef0d8ffc 2620 else if (INSTR (19, 19))
2e8cf49e 2621 {
ef0d8ffc 2622 index = INSTR (20, 20);
2e8cf49e
NC
2623 aarch64_set_vec_u64 (cpu, vd, index,
2624 aarch64_get_reg_u64 (cpu, rs, NO_SP));
2625 }
2626 else
2627 HALT_NYI;
2628}
2629
2630static void
2631do_vec_DUP_vector_into_vector (sim_cpu *cpu)
2632{
2633 /* instr[31] = 0
2634 instr[30] = half(0)/full(1)
2635 instr[29,21] = 00 1110 000
2636 instr[20,16] = element size and index
2637 instr[15,10] = 0000 01
2638 instr[9,5] = V source
2639 instr[4,0] = V dest. */
2640
ef0d8ffc
NC
2641 unsigned full = INSTR (30, 30);
2642 unsigned vs = INSTR (9, 5);
2643 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2644 int i, index;
2645
2646 NYI_assert (29, 21, 0x070);
2647 NYI_assert (15, 10, 0x01);
2648
ef0d8ffc 2649 if (INSTR (16, 16))
2e8cf49e 2650 {
ef0d8ffc 2651 index = INSTR (20, 17);
2e8cf49e
NC
2652
2653 for (i = 0; i < (full ? 16 : 8); i++)
2654 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, index));
2655 }
ef0d8ffc 2656 else if (INSTR (17, 17))
2e8cf49e 2657 {
ef0d8ffc 2658 index = INSTR (20, 18);
2e8cf49e
NC
2659
2660 for (i = 0; i < (full ? 8 : 4); i++)
2661 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, index));
2662 }
ef0d8ffc 2663 else if (INSTR (18, 18))
2e8cf49e 2664 {
ef0d8ffc 2665 index = INSTR (20, 19);
2e8cf49e
NC
2666
2667 for (i = 0; i < (full ? 4 : 2); i++)
2668 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, index));
2669 }
2670 else
2671 {
ef0d8ffc 2672 if (INSTR (19, 19) == 0)
2e8cf49e
NC
2673 HALT_UNALLOC;
2674
2675 if (! full)
2676 HALT_UNALLOC;
2677
ef0d8ffc 2678 index = INSTR (20, 20);
2e8cf49e
NC
2679
2680 for (i = 0; i < 2; i++)
2681 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, index));
2682 }
2683}
2684
2685static void
2686do_vec_TBL (sim_cpu *cpu)
2687{
2688 /* instr[31] = 0
2689 instr[30] = half(0)/full(1)
2690 instr[29,21] = 00 1110 000
2691 instr[20,16] = Vm
2692 instr[15] = 0
2693 instr[14,13] = vec length
2694 instr[12,10] = 000
2695 instr[9,5] = V start
2696 instr[4,0] = V dest */
2697
ef0d8ffc
NC
2698 int full = INSTR (30, 30);
2699 int len = INSTR (14, 13) + 1;
2700 unsigned vm = INSTR (20, 16);
2701 unsigned vn = INSTR (9, 5);
2702 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2703 unsigned i;
2704
2705 NYI_assert (29, 21, 0x070);
2706 NYI_assert (12, 10, 0);
2707
2708 for (i = 0; i < (full ? 16 : 8); i++)
2709 {
2710 unsigned int selector = aarch64_get_vec_u8 (cpu, vm, i);
2711 uint8_t val;
2712
2713 if (selector < 16)
2714 val = aarch64_get_vec_u8 (cpu, vn, selector);
2715 else if (selector < 32)
2716 val = len < 2 ? 0 : aarch64_get_vec_u8 (cpu, vn + 1, selector - 16);
2717 else if (selector < 48)
2718 val = len < 3 ? 0 : aarch64_get_vec_u8 (cpu, vn + 2, selector - 32);
2719 else if (selector < 64)
2720 val = len < 4 ? 0 : aarch64_get_vec_u8 (cpu, vn + 3, selector - 48);
2721 else
2722 val = 0;
2723
2724 aarch64_set_vec_u8 (cpu, vd, i, val);
2725 }
2726}
2727
2728static void
2729do_vec_TRN (sim_cpu *cpu)
2730{
2731 /* instr[31] = 0
2732 instr[30] = half(0)/full(1)
2733 instr[29,24] = 00 1110
2734 instr[23,22] = size
2735 instr[21] = 0
2736 instr[20,16] = Vm
2737 instr[15] = 0
2738 instr[14] = TRN1 (0) / TRN2 (1)
2739 instr[13,10] = 1010
2740 instr[9,5] = V source
2741 instr[4,0] = V dest. */
2742
ef0d8ffc
NC
2743 int full = INSTR (30, 30);
2744 int second = INSTR (14, 14);
2745 unsigned vm = INSTR (20, 16);
2746 unsigned vn = INSTR (9, 5);
2747 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2748 unsigned i;
2749
2750 NYI_assert (29, 24, 0x0E);
2751 NYI_assert (13, 10, 0xA);
2752
ef0d8ffc 2753 switch (INSTR (23, 22))
2e8cf49e
NC
2754 {
2755 case 0:
2756 for (i = 0; i < (full ? 8 : 4); i++)
2757 {
2758 aarch64_set_vec_u8
2759 (cpu, vd, i * 2,
2760 aarch64_get_vec_u8 (cpu, second ? vm : vn, i * 2));
2761 aarch64_set_vec_u8
2762 (cpu, vd, 1 * 2 + 1,
2763 aarch64_get_vec_u8 (cpu, second ? vn : vm, i * 2 + 1));
2764 }
2765 break;
2766
2767 case 1:
2768 for (i = 0; i < (full ? 4 : 2); i++)
2769 {
2770 aarch64_set_vec_u16
2771 (cpu, vd, i * 2,
2772 aarch64_get_vec_u16 (cpu, second ? vm : vn, i * 2));
2773 aarch64_set_vec_u16
2774 (cpu, vd, 1 * 2 + 1,
2775 aarch64_get_vec_u16 (cpu, second ? vn : vm, i * 2 + 1));
2776 }
2777 break;
2778
2779 case 2:
2780 aarch64_set_vec_u32
2781 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, second ? vm : vn, 0));
2782 aarch64_set_vec_u32
2783 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, second ? vn : vm, 1));
2784 aarch64_set_vec_u32
2785 (cpu, vd, 2, aarch64_get_vec_u32 (cpu, second ? vm : vn, 2));
2786 aarch64_set_vec_u32
2787 (cpu, vd, 3, aarch64_get_vec_u32 (cpu, second ? vn : vm, 3));
2788 break;
2789
2790 case 3:
2791 if (! full)
2792 HALT_UNALLOC;
2793
2794 aarch64_set_vec_u64 (cpu, vd, 0,
2795 aarch64_get_vec_u64 (cpu, second ? vm : vn, 0));
2796 aarch64_set_vec_u64 (cpu, vd, 1,
2797 aarch64_get_vec_u64 (cpu, second ? vn : vm, 1));
2798 break;
2e8cf49e
NC
2799 }
2800}
2801
2802static void
2803do_vec_DUP_scalar_into_vector (sim_cpu *cpu)
2804{
2805 /* instr[31] = 0
2806 instr[30] = 0=> zero top 64-bits, 1=> duplicate into top 64-bits
2807 [must be 1 for 64-bit xfer]
2808 instr[29,20] = 00 1110 0000
2809 instr[19,16] = element size: 0001=> 8-bits, 0010=> 16-bits,
2810 0100=> 32-bits. 1000=>64-bits
2811 instr[15,10] = 0000 11
2812 instr[9,5] = W source
2813 instr[4,0] = V dest. */
2814
2815 unsigned i;
ef0d8ffc
NC
2816 unsigned Vd = INSTR (4, 0);
2817 unsigned Rs = INSTR (9, 5);
2818 int both = INSTR (30, 30);
2e8cf49e
NC
2819
2820 NYI_assert (29, 20, 0x0E0);
2821 NYI_assert (15, 10, 0x03);
2822
ef0d8ffc 2823 switch (INSTR (19, 16))
2e8cf49e
NC
2824 {
2825 case 1:
2826 for (i = 0; i < (both ? 16 : 8); i++)
2827 aarch64_set_vec_u8 (cpu, Vd, i, aarch64_get_reg_u8 (cpu, Rs, NO_SP));
2828 break;
2829
2830 case 2:
2831 for (i = 0; i < (both ? 8 : 4); i++)
2832 aarch64_set_vec_u16 (cpu, Vd, i, aarch64_get_reg_u16 (cpu, Rs, NO_SP));
2833 break;
2834
2835 case 4:
2836 for (i = 0; i < (both ? 4 : 2); i++)
2837 aarch64_set_vec_u32 (cpu, Vd, i, aarch64_get_reg_u32 (cpu, Rs, NO_SP));
2838 break;
2839
2840 case 8:
2841 if (!both)
2842 HALT_NYI;
2843 aarch64_set_vec_u64 (cpu, Vd, 0, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2844 aarch64_set_vec_u64 (cpu, Vd, 1, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2845 break;
2846
2847 default:
2848 HALT_NYI;
2849 }
2850}
2851
2852static void
2853do_vec_UZP (sim_cpu *cpu)
2854{
2855 /* instr[31] = 0
2856 instr[30] = half(0)/full(1)
2857 instr[29,24] = 00 1110
2858 instr[23,22] = size: byte(00), half(01), word (10), long (11)
2859 instr[21] = 0
2860 instr[20,16] = Vm
2861 instr[15] = 0
2862 instr[14] = lower (0) / upper (1)
2863 instr[13,10] = 0110
2864 instr[9,5] = Vn
2865 instr[4,0] = Vd. */
2866
ef0d8ffc
NC
2867 int full = INSTR (30, 30);
2868 int upper = INSTR (14, 14);
2e8cf49e 2869
ef0d8ffc
NC
2870 unsigned vm = INSTR (20, 16);
2871 unsigned vn = INSTR (9, 5);
2872 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2873
2874 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2875 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2876 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2877 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2878
2879 uint64_t val1 = 0;
2880 uint64_t val2 = 0;
2881
2882 uint64_t input1 = upper ? val_n1 : val_m1;
2883 uint64_t input2 = upper ? val_n2 : val_m2;
2884 unsigned i;
2885
2886 NYI_assert (29, 24, 0x0E);
2887 NYI_assert (21, 21, 0);
2888 NYI_assert (15, 15, 0);
2889 NYI_assert (13, 10, 6);
2890
ef0d8ffc 2891 switch (INSTR (23, 23))
2e8cf49e
NC
2892 {
2893 case 0:
2894 for (i = 0; i < 8; i++)
2895 {
2896 val1 |= (input1 >> (i * 8)) & (0xFFULL << (i * 8));
2897 val2 |= (input2 >> (i * 8)) & (0xFFULL << (i * 8));
2898 }
2899 break;
2900
2901 case 1:
2902 for (i = 0; i < 4; i++)
2903 {
2904 val1 |= (input1 >> (i * 16)) & (0xFFFFULL << (i * 16));
2905 val2 |= (input2 >> (i * 16)) & (0xFFFFULL << (i * 16));
2906 }
2907 break;
2908
2909 case 2:
2910 val1 = ((input1 & 0xFFFFFFFF) | ((input1 >> 32) & 0xFFFFFFFF00000000ULL));
2911 val2 = ((input2 & 0xFFFFFFFF) | ((input2 >> 32) & 0xFFFFFFFF00000000ULL));
2912
2913 case 3:
2914 val1 = input1;
2915 val2 = input2;
2916 break;
2917 }
2918
2919 aarch64_set_vec_u64 (cpu, vd, 0, val1);
2920 if (full)
2921 aarch64_set_vec_u64 (cpu, vd, 1, val2);
2922}
2923
2924static void
2925do_vec_ZIP (sim_cpu *cpu)
2926{
2927 /* instr[31] = 0
2928 instr[30] = half(0)/full(1)
2929 instr[29,24] = 00 1110
2930 instr[23,22] = size: byte(00), hald(01), word (10), long (11)
2931 instr[21] = 0
2932 instr[20,16] = Vm
2933 instr[15] = 0
2934 instr[14] = lower (0) / upper (1)
2935 instr[13,10] = 1110
2936 instr[9,5] = Vn
2937 instr[4,0] = Vd. */
2938
ef0d8ffc
NC
2939 int full = INSTR (30, 30);
2940 int upper = INSTR (14, 14);
2e8cf49e 2941
ef0d8ffc
NC
2942 unsigned vm = INSTR (20, 16);
2943 unsigned vn = INSTR (9, 5);
2944 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
2945
2946 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2947 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2948 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2949 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2950
2951 uint64_t val1 = 0;
2952 uint64_t val2 = 0;
2953
2954 uint64_t input1 = upper ? val_n1 : val_m1;
2955 uint64_t input2 = upper ? val_n2 : val_m2;
2956
2957 NYI_assert (29, 24, 0x0E);
2958 NYI_assert (21, 21, 0);
2959 NYI_assert (15, 15, 0);
2960 NYI_assert (13, 10, 0xE);
2961
ef0d8ffc 2962 switch (INSTR (23, 23))
2e8cf49e
NC
2963 {
2964 case 0:
2965 val1 =
2966 ((input1 << 0) & (0xFF << 0))
2967 | ((input2 << 8) & (0xFF << 8))
2968 | ((input1 << 8) & (0xFF << 16))
2969 | ((input2 << 16) & (0xFF << 24))
2970 | ((input1 << 16) & (0xFFULL << 32))
2971 | ((input2 << 24) & (0xFFULL << 40))
2972 | ((input1 << 24) & (0xFFULL << 48))
2973 | ((input2 << 32) & (0xFFULL << 56));
2974
2975 val2 =
2976 ((input1 >> 32) & (0xFF << 0))
2977 | ((input2 >> 24) & (0xFF << 8))
2978 | ((input1 >> 24) & (0xFF << 16))
2979 | ((input2 >> 16) & (0xFF << 24))
2980 | ((input1 >> 16) & (0xFFULL << 32))
2981 | ((input2 >> 8) & (0xFFULL << 40))
2982 | ((input1 >> 8) & (0xFFULL << 48))
2983 | ((input2 >> 0) & (0xFFULL << 56));
2984 break;
2985
2986 case 1:
2987 val1 =
2988 ((input1 << 0) & (0xFFFF << 0))
2989 | ((input2 << 16) & (0xFFFF << 16))
2990 | ((input1 << 16) & (0xFFFFULL << 32))
2991 | ((input2 << 32) & (0xFFFFULL << 48));
2992
2993 val2 =
2994 ((input1 >> 32) & (0xFFFF << 0))
2995 | ((input2 >> 16) & (0xFFFF << 16))
2996 | ((input1 >> 16) & (0xFFFFULL << 32))
2997 | ((input2 >> 0) & (0xFFFFULL << 48));
2998 break;
2999
3000 case 2:
3001 val1 = (input1 & 0xFFFFFFFFULL) | (input2 << 32);
3002 val2 = (input2 & 0xFFFFFFFFULL) | (input1 << 32);
3003 break;
3004
3005 case 3:
3006 val1 = input1;
3007 val2 = input2;
3008 break;
3009 }
3010
3011 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3012 if (full)
3013 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3014}
3015
3016/* Floating point immediates are encoded in 8 bits.
3017 fpimm[7] = sign bit.
3018 fpimm[6:4] = signed exponent.
3019 fpimm[3:0] = fraction (assuming leading 1).
3020 i.e. F = s * 1.f * 2^(e - b). */
3021
3022static float
3023fp_immediate_for_encoding_32 (uint32_t imm8)
3024{
3025 float u;
3026 uint32_t s, e, f, i;
3027
3028 s = (imm8 >> 7) & 0x1;
3029 e = (imm8 >> 4) & 0x7;
3030 f = imm8 & 0xf;
3031
3032 /* The fp value is s * n/16 * 2r where n is 16+e. */
3033 u = (16.0 + f) / 16.0;
3034
3035 /* N.B. exponent is signed. */
3036 if (e < 4)
3037 {
3038 int epos = e;
3039
3040 for (i = 0; i <= epos; i++)
3041 u *= 2.0;
3042 }
3043 else
3044 {
3045 int eneg = 7 - e;
3046
3047 for (i = 0; i < eneg; i++)
3048 u /= 2.0;
3049 }
3050
3051 if (s)
3052 u = - u;
3053
3054 return u;
3055}
3056
3057static double
3058fp_immediate_for_encoding_64 (uint32_t imm8)
3059{
3060 double u;
3061 uint32_t s, e, f, i;
3062
3063 s = (imm8 >> 7) & 0x1;
3064 e = (imm8 >> 4) & 0x7;
3065 f = imm8 & 0xf;
3066
3067 /* The fp value is s * n/16 * 2r where n is 16+e. */
3068 u = (16.0 + f) / 16.0;
3069
3070 /* N.B. exponent is signed. */
3071 if (e < 4)
3072 {
3073 int epos = e;
3074
3075 for (i = 0; i <= epos; i++)
3076 u *= 2.0;
3077 }
3078 else
3079 {
3080 int eneg = 7 - e;
3081
3082 for (i = 0; i < eneg; i++)
3083 u /= 2.0;
3084 }
3085
3086 if (s)
3087 u = - u;
3088
3089 return u;
3090}
3091
3092static void
3093do_vec_MOV_immediate (sim_cpu *cpu)
3094{
3095 /* instr[31] = 0
3096 instr[30] = full/half selector
3097 instr[29,19] = 00111100000
3098 instr[18,16] = high 3 bits of uimm8
3099 instr[15,12] = size & shift:
3100 0000 => 32-bit
3101 0010 => 32-bit + LSL#8
3102 0100 => 32-bit + LSL#16
3103 0110 => 32-bit + LSL#24
3104 1010 => 16-bit + LSL#8
3105 1000 => 16-bit
3106 1101 => 32-bit + MSL#16
3107 1100 => 32-bit + MSL#8
3108 1110 => 8-bit
3109 1111 => double
3110 instr[11,10] = 01
3111 instr[9,5] = low 5-bits of uimm8
3112 instr[4,0] = Vd. */
3113
ef0d8ffc
NC
3114 int full = INSTR (30, 30);
3115 unsigned vd = INSTR (4, 0);
7517e550 3116 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3117 unsigned i;
3118
3119 NYI_assert (29, 19, 0x1E0);
3120 NYI_assert (11, 10, 1);
3121
ef0d8ffc 3122 switch (INSTR (15, 12))
2e8cf49e
NC
3123 {
3124 case 0x0: /* 32-bit, no shift. */
3125 case 0x2: /* 32-bit, shift by 8. */
3126 case 0x4: /* 32-bit, shift by 16. */
3127 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3128 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3129 for (i = 0; i < (full ? 4 : 2); i++)
3130 aarch64_set_vec_u32 (cpu, vd, i, val);
3131 break;
3132
3133 case 0xa: /* 16-bit, shift by 8. */
3134 val <<= 8;
3135 /* Fall through. */
3136 case 0x8: /* 16-bit, no shift. */
3137 for (i = 0; i < (full ? 8 : 4); i++)
3138 aarch64_set_vec_u16 (cpu, vd, i, val);
3139 /* Fall through. */
3140 case 0xd: /* 32-bit, mask shift by 16. */
3141 val <<= 8;
3142 val |= 0xFF;
3143 /* Fall through. */
3144 case 0xc: /* 32-bit, mask shift by 8. */
3145 val <<= 8;
3146 val |= 0xFF;
3147 for (i = 0; i < (full ? 4 : 2); i++)
3148 aarch64_set_vec_u32 (cpu, vd, i, val);
3149 break;
3150
3151 case 0xe: /* 8-bit, no shift. */
3152 for (i = 0; i < (full ? 16 : 8); i++)
3153 aarch64_set_vec_u8 (cpu, vd, i, val);
3154 break;
3155
3156 case 0xf: /* FMOV Vs.{2|4}S, #fpimm. */
3157 {
3158 float u = fp_immediate_for_encoding_32 (val);
3159 for (i = 0; i < (full ? 4 : 2); i++)
3160 aarch64_set_vec_float (cpu, vd, i, u);
3161 break;
3162 }
3163
3164 default:
3165 HALT_NYI;
3166 }
3167}
3168
3169static void
3170do_vec_MVNI (sim_cpu *cpu)
3171{
3172 /* instr[31] = 0
3173 instr[30] = full/half selector
3174 instr[29,19] = 10111100000
3175 instr[18,16] = high 3 bits of uimm8
3176 instr[15,12] = selector
3177 instr[11,10] = 01
3178 instr[9,5] = low 5-bits of uimm8
3179 instr[4,0] = Vd. */
3180
ef0d8ffc
NC
3181 int full = INSTR (30, 30);
3182 unsigned vd = INSTR (4, 0);
7517e550 3183 unsigned val = (INSTR (18, 16) << 5) | INSTR (9, 5);
2e8cf49e
NC
3184 unsigned i;
3185
3186 NYI_assert (29, 19, 0x5E0);
3187 NYI_assert (11, 10, 1);
3188
ef0d8ffc 3189 switch (INSTR (15, 12))
2e8cf49e
NC
3190 {
3191 case 0x0: /* 32-bit, no shift. */
3192 case 0x2: /* 32-bit, shift by 8. */
3193 case 0x4: /* 32-bit, shift by 16. */
3194 case 0x6: /* 32-bit, shift by 24. */
ef0d8ffc 3195 val <<= (8 * INSTR (14, 13));
2e8cf49e
NC
3196 val = ~ val;
3197 for (i = 0; i < (full ? 4 : 2); i++)
3198 aarch64_set_vec_u32 (cpu, vd, i, val);
3199 return;
3200
3201 case 0xa: /* 16-bit, 8 bit shift. */
3202 val <<= 8;
3203 case 0x8: /* 16-bit, no shift. */
3204 val = ~ val;
3205 for (i = 0; i < (full ? 8 : 4); i++)
3206 aarch64_set_vec_u16 (cpu, vd, i, val);
3207 return;
3208
3209 case 0xd: /* 32-bit, mask shift by 16. */
3210 val <<= 8;
3211 val |= 0xFF;
3212 case 0xc: /* 32-bit, mask shift by 8. */
3213 val <<= 8;
3214 val |= 0xFF;
3215 val = ~ val;
3216 for (i = 0; i < (full ? 4 : 2); i++)
3217 aarch64_set_vec_u32 (cpu, vd, i, val);
3218 return;
3219
3220 case 0xE: /* MOVI Dn, #mask64 */
3221 {
3222 uint64_t mask = 0;
3223
3224 for (i = 0; i < 8; i++)
3225 if (val & (1 << i))
7517e550 3226 mask |= (0xFFUL << (i * 8));
2e8cf49e 3227 aarch64_set_vec_u64 (cpu, vd, 0, mask);
7517e550 3228 aarch64_set_vec_u64 (cpu, vd, 1, mask);
2e8cf49e
NC
3229 return;
3230 }
3231
3232 case 0xf: /* FMOV Vd.2D, #fpimm. */
3233 {
3234 double u = fp_immediate_for_encoding_64 (val);
3235
3236 if (! full)
3237 HALT_UNALLOC;
3238
3239 aarch64_set_vec_double (cpu, vd, 0, u);
3240 aarch64_set_vec_double (cpu, vd, 1, u);
3241 return;
3242 }
3243
3244 default:
3245 HALT_NYI;
3246 }
3247}
3248
3249#define ABS(A) ((A) < 0 ? - (A) : (A))
3250
3251static void
3252do_vec_ABS (sim_cpu *cpu)
3253{
3254 /* instr[31] = 0
3255 instr[30] = half(0)/full(1)
3256 instr[29,24] = 00 1110
3257 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3258 instr[21,10] = 10 0000 1011 10
3259 instr[9,5] = Vn
3260 instr[4.0] = Vd. */
3261
ef0d8ffc
NC
3262 unsigned vn = INSTR (9, 5);
3263 unsigned vd = INSTR (4, 0);
3264 unsigned full = INSTR (30, 30);
2e8cf49e
NC
3265 unsigned i;
3266
3267 NYI_assert (29, 24, 0x0E);
3268 NYI_assert (21, 10, 0x82E);
3269
ef0d8ffc 3270 switch (INSTR (23, 22))
2e8cf49e
NC
3271 {
3272 case 0:
3273 for (i = 0; i < (full ? 16 : 8); i++)
3274 aarch64_set_vec_s8 (cpu, vd, i,
3275 ABS (aarch64_get_vec_s8 (cpu, vn, i)));
3276 break;
3277
3278 case 1:
3279 for (i = 0; i < (full ? 8 : 4); i++)
3280 aarch64_set_vec_s16 (cpu, vd, i,
3281 ABS (aarch64_get_vec_s16 (cpu, vn, i)));
3282 break;
3283
3284 case 2:
3285 for (i = 0; i < (full ? 4 : 2); i++)
3286 aarch64_set_vec_s32 (cpu, vd, i,
3287 ABS (aarch64_get_vec_s32 (cpu, vn, i)));
3288 break;
3289
3290 case 3:
3291 if (! full)
3292 HALT_NYI;
3293 for (i = 0; i < 2; i++)
3294 aarch64_set_vec_s64 (cpu, vd, i,
3295 ABS (aarch64_get_vec_s64 (cpu, vn, i)));
3296 break;
3297 }
3298}
3299
3300static void
3301do_vec_ADDV (sim_cpu *cpu)
3302{
3303 /* instr[31] = 0
3304 instr[30] = full/half selector
3305 instr[29,24] = 00 1110
3306 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3307 instr[21,10] = 11 0001 1011 10
3308 instr[9,5] = Vm
3309 instr[4.0] = Rd. */
3310
ef0d8ffc
NC
3311 unsigned vm = INSTR (9, 5);
3312 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
3313 unsigned i;
3314 uint64_t val = 0;
ef0d8ffc 3315 int full = INSTR (30, 30);
2e8cf49e
NC
3316
3317 NYI_assert (29, 24, 0x0E);
3318 NYI_assert (21, 10, 0xC6E);
3319
ef0d8ffc 3320 switch (INSTR (23, 22))
2e8cf49e
NC
3321 {
3322 case 0:
3323 for (i = 0; i < (full ? 16 : 8); i++)
3324 val += aarch64_get_vec_u8 (cpu, vm, i);
3325 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3326 return;
3327
3328 case 1:
3329 for (i = 0; i < (full ? 8 : 4); i++)
3330 val += aarch64_get_vec_u16 (cpu, vm, i);
3331 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3332 return;
3333
3334 case 2:
3335 for (i = 0; i < (full ? 4 : 2); i++)
3336 val += aarch64_get_vec_u32 (cpu, vm, i);
3337 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3338 return;
3339
3340 case 3:
3341 if (! full)
3342 HALT_UNALLOC;
3343 val = aarch64_get_vec_u64 (cpu, vm, 0);
3344 val += aarch64_get_vec_u64 (cpu, vm, 1);
3345 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3346 return;
2e8cf49e
NC
3347 }
3348}
3349
3350static void
3351do_vec_ins_2 (sim_cpu *cpu)
3352{
3353 /* instr[31,21] = 01001110000
3354 instr[20,18] = size & element selector
3355 instr[17,14] = 0000
3356 instr[13] = direction: to vec(0), from vec (1)
3357 instr[12,10] = 111
3358 instr[9,5] = Vm
3359 instr[4,0] = Vd. */
3360
3361 unsigned elem;
ef0d8ffc
NC
3362 unsigned vm = INSTR (9, 5);
3363 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
3364
3365 NYI_assert (31, 21, 0x270);
3366 NYI_assert (17, 14, 0);
3367 NYI_assert (12, 10, 7);
3368
ef0d8ffc 3369 if (INSTR (13, 13) == 1)
2e8cf49e 3370 {
ef0d8ffc 3371 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3372 {
3373 /* 32-bit moves. */
ef0d8ffc 3374 elem = INSTR (20, 19);
2e8cf49e
NC
3375 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3376 aarch64_get_vec_u32 (cpu, vm, elem));
3377 }
3378 else
3379 {
3380 /* 64-bit moves. */
ef0d8ffc 3381 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3382 HALT_NYI;
3383
ef0d8ffc 3384 elem = INSTR (20, 20);
2e8cf49e
NC
3385 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3386 aarch64_get_vec_u64 (cpu, vm, elem));
3387 }
3388 }
3389 else
3390 {
ef0d8ffc 3391 if (INSTR (18, 18) == 1)
2e8cf49e
NC
3392 {
3393 /* 32-bit moves. */
ef0d8ffc 3394 elem = INSTR (20, 19);
2e8cf49e
NC
3395 aarch64_set_vec_u32 (cpu, vd, elem,
3396 aarch64_get_reg_u32 (cpu, vm, NO_SP));
3397 }
3398 else
3399 {
3400 /* 64-bit moves. */
ef0d8ffc 3401 if (INSTR (19, 19) != 1)
2e8cf49e
NC
3402 HALT_NYI;
3403
ef0d8ffc 3404 elem = INSTR (20, 20);
2e8cf49e
NC
3405 aarch64_set_vec_u64 (cpu, vd, elem,
3406 aarch64_get_reg_u64 (cpu, vm, NO_SP));
3407 }
3408 }
3409}
3410
7517e550
NC
3411#define DO_VEC_WIDENING_MUL(N, DST_TYPE, READ_TYPE, WRITE_TYPE) \
3412 do \
3413 { \
3414 DST_TYPE a[N], b[N]; \
3415 \
3416 for (i = 0; i < (N); i++) \
3417 { \
3418 a[i] = aarch64_get_vec_##READ_TYPE (cpu, vn, i + bias); \
3419 b[i] = aarch64_get_vec_##READ_TYPE (cpu, vm, i + bias); \
3420 } \
3421 for (i = 0; i < (N); i++) \
3422 aarch64_set_vec_##WRITE_TYPE (cpu, vd, i, a[i] * b[i]); \
3423 } \
3424 while (0)
3425
2e8cf49e
NC
3426static void
3427do_vec_mull (sim_cpu *cpu)
3428{
3429 /* instr[31] = 0
3430 instr[30] = lower(0)/upper(1) selector
3431 instr[29] = signed(0)/unsigned(1)
3432 instr[28,24] = 0 1110
3433 instr[23,22] = size: 8-bit (00), 16-bit (01), 32-bit (10)
3434 instr[21] = 1
3435 instr[20,16] = Vm
3436 instr[15,10] = 11 0000
3437 instr[9,5] = Vn
3438 instr[4.0] = Vd. */
3439
ef0d8ffc
NC
3440 int unsign = INSTR (29, 29);
3441 int bias = INSTR (30, 30);
3442 unsigned vm = INSTR (20, 16);
3443 unsigned vn = INSTR ( 9, 5);
3444 unsigned vd = INSTR ( 4, 0);
2e8cf49e
NC
3445 unsigned i;
3446
3447 NYI_assert (28, 24, 0x0E);
3448 NYI_assert (15, 10, 0x30);
3449
7517e550
NC
3450 /* NB: Read source values before writing results, in case
3451 the source and destination vectors are the same. */
ef0d8ffc 3452 switch (INSTR (23, 22))
2e8cf49e
NC
3453 {
3454 case 0:
3455 if (bias)
3456 bias = 8;
3457 if (unsign)
7517e550 3458 DO_VEC_WIDENING_MUL (8, uint16_t, u8, u16);
2e8cf49e 3459 else
7517e550 3460 DO_VEC_WIDENING_MUL (8, int16_t, s8, s16);
2e8cf49e
NC
3461 return;
3462
3463 case 1:
3464 if (bias)
3465 bias = 4;
3466 if (unsign)
7517e550 3467 DO_VEC_WIDENING_MUL (4, uint32_t, u16, u32);
2e8cf49e 3468 else
7517e550 3469 DO_VEC_WIDENING_MUL (4, int32_t, s16, s32);
2e8cf49e
NC
3470 return;
3471
3472 case 2:
3473 if (bias)
3474 bias = 2;
3475 if (unsign)
7517e550 3476 DO_VEC_WIDENING_MUL (2, uint64_t, u32, u64);
2e8cf49e 3477 else
7517e550 3478 DO_VEC_WIDENING_MUL (2, int64_t, s32, s64);
2e8cf49e
NC
3479 return;
3480
3481 case 3:
2e8cf49e
NC
3482 HALT_NYI;
3483 }
3484}
3485
3486static void
3487do_vec_fadd (sim_cpu *cpu)
3488{
3489 /* instr[31] = 0
3490 instr[30] = half(0)/full(1)
3491 instr[29,24] = 001110
3492 instr[23] = FADD(0)/FSUB(1)
3493 instr[22] = float (0)/double(1)
3494 instr[21] = 1
3495 instr[20,16] = Vm
3496 instr[15,10] = 110101
3497 instr[9,5] = Vn
3498 instr[4.0] = Vd. */
3499
ef0d8ffc
NC
3500 unsigned vm = INSTR (20, 16);
3501 unsigned vn = INSTR (9, 5);
3502 unsigned vd = INSTR (4, 0);
2e8cf49e 3503 unsigned i;
ef0d8ffc 3504 int full = INSTR (30, 30);
2e8cf49e
NC
3505
3506 NYI_assert (29, 24, 0x0E);
3507 NYI_assert (21, 21, 1);
3508 NYI_assert (15, 10, 0x35);
3509
ef0d8ffc 3510 if (INSTR (23, 23))
2e8cf49e 3511 {
ef0d8ffc 3512 if (INSTR (22, 22))
2e8cf49e
NC
3513 {
3514 if (! full)
3515 HALT_NYI;
3516
3517 for (i = 0; i < 2; i++)
3518 aarch64_set_vec_double (cpu, vd, i,
3519 aarch64_get_vec_double (cpu, vn, i)
3520 - aarch64_get_vec_double (cpu, vm, i));
3521 }
3522 else
3523 {
3524 for (i = 0; i < (full ? 4 : 2); i++)
3525 aarch64_set_vec_float (cpu, vd, i,
3526 aarch64_get_vec_float (cpu, vn, i)
3527 - aarch64_get_vec_float (cpu, vm, i));
3528 }
3529 }
3530 else
3531 {
ef0d8ffc 3532 if (INSTR (22, 22))
2e8cf49e
NC
3533 {
3534 if (! full)
3535 HALT_NYI;
3536
3537 for (i = 0; i < 2; i++)
3538 aarch64_set_vec_double (cpu, vd, i,
3539 aarch64_get_vec_double (cpu, vm, i)
3540 + aarch64_get_vec_double (cpu, vn, i));
3541 }
3542 else
3543 {
3544 for (i = 0; i < (full ? 4 : 2); i++)
3545 aarch64_set_vec_float (cpu, vd, i,
3546 aarch64_get_vec_float (cpu, vm, i)
3547 + aarch64_get_vec_float (cpu, vn, i));
3548 }
3549 }
3550}
3551
3552static void
3553do_vec_add (sim_cpu *cpu)
3554{
3555 /* instr[31] = 0
3556 instr[30] = full/half selector
3557 instr[29,24] = 001110
3558 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3559 instr[21] = 1
3560 instr[20,16] = Vn
3561 instr[15,10] = 100001
3562 instr[9,5] = Vm
3563 instr[4.0] = Vd. */
3564
ef0d8ffc
NC
3565 unsigned vm = INSTR (20, 16);
3566 unsigned vn = INSTR (9, 5);
3567 unsigned vd = INSTR (4, 0);
2e8cf49e 3568 unsigned i;
ef0d8ffc 3569 int full = INSTR (30, 30);
2e8cf49e
NC
3570
3571 NYI_assert (29, 24, 0x0E);
3572 NYI_assert (21, 21, 1);
3573 NYI_assert (15, 10, 0x21);
3574
ef0d8ffc 3575 switch (INSTR (23, 22))
2e8cf49e
NC
3576 {
3577 case 0:
3578 for (i = 0; i < (full ? 16 : 8); i++)
3579 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
3580 + aarch64_get_vec_u8 (cpu, vm, i));
3581 return;
3582
3583 case 1:
3584 for (i = 0; i < (full ? 8 : 4); i++)
3585 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
3586 + aarch64_get_vec_u16 (cpu, vm, i));
3587 return;
3588
3589 case 2:
3590 for (i = 0; i < (full ? 4 : 2); i++)
3591 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
3592 + aarch64_get_vec_u32 (cpu, vm, i));
3593 return;
3594
3595 case 3:
3596 if (! full)
3597 HALT_UNALLOC;
3598 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vn, 0)
3599 + aarch64_get_vec_u64 (cpu, vm, 0));
3600 aarch64_set_vec_u64 (cpu, vd, 1,
3601 aarch64_get_vec_u64 (cpu, vn, 1)
3602 + aarch64_get_vec_u64 (cpu, vm, 1));
3603 return;
2e8cf49e
NC
3604 }
3605}
3606
3607static void
3608do_vec_mul (sim_cpu *cpu)
3609{
3610 /* instr[31] = 0
3611 instr[30] = full/half selector
3612 instr[29,24] = 00 1110
3613 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3614 instr[21] = 1
3615 instr[20,16] = Vn
3616 instr[15,10] = 10 0111
3617 instr[9,5] = Vm
3618 instr[4.0] = Vd. */
3619
ef0d8ffc
NC
3620 unsigned vm = INSTR (20, 16);
3621 unsigned vn = INSTR (9, 5);
3622 unsigned vd = INSTR (4, 0);
2e8cf49e 3623 unsigned i;
ef0d8ffc 3624 int full = INSTR (30, 30);
7517e550 3625 int bias = 0;
2e8cf49e
NC
3626
3627 NYI_assert (29, 24, 0x0E);
3628 NYI_assert (21, 21, 1);
3629 NYI_assert (15, 10, 0x27);
3630
ef0d8ffc 3631 switch (INSTR (23, 22))
2e8cf49e
NC
3632 {
3633 case 0:
7517e550 3634 DO_VEC_WIDENING_MUL (full ? 16 : 8, uint16_t, u8, u16);
2e8cf49e
NC
3635 return;
3636
3637 case 1:
7517e550 3638 DO_VEC_WIDENING_MUL (full ? 8 : 4, uint32_t, u16, u32);
2e8cf49e
NC
3639 return;
3640
3641 case 2:
7517e550 3642 DO_VEC_WIDENING_MUL (full ? 4 : 2, uint64_t, u32, u64);
2e8cf49e
NC
3643 return;
3644
2e8cf49e
NC
3645 case 3:
3646 HALT_UNALLOC;
3647 }
3648}
3649
3650static void
3651do_vec_MLA (sim_cpu *cpu)
3652{
3653 /* instr[31] = 0
3654 instr[30] = full/half selector
3655 instr[29,24] = 00 1110
3656 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3657 instr[21] = 1
3658 instr[20,16] = Vn
3659 instr[15,10] = 1001 01
3660 instr[9,5] = Vm
3661 instr[4.0] = Vd. */
3662
ef0d8ffc
NC
3663 unsigned vm = INSTR (20, 16);
3664 unsigned vn = INSTR (9, 5);
3665 unsigned vd = INSTR (4, 0);
2e8cf49e 3666 unsigned i;
ef0d8ffc 3667 int full = INSTR (30, 30);
2e8cf49e
NC
3668
3669 NYI_assert (29, 24, 0x0E);
3670 NYI_assert (21, 21, 1);
3671 NYI_assert (15, 10, 0x25);
3672
ef0d8ffc 3673 switch (INSTR (23, 22))
2e8cf49e
NC
3674 {
3675 case 0:
7517e550
NC
3676 {
3677 uint16_t a[16], b[16];
2e8cf49e 3678
7517e550
NC
3679 for (i = 0; i < (full ? 16 : 8); i++)
3680 {
3681 a[i] = aarch64_get_vec_u8 (cpu, vn, i);
3682 b[i] = aarch64_get_vec_u8 (cpu, vm, i);
3683 }
3684
3685 for (i = 0; i < (full ? 16 : 8); i++)
3686 {
3687 uint16_t v = aarch64_get_vec_u8 (cpu, vd, i);
3688
3689 aarch64_set_vec_u16 (cpu, vd, i, v + (a[i] * b[i]));
3690 }
3691 }
2e8cf49e
NC
3692 return;
3693
3694 case 1:
7517e550
NC
3695 {
3696 uint32_t a[8], b[8];
2e8cf49e 3697
7517e550
NC
3698 for (i = 0; i < (full ? 8 : 4); i++)
3699 {
3700 a[i] = aarch64_get_vec_u16 (cpu, vn, i);
3701 b[i] = aarch64_get_vec_u16 (cpu, vm, i);
3702 }
3703
3704 for (i = 0; i < (full ? 8 : 4); i++)
3705 {
3706 uint32_t v = aarch64_get_vec_u16 (cpu, vd, i);
3707
3708 aarch64_set_vec_u32 (cpu, vd, i, v + (a[i] * b[i]));
3709 }
3710 }
2e8cf49e
NC
3711 return;
3712
3713 case 2:
7517e550
NC
3714 {
3715 uint64_t a[4], b[4];
2e8cf49e 3716
7517e550
NC
3717 for (i = 0; i < (full ? 4 : 2); i++)
3718 {
3719 a[i] = aarch64_get_vec_u32 (cpu, vn, i);
3720 b[i] = aarch64_get_vec_u32 (cpu, vm, i);
3721 }
3722
3723 for (i = 0; i < (full ? 4 : 2); i++)
3724 {
3725 uint64_t v = aarch64_get_vec_u32 (cpu, vd, i);
3726
3727 aarch64_set_vec_u64 (cpu, vd, i, v + (a[i] * b[i]));
3728 }
3729 }
2e8cf49e
NC
3730 return;
3731
2e8cf49e
NC
3732 case 3:
3733 HALT_UNALLOC;
3734 }
3735}
3736
3737static float
3738fmaxnm (float a, float b)
3739{
3740 if (fpclassify (a) == FP_NORMAL)
3741 {
3742 if (fpclassify (b) == FP_NORMAL)
3743 return a > b ? a : b;
3744 return a;
3745 }
3746 else if (fpclassify (b) == FP_NORMAL)
3747 return b;
3748 return a;
3749}
3750
3751static float
3752fminnm (float a, float b)
3753{
3754 if (fpclassify (a) == FP_NORMAL)
3755 {
3756 if (fpclassify (b) == FP_NORMAL)
3757 return a < b ? a : b;
3758 return a;
3759 }
3760 else if (fpclassify (b) == FP_NORMAL)
3761 return b;
3762 return a;
3763}
3764
3765static double
3766dmaxnm (double a, double b)
3767{
3768 if (fpclassify (a) == FP_NORMAL)
3769 {
3770 if (fpclassify (b) == FP_NORMAL)
3771 return a > b ? a : b;
3772 return a;
3773 }
3774 else if (fpclassify (b) == FP_NORMAL)
3775 return b;
3776 return a;
3777}
3778
3779static double
3780dminnm (double a, double b)
3781{
3782 if (fpclassify (a) == FP_NORMAL)
3783 {
3784 if (fpclassify (b) == FP_NORMAL)
3785 return a < b ? a : b;
3786 return a;
3787 }
3788 else if (fpclassify (b) == FP_NORMAL)
3789 return b;
3790 return a;
3791}
3792
3793static void
3794do_vec_FminmaxNMP (sim_cpu *cpu)
3795{
ef0d8ffc
NC
3796 /* instr [31] = 0
3797 instr [30] = half (0)/full (1)
3798 instr [29,24] = 10 1110
3799 instr [23] = max(0)/min(1)
3800 instr [22] = float (0)/double (1)
3801 instr [21] = 1
3802 instr [20,16] = Vn
3803 instr [15,10] = 1100 01
3804 instr [9,5] = Vm
3805 instr [4.0] = Vd. */
3806
3807 unsigned vm = INSTR (20, 16);
3808 unsigned vn = INSTR (9, 5);
3809 unsigned vd = INSTR (4, 0);
3810 int full = INSTR (30, 30);
2e8cf49e
NC
3811
3812 NYI_assert (29, 24, 0x2E);
3813 NYI_assert (21, 21, 1);
3814 NYI_assert (15, 10, 0x31);
3815
ef0d8ffc 3816 if (INSTR (22, 22))
2e8cf49e 3817 {
ef0d8ffc 3818 double (* fn)(double, double) = INSTR (23, 23)
2e8cf49e
NC
3819 ? dminnm : dmaxnm;
3820
3821 if (! full)
3822 HALT_NYI;
3823 aarch64_set_vec_double (cpu, vd, 0,
3824 fn (aarch64_get_vec_double (cpu, vn, 0),
3825 aarch64_get_vec_double (cpu, vn, 1)));
3826 aarch64_set_vec_double (cpu, vd, 0,
3827 fn (aarch64_get_vec_double (cpu, vm, 0),
3828 aarch64_get_vec_double (cpu, vm, 1)));
3829 }
3830 else
3831 {
ef0d8ffc 3832 float (* fn)(float, float) = INSTR (23, 23)
2e8cf49e
NC
3833 ? fminnm : fmaxnm;
3834
3835 aarch64_set_vec_float (cpu, vd, 0,
3836 fn (aarch64_get_vec_float (cpu, vn, 0),
3837 aarch64_get_vec_float (cpu, vn, 1)));
3838 if (full)
3839 aarch64_set_vec_float (cpu, vd, 1,
3840 fn (aarch64_get_vec_float (cpu, vn, 2),
3841 aarch64_get_vec_float (cpu, vn, 3)));
3842
3843 aarch64_set_vec_float (cpu, vd, (full ? 2 : 1),
3844 fn (aarch64_get_vec_float (cpu, vm, 0),
3845 aarch64_get_vec_float (cpu, vm, 1)));
3846 if (full)
3847 aarch64_set_vec_float (cpu, vd, 3,
3848 fn (aarch64_get_vec_float (cpu, vm, 2),
3849 aarch64_get_vec_float (cpu, vm, 3)));
3850 }
3851}
3852
3853static void
3854do_vec_AND (sim_cpu *cpu)
3855{
3856 /* instr[31] = 0
3857 instr[30] = half (0)/full (1)
3858 instr[29,21] = 001110001
3859 instr[20,16] = Vm
3860 instr[15,10] = 000111
3861 instr[9,5] = Vn
3862 instr[4.0] = Vd. */
3863
ef0d8ffc
NC
3864 unsigned vm = INSTR (20, 16);
3865 unsigned vn = INSTR (9, 5);
3866 unsigned vd = INSTR (4, 0);
2e8cf49e 3867 unsigned i;
ef0d8ffc 3868 int full = INSTR (30, 30);
2e8cf49e
NC
3869
3870 NYI_assert (29, 21, 0x071);
3871 NYI_assert (15, 10, 0x07);
3872
3873 for (i = 0; i < (full ? 4 : 2); i++)
3874 aarch64_set_vec_u32 (cpu, vd, i,
3875 aarch64_get_vec_u32 (cpu, vn, i)
3876 & aarch64_get_vec_u32 (cpu, vm, i));
3877}
3878
3879static void
3880do_vec_BSL (sim_cpu *cpu)
3881{
3882 /* instr[31] = 0
3883 instr[30] = half (0)/full (1)
3884 instr[29,21] = 101110011
3885 instr[20,16] = Vm
3886 instr[15,10] = 000111
3887 instr[9,5] = Vn
3888 instr[4.0] = Vd. */
3889
ef0d8ffc
NC
3890 unsigned vm = INSTR (20, 16);
3891 unsigned vn = INSTR (9, 5);
3892 unsigned vd = INSTR (4, 0);
2e8cf49e 3893 unsigned i;
ef0d8ffc 3894 int full = INSTR (30, 30);
2e8cf49e
NC
3895
3896 NYI_assert (29, 21, 0x173);
3897 NYI_assert (15, 10, 0x07);
3898
3899 for (i = 0; i < (full ? 16 : 8); i++)
3900 aarch64_set_vec_u8 (cpu, vd, i,
3901 ( aarch64_get_vec_u8 (cpu, vd, i)
3902 & aarch64_get_vec_u8 (cpu, vn, i))
3903 | ((~ aarch64_get_vec_u8 (cpu, vd, i))
3904 & aarch64_get_vec_u8 (cpu, vm, i)));
3905}
3906
3907static void
3908do_vec_EOR (sim_cpu *cpu)
3909{
3910 /* instr[31] = 0
3911 instr[30] = half (0)/full (1)
3912 instr[29,21] = 10 1110 001
3913 instr[20,16] = Vm
3914 instr[15,10] = 000111
3915 instr[9,5] = Vn
3916 instr[4.0] = Vd. */
3917
ef0d8ffc
NC
3918 unsigned vm = INSTR (20, 16);
3919 unsigned vn = INSTR (9, 5);
3920 unsigned vd = INSTR (4, 0);
2e8cf49e 3921 unsigned i;
ef0d8ffc 3922 int full = INSTR (30, 30);
2e8cf49e
NC
3923
3924 NYI_assert (29, 21, 0x171);
3925 NYI_assert (15, 10, 0x07);
3926
3927 for (i = 0; i < (full ? 4 : 2); i++)
3928 aarch64_set_vec_u32 (cpu, vd, i,
3929 aarch64_get_vec_u32 (cpu, vn, i)
3930 ^ aarch64_get_vec_u32 (cpu, vm, i));
3931}
3932
3933static void
3934do_vec_bit (sim_cpu *cpu)
3935{
3936 /* instr[31] = 0
3937 instr[30] = half (0)/full (1)
3938 instr[29,23] = 10 1110 1
3939 instr[22] = BIT (0) / BIF (1)
3940 instr[21] = 1
3941 instr[20,16] = Vm
3942 instr[15,10] = 0001 11
3943 instr[9,5] = Vn
3944 instr[4.0] = Vd. */
3945
ef0d8ffc
NC
3946 unsigned vm = INSTR (20, 16);
3947 unsigned vn = INSTR (9, 5);
3948 unsigned vd = INSTR (4, 0);
3949 unsigned full = INSTR (30, 30);
3950 unsigned test_false = INSTR (22, 22);
2e8cf49e
NC
3951 unsigned i;
3952
3953 NYI_assert (29, 23, 0x5D);
3954 NYI_assert (21, 21, 1);
3955 NYI_assert (15, 10, 0x07);
3956
3957 if (test_false)
3958 {
3959 for (i = 0; i < (full ? 16 : 8); i++)
3960 if (aarch64_get_vec_u32 (cpu, vn, i) == 0)
3961 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
3962 }
3963 else
3964 {
3965 for (i = 0; i < (full ? 16 : 8); i++)
3966 if (aarch64_get_vec_u32 (cpu, vn, i) != 0)
3967 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
3968 }
3969}
3970
3971static void
3972do_vec_ORN (sim_cpu *cpu)
3973{
3974 /* instr[31] = 0
3975 instr[30] = half (0)/full (1)
3976 instr[29,21] = 00 1110 111
3977 instr[20,16] = Vm
3978 instr[15,10] = 00 0111
3979 instr[9,5] = Vn
3980 instr[4.0] = Vd. */
3981
ef0d8ffc
NC
3982 unsigned vm = INSTR (20, 16);
3983 unsigned vn = INSTR (9, 5);
3984 unsigned vd = INSTR (4, 0);
2e8cf49e 3985 unsigned i;
ef0d8ffc 3986 int full = INSTR (30, 30);
2e8cf49e
NC
3987
3988 NYI_assert (29, 21, 0x077);
3989 NYI_assert (15, 10, 0x07);
3990
3991 for (i = 0; i < (full ? 16 : 8); i++)
3992 aarch64_set_vec_u8 (cpu, vd, i,
3993 aarch64_get_vec_u8 (cpu, vn, i)
3994 | ~ aarch64_get_vec_u8 (cpu, vm, i));
3995}
3996
3997static void
3998do_vec_ORR (sim_cpu *cpu)
3999{
4000 /* instr[31] = 0
4001 instr[30] = half (0)/full (1)
4002 instr[29,21] = 00 1110 101
4003 instr[20,16] = Vm
4004 instr[15,10] = 0001 11
4005 instr[9,5] = Vn
4006 instr[4.0] = Vd. */
4007
ef0d8ffc
NC
4008 unsigned vm = INSTR (20, 16);
4009 unsigned vn = INSTR (9, 5);
4010 unsigned vd = INSTR (4, 0);
2e8cf49e 4011 unsigned i;
ef0d8ffc 4012 int full = INSTR (30, 30);
2e8cf49e
NC
4013
4014 NYI_assert (29, 21, 0x075);
4015 NYI_assert (15, 10, 0x07);
4016
4017 for (i = 0; i < (full ? 16 : 8); i++)
4018 aarch64_set_vec_u8 (cpu, vd, i,
4019 aarch64_get_vec_u8 (cpu, vn, i)
4020 | aarch64_get_vec_u8 (cpu, vm, i));
4021}
4022
4023static void
4024do_vec_BIC (sim_cpu *cpu)
4025{
4026 /* instr[31] = 0
4027 instr[30] = half (0)/full (1)
4028 instr[29,21] = 00 1110 011
4029 instr[20,16] = Vm
4030 instr[15,10] = 00 0111
4031 instr[9,5] = Vn
4032 instr[4.0] = Vd. */
4033
ef0d8ffc
NC
4034 unsigned vm = INSTR (20, 16);
4035 unsigned vn = INSTR (9, 5);
4036 unsigned vd = INSTR (4, 0);
2e8cf49e 4037 unsigned i;
ef0d8ffc 4038 int full = INSTR (30, 30);
2e8cf49e
NC
4039
4040 NYI_assert (29, 21, 0x073);
4041 NYI_assert (15, 10, 0x07);
4042
4043 for (i = 0; i < (full ? 16 : 8); i++)
4044 aarch64_set_vec_u8 (cpu, vd, i,
4045 aarch64_get_vec_u8 (cpu, vn, i)
4046 & ~ aarch64_get_vec_u8 (cpu, vm, i));
4047}
4048
4049static void
4050do_vec_XTN (sim_cpu *cpu)
4051{
4052 /* instr[31] = 0
4053 instr[30] = first part (0)/ second part (1)
4054 instr[29,24] = 00 1110
4055 instr[23,22] = size: byte(00), half(01), word (10)
4056 instr[21,10] = 1000 0100 1010
4057 instr[9,5] = Vs
4058 instr[4,0] = Vd. */
4059
ef0d8ffc
NC
4060 unsigned vs = INSTR (9, 5);
4061 unsigned vd = INSTR (4, 0);
4062 unsigned bias = INSTR (30, 30);
2e8cf49e
NC
4063 unsigned i;
4064
4065 NYI_assert (29, 24, 0x0E);
4066 NYI_assert (21, 10, 0x84A);
4067
ef0d8ffc 4068 switch (INSTR (23, 22))
2e8cf49e
NC
4069 {
4070 case 0:
4071 if (bias)
4072 for (i = 0; i < 8; i++)
4073 aarch64_set_vec_u8 (cpu, vd, i + 8,
4074 aarch64_get_vec_u16 (cpu, vs, i) >> 8);
4075 else
4076 for (i = 0; i < 8; i++)
4077 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i));
4078 return;
4079
4080 case 1:
4081 if (bias)
4082 for (i = 0; i < 4; i++)
4083 aarch64_set_vec_u16 (cpu, vd, i + 4,
4084 aarch64_get_vec_u32 (cpu, vs, i) >> 16);
4085 else
4086 for (i = 0; i < 4; i++)
4087 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, i));
4088 return;
4089
4090 case 2:
4091 if (bias)
4092 for (i = 0; i < 2; i++)
4093 aarch64_set_vec_u32 (cpu, vd, i + 4,
4094 aarch64_get_vec_u64 (cpu, vs, i) >> 32);
4095 else
4096 for (i = 0; i < 2; i++)
4097 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, i));
4098 return;
2e8cf49e
NC
4099 }
4100}
4101
2e8cf49e
NC
4102static void
4103do_vec_maxv (sim_cpu *cpu)
4104{
4105 /* instr[31] = 0
4106 instr[30] = half(0)/full(1)
4107 instr[29] = signed (0)/unsigned(1)
4108 instr[28,24] = 0 1110
4109 instr[23,22] = size: byte(00), half(01), word (10)
4110 instr[21] = 1
4111 instr[20,17] = 1 000
4112 instr[16] = max(0)/min(1)
4113 instr[15,10] = 1010 10
4114 instr[9,5] = V source
4115 instr[4.0] = R dest. */
4116
ef0d8ffc
NC
4117 unsigned vs = INSTR (9, 5);
4118 unsigned rd = INSTR (4, 0);
4119 unsigned full = INSTR (30, 30);
2e8cf49e
NC
4120 unsigned i;
4121
4122 NYI_assert (28, 24, 0x0E);
4123 NYI_assert (21, 21, 1);
4124 NYI_assert (20, 17, 8);
4125 NYI_assert (15, 10, 0x2A);
4126
7517e550 4127 switch ((INSTR (29, 29) << 1) | INSTR (16, 16))
2e8cf49e
NC
4128 {
4129 case 0: /* SMAXV. */
4130 {
4131 int64_t smax;
ef0d8ffc 4132 switch (INSTR (23, 22))
2e8cf49e
NC
4133 {
4134 case 0:
4135 smax = aarch64_get_vec_s8 (cpu, vs, 0);
4136 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4137 smax = max (smax, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4138 break;
4139 case 1:
4140 smax = aarch64_get_vec_s16 (cpu, vs, 0);
4141 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4142 smax = max (smax, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4143 break;
4144 case 2:
4145 smax = aarch64_get_vec_s32 (cpu, vs, 0);
4146 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4147 smax = max (smax, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4148 break;
2e8cf49e
NC
4149 case 3:
4150 HALT_UNALLOC;
4151 }
4152 aarch64_set_reg_s64 (cpu, rd, NO_SP, smax);
4153 return;
4154 }
4155
4156 case 1: /* SMINV. */
4157 {
4158 int64_t smin;
ef0d8ffc 4159 switch (INSTR (23, 22))
2e8cf49e
NC
4160 {
4161 case 0:
4162 smin = aarch64_get_vec_s8 (cpu, vs, 0);
4163 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4164 smin = min (smin, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4165 break;
4166 case 1:
4167 smin = aarch64_get_vec_s16 (cpu, vs, 0);
4168 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4169 smin = min (smin, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4170 break;
4171 case 2:
4172 smin = aarch64_get_vec_s32 (cpu, vs, 0);
4173 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4174 smin = min (smin, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e 4175 break;
5ab6d79e 4176
2e8cf49e
NC
4177 case 3:
4178 HALT_UNALLOC;
4179 }
4180 aarch64_set_reg_s64 (cpu, rd, NO_SP, smin);
4181 return;
4182 }
4183
4184 case 2: /* UMAXV. */
4185 {
4186 uint64_t umax;
ef0d8ffc 4187 switch (INSTR (23, 22))
2e8cf49e
NC
4188 {
4189 case 0:
4190 umax = aarch64_get_vec_u8 (cpu, vs, 0);
4191 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4192 umax = max (umax, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4193 break;
4194 case 1:
4195 umax = aarch64_get_vec_u16 (cpu, vs, 0);
4196 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4197 umax = max (umax, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4198 break;
4199 case 2:
4200 umax = aarch64_get_vec_u32 (cpu, vs, 0);
4201 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4202 umax = max (umax, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4203 break;
5ab6d79e 4204
2e8cf49e
NC
4205 case 3:
4206 HALT_UNALLOC;
4207 }
4208 aarch64_set_reg_u64 (cpu, rd, NO_SP, umax);
4209 return;
4210 }
4211
4212 case 3: /* UMINV. */
4213 {
4214 uint64_t umin;
ef0d8ffc 4215 switch (INSTR (23, 22))
2e8cf49e
NC
4216 {
4217 case 0:
4218 umin = aarch64_get_vec_u8 (cpu, vs, 0);
4219 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4220 umin = min (umin, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4221 break;
4222 case 1:
4223 umin = aarch64_get_vec_u16 (cpu, vs, 0);
4224 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4225 umin = min (umin, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4226 break;
4227 case 2:
4228 umin = aarch64_get_vec_u32 (cpu, vs, 0);
4229 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4230 umin = min (umin, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e 4231 break;
5ab6d79e 4232
2e8cf49e
NC
4233 case 3:
4234 HALT_UNALLOC;
4235 }
4236 aarch64_set_reg_u64 (cpu, rd, NO_SP, umin);
4237 return;
4238 }
2e8cf49e
NC
4239 }
4240}
4241
4242static void
4243do_vec_fminmaxV (sim_cpu *cpu)
4244{
4245 /* instr[31,24] = 0110 1110
4246 instr[23] = max(0)/min(1)
4247 instr[22,14] = 011 0000 11
4248 instr[13,12] = nm(00)/normal(11)
4249 instr[11,10] = 10
4250 instr[9,5] = V source
4251 instr[4.0] = R dest. */
4252
ef0d8ffc
NC
4253 unsigned vs = INSTR (9, 5);
4254 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
4255 unsigned i;
4256 float res = aarch64_get_vec_float (cpu, vs, 0);
4257
4258 NYI_assert (31, 24, 0x6E);
4259 NYI_assert (22, 14, 0x0C3);
4260 NYI_assert (11, 10, 2);
4261
ef0d8ffc 4262 if (INSTR (23, 23))
2e8cf49e 4263 {
ef0d8ffc 4264 switch (INSTR (13, 12))
2e8cf49e
NC
4265 {
4266 case 0: /* FMNINNMV. */
4267 for (i = 1; i < 4; i++)
4268 res = fminnm (res, aarch64_get_vec_float (cpu, vs, i));
4269 break;
4270
4271 case 3: /* FMINV. */
4272 for (i = 1; i < 4; i++)
bc273e17 4273 res = min (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4274 break;
4275
4276 default:
4277 HALT_NYI;
4278 }
4279 }
4280 else
4281 {
ef0d8ffc 4282 switch (INSTR (13, 12))
2e8cf49e
NC
4283 {
4284 case 0: /* FMNAXNMV. */
4285 for (i = 1; i < 4; i++)
4286 res = fmaxnm (res, aarch64_get_vec_float (cpu, vs, i));
4287 break;
4288
4289 case 3: /* FMAXV. */
4290 for (i = 1; i < 4; i++)
bc273e17 4291 res = max (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4292 break;
4293
4294 default:
4295 HALT_NYI;
4296 }
4297 }
4298
4299 aarch64_set_FP_float (cpu, rd, res);
4300}
4301
4302static void
4303do_vec_Fminmax (sim_cpu *cpu)
4304{
4305 /* instr[31] = 0
4306 instr[30] = half(0)/full(1)
4307 instr[29,24] = 00 1110
4308 instr[23] = max(0)/min(1)
4309 instr[22] = float(0)/double(1)
4310 instr[21] = 1
4311 instr[20,16] = Vm
4312 instr[15,14] = 11
4313 instr[13,12] = nm(00)/normal(11)
4314 instr[11,10] = 01
4315 instr[9,5] = Vn
4316 instr[4,0] = Vd. */
4317
ef0d8ffc
NC
4318 unsigned vm = INSTR (20, 16);
4319 unsigned vn = INSTR (9, 5);
4320 unsigned vd = INSTR (4, 0);
4321 unsigned full = INSTR (30, 30);
4322 unsigned min = INSTR (23, 23);
2e8cf49e
NC
4323 unsigned i;
4324
4325 NYI_assert (29, 24, 0x0E);
4326 NYI_assert (21, 21, 1);
4327 NYI_assert (15, 14, 3);
4328 NYI_assert (11, 10, 1);
4329
ef0d8ffc 4330 if (INSTR (22, 22))
2e8cf49e
NC
4331 {
4332 double (* func)(double, double);
4333
4334 if (! full)
4335 HALT_NYI;
4336
ef0d8ffc 4337 if (INSTR (13, 12) == 0)
2e8cf49e 4338 func = min ? dminnm : dmaxnm;
ef0d8ffc 4339 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4340 func = min ? fmin : fmax;
4341 else
4342 HALT_NYI;
4343
4344 for (i = 0; i < 2; i++)
4345 aarch64_set_vec_double (cpu, vd, i,
4346 func (aarch64_get_vec_double (cpu, vn, i),
4347 aarch64_get_vec_double (cpu, vm, i)));
4348 }
4349 else
4350 {
4351 float (* func)(float, float);
4352
ef0d8ffc 4353 if (INSTR (13, 12) == 0)
2e8cf49e 4354 func = min ? fminnm : fmaxnm;
ef0d8ffc 4355 else if (INSTR (13, 12) == 3)
2e8cf49e
NC
4356 func = min ? fminf : fmaxf;
4357 else
4358 HALT_NYI;
4359
4360 for (i = 0; i < (full ? 4 : 2); i++)
4361 aarch64_set_vec_float (cpu, vd, i,
4362 func (aarch64_get_vec_float (cpu, vn, i),
4363 aarch64_get_vec_float (cpu, vm, i)));
4364 }
4365}
4366
4367static void
4368do_vec_SCVTF (sim_cpu *cpu)
4369{
4370 /* instr[31] = 0
4371 instr[30] = Q
4372 instr[29,23] = 00 1110 0
4373 instr[22] = float(0)/double(1)
4374 instr[21,10] = 10 0001 1101 10
4375 instr[9,5] = Vn
4376 instr[4,0] = Vd. */
4377
ef0d8ffc
NC
4378 unsigned vn = INSTR (9, 5);
4379 unsigned vd = INSTR (4, 0);
4380 unsigned full = INSTR (30, 30);
4381 unsigned size = INSTR (22, 22);
2e8cf49e
NC
4382 unsigned i;
4383
4384 NYI_assert (29, 23, 0x1C);
4385 NYI_assert (21, 10, 0x876);
4386
4387 if (size)
4388 {
4389 if (! full)
4390 HALT_UNALLOC;
4391
4392 for (i = 0; i < 2; i++)
4393 {
4394 double val = (double) aarch64_get_vec_u64 (cpu, vn, i);
4395 aarch64_set_vec_double (cpu, vd, i, val);
4396 }
4397 }
4398 else
4399 {
4400 for (i = 0; i < (full ? 4 : 2); i++)
4401 {
4402 float val = (float) aarch64_get_vec_u32 (cpu, vn, i);
4403 aarch64_set_vec_float (cpu, vd, i, val);
4404 }
4405 }
4406}
4407
4408#define VEC_CMP(SOURCE, CMP) \
4409 do \
4410 { \
4411 switch (size) \
4412 { \
4413 case 0: \
4414 for (i = 0; i < (full ? 16 : 8); i++) \
4415 aarch64_set_vec_u8 (cpu, vd, i, \
4416 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4417 CMP \
4418 aarch64_get_vec_##SOURCE##8 (cpu, vm, i) \
4419 ? -1 : 0); \
4420 return; \
4421 case 1: \
4422 for (i = 0; i < (full ? 8 : 4); i++) \
4423 aarch64_set_vec_u16 (cpu, vd, i, \
4424 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4425 CMP \
4426 aarch64_get_vec_##SOURCE##16 (cpu, vm, i) \
4427 ? -1 : 0); \
4428 return; \
4429 case 2: \
4430 for (i = 0; i < (full ? 4 : 2); i++) \
4431 aarch64_set_vec_u32 (cpu, vd, i, \
4432 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4433 CMP \
4434 aarch64_get_vec_##SOURCE##32 (cpu, vm, i) \
4435 ? -1 : 0); \
4436 return; \
4437 case 3: \
4438 if (! full) \
4439 HALT_UNALLOC; \
4440 for (i = 0; i < 2; i++) \
4441 aarch64_set_vec_u64 (cpu, vd, i, \
4442 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4443 CMP \
4444 aarch64_get_vec_##SOURCE##64 (cpu, vm, i) \
4445 ? -1ULL : 0); \
4446 return; \
2e8cf49e
NC
4447 } \
4448 } \
4449 while (0)
4450
4451#define VEC_CMP0(SOURCE, CMP) \
4452 do \
4453 { \
4454 switch (size) \
4455 { \
4456 case 0: \
4457 for (i = 0; i < (full ? 16 : 8); i++) \
4458 aarch64_set_vec_u8 (cpu, vd, i, \
4459 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4460 CMP 0 ? -1 : 0); \
4461 return; \
4462 case 1: \
4463 for (i = 0; i < (full ? 8 : 4); i++) \
4464 aarch64_set_vec_u16 (cpu, vd, i, \
4465 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4466 CMP 0 ? -1 : 0); \
4467 return; \
4468 case 2: \
4469 for (i = 0; i < (full ? 4 : 2); i++) \
4470 aarch64_set_vec_u32 (cpu, vd, i, \
4471 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4472 CMP 0 ? -1 : 0); \
4473 return; \
4474 case 3: \
4475 if (! full) \
4476 HALT_UNALLOC; \
4477 for (i = 0; i < 2; i++) \
4478 aarch64_set_vec_u64 (cpu, vd, i, \
4479 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4480 CMP 0 ? -1ULL : 0); \
4481 return; \
2e8cf49e
NC
4482 } \
4483 } \
4484 while (0)
4485
4486#define VEC_FCMP0(CMP) \
4487 do \
4488 { \
4489 if (vm != 0) \
4490 HALT_NYI; \
ef0d8ffc 4491 if (INSTR (22, 22)) \
2e8cf49e
NC
4492 { \
4493 if (! full) \
4494 HALT_NYI; \
4495 for (i = 0; i < 2; i++) \
4496 aarch64_set_vec_u64 (cpu, vd, i, \
4497 aarch64_get_vec_double (cpu, vn, i) \
4498 CMP 0.0 ? -1 : 0); \
4499 } \
4500 else \
4501 { \
4502 for (i = 0; i < (full ? 4 : 2); i++) \
4503 aarch64_set_vec_u32 (cpu, vd, i, \
4504 aarch64_get_vec_float (cpu, vn, i) \
4505 CMP 0.0 ? -1 : 0); \
4506 } \
4507 return; \
4508 } \
4509 while (0)
4510
4511#define VEC_FCMP(CMP) \
4512 do \
4513 { \
ef0d8ffc 4514 if (INSTR (22, 22)) \
2e8cf49e
NC
4515 { \
4516 if (! full) \
4517 HALT_NYI; \
4518 for (i = 0; i < 2; i++) \
4519 aarch64_set_vec_u64 (cpu, vd, i, \
4520 aarch64_get_vec_double (cpu, vn, i) \
4521 CMP \
4522 aarch64_get_vec_double (cpu, vm, i) \
4523 ? -1 : 0); \
4524 } \
4525 else \
4526 { \
4527 for (i = 0; i < (full ? 4 : 2); i++) \
4528 aarch64_set_vec_u32 (cpu, vd, i, \
4529 aarch64_get_vec_float (cpu, vn, i) \
4530 CMP \
4531 aarch64_get_vec_float (cpu, vm, i) \
4532 ? -1 : 0); \
4533 } \
4534 return; \
4535 } \
4536 while (0)
4537
4538static void
4539do_vec_compare (sim_cpu *cpu)
4540{
4541 /* instr[31] = 0
4542 instr[30] = half(0)/full(1)
4543 instr[29] = part-of-comparison-type
4544 instr[28,24] = 0 1110
4545 instr[23,22] = size of integer compares: byte(00), half(01), word (10), long (11)
4546 type of float compares: single (-0) / double (-1)
4547 instr[21] = 1
4548 instr[20,16] = Vm or 00000 (compare vs 0)
4549 instr[15,10] = part-of-comparison-type
4550 instr[9,5] = Vn
4551 instr[4.0] = Vd. */
4552
ef0d8ffc
NC
4553 int full = INSTR (30, 30);
4554 int size = INSTR (23, 22);
4555 unsigned vm = INSTR (20, 16);
4556 unsigned vn = INSTR (9, 5);
4557 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
4558 unsigned i;
4559
4560 NYI_assert (28, 24, 0x0E);
4561 NYI_assert (21, 21, 1);
4562
ef0d8ffc
NC
4563 if ((INSTR (11, 11)
4564 && INSTR (14, 14))
4565 || ((INSTR (11, 11) == 0
4566 && INSTR (10, 10) == 0)))
2e8cf49e
NC
4567 {
4568 /* A compare vs 0. */
4569 if (vm != 0)
4570 {
ef0d8ffc 4571 if (INSTR (15, 10) == 0x2A)
2e8cf49e 4572 do_vec_maxv (cpu);
ef0d8ffc
NC
4573 else if (INSTR (15, 10) == 0x32
4574 || INSTR (15, 10) == 0x3E)
2e8cf49e 4575 do_vec_fminmaxV (cpu);
ef0d8ffc
NC
4576 else if (INSTR (29, 23) == 0x1C
4577 && INSTR (21, 10) == 0x876)
2e8cf49e
NC
4578 do_vec_SCVTF (cpu);
4579 else
4580 HALT_NYI;
4581 return;
4582 }
4583 }
4584
ef0d8ffc 4585 if (INSTR (14, 14))
2e8cf49e
NC
4586 {
4587 /* A floating point compare. */
7517e550 4588 unsigned decode = (INSTR (29, 29) << 5) | (INSTR (23, 23) << 4)
ef0d8ffc 4589 | INSTR (13, 10);
2e8cf49e
NC
4590
4591 NYI_assert (15, 15, 1);
4592
4593 switch (decode)
4594 {
4595 case /* 0b010010: GT#0 */ 0x12: VEC_FCMP0 (>);
4596 case /* 0b110010: GE#0 */ 0x32: VEC_FCMP0 (>=);
4597 case /* 0b010110: EQ#0 */ 0x16: VEC_FCMP0 (==);
4598 case /* 0b110110: LE#0 */ 0x36: VEC_FCMP0 (<=);
4599 case /* 0b011010: LT#0 */ 0x1A: VEC_FCMP0 (<);
4600 case /* 0b111001: GT */ 0x39: VEC_FCMP (>);
4601 case /* 0b101001: GE */ 0x29: VEC_FCMP (>=);
4602 case /* 0b001001: EQ */ 0x09: VEC_FCMP (==);
4603
4604 default:
4605 HALT_NYI;
4606 }
4607 }
4608 else
4609 {
7517e550 4610 unsigned decode = (INSTR (29, 29) << 6) | INSTR (15, 10);
2e8cf49e
NC
4611
4612 switch (decode)
4613 {
4614 case 0x0D: /* 0001101 GT */ VEC_CMP (s, > );
4615 case 0x0F: /* 0001111 GE */ VEC_CMP (s, >= );
4616 case 0x22: /* 0100010 GT #0 */ VEC_CMP0 (s, > );
4617 case 0x26: /* 0100110 EQ #0 */ VEC_CMP0 (s, == );
4618 case 0x2A: /* 0101010 LT #0 */ VEC_CMP0 (s, < );
4619 case 0x4D: /* 1001101 HI */ VEC_CMP (u, > );
4620 case 0x4F: /* 1001111 HS */ VEC_CMP (u, >= );
4621 case 0x62: /* 1100010 GE #0 */ VEC_CMP0 (s, >= );
4622 case 0x63: /* 1100011 EQ */ VEC_CMP (u, == );
4623 case 0x66: /* 1100110 LE #0 */ VEC_CMP0 (s, <= );
4624 default:
4625 if (vm == 0)
4626 HALT_NYI;
4627 do_vec_maxv (cpu);
4628 }
4629 }
4630}
4631
4632static void
4633do_vec_SSHL (sim_cpu *cpu)
4634{
4635 /* instr[31] = 0
4636 instr[30] = first part (0)/ second part (1)
4637 instr[29,24] = 00 1110
4638 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4639 instr[21] = 1
4640 instr[20,16] = Vm
4641 instr[15,10] = 0100 01
4642 instr[9,5] = Vn
4643 instr[4,0] = Vd. */
4644
ef0d8ffc
NC
4645 unsigned full = INSTR (30, 30);
4646 unsigned vm = INSTR (20, 16);
4647 unsigned vn = INSTR (9, 5);
4648 unsigned vd = INSTR (4, 0);
2e8cf49e 4649 unsigned i;
5ab6d79e 4650 signed int shift;
2e8cf49e
NC
4651
4652 NYI_assert (29, 24, 0x0E);
4653 NYI_assert (21, 21, 1);
4654 NYI_assert (15, 10, 0x11);
4655
4656 /* FIXME: What is a signed shift left in this context ?. */
4657
ef0d8ffc 4658 switch (INSTR (23, 22))
2e8cf49e
NC
4659 {
4660 case 0:
4661 for (i = 0; i < (full ? 16 : 8); i++)
5ab6d79e
NC
4662 {
4663 shift = aarch64_get_vec_s8 (cpu, vm, i);
4664 if (shift >= 0)
4665 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4666 << shift);
4667 else
4668 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4669 >> - shift);
4670 }
2e8cf49e
NC
4671 return;
4672
4673 case 1:
4674 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 4675 {
7517e550 4676 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
4677 if (shift >= 0)
4678 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4679 << shift);
4680 else
4681 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4682 >> - shift);
4683 }
2e8cf49e
NC
4684 return;
4685
4686 case 2:
4687 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 4688 {
7517e550 4689 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
4690 if (shift >= 0)
4691 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4692 << shift);
4693 else
4694 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4695 >> - shift);
4696 }
2e8cf49e
NC
4697 return;
4698
4699 case 3:
4700 if (! full)
4701 HALT_UNALLOC;
4702 for (i = 0; i < 2; i++)
5ab6d79e 4703 {
7517e550 4704 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
4705 if (shift >= 0)
4706 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4707 << shift);
4708 else
4709 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4710 >> - shift);
4711 }
2e8cf49e 4712 return;
2e8cf49e
NC
4713 }
4714}
4715
4716static void
4717do_vec_USHL (sim_cpu *cpu)
4718{
4719 /* instr[31] = 0
4720 instr[30] = first part (0)/ second part (1)
4721 instr[29,24] = 10 1110
4722 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4723 instr[21] = 1
4724 instr[20,16] = Vm
4725 instr[15,10] = 0100 01
4726 instr[9,5] = Vn
4727 instr[4,0] = Vd */
4728
ef0d8ffc
NC
4729 unsigned full = INSTR (30, 30);
4730 unsigned vm = INSTR (20, 16);
4731 unsigned vn = INSTR (9, 5);
4732 unsigned vd = INSTR (4, 0);
2e8cf49e 4733 unsigned i;
5ab6d79e 4734 signed int shift;
2e8cf49e
NC
4735
4736 NYI_assert (29, 24, 0x2E);
4737 NYI_assert (15, 10, 0x11);
4738
ef0d8ffc 4739 switch (INSTR (23, 22))
2e8cf49e
NC
4740 {
4741 case 0:
5ab6d79e
NC
4742 for (i = 0; i < (full ? 16 : 8); i++)
4743 {
4744 shift = aarch64_get_vec_s8 (cpu, vm, i);
4745 if (shift >= 0)
4746 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4747 << shift);
4748 else
4749 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4750 >> - shift);
4751 }
2e8cf49e
NC
4752 return;
4753
4754 case 1:
4755 for (i = 0; i < (full ? 8 : 4); i++)
5ab6d79e 4756 {
7517e550 4757 shift = aarch64_get_vec_s8 (cpu, vm, i * 2);
5ab6d79e
NC
4758 if (shift >= 0)
4759 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4760 << shift);
4761 else
4762 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4763 >> - shift);
4764 }
2e8cf49e
NC
4765 return;
4766
4767 case 2:
4768 for (i = 0; i < (full ? 4 : 2); i++)
5ab6d79e 4769 {
7517e550 4770 shift = aarch64_get_vec_s8 (cpu, vm, i * 4);
5ab6d79e
NC
4771 if (shift >= 0)
4772 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4773 << shift);
4774 else
4775 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4776 >> - shift);
4777 }
2e8cf49e
NC
4778 return;
4779
4780 case 3:
4781 if (! full)
4782 HALT_UNALLOC;
4783 for (i = 0; i < 2; i++)
5ab6d79e 4784 {
7517e550 4785 shift = aarch64_get_vec_s8 (cpu, vm, i * 8);
5ab6d79e
NC
4786 if (shift >= 0)
4787 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4788 << shift);
4789 else
4790 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4791 >> - shift);
4792 }
2e8cf49e 4793 return;
2e8cf49e
NC
4794 }
4795}
4796
4797static void
4798do_vec_FMLA (sim_cpu *cpu)
4799{
4800 /* instr[31] = 0
4801 instr[30] = full/half selector
4802 instr[29,23] = 0011100
4803 instr[22] = size: 0=>float, 1=>double
4804 instr[21] = 1
4805 instr[20,16] = Vn
4806 instr[15,10] = 1100 11
4807 instr[9,5] = Vm
4808 instr[4.0] = Vd. */
4809
ef0d8ffc
NC
4810 unsigned vm = INSTR (20, 16);
4811 unsigned vn = INSTR (9, 5);
4812 unsigned vd = INSTR (4, 0);
2e8cf49e 4813 unsigned i;
ef0d8ffc 4814 int full = INSTR (30, 30);
2e8cf49e
NC
4815
4816 NYI_assert (29, 23, 0x1C);
4817 NYI_assert (21, 21, 1);
4818 NYI_assert (15, 10, 0x33);
4819
ef0d8ffc 4820 if (INSTR (22, 22))
2e8cf49e
NC
4821 {
4822 if (! full)
4823 HALT_UNALLOC;
4824 for (i = 0; i < 2; i++)
4825 aarch64_set_vec_double (cpu, vd, i,
4826 aarch64_get_vec_double (cpu, vn, i) *
4827 aarch64_get_vec_double (cpu, vm, i) +
4828 aarch64_get_vec_double (cpu, vd, i));
4829 }
4830 else
4831 {
4832 for (i = 0; i < (full ? 4 : 2); i++)
4833 aarch64_set_vec_float (cpu, vd, i,
4834 aarch64_get_vec_float (cpu, vn, i) *
4835 aarch64_get_vec_float (cpu, vm, i) +
4836 aarch64_get_vec_float (cpu, vd, i));
4837 }
4838}
4839
4840static void
4841do_vec_max (sim_cpu *cpu)
4842{
4843 /* instr[31] = 0
4844 instr[30] = full/half selector
4845 instr[29] = SMAX (0) / UMAX (1)
4846 instr[28,24] = 0 1110
4847 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4848 instr[21] = 1
4849 instr[20,16] = Vn
4850 instr[15,10] = 0110 01
4851 instr[9,5] = Vm
4852 instr[4.0] = Vd. */
4853
ef0d8ffc
NC
4854 unsigned vm = INSTR (20, 16);
4855 unsigned vn = INSTR (9, 5);
4856 unsigned vd = INSTR (4, 0);
2e8cf49e 4857 unsigned i;
ef0d8ffc 4858 int full = INSTR (30, 30);
2e8cf49e
NC
4859
4860 NYI_assert (28, 24, 0x0E);
4861 NYI_assert (21, 21, 1);
4862 NYI_assert (15, 10, 0x19);
4863
ef0d8ffc 4864 if (INSTR (29, 29))
2e8cf49e 4865 {
ef0d8ffc 4866 switch (INSTR (23, 22))
2e8cf49e
NC
4867 {
4868 case 0:
4869 for (i = 0; i < (full ? 16 : 8); i++)
4870 aarch64_set_vec_u8 (cpu, vd, i,
4871 aarch64_get_vec_u8 (cpu, vn, i)
4872 > aarch64_get_vec_u8 (cpu, vm, i)
4873 ? aarch64_get_vec_u8 (cpu, vn, i)
4874 : aarch64_get_vec_u8 (cpu, vm, i));
4875 return;
4876
4877 case 1:
4878 for (i = 0; i < (full ? 8 : 4); i++)
4879 aarch64_set_vec_u16 (cpu, vd, i,
4880 aarch64_get_vec_u16 (cpu, vn, i)
4881 > aarch64_get_vec_u16 (cpu, vm, i)
4882 ? aarch64_get_vec_u16 (cpu, vn, i)
4883 : aarch64_get_vec_u16 (cpu, vm, i));
4884 return;
4885
4886 case 2:
4887 for (i = 0; i < (full ? 4 : 2); i++)
4888 aarch64_set_vec_u32 (cpu, vd, i,
4889 aarch64_get_vec_u32 (cpu, vn, i)
4890 > aarch64_get_vec_u32 (cpu, vm, i)
4891 ? aarch64_get_vec_u32 (cpu, vn, i)
4892 : aarch64_get_vec_u32 (cpu, vm, i));
4893 return;
4894
2e8cf49e
NC
4895 case 3:
4896 HALT_UNALLOC;
4897 }
4898 }
4899 else
4900 {
ef0d8ffc 4901 switch (INSTR (23, 22))
2e8cf49e
NC
4902 {
4903 case 0:
4904 for (i = 0; i < (full ? 16 : 8); i++)
4905 aarch64_set_vec_s8 (cpu, vd, i,
4906 aarch64_get_vec_s8 (cpu, vn, i)
4907 > aarch64_get_vec_s8 (cpu, vm, i)
4908 ? aarch64_get_vec_s8 (cpu, vn, i)
4909 : aarch64_get_vec_s8 (cpu, vm, i));
4910 return;
4911
4912 case 1:
4913 for (i = 0; i < (full ? 8 : 4); i++)
4914 aarch64_set_vec_s16 (cpu, vd, i,
4915 aarch64_get_vec_s16 (cpu, vn, i)
4916 > aarch64_get_vec_s16 (cpu, vm, i)
4917 ? aarch64_get_vec_s16 (cpu, vn, i)
4918 : aarch64_get_vec_s16 (cpu, vm, i));
4919 return;
4920
4921 case 2:
4922 for (i = 0; i < (full ? 4 : 2); i++)
4923 aarch64_set_vec_s32 (cpu, vd, i,
4924 aarch64_get_vec_s32 (cpu, vn, i)
4925 > aarch64_get_vec_s32 (cpu, vm, i)
4926 ? aarch64_get_vec_s32 (cpu, vn, i)
4927 : aarch64_get_vec_s32 (cpu, vm, i));
4928 return;
4929
2e8cf49e
NC
4930 case 3:
4931 HALT_UNALLOC;
4932 }
4933 }
4934}
4935
4936static void
4937do_vec_min (sim_cpu *cpu)
4938{
4939 /* instr[31] = 0
4940 instr[30] = full/half selector
4941 instr[29] = SMIN (0) / UMIN (1)
4942 instr[28,24] = 0 1110
4943 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4944 instr[21] = 1
4945 instr[20,16] = Vn
4946 instr[15,10] = 0110 11
4947 instr[9,5] = Vm
4948 instr[4.0] = Vd. */
4949
ef0d8ffc
NC
4950 unsigned vm = INSTR (20, 16);
4951 unsigned vn = INSTR (9, 5);
4952 unsigned vd = INSTR (4, 0);
2e8cf49e 4953 unsigned i;
ef0d8ffc 4954 int full = INSTR (30, 30);
2e8cf49e
NC
4955
4956 NYI_assert (28, 24, 0x0E);
4957 NYI_assert (21, 21, 1);
4958 NYI_assert (15, 10, 0x1B);
4959
ef0d8ffc 4960 if (INSTR (29, 29))
2e8cf49e 4961 {
ef0d8ffc 4962 switch (INSTR (23, 22))
2e8cf49e
NC
4963 {
4964 case 0:
4965 for (i = 0; i < (full ? 16 : 8); i++)
4966 aarch64_set_vec_u8 (cpu, vd, i,
4967 aarch64_get_vec_u8 (cpu, vn, i)
4968 < aarch64_get_vec_u8 (cpu, vm, i)
4969 ? aarch64_get_vec_u8 (cpu, vn, i)
4970 : aarch64_get_vec_u8 (cpu, vm, i));
4971 return;
4972
4973 case 1:
4974 for (i = 0; i < (full ? 8 : 4); i++)
4975 aarch64_set_vec_u16 (cpu, vd, i,
4976 aarch64_get_vec_u16 (cpu, vn, i)
4977 < aarch64_get_vec_u16 (cpu, vm, i)
4978 ? aarch64_get_vec_u16 (cpu, vn, i)
4979 : aarch64_get_vec_u16 (cpu, vm, i));
4980 return;
4981
4982 case 2:
4983 for (i = 0; i < (full ? 4 : 2); i++)
4984 aarch64_set_vec_u32 (cpu, vd, i,
4985 aarch64_get_vec_u32 (cpu, vn, i)
4986 < aarch64_get_vec_u32 (cpu, vm, i)
4987 ? aarch64_get_vec_u32 (cpu, vn, i)
4988 : aarch64_get_vec_u32 (cpu, vm, i));
4989 return;
4990
2e8cf49e
NC
4991 case 3:
4992 HALT_UNALLOC;
4993 }
4994 }
4995 else
4996 {
ef0d8ffc 4997 switch (INSTR (23, 22))
2e8cf49e
NC
4998 {
4999 case 0:
5000 for (i = 0; i < (full ? 16 : 8); i++)
5001 aarch64_set_vec_s8 (cpu, vd, i,
5002 aarch64_get_vec_s8 (cpu, vn, i)
5003 < aarch64_get_vec_s8 (cpu, vm, i)
5004 ? aarch64_get_vec_s8 (cpu, vn, i)
5005 : aarch64_get_vec_s8 (cpu, vm, i));
5006 return;
5007
5008 case 1:
5009 for (i = 0; i < (full ? 8 : 4); i++)
5010 aarch64_set_vec_s16 (cpu, vd, i,
5011 aarch64_get_vec_s16 (cpu, vn, i)
5012 < aarch64_get_vec_s16 (cpu, vm, i)
5013 ? aarch64_get_vec_s16 (cpu, vn, i)
5014 : aarch64_get_vec_s16 (cpu, vm, i));
5015 return;
5016
5017 case 2:
5018 for (i = 0; i < (full ? 4 : 2); i++)
5019 aarch64_set_vec_s32 (cpu, vd, i,
5020 aarch64_get_vec_s32 (cpu, vn, i)
5021 < aarch64_get_vec_s32 (cpu, vm, i)
5022 ? aarch64_get_vec_s32 (cpu, vn, i)
5023 : aarch64_get_vec_s32 (cpu, vm, i));
5024 return;
5025
2e8cf49e
NC
5026 case 3:
5027 HALT_UNALLOC;
5028 }
5029 }
5030}
5031
5032static void
5033do_vec_sub_long (sim_cpu *cpu)
5034{
5035 /* instr[31] = 0
5036 instr[30] = lower (0) / upper (1)
5037 instr[29] = signed (0) / unsigned (1)
5038 instr[28,24] = 0 1110
5039 instr[23,22] = size: bytes (00), half (01), word (10)
5040 instr[21] = 1
5041 insrt[20,16] = Vm
5042 instr[15,10] = 0010 00
5043 instr[9,5] = Vn
5044 instr[4,0] = V dest. */
5045
ef0d8ffc
NC
5046 unsigned size = INSTR (23, 22);
5047 unsigned vm = INSTR (20, 16);
5048 unsigned vn = INSTR (9, 5);
5049 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5050 unsigned bias = 0;
5051 unsigned i;
5052
5053 NYI_assert (28, 24, 0x0E);
5054 NYI_assert (21, 21, 1);
5055 NYI_assert (15, 10, 0x08);
5056
5057 if (size == 3)
5058 HALT_UNALLOC;
5059
ef0d8ffc 5060 switch (INSTR (30, 29))
2e8cf49e
NC
5061 {
5062 case 2: /* SSUBL2. */
5063 bias = 2;
5064 case 0: /* SSUBL. */
5065 switch (size)
5066 {
5067 case 0:
5068 bias *= 3;
5069 for (i = 0; i < 8; i++)
5070 aarch64_set_vec_s16 (cpu, vd, i,
5071 aarch64_get_vec_s8 (cpu, vn, i + bias)
5072 - aarch64_get_vec_s8 (cpu, vm, i + bias));
5073 break;
5074
5075 case 1:
5076 bias *= 2;
5077 for (i = 0; i < 4; i++)
5078 aarch64_set_vec_s32 (cpu, vd, i,
5079 aarch64_get_vec_s16 (cpu, vn, i + bias)
5080 - aarch64_get_vec_s16 (cpu, vm, i + bias));
5081 break;
5082
5083 case 2:
5084 for (i = 0; i < 2; i++)
5085 aarch64_set_vec_s64 (cpu, vd, i,
5086 aarch64_get_vec_s32 (cpu, vn, i + bias)
5087 - aarch64_get_vec_s32 (cpu, vm, i + bias));
5088 break;
5089
5090 default:
5091 HALT_UNALLOC;
5092 }
5093 break;
5094
5095 case 3: /* USUBL2. */
5096 bias = 2;
5097 case 1: /* USUBL. */
5098 switch (size)
5099 {
5100 case 0:
5101 bias *= 3;
5102 for (i = 0; i < 8; i++)
5103 aarch64_set_vec_u16 (cpu, vd, i,
5104 aarch64_get_vec_u8 (cpu, vn, i + bias)
5105 - aarch64_get_vec_u8 (cpu, vm, i + bias));
5106 break;
5107
5108 case 1:
5109 bias *= 2;
5110 for (i = 0; i < 4; i++)
5111 aarch64_set_vec_u32 (cpu, vd, i,
5112 aarch64_get_vec_u16 (cpu, vn, i + bias)
5113 - aarch64_get_vec_u16 (cpu, vm, i + bias));
5114 break;
5115
5116 case 2:
5117 for (i = 0; i < 2; i++)
5118 aarch64_set_vec_u64 (cpu, vd, i,
5119 aarch64_get_vec_u32 (cpu, vn, i + bias)
5120 - aarch64_get_vec_u32 (cpu, vm, i + bias));
5121 break;
5122
5123 default:
5124 HALT_UNALLOC;
5125 }
5126 break;
5127 }
5128}
5129
2e8cf49e
NC
5130static void
5131do_vec_ADDP (sim_cpu *cpu)
5132{
5133 /* instr[31] = 0
5134 instr[30] = half(0)/full(1)
5135 instr[29,24] = 00 1110
5136 instr[23,22] = size: bytes (00), half (01), word (10), long (11)
5137 instr[21] = 1
5138 insrt[20,16] = Vm
5139 instr[15,10] = 1011 11
5140 instr[9,5] = Vn
5141 instr[4,0] = V dest. */
5142
57aa1742
NC
5143 FRegister copy_vn;
5144 FRegister copy_vm;
ef0d8ffc
NC
5145 unsigned full = INSTR (30, 30);
5146 unsigned size = INSTR (23, 22);
5147 unsigned vm = INSTR (20, 16);
5148 unsigned vn = INSTR (9, 5);
5149 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5150 unsigned i, range;
5151
5152 NYI_assert (29, 24, 0x0E);
5153 NYI_assert (21, 21, 1);
5154 NYI_assert (15, 10, 0x2F);
5155
57aa1742
NC
5156 /* Make copies of the source registers in case vd == vn/vm. */
5157 copy_vn = cpu->fr[vn];
5158 copy_vm = cpu->fr[vm];
5159
2e8cf49e
NC
5160 switch (size)
5161 {
5162 case 0:
5163 range = full ? 8 : 4;
57aa1742
NC
5164 for (i = 0; i < range; i++)
5165 {
5166 aarch64_set_vec_u8 (cpu, vd, i,
5167 copy_vn.b[i * 2] + copy_vn.b[i * 2 + 1]);
5168 aarch64_set_vec_u8 (cpu, vd, i + range,
5169 copy_vm.b[i * 2] + copy_vm.b[i * 2 + 1]);
5170 }
2e8cf49e
NC
5171 return;
5172
5173 case 1:
5174 range = full ? 4 : 2;
57aa1742
NC
5175 for (i = 0; i < range; i++)
5176 {
5177 aarch64_set_vec_u16 (cpu, vd, i,
5178 copy_vn.h[i * 2] + copy_vn.h[i * 2 + 1]);
5179 aarch64_set_vec_u16 (cpu, vd, i + range,
5180 copy_vm.h[i * 2] + copy_vm.h[i * 2 + 1]);
5181 }
2e8cf49e
NC
5182 return;
5183
5184 case 2:
5185 range = full ? 2 : 1;
57aa1742
NC
5186 for (i = 0; i < range; i++)
5187 {
5188 aarch64_set_vec_u32 (cpu, vd, i,
5189 copy_vn.w[i * 2] + copy_vn.w[i * 2 + 1]);
5190 aarch64_set_vec_u32 (cpu, vd, i + range,
5191 copy_vm.w[i * 2] + copy_vm.w[i * 2 + 1]);
5192 }
2e8cf49e
NC
5193 return;
5194
5195 case 3:
5196 if (! full)
5197 HALT_UNALLOC;
57aa1742
NC
5198 aarch64_set_vec_u64 (cpu, vd, 0, copy_vn.v[0] + copy_vn.v[1]);
5199 aarch64_set_vec_u64 (cpu, vd, 1, copy_vm.v[0] + copy_vm.v[1]);
2e8cf49e 5200 return;
2e8cf49e
NC
5201 }
5202}
5203
5204static void
5205do_vec_UMOV (sim_cpu *cpu)
5206{
5207 /* instr[31] = 0
5208 instr[30] = 32-bit(0)/64-bit(1)
5209 instr[29,21] = 00 1110 000
5210 insrt[20,16] = size & index
5211 instr[15,10] = 0011 11
5212 instr[9,5] = V source
5213 instr[4,0] = R dest. */
5214
ef0d8ffc
NC
5215 unsigned vs = INSTR (9, 5);
5216 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
5217 unsigned index;
5218
5219 NYI_assert (29, 21, 0x070);
5220 NYI_assert (15, 10, 0x0F);
5221
ef0d8ffc 5222 if (INSTR (16, 16))
2e8cf49e
NC
5223 {
5224 /* Byte transfer. */
ef0d8ffc 5225 index = INSTR (20, 17);
2e8cf49e
NC
5226 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5227 aarch64_get_vec_u8 (cpu, vs, index));
5228 }
ef0d8ffc 5229 else if (INSTR (17, 17))
2e8cf49e 5230 {
ef0d8ffc 5231 index = INSTR (20, 18);
2e8cf49e
NC
5232 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5233 aarch64_get_vec_u16 (cpu, vs, index));
5234 }
ef0d8ffc 5235 else if (INSTR (18, 18))
2e8cf49e 5236 {
ef0d8ffc 5237 index = INSTR (20, 19);
2e8cf49e
NC
5238 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5239 aarch64_get_vec_u32 (cpu, vs, index));
5240 }
5241 else
5242 {
ef0d8ffc 5243 if (INSTR (30, 30) != 1)
2e8cf49e
NC
5244 HALT_UNALLOC;
5245
ef0d8ffc 5246 index = INSTR (20, 20);
2e8cf49e
NC
5247 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5248 aarch64_get_vec_u64 (cpu, vs, index));
5249 }
5250}
5251
5252static void
5253do_vec_FABS (sim_cpu *cpu)
5254{
5255 /* instr[31] = 0
5256 instr[30] = half(0)/full(1)
5257 instr[29,23] = 00 1110 1
5258 instr[22] = float(0)/double(1)
5259 instr[21,16] = 10 0000
5260 instr[15,10] = 1111 10
5261 instr[9,5] = Vn
5262 instr[4,0] = Vd. */
5263
ef0d8ffc
NC
5264 unsigned vn = INSTR (9, 5);
5265 unsigned vd = INSTR (4, 0);
5266 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5267 unsigned i;
5268
5269 NYI_assert (29, 23, 0x1D);
5270 NYI_assert (21, 10, 0x83E);
5271
ef0d8ffc 5272 if (INSTR (22, 22))
2e8cf49e
NC
5273 {
5274 if (! full)
5275 HALT_NYI;
5276
5277 for (i = 0; i < 2; i++)
5278 aarch64_set_vec_double (cpu, vd, i,
5279 fabs (aarch64_get_vec_double (cpu, vn, i)));
5280 }
5281 else
5282 {
5283 for (i = 0; i < (full ? 4 : 2); i++)
5284 aarch64_set_vec_float (cpu, vd, i,
5285 fabsf (aarch64_get_vec_float (cpu, vn, i)));
5286 }
5287}
5288
5289static void
5290do_vec_FCVTZS (sim_cpu *cpu)
5291{
5292 /* instr[31] = 0
5293 instr[30] = half (0) / all (1)
5294 instr[29,23] = 00 1110 1
5295 instr[22] = single (0) / double (1)
5296 instr[21,10] = 10 0001 1011 10
5297 instr[9,5] = Rn
5298 instr[4,0] = Rd. */
5299
ef0d8ffc
NC
5300 unsigned rn = INSTR (9, 5);
5301 unsigned rd = INSTR (4, 0);
5302 unsigned full = INSTR (30, 30);
2e8cf49e
NC
5303 unsigned i;
5304
5305 NYI_assert (31, 31, 0);
5306 NYI_assert (29, 23, 0x1D);
5307 NYI_assert (21, 10, 0x86E);
5308
ef0d8ffc 5309 if (INSTR (22, 22))
2e8cf49e
NC
5310 {
5311 if (! full)
5312 HALT_UNALLOC;
5313
5314 for (i = 0; i < 2; i++)
5315 aarch64_set_vec_s64 (cpu, rd, i,
5316 (int64_t) aarch64_get_vec_double (cpu, rn, i));
5317 }
5318 else
5319 for (i = 0; i < (full ? 4 : 2); i++)
5320 aarch64_set_vec_s32 (cpu, rd, i,
5321 (int32_t) aarch64_get_vec_float (cpu, rn, i));
5322}
5323
67f101ee
NC
5324static void
5325do_vec_REV64 (sim_cpu *cpu)
5326{
5327 /* instr[31] = 0
5328 instr[30] = full/half
5329 instr[29,24] = 00 1110
5330 instr[23,22] = size
5331 instr[21,10] = 10 0000 0000 10
5332 instr[9,5] = Rn
5333 instr[4,0] = Rd. */
5334
5335 unsigned rn = INSTR (9, 5);
5336 unsigned rd = INSTR (4, 0);
5337 unsigned size = INSTR (23, 22);
5338 unsigned full = INSTR (30, 30);
5339 unsigned i;
5340 FRegister val;
5341
5342 NYI_assert (29, 24, 0x0E);
5343 NYI_assert (21, 10, 0x802);
5344
5345 switch (size)
5346 {
5347 case 0:
5348 for (i = 0; i < (full ? 16 : 8); i++)
5349 val.b[i ^ 0x7] = aarch64_get_vec_u8 (cpu, rn, i);
5350 break;
5351
5352 case 1:
5353 for (i = 0; i < (full ? 8 : 4); i++)
5354 val.h[i ^ 0x3] = aarch64_get_vec_u16 (cpu, rn, i);
5355 break;
5356
5357 case 2:
5358 for (i = 0; i < (full ? 4 : 2); i++)
5359 val.w[i ^ 0x1] = aarch64_get_vec_u32 (cpu, rn, i);
5360 break;
5361
5362 case 3:
5363 HALT_UNALLOC;
5364 }
5365
5366 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5367 if (full)
5368 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5369}
5370
5371static void
5372do_vec_REV16 (sim_cpu *cpu)
5373{
5374 /* instr[31] = 0
5375 instr[30] = full/half
5376 instr[29,24] = 00 1110
5377 instr[23,22] = size
5378 instr[21,10] = 10 0000 0001 10
5379 instr[9,5] = Rn
5380 instr[4,0] = Rd. */
5381
5382 unsigned rn = INSTR (9, 5);
5383 unsigned rd = INSTR (4, 0);
5384 unsigned size = INSTR (23, 22);
5385 unsigned full = INSTR (30, 30);
5386 unsigned i;
5387 FRegister val;
5388
5389 NYI_assert (29, 24, 0x0E);
5390 NYI_assert (21, 10, 0x806);
5391
5392 switch (size)
5393 {
5394 case 0:
5395 for (i = 0; i < (full ? 16 : 8); i++)
5396 val.b[i ^ 0x1] = aarch64_get_vec_u8 (cpu, rn, i);
5397 break;
5398
5399 default:
5400 HALT_UNALLOC;
5401 }
5402
5403 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
5404 if (full)
5405 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
5406}
5407
2e8cf49e
NC
5408static void
5409do_vec_op1 (sim_cpu *cpu)
5410{
5411 /* instr[31] = 0
5412 instr[30] = half/full
5413 instr[29,24] = 00 1110
5414 instr[23,21] = ???
5415 instr[20,16] = Vm
5416 instr[15,10] = sub-opcode
5417 instr[9,5] = Vn
5418 instr[4,0] = Vd */
5419 NYI_assert (29, 24, 0x0E);
5420
ef0d8ffc 5421 if (INSTR (21, 21) == 0)
2e8cf49e 5422 {
ef0d8ffc 5423 if (INSTR (23, 22) == 0)
2e8cf49e 5424 {
ef0d8ffc
NC
5425 if (INSTR (30, 30) == 1
5426 && INSTR (17, 14) == 0
5427 && INSTR (12, 10) == 7)
2e8cf49e
NC
5428 return do_vec_ins_2 (cpu);
5429
ef0d8ffc 5430 switch (INSTR (15, 10))
2e8cf49e
NC
5431 {
5432 case 0x01: do_vec_DUP_vector_into_vector (cpu); return;
5433 case 0x03: do_vec_DUP_scalar_into_vector (cpu); return;
5434 case 0x07: do_vec_INS (cpu); return;
5435 case 0x0A: do_vec_TRN (cpu); return;
5436
5437 case 0x0F:
ef0d8ffc 5438 if (INSTR (17, 16) == 0)
2e8cf49e
NC
5439 {
5440 do_vec_MOV_into_scalar (cpu);
5441 return;
5442 }
5443 break;
5444
5445 case 0x00:
5446 case 0x08:
5447 case 0x10:
5448 case 0x18:
5449 do_vec_TBL (cpu); return;
5450
5451 case 0x06:
5452 case 0x16:
5453 do_vec_UZP (cpu); return;
5454
5455 case 0x0E:
5456 case 0x1E:
5457 do_vec_ZIP (cpu); return;
5458
5459 default:
5460 HALT_NYI;
5461 }
5462 }
5463
ef0d8ffc 5464 switch (INSTR (13, 10))
2e8cf49e
NC
5465 {
5466 case 0x6: do_vec_UZP (cpu); return;
5467 case 0xE: do_vec_ZIP (cpu); return;
5468 case 0xA: do_vec_TRN (cpu); return;
5469 case 0xF: do_vec_UMOV (cpu); return;
5470 default: HALT_NYI;
5471 }
5472 }
5473
ef0d8ffc 5474 switch (INSTR (15, 10))
2e8cf49e 5475 {
67f101ee
NC
5476 case 0x02: do_vec_REV64 (cpu); return;
5477 case 0x06: do_vec_REV16 (cpu); return;
5478
2e8cf49e 5479 case 0x07:
ef0d8ffc 5480 switch (INSTR (23, 21))
2e8cf49e
NC
5481 {
5482 case 1: do_vec_AND (cpu); return;
5483 case 3: do_vec_BIC (cpu); return;
5484 case 5: do_vec_ORR (cpu); return;
5485 case 7: do_vec_ORN (cpu); return;
5486 default: HALT_NYI;
5487 }
5488
5489 case 0x08: do_vec_sub_long (cpu); return;
5490 case 0x0a: do_vec_XTN (cpu); return;
5491 case 0x11: do_vec_SSHL (cpu); return;
5492 case 0x19: do_vec_max (cpu); return;
5493 case 0x1B: do_vec_min (cpu); return;
5494 case 0x21: do_vec_add (cpu); return;
5495 case 0x25: do_vec_MLA (cpu); return;
5496 case 0x27: do_vec_mul (cpu); return;
5497 case 0x2F: do_vec_ADDP (cpu); return;
5498 case 0x30: do_vec_mull (cpu); return;
5499 case 0x33: do_vec_FMLA (cpu); return;
5500 case 0x35: do_vec_fadd (cpu); return;
5501
5502 case 0x2E:
ef0d8ffc 5503 switch (INSTR (20, 16))
2e8cf49e
NC
5504 {
5505 case 0x00: do_vec_ABS (cpu); return;
5506 case 0x01: do_vec_FCVTZS (cpu); return;
5507 case 0x11: do_vec_ADDV (cpu); return;
5508 default: HALT_NYI;
5509 }
5510
5511 case 0x31:
5512 case 0x3B:
5513 do_vec_Fminmax (cpu); return;
5514
5515 case 0x0D:
5516 case 0x0F:
5517 case 0x22:
5518 case 0x23:
5519 case 0x26:
5520 case 0x2A:
5521 case 0x32:
5522 case 0x36:
5523 case 0x39:
5524 case 0x3A:
5525 do_vec_compare (cpu); return;
5526
5527 case 0x3E:
5528 do_vec_FABS (cpu); return;
5529
5530 default:
5531 HALT_NYI;
5532 }
5533}
5534
5535static void
5536do_vec_xtl (sim_cpu *cpu)
5537{
5538 /* instr[31] = 0
5539 instr[30,29] = SXTL (00), UXTL (01), SXTL2 (10), UXTL2 (11)
5540 instr[28,22] = 0 1111 00
5541 instr[21,16] = size & shift (USHLL, SSHLL, USHLL2, SSHLL2)
5542 instr[15,10] = 1010 01
5543 instr[9,5] = V source
5544 instr[4,0] = V dest. */
5545
ef0d8ffc
NC
5546 unsigned vs = INSTR (9, 5);
5547 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5548 unsigned i, shift, bias = 0;
5549
5550 NYI_assert (28, 22, 0x3C);
5551 NYI_assert (15, 10, 0x29);
5552
ef0d8ffc 5553 switch (INSTR (30, 29))
2e8cf49e
NC
5554 {
5555 case 2: /* SXTL2, SSHLL2. */
5556 bias = 2;
5557 case 0: /* SXTL, SSHLL. */
ef0d8ffc 5558 if (INSTR (21, 21))
2e8cf49e 5559 {
7517e550
NC
5560 int64_t val1, val2;
5561
ef0d8ffc 5562 shift = INSTR (20, 16);
7517e550
NC
5563 /* Get the source values before setting the destination values
5564 in case the source and destination are the same. */
5565 val1 = aarch64_get_vec_s32 (cpu, vs, bias) << shift;
5566 val2 = aarch64_get_vec_s32 (cpu, vs, bias + 1) << shift;
5567 aarch64_set_vec_s64 (cpu, vd, 0, val1);
5568 aarch64_set_vec_s64 (cpu, vd, 1, val2);
2e8cf49e 5569 }
ef0d8ffc 5570 else if (INSTR (20, 20))
2e8cf49e 5571 {
7517e550
NC
5572 int32_t v[4];
5573 int32_t v1,v2,v3,v4;
5574
ef0d8ffc 5575 shift = INSTR (19, 16);
2e8cf49e
NC
5576 bias *= 2;
5577 for (i = 0; i < 4; i++)
7517e550
NC
5578 v[i] = aarch64_get_vec_s16 (cpu, vs, bias + i) << shift;
5579 for (i = 0; i < 4; i++)
5580 aarch64_set_vec_s32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5581 }
5582 else
5583 {
7517e550 5584 int16_t v[8];
2e8cf49e
NC
5585 NYI_assert (19, 19, 1);
5586
ef0d8ffc 5587 shift = INSTR (18, 16);
2e8cf49e
NC
5588 bias *= 3;
5589 for (i = 0; i < 8; i++)
7517e550
NC
5590 v[i] = aarch64_get_vec_s8 (cpu, vs, i + bias) << shift;
5591 for (i = 0; i < 8; i++)
5592 aarch64_set_vec_s16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5593 }
5594 return;
5595
5596 case 3: /* UXTL2, USHLL2. */
5597 bias = 2;
5598 case 1: /* UXTL, USHLL. */
ef0d8ffc 5599 if (INSTR (21, 21))
2e8cf49e 5600 {
7517e550 5601 uint64_t v1, v2;
ef0d8ffc 5602 shift = INSTR (20, 16);
7517e550
NC
5603 v1 = aarch64_get_vec_u32 (cpu, vs, bias) << shift;
5604 v2 = aarch64_get_vec_u32 (cpu, vs, bias + 1) << shift;
5605 aarch64_set_vec_u64 (cpu, vd, 0, v1);
5606 aarch64_set_vec_u64 (cpu, vd, 1, v2);
2e8cf49e 5607 }
ef0d8ffc 5608 else if (INSTR (20, 20))
2e8cf49e 5609 {
7517e550 5610 uint32_t v[4];
ef0d8ffc 5611 shift = INSTR (19, 16);
2e8cf49e
NC
5612 bias *= 2;
5613 for (i = 0; i < 4; i++)
7517e550
NC
5614 v[i] = aarch64_get_vec_u16 (cpu, vs, i + bias) << shift;
5615 for (i = 0; i < 4; i++)
5616 aarch64_set_vec_u32 (cpu, vd, i, v[i]);
2e8cf49e
NC
5617 }
5618 else
5619 {
7517e550 5620 uint16_t v[8];
2e8cf49e
NC
5621 NYI_assert (19, 19, 1);
5622
ef0d8ffc 5623 shift = INSTR (18, 16);
2e8cf49e
NC
5624 bias *= 3;
5625 for (i = 0; i < 8; i++)
7517e550
NC
5626 v[i] = aarch64_get_vec_u8 (cpu, vs, i + bias) << shift;
5627 for (i = 0; i < 8; i++)
5628 aarch64_set_vec_u16 (cpu, vd, i, v[i]);
2e8cf49e
NC
5629 }
5630 return;
2e8cf49e
NC
5631 }
5632}
5633
5634static void
5635do_vec_SHL (sim_cpu *cpu)
5636{
5637 /* instr [31] = 0
5638 instr [30] = half(0)/full(1)
5639 instr [29,23] = 001 1110
5640 instr [22,16] = size and shift amount
5641 instr [15,10] = 01 0101
5642 instr [9, 5] = Vs
5643 instr [4, 0] = Vd. */
5644
5645 int shift;
ef0d8ffc
NC
5646 int full = INSTR (30, 30);
5647 unsigned vs = INSTR (9, 5);
5648 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5649 unsigned i;
5650
5651 NYI_assert (29, 23, 0x1E);
5652 NYI_assert (15, 10, 0x15);
5653
ef0d8ffc 5654 if (INSTR (22, 22))
2e8cf49e 5655 {
ef0d8ffc 5656 shift = INSTR (21, 16);
2e8cf49e
NC
5657
5658 if (full == 0)
5659 HALT_UNALLOC;
5660
5661 for (i = 0; i < 2; i++)
5662 {
5663 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5664 aarch64_set_vec_u64 (cpu, vd, i, val << shift);
5665 }
5666
5667 return;
5668 }
5669
ef0d8ffc 5670 if (INSTR (21, 21))
2e8cf49e 5671 {
ef0d8ffc 5672 shift = INSTR (20, 16);
2e8cf49e
NC
5673
5674 for (i = 0; i < (full ? 4 : 2); i++)
5675 {
5676 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5677 aarch64_set_vec_u32 (cpu, vd, i, val << shift);
5678 }
5679
5680 return;
5681 }
5682
ef0d8ffc 5683 if (INSTR (20, 20))
2e8cf49e 5684 {
ef0d8ffc 5685 shift = INSTR (19, 16);
2e8cf49e
NC
5686
5687 for (i = 0; i < (full ? 8 : 4); i++)
5688 {
5689 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5690 aarch64_set_vec_u16 (cpu, vd, i, val << shift);
5691 }
5692
5693 return;
5694 }
5695
ef0d8ffc 5696 if (INSTR (19, 19) == 0)
2e8cf49e
NC
5697 HALT_UNALLOC;
5698
ef0d8ffc 5699 shift = INSTR (18, 16);
2e8cf49e
NC
5700
5701 for (i = 0; i < (full ? 16 : 8); i++)
5702 {
5703 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5704 aarch64_set_vec_u8 (cpu, vd, i, val << shift);
5705 }
5706}
5707
5708static void
5709do_vec_SSHR_USHR (sim_cpu *cpu)
5710{
5711 /* instr [31] = 0
5712 instr [30] = half(0)/full(1)
5713 instr [29] = signed(0)/unsigned(1)
5ab6d79e 5714 instr [28,23] = 0 1111 0
2e8cf49e
NC
5715 instr [22,16] = size and shift amount
5716 instr [15,10] = 0000 01
5717 instr [9, 5] = Vs
5718 instr [4, 0] = Vd. */
5719
5ab6d79e
NC
5720 int full = INSTR (30, 30);
5721 int sign = ! INSTR (29, 29);
5722 unsigned shift = INSTR (22, 16);
5723 unsigned vs = INSTR (9, 5);
5724 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5725 unsigned i;
5726
5727 NYI_assert (28, 23, 0x1E);
5728 NYI_assert (15, 10, 0x01);
5729
ef0d8ffc 5730 if (INSTR (22, 22))
2e8cf49e 5731 {
5ab6d79e 5732 shift = 128 - shift;
2e8cf49e
NC
5733
5734 if (full == 0)
5735 HALT_UNALLOC;
5736
5737 if (sign)
5738 for (i = 0; i < 2; i++)
5739 {
5740 int64_t val = aarch64_get_vec_s64 (cpu, vs, i);
5741 aarch64_set_vec_s64 (cpu, vd, i, val >> shift);
5742 }
5743 else
5744 for (i = 0; i < 2; i++)
5745 {
5746 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5747 aarch64_set_vec_u64 (cpu, vd, i, val >> shift);
5748 }
5749
5750 return;
5751 }
5752
ef0d8ffc 5753 if (INSTR (21, 21))
2e8cf49e 5754 {
5ab6d79e 5755 shift = 64 - shift;
2e8cf49e
NC
5756
5757 if (sign)
5758 for (i = 0; i < (full ? 4 : 2); i++)
5759 {
5760 int32_t val = aarch64_get_vec_s32 (cpu, vs, i);
5761 aarch64_set_vec_s32 (cpu, vd, i, val >> shift);
5762 }
5763 else
5764 for (i = 0; i < (full ? 4 : 2); i++)
5765 {
5766 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5767 aarch64_set_vec_u32 (cpu, vd, i, val >> shift);
5768 }
5769
5770 return;
5771 }
5772
ef0d8ffc 5773 if (INSTR (20, 20))
2e8cf49e 5774 {
5ab6d79e 5775 shift = 32 - shift;
2e8cf49e
NC
5776
5777 if (sign)
5778 for (i = 0; i < (full ? 8 : 4); i++)
5779 {
5780 int16_t val = aarch64_get_vec_s16 (cpu, vs, i);
5781 aarch64_set_vec_s16 (cpu, vd, i, val >> shift);
5782 }
5783 else
5784 for (i = 0; i < (full ? 8 : 4); i++)
5785 {
5786 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5787 aarch64_set_vec_u16 (cpu, vd, i, val >> shift);
5788 }
5789
5790 return;
5791 }
5792
ef0d8ffc 5793 if (INSTR (19, 19) == 0)
2e8cf49e
NC
5794 HALT_UNALLOC;
5795
5ab6d79e 5796 shift = 16 - shift;
2e8cf49e
NC
5797
5798 if (sign)
5799 for (i = 0; i < (full ? 16 : 8); i++)
5800 {
5801 int8_t val = aarch64_get_vec_s8 (cpu, vs, i);
5802 aarch64_set_vec_s8 (cpu, vd, i, val >> shift);
5803 }
5804 else
5805 for (i = 0; i < (full ? 16 : 8); i++)
5806 {
5807 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5808 aarch64_set_vec_u8 (cpu, vd, i, val >> shift);
5809 }
5810}
5811
e101a78b
NC
5812static void
5813do_vec_MUL_by_element (sim_cpu *cpu)
5814{
5815 /* instr[31] = 0
5816 instr[30] = half/full
5817 instr[29,24] = 00 1111
5818 instr[23,22] = size
5819 instr[21] = L
5820 instr[20] = M
5821 instr[19,16] = m
5822 instr[15,12] = 1000
5823 instr[11] = H
5824 instr[10] = 0
5825 instr[9,5] = Vn
5826 instr[4,0] = Vd */
5827
ef0d8ffc
NC
5828 unsigned full = INSTR (30, 30);
5829 unsigned L = INSTR (21, 21);
5830 unsigned H = INSTR (11, 11);
5831 unsigned vn = INSTR (9, 5);
5832 unsigned vd = INSTR (4, 0);
5833 unsigned size = INSTR (23, 22);
e101a78b
NC
5834 unsigned index;
5835 unsigned vm;
5836 unsigned e;
5837
5838 NYI_assert (29, 24, 0x0F);
5839 NYI_assert (15, 12, 0x8);
5840 NYI_assert (10, 10, 0);
5841
5842 switch (size)
5843 {
5844 case 1:
5845 {
5846 /* 16 bit products. */
5847 uint16_t product;
5848 uint16_t element1;
5849 uint16_t element2;
5850
ef0d8ffc
NC
5851 index = (H << 2) | (L << 1) | INSTR (20, 20);
5852 vm = INSTR (19, 16);
e101a78b
NC
5853 element2 = aarch64_get_vec_u16 (cpu, vm, index);
5854
5855 for (e = 0; e < (full ? 8 : 4); e ++)
5856 {
5857 element1 = aarch64_get_vec_u16 (cpu, vn, e);
5858 product = element1 * element2;
5859 aarch64_set_vec_u16 (cpu, vd, e, product);
5860 }
5861 }
5862 break;
5863
5864 case 2:
5865 {
5866 /* 32 bit products. */
5867 uint32_t product;
5868 uint32_t element1;
5869 uint32_t element2;
5870
5871 index = (H << 1) | L;
ef0d8ffc 5872 vm = INSTR (20, 16);
e101a78b
NC
5873 element2 = aarch64_get_vec_u32 (cpu, vm, index);
5874
5875 for (e = 0; e < (full ? 4 : 2); e ++)
5876 {
5877 element1 = aarch64_get_vec_u32 (cpu, vn, e);
5878 product = element1 * element2;
5879 aarch64_set_vec_u32 (cpu, vd, e, product);
5880 }
5881 }
5882 break;
5883
5884 default:
5885 HALT_UNALLOC;
5886 }
5887}
5888
2e8cf49e
NC
5889static void
5890do_vec_op2 (sim_cpu *cpu)
5891{
5892 /* instr[31] = 0
5893 instr[30] = half/full
5894 instr[29,24] = 00 1111
5895 instr[23] = ?
5896 instr[22,16] = element size & index
5897 instr[15,10] = sub-opcode
5898 instr[9,5] = Vm
e101a78b 5899 instr[4,0] = Vd */
2e8cf49e
NC
5900
5901 NYI_assert (29, 24, 0x0F);
5902
ef0d8ffc 5903 if (INSTR (23, 23) != 0)
2e8cf49e 5904 {
ef0d8ffc 5905 switch (INSTR (15, 10))
e101a78b
NC
5906 {
5907 case 0x20:
5908 case 0x22: do_vec_MUL_by_element (cpu); return;
5909 default: HALT_NYI;
5910 }
5911 }
5912 else
5913 {
ef0d8ffc 5914 switch (INSTR (15, 10))
e101a78b
NC
5915 {
5916 case 0x01: do_vec_SSHR_USHR (cpu); return;
5917 case 0x15: do_vec_SHL (cpu); return;
5918 case 0x20:
5919 case 0x22: do_vec_MUL_by_element (cpu); return;
5920 case 0x29: do_vec_xtl (cpu); return;
5921 default: HALT_NYI;
5922 }
2e8cf49e
NC
5923 }
5924}
5925
5926static void
5927do_vec_neg (sim_cpu *cpu)
5928{
5929 /* instr[31] = 0
5930 instr[30] = full(1)/half(0)
5931 instr[29,24] = 10 1110
5932 instr[23,22] = size: byte(00), half (01), word (10), long (11)
5933 instr[21,10] = 1000 0010 1110
5934 instr[9,5] = Vs
5935 instr[4,0] = Vd */
5936
ef0d8ffc
NC
5937 int full = INSTR (30, 30);
5938 unsigned vs = INSTR (9, 5);
5939 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5940 unsigned i;
5941
5942 NYI_assert (29, 24, 0x2E);
5943 NYI_assert (21, 10, 0x82E);
5944
ef0d8ffc 5945 switch (INSTR (23, 22))
2e8cf49e
NC
5946 {
5947 case 0:
5948 for (i = 0; i < (full ? 16 : 8); i++)
5949 aarch64_set_vec_s8 (cpu, vd, i, - aarch64_get_vec_s8 (cpu, vs, i));
5950 return;
5951
5952 case 1:
5953 for (i = 0; i < (full ? 8 : 4); i++)
5954 aarch64_set_vec_s16 (cpu, vd, i, - aarch64_get_vec_s16 (cpu, vs, i));
5955 return;
5956
5957 case 2:
5958 for (i = 0; i < (full ? 4 : 2); i++)
5959 aarch64_set_vec_s32 (cpu, vd, i, - aarch64_get_vec_s32 (cpu, vs, i));
5960 return;
5961
5962 case 3:
5963 if (! full)
5964 HALT_NYI;
5965 for (i = 0; i < 2; i++)
5966 aarch64_set_vec_s64 (cpu, vd, i, - aarch64_get_vec_s64 (cpu, vs, i));
5967 return;
2e8cf49e
NC
5968 }
5969}
5970
5971static void
5972do_vec_sqrt (sim_cpu *cpu)
5973{
5974 /* instr[31] = 0
5975 instr[30] = full(1)/half(0)
5976 instr[29,23] = 101 1101
5977 instr[22] = single(0)/double(1)
5978 instr[21,10] = 1000 0111 1110
5979 instr[9,5] = Vs
5980 instr[4,0] = Vd. */
5981
ef0d8ffc
NC
5982 int full = INSTR (30, 30);
5983 unsigned vs = INSTR (9, 5);
5984 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
5985 unsigned i;
5986
5987 NYI_assert (29, 23, 0x5B);
5988 NYI_assert (21, 10, 0x87E);
5989
ef0d8ffc 5990 if (INSTR (22, 22) == 0)
2e8cf49e
NC
5991 for (i = 0; i < (full ? 4 : 2); i++)
5992 aarch64_set_vec_float (cpu, vd, i,
5993 sqrtf (aarch64_get_vec_float (cpu, vs, i)));
5994 else
5995 for (i = 0; i < 2; i++)
5996 aarch64_set_vec_double (cpu, vd, i,
5997 sqrt (aarch64_get_vec_double (cpu, vs, i)));
5998}
5999
6000static void
6001do_vec_mls_indexed (sim_cpu *cpu)
6002{
6003 /* instr[31] = 0
6004 instr[30] = half(0)/full(1)
6005 instr[29,24] = 10 1111
6006 instr[23,22] = 16-bit(01)/32-bit(10)
6007 instr[21,20+11] = index (if 16-bit)
6008 instr[21+11] = index (if 32-bit)
6009 instr[20,16] = Vm
6010 instr[15,12] = 0100
6011 instr[11] = part of index
6012 instr[10] = 0
6013 instr[9,5] = Vs
6014 instr[4,0] = Vd. */
6015
ef0d8ffc
NC
6016 int full = INSTR (30, 30);
6017 unsigned vs = INSTR (9, 5);
6018 unsigned vd = INSTR (4, 0);
6019 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
6020 unsigned i;
6021
6022 NYI_assert (15, 12, 4);
6023 NYI_assert (10, 10, 0);
6024
ef0d8ffc 6025 switch (INSTR (23, 22))
2e8cf49e
NC
6026 {
6027 case 1:
6028 {
6029 unsigned elem;
6030 uint32_t val;
6031
6032 if (vm > 15)
6033 HALT_NYI;
6034
7517e550 6035 elem = (INSTR (21, 20) << 1) | INSTR (11, 11);
2e8cf49e
NC
6036 val = aarch64_get_vec_u16 (cpu, vm, elem);
6037
6038 for (i = 0; i < (full ? 8 : 4); i++)
6039 aarch64_set_vec_u32 (cpu, vd, i,
6040 aarch64_get_vec_u32 (cpu, vd, i) -
6041 (aarch64_get_vec_u32 (cpu, vs, i) * val));
6042 return;
6043 }
6044
6045 case 2:
6046 {
7517e550 6047 unsigned elem = (INSTR (21, 21) << 1) | INSTR (11, 11);
2e8cf49e
NC
6048 uint64_t val = aarch64_get_vec_u32 (cpu, vm, elem);
6049
6050 for (i = 0; i < (full ? 4 : 2); i++)
6051 aarch64_set_vec_u64 (cpu, vd, i,
6052 aarch64_get_vec_u64 (cpu, vd, i) -
6053 (aarch64_get_vec_u64 (cpu, vs, i) * val));
6054 return;
6055 }
6056
6057 case 0:
6058 case 3:
6059 default:
6060 HALT_NYI;
6061 }
6062}
6063
6064static void
6065do_vec_SUB (sim_cpu *cpu)
6066{
6067 /* instr [31] = 0
6068 instr [30] = half(0)/full(1)
6069 instr [29,24] = 10 1110
6070 instr [23,22] = size: byte(00, half(01), word (10), long (11)
6071 instr [21] = 1
6072 instr [20,16] = Vm
6073 instr [15,10] = 10 0001
6074 instr [9, 5] = Vn
6075 instr [4, 0] = Vd. */
6076
ef0d8ffc
NC
6077 unsigned full = INSTR (30, 30);
6078 unsigned vm = INSTR (20, 16);
6079 unsigned vn = INSTR (9, 5);
6080 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6081 unsigned i;
6082
6083 NYI_assert (29, 24, 0x2E);
6084 NYI_assert (21, 21, 1);
6085 NYI_assert (15, 10, 0x21);
6086
ef0d8ffc 6087 switch (INSTR (23, 22))
2e8cf49e
NC
6088 {
6089 case 0:
6090 for (i = 0; i < (full ? 16 : 8); i++)
6091 aarch64_set_vec_s8 (cpu, vd, i,
6092 aarch64_get_vec_s8 (cpu, vn, i)
6093 - aarch64_get_vec_s8 (cpu, vm, i));
6094 return;
6095
6096 case 1:
6097 for (i = 0; i < (full ? 8 : 4); i++)
6098 aarch64_set_vec_s16 (cpu, vd, i,
6099 aarch64_get_vec_s16 (cpu, vn, i)
6100 - aarch64_get_vec_s16 (cpu, vm, i));
6101 return;
6102
6103 case 2:
6104 for (i = 0; i < (full ? 4 : 2); i++)
6105 aarch64_set_vec_s32 (cpu, vd, i,
6106 aarch64_get_vec_s32 (cpu, vn, i)
6107 - aarch64_get_vec_s32 (cpu, vm, i));
6108 return;
6109
6110 case 3:
6111 if (full == 0)
6112 HALT_UNALLOC;
6113
6114 for (i = 0; i < 2; i++)
6115 aarch64_set_vec_s64 (cpu, vd, i,
6116 aarch64_get_vec_s64 (cpu, vn, i)
6117 - aarch64_get_vec_s64 (cpu, vm, i));
6118 return;
2e8cf49e
NC
6119 }
6120}
6121
6122static void
6123do_vec_MLS (sim_cpu *cpu)
6124{
6125 /* instr [31] = 0
6126 instr [30] = half(0)/full(1)
6127 instr [29,24] = 10 1110
6128 instr [23,22] = size: byte(00, half(01), word (10)
6129 instr [21] = 1
6130 instr [20,16] = Vm
6131 instr [15,10] = 10 0101
6132 instr [9, 5] = Vn
6133 instr [4, 0] = Vd. */
6134
ef0d8ffc
NC
6135 unsigned full = INSTR (30, 30);
6136 unsigned vm = INSTR (20, 16);
6137 unsigned vn = INSTR (9, 5);
6138 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6139 unsigned i;
6140
6141 NYI_assert (29, 24, 0x2E);
6142 NYI_assert (21, 21, 1);
6143 NYI_assert (15, 10, 0x25);
6144
ef0d8ffc 6145 switch (INSTR (23, 22))
2e8cf49e
NC
6146 {
6147 case 0:
6148 for (i = 0; i < (full ? 16 : 8); i++)
6149 aarch64_set_vec_u8 (cpu, vd, i,
6150 (aarch64_get_vec_u8 (cpu, vn, i)
6151 * aarch64_get_vec_u8 (cpu, vm, i))
6152 - aarch64_get_vec_u8 (cpu, vd, i));
6153 return;
6154
6155 case 1:
6156 for (i = 0; i < (full ? 8 : 4); i++)
6157 aarch64_set_vec_u16 (cpu, vd, i,
6158 (aarch64_get_vec_u16 (cpu, vn, i)
6159 * aarch64_get_vec_u16 (cpu, vm, i))
6160 - aarch64_get_vec_u16 (cpu, vd, i));
6161 return;
6162
6163 case 2:
6164 for (i = 0; i < (full ? 4 : 2); i++)
6165 aarch64_set_vec_u32 (cpu, vd, i,
6166 (aarch64_get_vec_u32 (cpu, vn, i)
6167 * aarch64_get_vec_u32 (cpu, vm, i))
6168 - aarch64_get_vec_u32 (cpu, vd, i));
6169 return;
6170
6171 default:
6172 HALT_UNALLOC;
6173 }
6174}
6175
6176static void
6177do_vec_FDIV (sim_cpu *cpu)
6178{
6179 /* instr [31] = 0
6180 instr [30] = half(0)/full(1)
6181 instr [29,23] = 10 1110 0
6182 instr [22] = float()/double(1)
6183 instr [21] = 1
6184 instr [20,16] = Vm
6185 instr [15,10] = 1111 11
6186 instr [9, 5] = Vn
6187 instr [4, 0] = Vd. */
6188
ef0d8ffc
NC
6189 unsigned full = INSTR (30, 30);
6190 unsigned vm = INSTR (20, 16);
6191 unsigned vn = INSTR (9, 5);
6192 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6193 unsigned i;
6194
6195 NYI_assert (29, 23, 0x5C);
6196 NYI_assert (21, 21, 1);
6197 NYI_assert (15, 10, 0x3F);
6198
ef0d8ffc 6199 if (INSTR (22, 22))
2e8cf49e
NC
6200 {
6201 if (! full)
6202 HALT_UNALLOC;
6203
6204 for (i = 0; i < 2; i++)
6205 aarch64_set_vec_double (cpu, vd, i,
6206 aarch64_get_vec_double (cpu, vn, i)
6207 / aarch64_get_vec_double (cpu, vm, i));
6208 }
6209 else
6210 for (i = 0; i < (full ? 4 : 2); i++)
6211 aarch64_set_vec_float (cpu, vd, i,
6212 aarch64_get_vec_float (cpu, vn, i)
6213 / aarch64_get_vec_float (cpu, vm, i));
6214}
6215
6216static void
6217do_vec_FMUL (sim_cpu *cpu)
6218{
6219 /* instr [31] = 0
6220 instr [30] = half(0)/full(1)
6221 instr [29,23] = 10 1110 0
6222 instr [22] = float(0)/double(1)
6223 instr [21] = 1
6224 instr [20,16] = Vm
6225 instr [15,10] = 1101 11
6226 instr [9, 5] = Vn
6227 instr [4, 0] = Vd. */
6228
ef0d8ffc
NC
6229 unsigned full = INSTR (30, 30);
6230 unsigned vm = INSTR (20, 16);
6231 unsigned vn = INSTR (9, 5);
6232 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6233 unsigned i;
6234
6235 NYI_assert (29, 23, 0x5C);
6236 NYI_assert (21, 21, 1);
6237 NYI_assert (15, 10, 0x37);
6238
ef0d8ffc 6239 if (INSTR (22, 22))
2e8cf49e
NC
6240 {
6241 if (! full)
6242 HALT_UNALLOC;
6243
6244 for (i = 0; i < 2; i++)
6245 aarch64_set_vec_double (cpu, vd, i,
6246 aarch64_get_vec_double (cpu, vn, i)
6247 * aarch64_get_vec_double (cpu, vm, i));
6248 }
6249 else
6250 for (i = 0; i < (full ? 4 : 2); i++)
6251 aarch64_set_vec_float (cpu, vd, i,
6252 aarch64_get_vec_float (cpu, vn, i)
6253 * aarch64_get_vec_float (cpu, vm, i));
6254}
6255
6256static void
6257do_vec_FADDP (sim_cpu *cpu)
6258{
6259 /* instr [31] = 0
6260 instr [30] = half(0)/full(1)
6261 instr [29,23] = 10 1110 0
6262 instr [22] = float(0)/double(1)
6263 instr [21] = 1
6264 instr [20,16] = Vm
6265 instr [15,10] = 1101 01
6266 instr [9, 5] = Vn
6267 instr [4, 0] = Vd. */
6268
ef0d8ffc
NC
6269 unsigned full = INSTR (30, 30);
6270 unsigned vm = INSTR (20, 16);
6271 unsigned vn = INSTR (9, 5);
6272 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6273
6274 NYI_assert (29, 23, 0x5C);
6275 NYI_assert (21, 21, 1);
6276 NYI_assert (15, 10, 0x35);
6277
ef0d8ffc 6278 if (INSTR (22, 22))
2e8cf49e 6279 {
57aa1742
NC
6280 /* Extract values before adding them incase vd == vn/vm. */
6281 double tmp1 = aarch64_get_vec_double (cpu, vn, 0);
6282 double tmp2 = aarch64_get_vec_double (cpu, vn, 1);
6283 double tmp3 = aarch64_get_vec_double (cpu, vm, 0);
6284 double tmp4 = aarch64_get_vec_double (cpu, vm, 1);
6285
2e8cf49e
NC
6286 if (! full)
6287 HALT_UNALLOC;
6288
57aa1742
NC
6289 aarch64_set_vec_double (cpu, vd, 0, tmp1 + tmp2);
6290 aarch64_set_vec_double (cpu, vd, 1, tmp3 + tmp4);
2e8cf49e
NC
6291 }
6292 else
6293 {
57aa1742
NC
6294 /* Extract values before adding them incase vd == vn/vm. */
6295 float tmp1 = aarch64_get_vec_float (cpu, vn, 0);
6296 float tmp2 = aarch64_get_vec_float (cpu, vn, 1);
6297 float tmp5 = aarch64_get_vec_float (cpu, vm, 0);
6298 float tmp6 = aarch64_get_vec_float (cpu, vm, 1);
6299
2e8cf49e 6300 if (full)
57aa1742
NC
6301 {
6302 float tmp3 = aarch64_get_vec_float (cpu, vn, 2);
6303 float tmp4 = aarch64_get_vec_float (cpu, vn, 3);
6304 float tmp7 = aarch64_get_vec_float (cpu, vm, 2);
6305 float tmp8 = aarch64_get_vec_float (cpu, vm, 3);
6306
6307 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6308 aarch64_set_vec_float (cpu, vd, 1, tmp3 + tmp4);
6309 aarch64_set_vec_float (cpu, vd, 2, tmp5 + tmp6);
6310 aarch64_set_vec_float (cpu, vd, 3, tmp7 + tmp8);
6311 }
6312 else
6313 {
6314 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6315 aarch64_set_vec_float (cpu, vd, 1, tmp5 + tmp6);
6316 }
2e8cf49e
NC
6317 }
6318}
6319
6320static void
6321do_vec_FSQRT (sim_cpu *cpu)
6322{
6323 /* instr[31] = 0
6324 instr[30] = half(0)/full(1)
6325 instr[29,23] = 10 1110 1
6326 instr[22] = single(0)/double(1)
6327 instr[21,10] = 10 0001 1111 10
6328 instr[9,5] = Vsrc
6329 instr[4,0] = Vdest. */
6330
ef0d8ffc
NC
6331 unsigned vn = INSTR (9, 5);
6332 unsigned vd = INSTR (4, 0);
6333 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6334 int i;
6335
6336 NYI_assert (29, 23, 0x5D);
6337 NYI_assert (21, 10, 0x87E);
6338
ef0d8ffc 6339 if (INSTR (22, 22))
2e8cf49e
NC
6340 {
6341 if (! full)
6342 HALT_UNALLOC;
6343
6344 for (i = 0; i < 2; i++)
6345 aarch64_set_vec_double (cpu, vd, i,
6346 sqrt (aarch64_get_vec_double (cpu, vn, i)));
6347 }
6348 else
6349 {
6350 for (i = 0; i < (full ? 4 : 2); i++)
6351 aarch64_set_vec_float (cpu, vd, i,
6352 sqrtf (aarch64_get_vec_float (cpu, vn, i)));
6353 }
6354}
6355
6356static void
6357do_vec_FNEG (sim_cpu *cpu)
6358{
6359 /* instr[31] = 0
6360 instr[30] = half (0)/full (1)
6361 instr[29,23] = 10 1110 1
6362 instr[22] = single (0)/double (1)
6363 instr[21,10] = 10 0000 1111 10
6364 instr[9,5] = Vsrc
6365 instr[4,0] = Vdest. */
6366
ef0d8ffc
NC
6367 unsigned vn = INSTR (9, 5);
6368 unsigned vd = INSTR (4, 0);
6369 unsigned full = INSTR (30, 30);
2e8cf49e
NC
6370 int i;
6371
6372 NYI_assert (29, 23, 0x5D);
6373 NYI_assert (21, 10, 0x83E);
6374
ef0d8ffc 6375 if (INSTR (22, 22))
2e8cf49e
NC
6376 {
6377 if (! full)
6378 HALT_UNALLOC;
6379
6380 for (i = 0; i < 2; i++)
6381 aarch64_set_vec_double (cpu, vd, i,
6382 - aarch64_get_vec_double (cpu, vn, i));
6383 }
6384 else
6385 {
6386 for (i = 0; i < (full ? 4 : 2); i++)
6387 aarch64_set_vec_float (cpu, vd, i,
6388 - aarch64_get_vec_float (cpu, vn, i));
6389 }
6390}
6391
6392static void
6393do_vec_NOT (sim_cpu *cpu)
6394{
6395 /* instr[31] = 0
6396 instr[30] = half (0)/full (1)
5ab6d79e 6397 instr[29,10] = 10 1110 0010 0000 0101 10
2e8cf49e
NC
6398 instr[9,5] = Vn
6399 instr[4.0] = Vd. */
6400
ef0d8ffc
NC
6401 unsigned vn = INSTR (9, 5);
6402 unsigned vd = INSTR (4, 0);
2e8cf49e 6403 unsigned i;
ef0d8ffc 6404 int full = INSTR (30, 30);
2e8cf49e
NC
6405
6406 NYI_assert (29, 10, 0xB8816);
6407
6408 for (i = 0; i < (full ? 16 : 8); i++)
6409 aarch64_set_vec_u8 (cpu, vd, i, ~ aarch64_get_vec_u8 (cpu, vn, i));
6410}
6411
5ab6d79e
NC
6412static unsigned int
6413clz (uint64_t val, unsigned size)
6414{
6415 uint64_t mask = 1;
6416 int count;
6417
6418 mask <<= (size - 1);
6419 count = 0;
6420 do
6421 {
6422 if (val & mask)
6423 break;
6424 mask >>= 1;
6425 count ++;
6426 }
6427 while (mask);
6428
6429 return count;
6430}
6431
6432static void
6433do_vec_CLZ (sim_cpu *cpu)
6434{
6435 /* instr[31] = 0
6436 instr[30] = half (0)/full (1)
6437 instr[29,24] = 10 1110
6438 instr[23,22] = size
6439 instr[21,10] = 10 0000 0100 10
6440 instr[9,5] = Vn
6441 instr[4.0] = Vd. */
6442
6443 unsigned vn = INSTR (9, 5);
6444 unsigned vd = INSTR (4, 0);
6445 unsigned i;
6446 int full = INSTR (30,30);
6447
6448 NYI_assert (29, 24, 0x2E);
6449 NYI_assert (21, 10, 0x812);
6450
6451 switch (INSTR (23, 22))
6452 {
6453 case 0:
6454 for (i = 0; i < (full ? 16 : 8); i++)
6455 aarch64_set_vec_u8 (cpu, vd, i, clz (aarch64_get_vec_u8 (cpu, vn, i), 8));
6456 break;
6457 case 1:
6458 for (i = 0; i < (full ? 8 : 4); i++)
6459 aarch64_set_vec_u16 (cpu, vd, i, clz (aarch64_get_vec_u16 (cpu, vn, i), 16));
6460 break;
6461 case 2:
6462 for (i = 0; i < (full ? 4 : 2); i++)
6463 aarch64_set_vec_u32 (cpu, vd, i, clz (aarch64_get_vec_u32 (cpu, vn, i), 32));
6464 break;
6465 case 3:
6466 if (! full)
6467 HALT_UNALLOC;
6468 aarch64_set_vec_u64 (cpu, vd, 0, clz (aarch64_get_vec_u64 (cpu, vn, 0), 64));
6469 aarch64_set_vec_u64 (cpu, vd, 1, clz (aarch64_get_vec_u64 (cpu, vn, 1), 64));
6470 break;
6471 }
6472}
6473
2e8cf49e
NC
6474static void
6475do_vec_MOV_element (sim_cpu *cpu)
6476{
6477 /* instr[31,21] = 0110 1110 000
6478 instr[20,16] = size & dest index
6479 instr[15] = 0
6480 instr[14,11] = source index
6481 instr[10] = 1
6482 instr[9,5] = Vs
6483 instr[4.0] = Vd. */
6484
ef0d8ffc
NC
6485 unsigned vs = INSTR (9, 5);
6486 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
6487 unsigned src_index;
6488 unsigned dst_index;
6489
6490 NYI_assert (31, 21, 0x370);
6491 NYI_assert (15, 15, 0);
6492 NYI_assert (10, 10, 1);
6493
ef0d8ffc 6494 if (INSTR (16, 16))
2e8cf49e
NC
6495 {
6496 /* Move a byte. */
ef0d8ffc
NC
6497 src_index = INSTR (14, 11);
6498 dst_index = INSTR (20, 17);
2e8cf49e
NC
6499 aarch64_set_vec_u8 (cpu, vd, dst_index,
6500 aarch64_get_vec_u8 (cpu, vs, src_index));
6501 }
ef0d8ffc 6502 else if (INSTR (17, 17))
2e8cf49e
NC
6503 {
6504 /* Move 16-bits. */
6505 NYI_assert (11, 11, 0);
ef0d8ffc
NC
6506 src_index = INSTR (14, 12);
6507 dst_index = INSTR (20, 18);
2e8cf49e
NC
6508 aarch64_set_vec_u16 (cpu, vd, dst_index,
6509 aarch64_get_vec_u16 (cpu, vs, src_index));
6510 }
ef0d8ffc 6511 else if (INSTR (18, 18))
2e8cf49e
NC
6512 {
6513 /* Move 32-bits. */
6514 NYI_assert (12, 11, 0);
ef0d8ffc
NC
6515 src_index = INSTR (14, 13);
6516 dst_index = INSTR (20, 19);
2e8cf49e
NC
6517 aarch64_set_vec_u32 (cpu, vd, dst_index,
6518 aarch64_get_vec_u32 (cpu, vs, src_index));
6519 }
6520 else
6521 {
6522 NYI_assert (19, 19, 1);
6523 NYI_assert (13, 11, 0);
ef0d8ffc
NC
6524 src_index = INSTR (14, 14);
6525 dst_index = INSTR (20, 20);
2e8cf49e
NC
6526 aarch64_set_vec_u64 (cpu, vd, dst_index,
6527 aarch64_get_vec_u64 (cpu, vs, src_index));
6528 }
6529}
6530
67f101ee
NC
6531static void
6532do_vec_REV32 (sim_cpu *cpu)
6533{
6534 /* instr[31] = 0
6535 instr[30] = full/half
6536 instr[29,24] = 10 1110
6537 instr[23,22] = size
6538 instr[21,10] = 10 0000 0000 10
6539 instr[9,5] = Rn
6540 instr[4,0] = Rd. */
6541
6542 unsigned rn = INSTR (9, 5);
6543 unsigned rd = INSTR (4, 0);
6544 unsigned size = INSTR (23, 22);
6545 unsigned full = INSTR (30, 30);
6546 unsigned i;
6547 FRegister val;
6548
6549 NYI_assert (29, 24, 0x2E);
6550 NYI_assert (21, 10, 0x802);
6551
6552 switch (size)
6553 {
6554 case 0:
6555 for (i = 0; i < (full ? 16 : 8); i++)
6556 val.b[i ^ 0x3] = aarch64_get_vec_u8 (cpu, rn, i);
6557 break;
6558
6559 case 1:
6560 for (i = 0; i < (full ? 8 : 4); i++)
6561 val.h[i ^ 0x1] = aarch64_get_vec_u16 (cpu, rn, i);
6562 break;
6563
6564 default:
6565 HALT_UNALLOC;
6566 }
6567
6568 aarch64_set_vec_u64 (cpu, rd, 0, val.v[0]);
6569 if (full)
6570 aarch64_set_vec_u64 (cpu, rd, 1, val.v[1]);
6571}
6572
6573static void
6574do_vec_EXT (sim_cpu *cpu)
6575{
6576 /* instr[31] = 0
6577 instr[30] = full/half
6578 instr[29,21] = 10 1110 000
6579 instr[20,16] = Vm
6580 instr[15] = 0
6581 instr[14,11] = source index
6582 instr[10] = 0
6583 instr[9,5] = Vn
6584 instr[4.0] = Vd. */
6585
6586 unsigned vm = INSTR (20, 16);
6587 unsigned vn = INSTR (9, 5);
6588 unsigned vd = INSTR (4, 0);
6589 unsigned src_index = INSTR (14, 11);
6590 unsigned full = INSTR (30, 30);
6591 unsigned i;
6592 unsigned j;
6593 FRegister val;
6594
6595 NYI_assert (31, 21, 0x370);
6596 NYI_assert (15, 15, 0);
6597 NYI_assert (10, 10, 0);
6598
6599 if (!full && (src_index & 0x8))
6600 HALT_UNALLOC;
6601
6602 j = 0;
6603
6604 for (i = src_index; i < (full ? 16 : 8); i++)
6605 val.b[j ++] = aarch64_get_vec_u8 (cpu, vn, i);
6606 for (i = 0; i < src_index; i++)
6607 val.b[j ++] = aarch64_get_vec_u8 (cpu, vm, i);
6608
6609 aarch64_set_vec_u64 (cpu, vd, 0, val.v[0]);
6610 if (full)
6611 aarch64_set_vec_u64 (cpu, vd, 1, val.v[1]);
6612}
6613
2e8cf49e
NC
6614static void
6615dexAdvSIMD0 (sim_cpu *cpu)
6616{
6617 /* instr [28,25] = 0 111. */
ef0d8ffc
NC
6618 if ( INSTR (15, 10) == 0x07
6619 && (INSTR (9, 5) ==
6620 INSTR (20, 16)))
2e8cf49e 6621 {
ef0d8ffc
NC
6622 if (INSTR (31, 21) == 0x075
6623 || INSTR (31, 21) == 0x275)
2e8cf49e
NC
6624 {
6625 do_vec_MOV_whole_vector (cpu);
6626 return;
6627 }
6628 }
6629
ef0d8ffc 6630 if (INSTR (29, 19) == 0x1E0)
2e8cf49e
NC
6631 {
6632 do_vec_MOV_immediate (cpu);
6633 return;
6634 }
6635
ef0d8ffc 6636 if (INSTR (29, 19) == 0x5E0)
2e8cf49e
NC
6637 {
6638 do_vec_MVNI (cpu);
6639 return;
6640 }
6641
ef0d8ffc
NC
6642 if (INSTR (29, 19) == 0x1C0
6643 || INSTR (29, 19) == 0x1C1)
2e8cf49e 6644 {
ef0d8ffc 6645 if (INSTR (15, 10) == 0x03)
2e8cf49e
NC
6646 {
6647 do_vec_DUP_scalar_into_vector (cpu);
6648 return;
6649 }
6650 }
6651
ef0d8ffc 6652 switch (INSTR (29, 24))
2e8cf49e
NC
6653 {
6654 case 0x0E: do_vec_op1 (cpu); return;
6655 case 0x0F: do_vec_op2 (cpu); return;
6656
2e8cf49e 6657 case 0x2E:
ef0d8ffc 6658 if (INSTR (21, 21) == 1)
2e8cf49e 6659 {
ef0d8ffc 6660 switch (INSTR (15, 10))
2e8cf49e 6661 {
67f101ee
NC
6662 case 0x02:
6663 do_vec_REV32 (cpu);
6664 return;
6665
2e8cf49e 6666 case 0x07:
ef0d8ffc 6667 switch (INSTR (23, 22))
2e8cf49e
NC
6668 {
6669 case 0: do_vec_EOR (cpu); return;
6670 case 1: do_vec_BSL (cpu); return;
6671 case 2:
6672 case 3: do_vec_bit (cpu); return;
6673 }
6674 break;
6675
6676 case 0x08: do_vec_sub_long (cpu); return;
6677 case 0x11: do_vec_USHL (cpu); return;
5ab6d79e 6678 case 0x12: do_vec_CLZ (cpu); return;
2e8cf49e
NC
6679 case 0x16: do_vec_NOT (cpu); return;
6680 case 0x19: do_vec_max (cpu); return;
6681 case 0x1B: do_vec_min (cpu); return;
6682 case 0x21: do_vec_SUB (cpu); return;
6683 case 0x25: do_vec_MLS (cpu); return;
6684 case 0x31: do_vec_FminmaxNMP (cpu); return;
6685 case 0x35: do_vec_FADDP (cpu); return;
6686 case 0x37: do_vec_FMUL (cpu); return;
6687 case 0x3F: do_vec_FDIV (cpu); return;
6688
6689 case 0x3E:
ef0d8ffc 6690 switch (INSTR (20, 16))
2e8cf49e
NC
6691 {
6692 case 0x00: do_vec_FNEG (cpu); return;
6693 case 0x01: do_vec_FSQRT (cpu); return;
6694 default: HALT_NYI;
6695 }
6696
6697 case 0x0D:
6698 case 0x0F:
6699 case 0x22:
6700 case 0x23:
6701 case 0x26:
6702 case 0x2A:
6703 case 0x32:
6704 case 0x36:
6705 case 0x39:
6706 case 0x3A:
6707 do_vec_compare (cpu); return;
6708
5ab6d79e
NC
6709 default:
6710 break;
2e8cf49e
NC
6711 }
6712 }
6713
ef0d8ffc 6714 if (INSTR (31, 21) == 0x370)
2e8cf49e 6715 {
67f101ee
NC
6716 if (INSTR (10, 10))
6717 do_vec_MOV_element (cpu);
6718 else
6719 do_vec_EXT (cpu);
2e8cf49e
NC
6720 return;
6721 }
6722
ef0d8ffc 6723 switch (INSTR (21, 10))
2e8cf49e
NC
6724 {
6725 case 0x82E: do_vec_neg (cpu); return;
6726 case 0x87E: do_vec_sqrt (cpu); return;
6727 default:
ef0d8ffc 6728 if (INSTR (15, 10) == 0x30)
2e8cf49e
NC
6729 {
6730 do_vec_mull (cpu);
6731 return;
6732 }
6733 break;
6734 }
6735 break;
6736
67f101ee
NC
6737 case 0x2f:
6738 switch (INSTR (15, 10))
6739 {
6740 case 0x01: do_vec_SSHR_USHR (cpu); return;
6741 case 0x10:
6742 case 0x12: do_vec_mls_indexed (cpu); return;
6743 case 0x29: do_vec_xtl (cpu); return;
6744 default:
6745 HALT_NYI;
6746 }
6747
2e8cf49e
NC
6748 default:
6749 break;
6750 }
6751
6752 HALT_NYI;
6753}
6754
6755/* 3 sources. */
6756
6757/* Float multiply add. */
6758static void
6759fmadds (sim_cpu *cpu)
6760{
ef0d8ffc
NC
6761 unsigned sa = INSTR (14, 10);
6762 unsigned sm = INSTR (20, 16);
6763 unsigned sn = INSTR ( 9, 5);
6764 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
6765
6766 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6767 + aarch64_get_FP_float (cpu, sn)
6768 * aarch64_get_FP_float (cpu, sm));
6769}
6770
6771/* Double multiply add. */
6772static void
6773fmaddd (sim_cpu *cpu)
6774{
ef0d8ffc
NC
6775 unsigned sa = INSTR (14, 10);
6776 unsigned sm = INSTR (20, 16);
6777 unsigned sn = INSTR ( 9, 5);
6778 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
6779
6780 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6781 + aarch64_get_FP_double (cpu, sn)
6782 * aarch64_get_FP_double (cpu, sm));
6783}
6784
6785/* Float multiply subtract. */
6786static void
6787fmsubs (sim_cpu *cpu)
6788{
ef0d8ffc
NC
6789 unsigned sa = INSTR (14, 10);
6790 unsigned sm = INSTR (20, 16);
6791 unsigned sn = INSTR ( 9, 5);
6792 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
6793
6794 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6795 - aarch64_get_FP_float (cpu, sn)
6796 * aarch64_get_FP_float (cpu, sm));
6797}
6798
6799/* Double multiply subtract. */
6800static void
6801fmsubd (sim_cpu *cpu)
6802{
ef0d8ffc
NC
6803 unsigned sa = INSTR (14, 10);
6804 unsigned sm = INSTR (20, 16);
6805 unsigned sn = INSTR ( 9, 5);
6806 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
6807
6808 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6809 - aarch64_get_FP_double (cpu, sn)
6810 * aarch64_get_FP_double (cpu, sm));
6811}
6812
6813/* Float negative multiply add. */
6814static void
6815fnmadds (sim_cpu *cpu)
6816{
ef0d8ffc
NC
6817 unsigned sa = INSTR (14, 10);
6818 unsigned sm = INSTR (20, 16);
6819 unsigned sn = INSTR ( 9, 5);
6820 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
6821
6822 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6823 + (- aarch64_get_FP_float (cpu, sn))
6824 * aarch64_get_FP_float (cpu, sm));
6825}
6826
6827/* Double negative multiply add. */
6828static void
6829fnmaddd (sim_cpu *cpu)
6830{
ef0d8ffc
NC
6831 unsigned sa = INSTR (14, 10);
6832 unsigned sm = INSTR (20, 16);
6833 unsigned sn = INSTR ( 9, 5);
6834 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
6835
6836 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6837 + (- aarch64_get_FP_double (cpu, sn))
6838 * aarch64_get_FP_double (cpu, sm));
6839}
6840
6841/* Float negative multiply subtract. */
6842static void
6843fnmsubs (sim_cpu *cpu)
6844{
ef0d8ffc
NC
6845 unsigned sa = INSTR (14, 10);
6846 unsigned sm = INSTR (20, 16);
6847 unsigned sn = INSTR ( 9, 5);
6848 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
6849
6850 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6851 + aarch64_get_FP_float (cpu, sn)
6852 * aarch64_get_FP_float (cpu, sm));
6853}
6854
6855/* Double negative multiply subtract. */
6856static void
6857fnmsubd (sim_cpu *cpu)
6858{
ef0d8ffc
NC
6859 unsigned sa = INSTR (14, 10);
6860 unsigned sm = INSTR (20, 16);
6861 unsigned sn = INSTR ( 9, 5);
6862 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
6863
6864 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6865 + aarch64_get_FP_double (cpu, sn)
6866 * aarch64_get_FP_double (cpu, sm));
6867}
6868
6869static void
6870dexSimpleFPDataProc3Source (sim_cpu *cpu)
6871{
6872 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
6873 instr[30] = 0
6874 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
6875 instr[28,25] = 1111
6876 instr[24] = 1
6877 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
6878 instr[21] ==> o1 : 0 ==> unnegated, 1 ==> negated
6879 instr[15] ==> o2 : 0 ==> ADD, 1 ==> SUB */
6880
7517e550 6881 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
2e8cf49e 6882 /* dispatch on combined type:o1:o2. */
7517e550 6883 uint32_t dispatch = (INSTR (23, 21) << 1) | INSTR (15, 15);
2e8cf49e
NC
6884
6885 if (M_S != 0)
6886 HALT_UNALLOC;
6887
6888 switch (dispatch)
6889 {
6890 case 0: fmadds (cpu); return;
6891 case 1: fmsubs (cpu); return;
6892 case 2: fnmadds (cpu); return;
6893 case 3: fnmsubs (cpu); return;
6894 case 4: fmaddd (cpu); return;
6895 case 5: fmsubd (cpu); return;
6896 case 6: fnmaddd (cpu); return;
6897 case 7: fnmsubd (cpu); return;
6898 default:
6899 /* type > 1 is currently unallocated. */
6900 HALT_UNALLOC;
6901 }
6902}
6903
6904static void
6905dexSimpleFPFixedConvert (sim_cpu *cpu)
6906{
6907 HALT_NYI;
6908}
6909
6910static void
6911dexSimpleFPCondCompare (sim_cpu *cpu)
6912{
5ab6d79e
NC
6913 /* instr [31,23] = 0001 1110 0
6914 instr [22] = type
6915 instr [21] = 1
6916 instr [20,16] = Rm
6917 instr [15,12] = condition
6918 instr [11,10] = 01
6919 instr [9,5] = Rn
6920 instr [4] = 0
6921 instr [3,0] = nzcv */
6922
6923 unsigned rm = INSTR (20, 16);
6924 unsigned rn = INSTR (9, 5);
6925
6926 NYI_assert (31, 23, 0x3C);
6927 NYI_assert (11, 10, 0x1);
6928 NYI_assert (4, 4, 0);
6929
6930 if (! testConditionCode (cpu, INSTR (15, 12)))
6931 {
6932 aarch64_set_CPSR (cpu, INSTR (3, 0));
6933 return;
6934 }
6935
6936 if (INSTR (22, 22))
6937 {
6938 /* Double precision. */
6939 double val1 = aarch64_get_vec_double (cpu, rn, 0);
6940 double val2 = aarch64_get_vec_double (cpu, rm, 0);
6941
6942 /* FIXME: Check for NaNs. */
6943 if (val1 == val2)
6944 aarch64_set_CPSR (cpu, (Z | C));
6945 else if (val1 < val2)
6946 aarch64_set_CPSR (cpu, N);
6947 else /* val1 > val2 */
6948 aarch64_set_CPSR (cpu, C);
6949 }
6950 else
6951 {
6952 /* Single precision. */
6953 float val1 = aarch64_get_vec_float (cpu, rn, 0);
6954 float val2 = aarch64_get_vec_float (cpu, rm, 0);
ef0d8ffc 6955
5ab6d79e
NC
6956 /* FIXME: Check for NaNs. */
6957 if (val1 == val2)
6958 aarch64_set_CPSR (cpu, (Z | C));
6959 else if (val1 < val2)
6960 aarch64_set_CPSR (cpu, N);
6961 else /* val1 > val2 */
6962 aarch64_set_CPSR (cpu, C);
6963 }
2e8cf49e
NC
6964}
6965
6966/* 2 sources. */
6967
6968/* Float add. */
6969static void
6970fadds (sim_cpu *cpu)
6971{
ef0d8ffc
NC
6972 unsigned sm = INSTR (20, 16);
6973 unsigned sn = INSTR ( 9, 5);
6974 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
6975
6976 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6977 + aarch64_get_FP_float (cpu, sm));
6978}
6979
6980/* Double add. */
6981static void
6982faddd (sim_cpu *cpu)
6983{
ef0d8ffc
NC
6984 unsigned sm = INSTR (20, 16);
6985 unsigned sn = INSTR ( 9, 5);
6986 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
6987
6988 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6989 + aarch64_get_FP_double (cpu, sm));
6990}
6991
6992/* Float divide. */
6993static void
6994fdivs (sim_cpu *cpu)
6995{
ef0d8ffc
NC
6996 unsigned sm = INSTR (20, 16);
6997 unsigned sn = INSTR ( 9, 5);
6998 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
6999
7000 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7001 / aarch64_get_FP_float (cpu, sm));
7002}
7003
7004/* Double divide. */
7005static void
7006fdivd (sim_cpu *cpu)
7007{
ef0d8ffc
NC
7008 unsigned sm = INSTR (20, 16);
7009 unsigned sn = INSTR ( 9, 5);
7010 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7011
7012 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7013 / aarch64_get_FP_double (cpu, sm));
7014}
7015
7016/* Float multiply. */
7017static void
7018fmuls (sim_cpu *cpu)
7019{
ef0d8ffc
NC
7020 unsigned sm = INSTR (20, 16);
7021 unsigned sn = INSTR ( 9, 5);
7022 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7023
7024 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7025 * aarch64_get_FP_float (cpu, sm));
7026}
7027
7028/* Double multiply. */
7029static void
7030fmuld (sim_cpu *cpu)
7031{
ef0d8ffc
NC
7032 unsigned sm = INSTR (20, 16);
7033 unsigned sn = INSTR ( 9, 5);
7034 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7035
7036 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7037 * aarch64_get_FP_double (cpu, sm));
7038}
7039
7040/* Float negate and multiply. */
7041static void
7042fnmuls (sim_cpu *cpu)
7043{
ef0d8ffc
NC
7044 unsigned sm = INSTR (20, 16);
7045 unsigned sn = INSTR ( 9, 5);
7046 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7047
7048 aarch64_set_FP_float (cpu, sd, - (aarch64_get_FP_float (cpu, sn)
7049 * aarch64_get_FP_float (cpu, sm)));
7050}
7051
7052/* Double negate and multiply. */
7053static void
7054fnmuld (sim_cpu *cpu)
7055{
ef0d8ffc
NC
7056 unsigned sm = INSTR (20, 16);
7057 unsigned sn = INSTR ( 9, 5);
7058 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7059
7060 aarch64_set_FP_double (cpu, sd, - (aarch64_get_FP_double (cpu, sn)
7061 * aarch64_get_FP_double (cpu, sm)));
7062}
7063
7064/* Float subtract. */
7065static void
7066fsubs (sim_cpu *cpu)
7067{
ef0d8ffc
NC
7068 unsigned sm = INSTR (20, 16);
7069 unsigned sn = INSTR ( 9, 5);
7070 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7071
7072 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
7073 - aarch64_get_FP_float (cpu, sm));
7074}
7075
7076/* Double subtract. */
7077static void
7078fsubd (sim_cpu *cpu)
7079{
ef0d8ffc
NC
7080 unsigned sm = INSTR (20, 16);
7081 unsigned sn = INSTR ( 9, 5);
7082 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7083
7084 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
7085 - aarch64_get_FP_double (cpu, sm));
7086}
7087
7088static void
7089do_FMINNM (sim_cpu *cpu)
7090{
7091 /* instr[31,23] = 0 0011 1100
7092 instr[22] = float(0)/double(1)
7093 instr[21] = 1
7094 instr[20,16] = Sm
7095 instr[15,10] = 01 1110
7096 instr[9,5] = Sn
7097 instr[4,0] = Cpu */
7098
ef0d8ffc
NC
7099 unsigned sm = INSTR (20, 16);
7100 unsigned sn = INSTR ( 9, 5);
7101 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7102
7103 NYI_assert (31, 23, 0x03C);
7104 NYI_assert (15, 10, 0x1E);
7105
ef0d8ffc 7106 if (INSTR (22, 22))
2e8cf49e
NC
7107 aarch64_set_FP_double (cpu, sd,
7108 dminnm (aarch64_get_FP_double (cpu, sn),
7109 aarch64_get_FP_double (cpu, sm)));
7110 else
7111 aarch64_set_FP_float (cpu, sd,
7112 fminnm (aarch64_get_FP_float (cpu, sn),
7113 aarch64_get_FP_float (cpu, sm)));
7114}
7115
7116static void
7117do_FMAXNM (sim_cpu *cpu)
7118{
7119 /* instr[31,23] = 0 0011 1100
7120 instr[22] = float(0)/double(1)
7121 instr[21] = 1
7122 instr[20,16] = Sm
7123 instr[15,10] = 01 1010
7124 instr[9,5] = Sn
7125 instr[4,0] = Cpu */
7126
ef0d8ffc
NC
7127 unsigned sm = INSTR (20, 16);
7128 unsigned sn = INSTR ( 9, 5);
7129 unsigned sd = INSTR ( 4, 0);
2e8cf49e
NC
7130
7131 NYI_assert (31, 23, 0x03C);
7132 NYI_assert (15, 10, 0x1A);
7133
ef0d8ffc 7134 if (INSTR (22, 22))
2e8cf49e
NC
7135 aarch64_set_FP_double (cpu, sd,
7136 dmaxnm (aarch64_get_FP_double (cpu, sn),
7137 aarch64_get_FP_double (cpu, sm)));
7138 else
7139 aarch64_set_FP_float (cpu, sd,
7140 fmaxnm (aarch64_get_FP_float (cpu, sn),
7141 aarch64_get_FP_float (cpu, sm)));
7142}
7143
7144static void
7145dexSimpleFPDataProc2Source (sim_cpu *cpu)
7146{
7147 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7148 instr[30] = 0
7149 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7150 instr[28,25] = 1111
7151 instr[24] = 0
7152 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7153 instr[21] = 1
7154 instr[20,16] = Vm
7155 instr[15,12] ==> opcode : 0000 ==> FMUL, 0001 ==> FDIV
7156 0010 ==> FADD, 0011 ==> FSUB,
7157 0100 ==> FMAX, 0101 ==> FMIN
7158 0110 ==> FMAXNM, 0111 ==> FMINNM
7159 1000 ==> FNMUL, ow ==> UNALLOC
7160 instr[11,10] = 10
7161 instr[9,5] = Vn
7162 instr[4,0] = Vd */
7163
7517e550 7164 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc 7165 uint32_t type = INSTR (23, 22);
2e8cf49e 7166 /* Dispatch on opcode. */
ef0d8ffc 7167 uint32_t dispatch = INSTR (15, 12);
2e8cf49e
NC
7168
7169 if (type > 1)
7170 HALT_UNALLOC;
7171
7172 if (M_S != 0)
7173 HALT_UNALLOC;
7174
7175 if (type)
7176 switch (dispatch)
7177 {
7178 case 0: fmuld (cpu); return;
7179 case 1: fdivd (cpu); return;
7180 case 2: faddd (cpu); return;
7181 case 3: fsubd (cpu); return;
7182 case 6: do_FMAXNM (cpu); return;
7183 case 7: do_FMINNM (cpu); return;
7184 case 8: fnmuld (cpu); return;
7185
7186 /* Have not yet implemented fmax and fmin. */
7187 case 4:
7188 case 5:
7189 HALT_NYI;
7190
7191 default:
7192 HALT_UNALLOC;
7193 }
7194 else /* type == 0 => floats. */
7195 switch (dispatch)
7196 {
7197 case 0: fmuls (cpu); return;
7198 case 1: fdivs (cpu); return;
7199 case 2: fadds (cpu); return;
7200 case 3: fsubs (cpu); return;
7201 case 6: do_FMAXNM (cpu); return;
7202 case 7: do_FMINNM (cpu); return;
7203 case 8: fnmuls (cpu); return;
7204
7205 case 4:
7206 case 5:
7207 HALT_NYI;
7208
7209 default:
7210 HALT_UNALLOC;
7211 }
7212}
7213
7214static void
7215dexSimpleFPCondSelect (sim_cpu *cpu)
7216{
7217 /* FCSEL
7218 instr[31,23] = 0 0011 1100
7219 instr[22] = 0=>single 1=>double
7220 instr[21] = 1
7221 instr[20,16] = Sm
7222 instr[15,12] = cond
7223 instr[11,10] = 11
7224 instr[9,5] = Sn
7225 instr[4,0] = Cpu */
ef0d8ffc
NC
7226 unsigned sm = INSTR (20, 16);
7227 unsigned sn = INSTR ( 9, 5);
7228 unsigned sd = INSTR ( 4, 0);
7229 uint32_t set = testConditionCode (cpu, INSTR (15, 12));
2e8cf49e
NC
7230
7231 NYI_assert (31, 23, 0x03C);
7232 NYI_assert (11, 10, 0x3);
7233
ef0d8ffc 7234 if (INSTR (22, 22))
2e8cf49e
NC
7235 aarch64_set_FP_double (cpu, sd, set ? sn : sm);
7236 else
7237 aarch64_set_FP_float (cpu, sd, set ? sn : sm);
7238}
7239
7240/* Store 32 bit unscaled signed 9 bit. */
7241static void
7242fsturs (sim_cpu *cpu, int32_t offset)
7243{
ef0d8ffc
NC
7244 unsigned int rn = INSTR (9, 5);
7245 unsigned int st = INSTR (4, 0);
2e8cf49e 7246
e101a78b
NC
7247 aarch64_set_mem_u32 (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
7248 aarch64_get_vec_u32 (cpu, rn, 0));
2e8cf49e
NC
7249}
7250
7251/* Store 64 bit unscaled signed 9 bit. */
7252static void
7253fsturd (sim_cpu *cpu, int32_t offset)
7254{
ef0d8ffc
NC
7255 unsigned int rn = INSTR (9, 5);
7256 unsigned int st = INSTR (4, 0);
2e8cf49e 7257
e101a78b
NC
7258 aarch64_set_mem_u64 (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
7259 aarch64_get_vec_u64 (cpu, rn, 0));
2e8cf49e
NC
7260}
7261
7262/* Store 128 bit unscaled signed 9 bit. */
7263static void
7264fsturq (sim_cpu *cpu, int32_t offset)
7265{
ef0d8ffc
NC
7266 unsigned int rn = INSTR (9, 5);
7267 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7268 FRegister a;
7269
7270 aarch64_get_FP_long_double (cpu, rn, & a);
7271 aarch64_set_mem_long_double (cpu,
7272 aarch64_get_reg_u64 (cpu, st, 1)
7273 + offset, a);
7274}
7275
7276/* TODO FP move register. */
7277
7278/* 32 bit fp to fp move register. */
7279static void
7280ffmovs (sim_cpu *cpu)
7281{
ef0d8ffc
NC
7282 unsigned int rn = INSTR (9, 5);
7283 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7284
7285 aarch64_set_FP_float (cpu, st, aarch64_get_FP_float (cpu, rn));
7286}
7287
7288/* 64 bit fp to fp move register. */
7289static void
7290ffmovd (sim_cpu *cpu)
7291{
ef0d8ffc
NC
7292 unsigned int rn = INSTR (9, 5);
7293 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7294
7295 aarch64_set_FP_double (cpu, st, aarch64_get_FP_double (cpu, rn));
7296}
7297
7298/* 32 bit GReg to Vec move register. */
7299static void
7300fgmovs (sim_cpu *cpu)
7301{
ef0d8ffc
NC
7302 unsigned int rn = INSTR (9, 5);
7303 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7304
7305 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_reg_u32 (cpu, rn, NO_SP));
7306}
7307
7308/* 64 bit g to fp move register. */
7309static void
7310fgmovd (sim_cpu *cpu)
7311{
ef0d8ffc
NC
7312 unsigned int rn = INSTR (9, 5);
7313 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7314
7315 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_reg_u64 (cpu, rn, NO_SP));
7316}
7317
7318/* 32 bit fp to g move register. */
7319static void
7320gfmovs (sim_cpu *cpu)
7321{
ef0d8ffc
NC
7322 unsigned int rn = INSTR (9, 5);
7323 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7324
7325 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u32 (cpu, rn, 0));
7326}
7327
7328/* 64 bit fp to g move register. */
7329static void
7330gfmovd (sim_cpu *cpu)
7331{
ef0d8ffc
NC
7332 unsigned int rn = INSTR (9, 5);
7333 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7334
7335 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u64 (cpu, rn, 0));
7336}
7337
7338/* FP move immediate
7339
7340 These install an immediate 8 bit value in the target register
7341 where the 8 bits comprise 1 sign bit, 4 bits of fraction and a 3
7342 bit exponent. */
7343
7344static void
7345fmovs (sim_cpu *cpu)
7346{
ef0d8ffc
NC
7347 unsigned int sd = INSTR (4, 0);
7348 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7349 float f = fp_immediate_for_encoding_32 (imm);
7350
7351 aarch64_set_FP_float (cpu, sd, f);
7352}
7353
7354static void
7355fmovd (sim_cpu *cpu)
7356{
ef0d8ffc
NC
7357 unsigned int sd = INSTR (4, 0);
7358 uint32_t imm = INSTR (20, 13);
2e8cf49e
NC
7359 double d = fp_immediate_for_encoding_64 (imm);
7360
7361 aarch64_set_FP_double (cpu, sd, d);
7362}
7363
7364static void
7365dexSimpleFPImmediate (sim_cpu *cpu)
7366{
7367 /* instr[31,23] == 00111100
7368 instr[22] == type : single(0)/double(1)
7369 instr[21] == 1
7370 instr[20,13] == imm8
7371 instr[12,10] == 100
7372 instr[9,5] == imm5 : 00000 ==> PK, ow ==> UNALLOC
7373 instr[4,0] == Rd */
ef0d8ffc 7374 uint32_t imm5 = INSTR (9, 5);
2e8cf49e
NC
7375
7376 NYI_assert (31, 23, 0x3C);
7377
7378 if (imm5 != 0)
7379 HALT_UNALLOC;
7380
ef0d8ffc 7381 if (INSTR (22, 22))
2e8cf49e
NC
7382 fmovd (cpu);
7383 else
7384 fmovs (cpu);
7385}
7386
7387/* TODO specific decode and execute for group Load Store. */
7388
7389/* TODO FP load/store single register (unscaled offset). */
7390
7391/* TODO load 8 bit unscaled signed 9 bit. */
7392/* TODO load 16 bit unscaled signed 9 bit. */
7393
7394/* Load 32 bit unscaled signed 9 bit. */
7395static void
7396fldurs (sim_cpu *cpu, int32_t offset)
7397{
ef0d8ffc
NC
7398 unsigned int rn = INSTR (9, 5);
7399 unsigned int st = INSTR (4, 0);
2e8cf49e 7400
e101a78b
NC
7401 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
7402 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7403}
7404
7405/* Load 64 bit unscaled signed 9 bit. */
7406static void
7407fldurd (sim_cpu *cpu, int32_t offset)
7408{
ef0d8ffc
NC
7409 unsigned int rn = INSTR (9, 5);
7410 unsigned int st = INSTR (4, 0);
2e8cf49e 7411
e101a78b
NC
7412 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64
7413 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7414}
7415
7416/* Load 128 bit unscaled signed 9 bit. */
7417static void
7418fldurq (sim_cpu *cpu, int32_t offset)
7419{
ef0d8ffc
NC
7420 unsigned int rn = INSTR (9, 5);
7421 unsigned int st = INSTR (4, 0);
2e8cf49e
NC
7422 FRegister a;
7423 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
7424
7425 aarch64_get_mem_long_double (cpu, addr, & a);
7426 aarch64_set_FP_long_double (cpu, st, a);
7427}
7428
7429/* TODO store 8 bit unscaled signed 9 bit. */
7430/* TODO store 16 bit unscaled signed 9 bit. */
7431
7432
7433/* 1 source. */
7434
7435/* Float absolute value. */
7436static void
7437fabss (sim_cpu *cpu)
7438{
ef0d8ffc
NC
7439 unsigned sn = INSTR (9, 5);
7440 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7441 float value = aarch64_get_FP_float (cpu, sn);
7442
7443 aarch64_set_FP_float (cpu, sd, fabsf (value));
7444}
7445
7446/* Double absolute value. */
7447static void
7448fabcpu (sim_cpu *cpu)
7449{
ef0d8ffc
NC
7450 unsigned sn = INSTR (9, 5);
7451 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7452 double value = aarch64_get_FP_double (cpu, sn);
7453
7454 aarch64_set_FP_double (cpu, sd, fabs (value));
7455}
7456
7457/* Float negative value. */
7458static void
7459fnegs (sim_cpu *cpu)
7460{
ef0d8ffc
NC
7461 unsigned sn = INSTR (9, 5);
7462 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7463
7464 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sn));
7465}
7466
7467/* Double negative value. */
7468static void
7469fnegd (sim_cpu *cpu)
7470{
ef0d8ffc
NC
7471 unsigned sn = INSTR (9, 5);
7472 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7473
7474 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sn));
7475}
7476
7477/* Float square root. */
7478static void
7479fsqrts (sim_cpu *cpu)
7480{
ef0d8ffc
NC
7481 unsigned sn = INSTR (9, 5);
7482 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7483
7484 aarch64_set_FP_float (cpu, sd, sqrt (aarch64_get_FP_float (cpu, sn)));
7485}
7486
7487/* Double square root. */
7488static void
7489fsqrtd (sim_cpu *cpu)
7490{
ef0d8ffc
NC
7491 unsigned sn = INSTR (9, 5);
7492 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7493
7494 aarch64_set_FP_double (cpu, sd,
7495 sqrt (aarch64_get_FP_double (cpu, sn)));
7496}
7497
7498/* Convert double to float. */
7499static void
7500fcvtds (sim_cpu *cpu)
7501{
ef0d8ffc
NC
7502 unsigned sn = INSTR (9, 5);
7503 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7504
7505 aarch64_set_FP_float (cpu, sd, (float) aarch64_get_FP_double (cpu, sn));
7506}
7507
7508/* Convert float to double. */
7509static void
7510fcvtcpu (sim_cpu *cpu)
7511{
ef0d8ffc
NC
7512 unsigned sn = INSTR (9, 5);
7513 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7514
7515 aarch64_set_FP_double (cpu, sd, (double) aarch64_get_FP_float (cpu, sn));
7516}
7517
7518static void
7519do_FRINT (sim_cpu *cpu)
7520{
7521 /* instr[31,23] = 0001 1110 0
7522 instr[22] = single(0)/double(1)
7523 instr[21,18] = 1001
7524 instr[17,15] = rounding mode
7525 instr[14,10] = 10000
7526 instr[9,5] = source
7527 instr[4,0] = dest */
7528
7529 float val;
ef0d8ffc
NC
7530 unsigned rs = INSTR (9, 5);
7531 unsigned rd = INSTR (4, 0);
7532 unsigned int rmode = INSTR (17, 15);
2e8cf49e
NC
7533
7534 NYI_assert (31, 23, 0x03C);
7535 NYI_assert (21, 18, 0x9);
7536 NYI_assert (14, 10, 0x10);
7537
7538 if (rmode == 6 || rmode == 7)
7539 /* FIXME: Add support for rmode == 6 exactness check. */
7540 rmode = uimm (aarch64_get_FPSR (cpu), 23, 22);
7541
ef0d8ffc 7542 if (INSTR (22, 22))
2e8cf49e
NC
7543 {
7544 double val = aarch64_get_FP_double (cpu, rs);
7545
7546 switch (rmode)
7547 {
7548 case 0: /* mode N: nearest or even. */
7549 {
7550 double rval = round (val);
7551
7552 if (val - rval == 0.5)
7553 {
7554 if (((rval / 2.0) * 2.0) != rval)
7555 rval += 1.0;
7556 }
7557
7558 aarch64_set_FP_double (cpu, rd, round (val));
7559 return;
7560 }
7561
7562 case 1: /* mode P: towards +inf. */
7563 if (val < 0.0)
7564 aarch64_set_FP_double (cpu, rd, trunc (val));
7565 else
7566 aarch64_set_FP_double (cpu, rd, round (val));
7567 return;
7568
7569 case 2: /* mode M: towards -inf. */
7570 if (val < 0.0)
7571 aarch64_set_FP_double (cpu, rd, round (val));
7572 else
7573 aarch64_set_FP_double (cpu, rd, trunc (val));
7574 return;
7575
7576 case 3: /* mode Z: towards 0. */
7577 aarch64_set_FP_double (cpu, rd, trunc (val));
7578 return;
7579
7580 case 4: /* mode A: away from 0. */
7581 aarch64_set_FP_double (cpu, rd, round (val));
7582 return;
7583
7584 case 6: /* mode X: use FPCR with exactness check. */
7585 case 7: /* mode I: use FPCR mode. */
7586 HALT_NYI;
7587
7588 default:
7589 HALT_UNALLOC;
7590 }
7591 }
7592
7593 val = aarch64_get_FP_float (cpu, rs);
7594
7595 switch (rmode)
7596 {
7597 case 0: /* mode N: nearest or even. */
7598 {
7599 float rval = roundf (val);
7600
7601 if (val - rval == 0.5)
7602 {
7603 if (((rval / 2.0) * 2.0) != rval)
7604 rval += 1.0;
7605 }
7606
7607 aarch64_set_FP_float (cpu, rd, rval);
7608 return;
7609 }
7610
7611 case 1: /* mode P: towards +inf. */
7612 if (val < 0.0)
7613 aarch64_set_FP_float (cpu, rd, truncf (val));
7614 else
7615 aarch64_set_FP_float (cpu, rd, roundf (val));
7616 return;
7617
7618 case 2: /* mode M: towards -inf. */
7619 if (val < 0.0)
7620 aarch64_set_FP_float (cpu, rd, truncf (val));
7621 else
7622 aarch64_set_FP_float (cpu, rd, roundf (val));
7623 return;
7624
7625 case 3: /* mode Z: towards 0. */
7626 aarch64_set_FP_float (cpu, rd, truncf (val));
7627 return;
7628
7629 case 4: /* mode A: away from 0. */
7630 aarch64_set_FP_float (cpu, rd, roundf (val));
7631 return;
7632
7633 case 6: /* mode X: use FPCR with exactness check. */
7634 case 7: /* mode I: use FPCR mode. */
7635 HALT_NYI;
7636
7637 default:
7638 HALT_UNALLOC;
7639 }
7640}
7641
5ab6d79e
NC
7642/* Convert half to float. */
7643static void
ef0d8ffc 7644do_FCVT_half_to_single (sim_cpu *cpu)
5ab6d79e
NC
7645{
7646 unsigned rn = INSTR (9, 5);
7647 unsigned rd = INSTR (4, 0);
7648
7649 NYI_assert (31, 10, 0x7B890);
7650
7651 aarch64_set_FP_float (cpu, rd, (float) aarch64_get_FP_half (cpu, rn));
7652}
7653
7517e550 7654/* Convert half to double. */
5ab6d79e 7655static void
ef0d8ffc 7656do_FCVT_half_to_double (sim_cpu *cpu)
5ab6d79e
NC
7657{
7658 unsigned rn = INSTR (9, 5);
7659 unsigned rd = INSTR (4, 0);
7660
7661 NYI_assert (31, 10, 0x7B8B0);
ef0d8ffc 7662
5ab6d79e
NC
7663 aarch64_set_FP_double (cpu, rd, (double) aarch64_get_FP_half (cpu, rn));
7664}
7665
7666static void
ef0d8ffc 7667do_FCVT_single_to_half (sim_cpu *cpu)
5ab6d79e
NC
7668{
7669 unsigned rn = INSTR (9, 5);
7670 unsigned rd = INSTR (4, 0);
7671
7672 NYI_assert (31, 10, 0x788F0);
7673
7674 aarch64_set_FP_half (cpu, rd, aarch64_get_FP_float (cpu, rn));
7675}
7676
7517e550 7677/* Convert double to half. */
5ab6d79e 7678static void
ef0d8ffc 7679do_FCVT_double_to_half (sim_cpu *cpu)
5ab6d79e
NC
7680{
7681 unsigned rn = INSTR (9, 5);
7682 unsigned rd = INSTR (4, 0);
7683
7684 NYI_assert (31, 10, 0x798F0);
ef0d8ffc 7685
5ab6d79e
NC
7686 aarch64_set_FP_half (cpu, rd, (float) aarch64_get_FP_double (cpu, rn));
7687}
7688
2e8cf49e
NC
7689static void
7690dexSimpleFPDataProc1Source (sim_cpu *cpu)
7691{
7692 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7693 instr[30] = 0
7694 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7695 instr[28,25] = 1111
7696 instr[24] = 0
7697 instr[23,22] ==> type : 00 ==> source is single,
7698 01 ==> source is double
7699 10 ==> UNALLOC
7700 11 ==> UNALLOC or source is half
7701 instr[21] = 1
7702 instr[20,15] ==> opcode : with type 00 or 01
7703 000000 ==> FMOV, 000001 ==> FABS,
7704 000010 ==> FNEG, 000011 ==> FSQRT,
7705 000100 ==> UNALLOC, 000101 ==> FCVT,(to single/double)
7706 000110 ==> UNALLOC, 000111 ==> FCVT (to half)
7707 001000 ==> FRINTN, 001001 ==> FRINTP,
7708 001010 ==> FRINTM, 001011 ==> FRINTZ,
7709 001100 ==> FRINTA, 001101 ==> UNALLOC
7710 001110 ==> FRINTX, 001111 ==> FRINTI
7711 with type 11
7712 000100 ==> FCVT (half-to-single)
7713 000101 ==> FCVT (half-to-double)
7714 instr[14,10] = 10000. */
7715
7517e550 7716 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
7717 uint32_t type = INSTR (23, 22);
7718 uint32_t opcode = INSTR (20, 15);
2e8cf49e
NC
7719
7720 if (M_S != 0)
7721 HALT_UNALLOC;
7722
7723 if (type == 3)
7724 {
5ab6d79e
NC
7725 if (opcode == 4)
7726 do_FCVT_half_to_single (cpu);
7727 else if (opcode == 5)
7728 do_FCVT_half_to_double (cpu);
2e8cf49e
NC
7729 else
7730 HALT_UNALLOC;
5ab6d79e 7731 return;
2e8cf49e
NC
7732 }
7733
7734 if (type == 2)
7735 HALT_UNALLOC;
7736
7737 switch (opcode)
7738 {
7739 case 0:
7740 if (type)
7741 ffmovd (cpu);
7742 else
7743 ffmovs (cpu);
7744 return;
7745
7746 case 1:
7747 if (type)
7748 fabcpu (cpu);
7749 else
7750 fabss (cpu);
7751 return;
7752
7753 case 2:
7754 if (type)
7755 fnegd (cpu);
7756 else
7757 fnegs (cpu);
7758 return;
7759
7760 case 3:
7761 if (type)
7762 fsqrtd (cpu);
7763 else
7764 fsqrts (cpu);
7765 return;
7766
7767 case 4:
7768 if (type)
7769 fcvtds (cpu);
7770 else
7771 HALT_UNALLOC;
7772 return;
7773
7774 case 5:
7775 if (type)
7776 HALT_UNALLOC;
7777 fcvtcpu (cpu);
7778 return;
7779
7780 case 8: /* FRINTN etc. */
7781 case 9:
7782 case 10:
7783 case 11:
7784 case 12:
7785 case 14:
7786 case 15:
7787 do_FRINT (cpu);
7788 return;
7789
5ab6d79e
NC
7790 case 7:
7791 if (INSTR (22, 22))
7792 do_FCVT_double_to_half (cpu);
7793 else
7794 do_FCVT_single_to_half (cpu);
7795 return;
7796
2e8cf49e
NC
7797 case 13:
7798 HALT_NYI;
7799
7800 default:
7801 HALT_UNALLOC;
7802 }
7803}
7804
7805/* 32 bit signed int to float. */
7806static void
7807scvtf32 (sim_cpu *cpu)
7808{
ef0d8ffc
NC
7809 unsigned rn = INSTR (9, 5);
7810 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7811
7812 aarch64_set_FP_float
7813 (cpu, sd, (float) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7814}
7815
7816/* signed int to float. */
7817static void
7818scvtf (sim_cpu *cpu)
7819{
ef0d8ffc
NC
7820 unsigned rn = INSTR (9, 5);
7821 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7822
7823 aarch64_set_FP_float
7824 (cpu, sd, (float) aarch64_get_reg_s64 (cpu, rn, NO_SP));
7825}
7826
7827/* 32 bit signed int to double. */
7828static void
7829scvtd32 (sim_cpu *cpu)
7830{
ef0d8ffc
NC
7831 unsigned rn = INSTR (9, 5);
7832 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7833
7834 aarch64_set_FP_double
7835 (cpu, sd, (double) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7836}
7837
7838/* signed int to double. */
7839static void
7840scvtd (sim_cpu *cpu)
7841{
ef0d8ffc
NC
7842 unsigned rn = INSTR (9, 5);
7843 unsigned sd = INSTR (4, 0);
2e8cf49e
NC
7844
7845 aarch64_set_FP_double
7846 (cpu, sd, (double) aarch64_get_reg_s64 (cpu, rn, NO_SP));
7847}
7848
7849static const float FLOAT_INT_MAX = (float) INT_MAX;
7850static const float FLOAT_INT_MIN = (float) INT_MIN;
7851static const double DOUBLE_INT_MAX = (double) INT_MAX;
7852static const double DOUBLE_INT_MIN = (double) INT_MIN;
7853static const float FLOAT_LONG_MAX = (float) LONG_MAX;
7854static const float FLOAT_LONG_MIN = (float) LONG_MIN;
7855static const double DOUBLE_LONG_MAX = (double) LONG_MAX;
7856static const double DOUBLE_LONG_MIN = (double) LONG_MIN;
7857
7858/* Check for FP exception conditions:
7859 NaN raises IO
7860 Infinity raises IO
7861 Out of Range raises IO and IX and saturates value
7862 Denormal raises ID and IX and sets to zero. */
7863#define RAISE_EXCEPTIONS(F, VALUE, FTYPE, ITYPE) \
7864 do \
7865 { \
7866 switch (fpclassify (F)) \
7867 { \
7868 case FP_INFINITE: \
7869 case FP_NAN: \
7870 aarch64_set_FPSR (cpu, IO); \
7871 if (signbit (F)) \
7872 VALUE = ITYPE##_MAX; \
7873 else \
7874 VALUE = ITYPE##_MIN; \
7875 break; \
7876 \
7877 case FP_NORMAL: \
7878 if (F >= FTYPE##_##ITYPE##_MAX) \
7879 { \
7880 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7881 VALUE = ITYPE##_MAX; \
7882 } \
7883 else if (F <= FTYPE##_##ITYPE##_MIN) \
7884 { \
7885 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7886 VALUE = ITYPE##_MIN; \
7887 } \
7888 break; \
7889 \
7890 case FP_SUBNORMAL: \
7891 aarch64_set_FPSR_bits (cpu, IO | IX | ID, IX | ID); \
7892 VALUE = 0; \
7893 break; \
7894 \
7895 default: \
7896 case FP_ZERO: \
7897 VALUE = 0; \
7898 break; \
7899 } \
7900 } \
7901 while (0)
7902
7903/* 32 bit convert float to signed int truncate towards zero. */
7904static void
7905fcvtszs32 (sim_cpu *cpu)
7906{
ef0d8ffc
NC
7907 unsigned sn = INSTR (9, 5);
7908 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
7909 /* TODO : check that this rounds toward zero. */
7910 float f = aarch64_get_FP_float (cpu, sn);
7911 int32_t value = (int32_t) f;
7912
7913 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
7914
7915 /* Avoid sign extension to 64 bit. */
7916 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7917}
7918
7919/* 64 bit convert float to signed int truncate towards zero. */
7920static void
7921fcvtszs (sim_cpu *cpu)
7922{
ef0d8ffc
NC
7923 unsigned sn = INSTR (9, 5);
7924 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
7925 float f = aarch64_get_FP_float (cpu, sn);
7926 int64_t value = (int64_t) f;
7927
7928 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
7929
7930 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7931}
7932
7933/* 32 bit convert double to signed int truncate towards zero. */
7934static void
7935fcvtszd32 (sim_cpu *cpu)
7936{
ef0d8ffc
NC
7937 unsigned sn = INSTR (9, 5);
7938 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
7939 /* TODO : check that this rounds toward zero. */
7940 double d = aarch64_get_FP_double (cpu, sn);
7941 int32_t value = (int32_t) d;
7942
7943 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
7944
7945 /* Avoid sign extension to 64 bit. */
7946 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7947}
7948
7949/* 64 bit convert double to signed int truncate towards zero. */
7950static void
7951fcvtszd (sim_cpu *cpu)
7952{
ef0d8ffc
NC
7953 unsigned sn = INSTR (9, 5);
7954 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
7955 /* TODO : check that this rounds toward zero. */
7956 double d = aarch64_get_FP_double (cpu, sn);
7957 int64_t value;
7958
7959 value = (int64_t) d;
7960
7961 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7962
7963 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7964}
7965
7966static void
7967do_fcvtzu (sim_cpu *cpu)
7968{
7969 /* instr[31] = size: 32-bit (0), 64-bit (1)
7970 instr[30,23] = 00111100
7971 instr[22] = type: single (0)/ double (1)
7972 instr[21] = enable (0)/disable(1) precision
7973 instr[20,16] = 11001
7974 instr[15,10] = precision
7975 instr[9,5] = Rs
7976 instr[4,0] = Rd. */
7977
ef0d8ffc
NC
7978 unsigned rs = INSTR (9, 5);
7979 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
7980
7981 NYI_assert (30, 23, 0x3C);
7982 NYI_assert (20, 16, 0x19);
7983
ef0d8ffc 7984 if (INSTR (21, 21) != 1)
2e8cf49e
NC
7985 /* Convert to fixed point. */
7986 HALT_NYI;
7987
ef0d8ffc 7988 if (INSTR (31, 31))
2e8cf49e
NC
7989 {
7990 /* Convert to unsigned 64-bit integer. */
ef0d8ffc 7991 if (INSTR (22, 22))
2e8cf49e
NC
7992 {
7993 double d = aarch64_get_FP_double (cpu, rs);
7994 uint64_t value = (uint64_t) d;
7995
7996 /* Do not raise an exception if we have reached ULONG_MAX. */
7997 if (value != (1UL << 63))
7998 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7999
8000 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8001 }
8002 else
8003 {
8004 float f = aarch64_get_FP_float (cpu, rs);
8005 uint64_t value = (uint64_t) f;
8006
8007 /* Do not raise an exception if we have reached ULONG_MAX. */
8008 if (value != (1UL << 63))
8009 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
8010
8011 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8012 }
8013 }
8014 else
8015 {
8016 uint32_t value;
8017
8018 /* Convert to unsigned 32-bit integer. */
ef0d8ffc 8019 if (INSTR (22, 22))
2e8cf49e
NC
8020 {
8021 double d = aarch64_get_FP_double (cpu, rs);
8022
8023 value = (uint32_t) d;
8024 /* Do not raise an exception if we have reached UINT_MAX. */
8025 if (value != (1UL << 31))
8026 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
8027 }
8028 else
8029 {
8030 float f = aarch64_get_FP_float (cpu, rs);
8031
8032 value = (uint32_t) f;
8033 /* Do not raise an exception if we have reached UINT_MAX. */
8034 if (value != (1UL << 31))
8035 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
8036 }
8037
8038 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8039 }
8040}
8041
8042static void
8043do_UCVTF (sim_cpu *cpu)
8044{
8045 /* instr[31] = size: 32-bit (0), 64-bit (1)
8046 instr[30,23] = 001 1110 0
8047 instr[22] = type: single (0)/ double (1)
8048 instr[21] = enable (0)/disable(1) precision
8049 instr[20,16] = 0 0011
8050 instr[15,10] = precision
8051 instr[9,5] = Rs
8052 instr[4,0] = Rd. */
8053
ef0d8ffc
NC
8054 unsigned rs = INSTR (9, 5);
8055 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8056
8057 NYI_assert (30, 23, 0x3C);
8058 NYI_assert (20, 16, 0x03);
8059
ef0d8ffc 8060 if (INSTR (21, 21) != 1)
2e8cf49e
NC
8061 HALT_NYI;
8062
8063 /* FIXME: Add exception raising. */
ef0d8ffc 8064 if (INSTR (31, 31))
2e8cf49e
NC
8065 {
8066 uint64_t value = aarch64_get_reg_u64 (cpu, rs, NO_SP);
8067
ef0d8ffc 8068 if (INSTR (22, 22))
2e8cf49e
NC
8069 aarch64_set_FP_double (cpu, rd, (double) value);
8070 else
8071 aarch64_set_FP_float (cpu, rd, (float) value);
8072 }
8073 else
8074 {
8075 uint32_t value = aarch64_get_reg_u32 (cpu, rs, NO_SP);
8076
ef0d8ffc 8077 if (INSTR (22, 22))
2e8cf49e
NC
8078 aarch64_set_FP_double (cpu, rd, (double) value);
8079 else
8080 aarch64_set_FP_float (cpu, rd, (float) value);
8081 }
8082}
8083
8084static void
8085float_vector_move (sim_cpu *cpu)
8086{
8087 /* instr[31,17] == 100 1111 0101 0111
8088 instr[16] ==> direction 0=> to GR, 1=> from GR
8089 instr[15,10] => ???
8090 instr[9,5] ==> source
8091 instr[4,0] ==> dest. */
8092
ef0d8ffc
NC
8093 unsigned rn = INSTR (9, 5);
8094 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8095
8096 NYI_assert (31, 17, 0x4F57);
8097
ef0d8ffc 8098 if (INSTR (15, 10) != 0)
2e8cf49e
NC
8099 HALT_UNALLOC;
8100
ef0d8ffc 8101 if (INSTR (16, 16))
2e8cf49e
NC
8102 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_reg_u64 (cpu, rn, NO_SP));
8103 else
8104 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, rn, 1));
8105}
8106
8107static void
8108dexSimpleFPIntegerConvert (sim_cpu *cpu)
8109{
8110 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8111 instr[30 = 0
8112 instr[29] = S : 0 ==> OK, 1 ==> UNALLOC
8113 instr[28,25] = 1111
8114 instr[24] = 0
8115 instr[23,22] = type : 00 ==> single, 01 ==> double, 1x ==> UNALLOC
8116 instr[21] = 1
8117 instr[20,19] = rmode
8118 instr[18,16] = opcode
8119 instr[15,10] = 10 0000 */
8120
8121 uint32_t rmode_opcode;
8122 uint32_t size_type;
8123 uint32_t type;
8124 uint32_t size;
8125 uint32_t S;
8126
ef0d8ffc 8127 if (INSTR (31, 17) == 0x4F57)
2e8cf49e
NC
8128 {
8129 float_vector_move (cpu);
8130 return;
8131 }
8132
ef0d8ffc
NC
8133 size = INSTR (31, 31);
8134 S = INSTR (29, 29);
2e8cf49e
NC
8135 if (S != 0)
8136 HALT_UNALLOC;
8137
ef0d8ffc 8138 type = INSTR (23, 22);
2e8cf49e
NC
8139 if (type > 1)
8140 HALT_UNALLOC;
8141
ef0d8ffc 8142 rmode_opcode = INSTR (20, 16);
2e8cf49e
NC
8143 size_type = (size << 1) | type; /* 0==32f, 1==32d, 2==64f, 3==64d. */
8144
8145 switch (rmode_opcode)
8146 {
8147 case 2: /* SCVTF. */
8148 switch (size_type)
8149 {
8150 case 0: scvtf32 (cpu); return;
8151 case 1: scvtd32 (cpu); return;
8152 case 2: scvtf (cpu); return;
8153 case 3: scvtd (cpu); return;
2e8cf49e
NC
8154 }
8155
8156 case 6: /* FMOV GR, Vec. */
8157 switch (size_type)
8158 {
8159 case 0: gfmovs (cpu); return;
8160 case 3: gfmovd (cpu); return;
8161 default: HALT_UNALLOC;
8162 }
8163
8164 case 7: /* FMOV vec, GR. */
8165 switch (size_type)
8166 {
8167 case 0: fgmovs (cpu); return;
8168 case 3: fgmovd (cpu); return;
8169 default: HALT_UNALLOC;
8170 }
8171
8172 case 24: /* FCVTZS. */
8173 switch (size_type)
8174 {
8175 case 0: fcvtszs32 (cpu); return;
8176 case 1: fcvtszd32 (cpu); return;
8177 case 2: fcvtszs (cpu); return;
8178 case 3: fcvtszd (cpu); return;
2e8cf49e
NC
8179 }
8180
8181 case 25: do_fcvtzu (cpu); return;
8182 case 3: do_UCVTF (cpu); return;
8183
8184 case 0: /* FCVTNS. */
8185 case 1: /* FCVTNU. */
8186 case 4: /* FCVTAS. */
8187 case 5: /* FCVTAU. */
8188 case 8: /* FCVPTS. */
8189 case 9: /* FCVTPU. */
8190 case 16: /* FCVTMS. */
8191 case 17: /* FCVTMU. */
8192 default:
8193 HALT_NYI;
8194 }
8195}
8196
8197static void
8198set_flags_for_float_compare (sim_cpu *cpu, float fvalue1, float fvalue2)
8199{
8200 uint32_t flags;
8201
8202 if (isnan (fvalue1) || isnan (fvalue2))
8203 flags = C|V;
8204 else
8205 {
8206 float result = fvalue1 - fvalue2;
8207
8208 if (result == 0.0)
8209 flags = Z|C;
8210 else if (result < 0)
8211 flags = N;
8212 else /* (result > 0). */
8213 flags = C;
8214 }
8215
8216 aarch64_set_CPSR (cpu, flags);
8217}
8218
8219static void
8220fcmps (sim_cpu *cpu)
8221{
ef0d8ffc
NC
8222 unsigned sm = INSTR (20, 16);
8223 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8224
8225 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8226 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8227
8228 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8229}
8230
8231/* Float compare to zero -- Invalid Operation exception
8232 only on signaling NaNs. */
8233static void
8234fcmpzs (sim_cpu *cpu)
8235{
ef0d8ffc 8236 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8237 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8238
8239 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8240}
8241
8242/* Float compare -- Invalid Operation exception on all NaNs. */
8243static void
8244fcmpes (sim_cpu *cpu)
8245{
ef0d8ffc
NC
8246 unsigned sm = INSTR (20, 16);
8247 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8248
8249 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8250 float fvalue2 = aarch64_get_FP_float (cpu, sm);
8251
8252 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
8253}
8254
8255/* Float compare to zero -- Invalid Operation exception on all NaNs. */
8256static void
8257fcmpzes (sim_cpu *cpu)
8258{
ef0d8ffc 8259 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8260 float fvalue1 = aarch64_get_FP_float (cpu, sn);
8261
8262 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
8263}
8264
8265static void
8266set_flags_for_double_compare (sim_cpu *cpu, double dval1, double dval2)
8267{
8268 uint32_t flags;
8269
8270 if (isnan (dval1) || isnan (dval2))
8271 flags = C|V;
8272 else
8273 {
8274 double result = dval1 - dval2;
8275
8276 if (result == 0.0)
8277 flags = Z|C;
8278 else if (result < 0)
8279 flags = N;
8280 else /* (result > 0). */
8281 flags = C;
8282 }
8283
8284 aarch64_set_CPSR (cpu, flags);
8285}
8286
8287/* Double compare -- Invalid Operation exception only on signaling NaNs. */
8288static void
8289fcmpd (sim_cpu *cpu)
8290{
ef0d8ffc
NC
8291 unsigned sm = INSTR (20, 16);
8292 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8293
8294 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8295 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8296
8297 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8298}
8299
8300/* Double compare to zero -- Invalid Operation exception
8301 only on signaling NaNs. */
8302static void
8303fcmpzd (sim_cpu *cpu)
8304{
ef0d8ffc 8305 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8306 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8307
8308 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8309}
8310
8311/* Double compare -- Invalid Operation exception on all NaNs. */
8312static void
8313fcmped (sim_cpu *cpu)
8314{
ef0d8ffc
NC
8315 unsigned sm = INSTR (20, 16);
8316 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8317
8318 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8319 double dvalue2 = aarch64_get_FP_double (cpu, sm);
8320
8321 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
8322}
8323
8324/* Double compare to zero -- Invalid Operation exception on all NaNs. */
8325static void
8326fcmpzed (sim_cpu *cpu)
8327{
ef0d8ffc 8328 unsigned sn = INSTR ( 9, 5);
2e8cf49e
NC
8329 double dvalue1 = aarch64_get_FP_double (cpu, sn);
8330
8331 set_flags_for_double_compare (cpu, dvalue1, 0.0);
8332}
8333
8334static void
8335dexSimpleFPCompare (sim_cpu *cpu)
8336{
8337 /* assert instr[28,25] == 1111
8338 instr[30:24:21:13,10] = 0011000
8339 instr[31] = M : 0 ==> OK, 1 ==> UNALLOC
8340 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
8341 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
8342 instr[15,14] ==> op : 00 ==> OK, ow ==> UNALLOC
8343 instr[4,0] ==> opcode2 : 00000 ==> FCMP, 10000 ==> FCMPE,
8344 01000 ==> FCMPZ, 11000 ==> FCMPEZ,
8345 ow ==> UNALLOC */
8346 uint32_t dispatch;
7517e550 8347 uint32_t M_S = (INSTR (31, 31) << 1) | INSTR (29, 29);
ef0d8ffc
NC
8348 uint32_t type = INSTR (23, 22);
8349 uint32_t op = INSTR (15, 14);
8350 uint32_t op2_2_0 = INSTR (2, 0);
2e8cf49e
NC
8351
8352 if (op2_2_0 != 0)
8353 HALT_UNALLOC;
8354
8355 if (M_S != 0)
8356 HALT_UNALLOC;
8357
8358 if (type > 1)
8359 HALT_UNALLOC;
8360
8361 if (op != 0)
8362 HALT_UNALLOC;
8363
8364 /* dispatch on type and top 2 bits of opcode. */
ef0d8ffc 8365 dispatch = (type << 2) | INSTR (4, 3);
2e8cf49e
NC
8366
8367 switch (dispatch)
8368 {
8369 case 0: fcmps (cpu); return;
8370 case 1: fcmpzs (cpu); return;
8371 case 2: fcmpes (cpu); return;
8372 case 3: fcmpzes (cpu); return;
8373 case 4: fcmpd (cpu); return;
8374 case 5: fcmpzd (cpu); return;
8375 case 6: fcmped (cpu); return;
8376 case 7: fcmpzed (cpu); return;
2e8cf49e
NC
8377 }
8378}
8379
8380static void
8381do_scalar_FADDP (sim_cpu *cpu)
8382{
7517e550 8383 /* instr [31,23] = 0111 1110 0
2e8cf49e 8384 instr [22] = single(0)/double(1)
7517e550 8385 instr [21,10] = 11 0000 1101 10
2e8cf49e
NC
8386 instr [9,5] = Fn
8387 instr [4,0] = Fd. */
8388
ef0d8ffc
NC
8389 unsigned Fn = INSTR (9, 5);
8390 unsigned Fd = INSTR (4, 0);
2e8cf49e
NC
8391
8392 NYI_assert (31, 23, 0x0FC);
8393 NYI_assert (21, 10, 0xC36);
8394
ef0d8ffc 8395 if (INSTR (22, 22))
2e8cf49e
NC
8396 {
8397 double val1 = aarch64_get_vec_double (cpu, Fn, 0);
8398 double val2 = aarch64_get_vec_double (cpu, Fn, 1);
8399
8400 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8401 }
8402 else
8403 {
8404 float val1 = aarch64_get_vec_float (cpu, Fn, 0);
8405 float val2 = aarch64_get_vec_float (cpu, Fn, 1);
8406
8407 aarch64_set_FP_float (cpu, Fd, val1 + val2);
8408 }
8409}
8410
8411/* Floating point absolute difference. */
8412
8413static void
8414do_scalar_FABD (sim_cpu *cpu)
8415{
8416 /* instr [31,23] = 0111 1110 1
8417 instr [22] = float(0)/double(1)
8418 instr [21] = 1
8419 instr [20,16] = Rm
8420 instr [15,10] = 1101 01
8421 instr [9, 5] = Rn
8422 instr [4, 0] = Rd. */
8423
ef0d8ffc
NC
8424 unsigned rm = INSTR (20, 16);
8425 unsigned rn = INSTR (9, 5);
8426 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8427
8428 NYI_assert (31, 23, 0x0FD);
8429 NYI_assert (21, 21, 1);
8430 NYI_assert (15, 10, 0x35);
8431
ef0d8ffc 8432 if (INSTR (22, 22))
2e8cf49e
NC
8433 aarch64_set_FP_double (cpu, rd,
8434 fabs (aarch64_get_FP_double (cpu, rn)
8435 - aarch64_get_FP_double (cpu, rm)));
8436 else
8437 aarch64_set_FP_float (cpu, rd,
8438 fabsf (aarch64_get_FP_float (cpu, rn)
8439 - aarch64_get_FP_float (cpu, rm)));
8440}
8441
8442static void
8443do_scalar_CMGT (sim_cpu *cpu)
8444{
8445 /* instr [31,21] = 0101 1110 111
8446 instr [20,16] = Rm
8447 instr [15,10] = 00 1101
8448 instr [9, 5] = Rn
8449 instr [4, 0] = Rd. */
8450
ef0d8ffc
NC
8451 unsigned rm = INSTR (20, 16);
8452 unsigned rn = INSTR (9, 5);
8453 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8454
8455 NYI_assert (31, 21, 0x2F7);
8456 NYI_assert (15, 10, 0x0D);
8457
8458 aarch64_set_vec_u64 (cpu, rd, 0,
8459 aarch64_get_vec_u64 (cpu, rn, 0) >
8460 aarch64_get_vec_u64 (cpu, rm, 0) ? -1L : 0L);
8461}
8462
8463static void
8464do_scalar_USHR (sim_cpu *cpu)
8465{
8466 /* instr [31,23] = 0111 1111 0
8467 instr [22,16] = shift amount
8468 instr [15,10] = 0000 01
8469 instr [9, 5] = Rn
8470 instr [4, 0] = Rd. */
8471
5ab6d79e
NC
8472 unsigned amount = 128 - INSTR (22, 16);
8473 unsigned rn = INSTR (9, 5);
8474 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8475
8476 NYI_assert (31, 23, 0x0FE);
8477 NYI_assert (15, 10, 0x01);
8478
8479 aarch64_set_vec_u64 (cpu, rd, 0,
8480 aarch64_get_vec_u64 (cpu, rn, 0) >> amount);
8481}
8482
8483static void
5ab6d79e
NC
8484do_scalar_SSHL (sim_cpu *cpu)
8485{
8486 /* instr [31,21] = 0101 1110 111
8487 instr [20,16] = Rm
8488 instr [15,10] = 0100 01
8489 instr [9, 5] = Rn
8490 instr [4, 0] = Rd. */
8491
8492 unsigned rm = INSTR (20, 16);
8493 unsigned rn = INSTR (9, 5);
8494 unsigned rd = INSTR (4, 0);
8495 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
8496
8497 NYI_assert (31, 21, 0x2F7);
8498 NYI_assert (15, 10, 0x11);
8499
8500 if (shift >= 0)
8501 aarch64_set_vec_s64 (cpu, rd, 0,
8502 aarch64_get_vec_s64 (cpu, rn, 0) << shift);
8503 else
8504 aarch64_set_vec_s64 (cpu, rd, 0,
ef0d8ffc 8505 aarch64_get_vec_s64 (cpu, rn, 0) >> - shift);
5ab6d79e
NC
8506}
8507
8508static void
8509do_scalar_shift (sim_cpu *cpu)
2e8cf49e 8510{
5ab6d79e 8511 /* instr [31,23] = 0101 1111 0
2e8cf49e 8512 instr [22,16] = shift amount
5ab6d79e
NC
8513 instr [15,10] = 0101 01 [SHL]
8514 instr [15,10] = 0000 01 [SSHR]
2e8cf49e
NC
8515 instr [9, 5] = Rn
8516 instr [4, 0] = Rd. */
8517
5ab6d79e
NC
8518 unsigned rn = INSTR (9, 5);
8519 unsigned rd = INSTR (4, 0);
8520 unsigned amount;
2e8cf49e
NC
8521
8522 NYI_assert (31, 23, 0x0BE);
2e8cf49e 8523
5ab6d79e 8524 if (INSTR (22, 22) == 0)
2e8cf49e
NC
8525 HALT_UNALLOC;
8526
5ab6d79e
NC
8527 switch (INSTR (15, 10))
8528 {
8529 case 0x01: /* SSHR */
8530 amount = 128 - INSTR (22, 16);
8531 aarch64_set_vec_s64 (cpu, rd, 0,
8532 aarch64_get_vec_s64 (cpu, rn, 0) >> amount);
8533 return;
8534 case 0x15: /* SHL */
8535 amount = INSTR (22, 16) - 64;
8536 aarch64_set_vec_u64 (cpu, rd, 0,
8537 aarch64_get_vec_u64 (cpu, rn, 0) << amount);
8538 return;
8539 default:
8540 HALT_NYI;
8541 }
2e8cf49e
NC
8542}
8543
8544/* FCMEQ FCMGT FCMGE. */
8545static void
8546do_scalar_FCM (sim_cpu *cpu)
8547{
8548 /* instr [31,30] = 01
8549 instr [29] = U
8550 instr [28,24] = 1 1110
8551 instr [23] = E
8552 instr [22] = size
8553 instr [21] = 1
8554 instr [20,16] = Rm
8555 instr [15,12] = 1110
8556 instr [11] = AC
8557 instr [10] = 1
8558 instr [9, 5] = Rn
8559 instr [4, 0] = Rd. */
8560
ef0d8ffc
NC
8561 unsigned rm = INSTR (20, 16);
8562 unsigned rn = INSTR (9, 5);
8563 unsigned rd = INSTR (4, 0);
7517e550 8564 unsigned EUac = (INSTR (23, 23) << 2) | (INSTR (29, 29) << 1) | INSTR (11, 11);
2e8cf49e
NC
8565 unsigned result;
8566 float val1;
8567 float val2;
8568
8569 NYI_assert (31, 30, 1);
8570 NYI_assert (28, 24, 0x1E);
8571 NYI_assert (21, 21, 1);
8572 NYI_assert (15, 12, 0xE);
8573 NYI_assert (10, 10, 1);
8574
ef0d8ffc 8575 if (INSTR (22, 22))
2e8cf49e
NC
8576 {
8577 double val1 = aarch64_get_FP_double (cpu, rn);
8578 double val2 = aarch64_get_FP_double (cpu, rm);
8579
8580 switch (EUac)
8581 {
8582 case 0: /* 000 */
8583 result = val1 == val2;
8584 break;
8585
8586 case 3: /* 011 */
8587 val1 = fabs (val1);
8588 val2 = fabs (val2);
8589 /* Fall through. */
8590 case 2: /* 010 */
8591 result = val1 >= val2;
8592 break;
8593
8594 case 7: /* 111 */
8595 val1 = fabs (val1);
8596 val2 = fabs (val2);
8597 /* Fall through. */
8598 case 6: /* 110 */
8599 result = val1 > val2;
8600 break;
8601
8602 default:
8603 HALT_UNALLOC;
8604 }
8605
8606 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8607 return;
8608 }
8609
8610 val1 = aarch64_get_FP_float (cpu, rn);
8611 val2 = aarch64_get_FP_float (cpu, rm);
8612
8613 switch (EUac)
8614 {
8615 case 0: /* 000 */
8616 result = val1 == val2;
8617 break;
8618
8619 case 3: /* 011 */
8620 val1 = fabsf (val1);
8621 val2 = fabsf (val2);
8622 /* Fall through. */
8623 case 2: /* 010 */
8624 result = val1 >= val2;
8625 break;
8626
8627 case 7: /* 111 */
8628 val1 = fabsf (val1);
8629 val2 = fabsf (val2);
8630 /* Fall through. */
8631 case 6: /* 110 */
8632 result = val1 > val2;
8633 break;
8634
8635 default:
8636 HALT_UNALLOC;
8637 }
8638
8639 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8640}
8641
8642/* An alias of DUP. */
8643static void
8644do_scalar_MOV (sim_cpu *cpu)
8645{
8646 /* instr [31,21] = 0101 1110 000
8647 instr [20,16] = imm5
8648 instr [15,10] = 0000 01
8649 instr [9, 5] = Rn
8650 instr [4, 0] = Rd. */
8651
ef0d8ffc
NC
8652 unsigned rn = INSTR (9, 5);
8653 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8654 unsigned index;
8655
8656 NYI_assert (31, 21, 0x2F0);
8657 NYI_assert (15, 10, 0x01);
8658
ef0d8ffc 8659 if (INSTR (16, 16))
2e8cf49e
NC
8660 {
8661 /* 8-bit. */
ef0d8ffc 8662 index = INSTR (20, 17);
2e8cf49e
NC
8663 aarch64_set_vec_u8
8664 (cpu, rd, 0, aarch64_get_vec_u8 (cpu, rn, index));
8665 }
ef0d8ffc 8666 else if (INSTR (17, 17))
2e8cf49e
NC
8667 {
8668 /* 16-bit. */
ef0d8ffc 8669 index = INSTR (20, 18);
2e8cf49e
NC
8670 aarch64_set_vec_u16
8671 (cpu, rd, 0, aarch64_get_vec_u16 (cpu, rn, index));
8672 }
ef0d8ffc 8673 else if (INSTR (18, 18))
2e8cf49e
NC
8674 {
8675 /* 32-bit. */
ef0d8ffc 8676 index = INSTR (20, 19);
2e8cf49e
NC
8677 aarch64_set_vec_u32
8678 (cpu, rd, 0, aarch64_get_vec_u32 (cpu, rn, index));
8679 }
ef0d8ffc 8680 else if (INSTR (19, 19))
2e8cf49e
NC
8681 {
8682 /* 64-bit. */
ef0d8ffc 8683 index = INSTR (20, 20);
2e8cf49e
NC
8684 aarch64_set_vec_u64
8685 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, index));
8686 }
8687 else
8688 HALT_UNALLOC;
8689}
8690
e101a78b
NC
8691static void
8692do_scalar_NEG (sim_cpu *cpu)
8693{
5ab6d79e 8694 /* instr [31,10] = 0111 1110 1110 0000 1011 10
e101a78b
NC
8695 instr [9, 5] = Rn
8696 instr [4, 0] = Rd. */
8697
ef0d8ffc
NC
8698 unsigned rn = INSTR (9, 5);
8699 unsigned rd = INSTR (4, 0);
e101a78b 8700
5ab6d79e 8701 NYI_assert (31, 10, 0x1FB82E);
e101a78b
NC
8702
8703 aarch64_set_vec_u64 (cpu, rd, 0, - aarch64_get_vec_u64 (cpu, rn, 0));
8704}
8705
5ab6d79e
NC
8706static void
8707do_scalar_USHL (sim_cpu *cpu)
8708{
8709 /* instr [31,21] = 0111 1110 111
8710 instr [20,16] = Rm
8711 instr [15,10] = 0100 01
8712 instr [9, 5] = Rn
8713 instr [4, 0] = Rd. */
8714
8715 unsigned rm = INSTR (20, 16);
8716 unsigned rn = INSTR (9, 5);
8717 unsigned rd = INSTR (4, 0);
8718 signed int shift = aarch64_get_vec_s8 (cpu, rm, 0);
8719
8720 NYI_assert (31, 21, 0x3F7);
8721 NYI_assert (15, 10, 0x11);
8722
8723 if (shift >= 0)
8724 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) << shift);
8725 else
8726 aarch64_set_vec_u64 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, 0) >> - shift);
8727}
8728
2e8cf49e
NC
8729static void
8730do_double_add (sim_cpu *cpu)
8731{
5ab6d79e
NC
8732 /* instr [31,21] = 0101 1110 111
8733 instr [20,16] = Fn
8734 instr [15,10] = 1000 01
8735 instr [9,5] = Fm
8736 instr [4,0] = Fd. */
2e8cf49e
NC
8737 unsigned Fd;
8738 unsigned Fm;
8739 unsigned Fn;
8740 double val1;
8741 double val2;
8742
5ab6d79e
NC
8743 NYI_assert (31, 21, 0x2F7);
8744 NYI_assert (15, 10, 0x21);
8745
8746 Fd = INSTR (4, 0);
8747 Fm = INSTR (9, 5);
8748 Fn = INSTR (20, 16);
8749
8750 val1 = aarch64_get_FP_double (cpu, Fm);
8751 val2 = aarch64_get_FP_double (cpu, Fn);
8752
8753 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8754}
8755
7517e550
NC
8756static void
8757do_scalar_UCVTF (sim_cpu *cpu)
8758{
8759 /* instr [31,23] = 0111 1110 0
8760 instr [22] = single(0)/double(1)
8761 instr [21,10] = 10 0001 1101 10
8762 instr [9,5] = rn
8763 instr [4,0] = rd. */
8764
8765 unsigned rn = INSTR (9, 5);
8766 unsigned rd = INSTR (4, 0);
8767
8768 NYI_assert (31, 23, 0x0FC);
8769 NYI_assert (21, 10, 0x876);
8770
8771 if (INSTR (22, 22))
8772 {
8773 uint64_t val = aarch64_get_vec_u64 (cpu, rn, 0);
8774
8775 aarch64_set_vec_double (cpu, rd, 0, (double) val);
8776 }
8777 else
8778 {
8779 uint32_t val = aarch64_get_vec_u32 (cpu, rn, 0);
8780
8781 aarch64_set_vec_float (cpu, rd, 0, (float) val);
8782 }
8783}
8784
5ab6d79e
NC
8785static void
8786do_scalar_vec (sim_cpu *cpu)
8787{
8788 /* instr [30] = 1. */
8789 /* instr [28,25] = 1111. */
ef0d8ffc 8790 switch (INSTR (31, 23))
2e8cf49e
NC
8791 {
8792 case 0xBC:
ef0d8ffc 8793 switch (INSTR (15, 10))
2e8cf49e
NC
8794 {
8795 case 0x01: do_scalar_MOV (cpu); return;
8796 case 0x39: do_scalar_FCM (cpu); return;
8797 case 0x3B: do_scalar_FCM (cpu); return;
8798 }
8799 break;
8800
5ab6d79e 8801 case 0xBE: do_scalar_shift (cpu); return;
2e8cf49e
NC
8802
8803 case 0xFC:
ef0d8ffc 8804 switch (INSTR (15, 10))
2e8cf49e 8805 {
7517e550
NC
8806 case 0x36:
8807 switch (INSTR (21, 16))
8808 {
8809 case 0x30: do_scalar_FADDP (cpu); return;
8810 case 0x21: do_scalar_UCVTF (cpu); return;
8811 }
8812 HALT_NYI;
2e8cf49e
NC
8813 case 0x39: do_scalar_FCM (cpu); return;
8814 case 0x3B: do_scalar_FCM (cpu); return;
8815 }
8816 break;
8817
8818 case 0xFD:
ef0d8ffc 8819 switch (INSTR (15, 10))
2e8cf49e
NC
8820 {
8821 case 0x0D: do_scalar_CMGT (cpu); return;
5ab6d79e
NC
8822 case 0x11: do_scalar_USHL (cpu); return;
8823 case 0x2E: do_scalar_NEG (cpu); return;
2e8cf49e
NC
8824 case 0x35: do_scalar_FABD (cpu); return;
8825 case 0x39: do_scalar_FCM (cpu); return;
8826 case 0x3B: do_scalar_FCM (cpu); return;
8827 default:
8828 HALT_NYI;
8829 }
8830
8831 case 0xFE: do_scalar_USHR (cpu); return;
5ab6d79e
NC
8832
8833 case 0xBD:
8834 switch (INSTR (15, 10))
8835 {
8836 case 0x21: do_double_add (cpu); return;
8837 case 0x11: do_scalar_SSHL (cpu); return;
8838 default:
8839 HALT_NYI;
8840 }
ef0d8ffc 8841
2e8cf49e 8842 default:
5ab6d79e 8843 HALT_NYI;
2e8cf49e 8844 }
2e8cf49e
NC
8845}
8846
8847static void
8848dexAdvSIMD1 (sim_cpu *cpu)
8849{
8850 /* instr [28,25] = 1 111. */
8851
5ab6d79e 8852 /* We are currently only interested in the basic
2e8cf49e 8853 scalar fp routines which all have bit 30 = 0. */
ef0d8ffc 8854 if (INSTR (30, 30))
5ab6d79e 8855 do_scalar_vec (cpu);
2e8cf49e
NC
8856
8857 /* instr[24] is set for FP data processing 3-source and clear for
8858 all other basic scalar fp instruction groups. */
ef0d8ffc 8859 else if (INSTR (24, 24))
2e8cf49e
NC
8860 dexSimpleFPDataProc3Source (cpu);
8861
8862 /* instr[21] is clear for floating <-> fixed conversions and set for
8863 all other basic scalar fp instruction groups. */
ef0d8ffc 8864 else if (!INSTR (21, 21))
2e8cf49e
NC
8865 dexSimpleFPFixedConvert (cpu);
8866
8867 /* instr[11,10] : 01 ==> cond compare, 10 ==> Data Proc 2 Source
8868 11 ==> cond select, 00 ==> other. */
8869 else
ef0d8ffc 8870 switch (INSTR (11, 10))
2e8cf49e
NC
8871 {
8872 case 1: dexSimpleFPCondCompare (cpu); return;
8873 case 2: dexSimpleFPDataProc2Source (cpu); return;
8874 case 3: dexSimpleFPCondSelect (cpu); return;
8875
8876 default:
8877 /* Now an ordered cascade of tests.
ef0d8ffc
NC
8878 FP immediate has instr [12] == 1.
8879 FP compare has instr [13] == 1.
8880 FP Data Proc 1 Source has instr [14] == 1.
8881 FP floating <--> integer conversions has instr [15] == 0. */
8882 if (INSTR (12, 12))
2e8cf49e
NC
8883 dexSimpleFPImmediate (cpu);
8884
ef0d8ffc 8885 else if (INSTR (13, 13))
2e8cf49e
NC
8886 dexSimpleFPCompare (cpu);
8887
ef0d8ffc 8888 else if (INSTR (14, 14))
2e8cf49e
NC
8889 dexSimpleFPDataProc1Source (cpu);
8890
ef0d8ffc 8891 else if (!INSTR (15, 15))
2e8cf49e
NC
8892 dexSimpleFPIntegerConvert (cpu);
8893
8894 else
8895 /* If we get here then instr[15] == 1 which means UNALLOC. */
8896 HALT_UNALLOC;
8897 }
8898}
8899
8900/* PC relative addressing. */
8901
8902static void
8903pcadr (sim_cpu *cpu)
8904{
8905 /* instr[31] = op : 0 ==> ADR, 1 ==> ADRP
8906 instr[30,29] = immlo
8907 instr[23,5] = immhi. */
8908 uint64_t address;
ef0d8ffc
NC
8909 unsigned rd = INSTR (4, 0);
8910 uint32_t isPage = INSTR (31, 31);
2e8cf49e
NC
8911 union { int64_t u64; uint64_t s64; } imm;
8912 uint64_t offset;
8913
8914 imm.s64 = simm64 (aarch64_get_instr (cpu), 23, 5);
8915 offset = imm.u64;
ef0d8ffc 8916 offset = (offset << 2) | INSTR (30, 29);
2e8cf49e
NC
8917
8918 address = aarch64_get_PC (cpu);
8919
8920 if (isPage)
8921 {
8922 offset <<= 12;
8923 address &= ~0xfff;
8924 }
8925
8926 aarch64_set_reg_u64 (cpu, rd, NO_SP, address + offset);
8927}
8928
8929/* Specific decode and execute for group Data Processing Immediate. */
8930
8931static void
8932dexPCRelAddressing (sim_cpu *cpu)
8933{
8934 /* assert instr[28,24] = 10000. */
8935 pcadr (cpu);
8936}
8937
8938/* Immediate logical.
8939 The bimm32/64 argument is constructed by replicating a 2, 4, 8,
8940 16, 32 or 64 bit sequence pulled out at decode and possibly
8941 inverting it..
8942
8943 N.B. the output register (dest) can normally be Xn or SP
8944 the exception occurs for flag setting instructions which may
8945 only use Xn for the output (dest). The input register can
8946 never be SP. */
8947
8948/* 32 bit and immediate. */
8949static void
8950and32 (sim_cpu *cpu, uint32_t bimm)
8951{
ef0d8ffc
NC
8952 unsigned rn = INSTR (9, 5);
8953 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8954
8955 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8956 aarch64_get_reg_u32 (cpu, rn, NO_SP) & bimm);
8957}
8958
8959/* 64 bit and immediate. */
8960static void
8961and64 (sim_cpu *cpu, uint64_t bimm)
8962{
ef0d8ffc
NC
8963 unsigned rn = INSTR (9, 5);
8964 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8965
8966 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8967 aarch64_get_reg_u64 (cpu, rn, NO_SP) & bimm);
8968}
8969
8970/* 32 bit and immediate set flags. */
8971static void
8972ands32 (sim_cpu *cpu, uint32_t bimm)
8973{
ef0d8ffc
NC
8974 unsigned rn = INSTR (9, 5);
8975 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8976
8977 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8978 uint32_t value2 = bimm;
8979
8980 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8981 set_flags_for_binop32 (cpu, value1 & value2);
8982}
8983
8984/* 64 bit and immediate set flags. */
8985static void
8986ands64 (sim_cpu *cpu, uint64_t bimm)
8987{
ef0d8ffc
NC
8988 unsigned rn = INSTR (9, 5);
8989 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
8990
8991 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8992 uint64_t value2 = bimm;
8993
8994 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8995 set_flags_for_binop64 (cpu, value1 & value2);
8996}
8997
8998/* 32 bit exclusive or immediate. */
8999static void
9000eor32 (sim_cpu *cpu, uint32_t bimm)
9001{
ef0d8ffc
NC
9002 unsigned rn = INSTR (9, 5);
9003 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9004
9005 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9006 aarch64_get_reg_u32 (cpu, rn, NO_SP) ^ bimm);
9007}
9008
9009/* 64 bit exclusive or immediate. */
9010static void
9011eor64 (sim_cpu *cpu, uint64_t bimm)
9012{
ef0d8ffc
NC
9013 unsigned rn = INSTR (9, 5);
9014 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9015
9016 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9017 aarch64_get_reg_u64 (cpu, rn, NO_SP) ^ bimm);
9018}
9019
9020/* 32 bit or immediate. */
9021static void
9022orr32 (sim_cpu *cpu, uint32_t bimm)
9023{
ef0d8ffc
NC
9024 unsigned rn = INSTR (9, 5);
9025 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9026
9027 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9028 aarch64_get_reg_u32 (cpu, rn, NO_SP) | bimm);
9029}
9030
9031/* 64 bit or immediate. */
9032static void
9033orr64 (sim_cpu *cpu, uint64_t bimm)
9034{
ef0d8ffc
NC
9035 unsigned rn = INSTR (9, 5);
9036 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9037
9038 aarch64_set_reg_u64 (cpu, rd, SP_OK,
9039 aarch64_get_reg_u64 (cpu, rn, NO_SP) | bimm);
9040}
9041
9042/* Logical shifted register.
9043 These allow an optional LSL, ASR, LSR or ROR to the second source
9044 register with a count up to the register bit count.
9045 N.B register args may not be SP. */
9046
9047/* 32 bit AND shifted register. */
9048static void
9049and32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9050{
ef0d8ffc
NC
9051 unsigned rm = INSTR (20, 16);
9052 unsigned rn = INSTR (9, 5);
9053 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9054
9055 aarch64_set_reg_u64
9056 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9057 & shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9058}
9059
9060/* 64 bit AND shifted register. */
9061static void
9062and64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9063{
ef0d8ffc
NC
9064 unsigned rm = INSTR (20, 16);
9065 unsigned rn = INSTR (9, 5);
9066 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9067
9068 aarch64_set_reg_u64
9069 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9070 & shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9071}
9072
9073/* 32 bit AND shifted register setting flags. */
9074static void
9075ands32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9076{
ef0d8ffc
NC
9077 unsigned rm = INSTR (20, 16);
9078 unsigned rn = INSTR (9, 5);
9079 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9080
9081 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9082 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9083 shift, count);
9084
9085 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9086 set_flags_for_binop32 (cpu, value1 & value2);
9087}
9088
9089/* 64 bit AND shifted register setting flags. */
9090static void
9091ands64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9092{
ef0d8ffc
NC
9093 unsigned rm = INSTR (20, 16);
9094 unsigned rn = INSTR (9, 5);
9095 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9096
9097 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9098 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9099 shift, count);
9100
9101 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9102 set_flags_for_binop64 (cpu, value1 & value2);
9103}
9104
9105/* 32 bit BIC shifted register. */
9106static void
9107bic32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9108{
ef0d8ffc
NC
9109 unsigned rm = INSTR (20, 16);
9110 unsigned rn = INSTR (9, 5);
9111 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9112
9113 aarch64_set_reg_u64
9114 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9115 & ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9116}
9117
9118/* 64 bit BIC shifted register. */
9119static void
9120bic64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9121{
ef0d8ffc
NC
9122 unsigned rm = INSTR (20, 16);
9123 unsigned rn = INSTR (9, 5);
9124 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9125
9126 aarch64_set_reg_u64
9127 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9128 & ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9129}
9130
9131/* 32 bit BIC shifted register setting flags. */
9132static void
9133bics32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9134{
ef0d8ffc
NC
9135 unsigned rm = INSTR (20, 16);
9136 unsigned rn = INSTR (9, 5);
9137 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9138
9139 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9140 uint32_t value2 = ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9141 shift, count);
9142
9143 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9144 set_flags_for_binop32 (cpu, value1 & value2);
9145}
9146
9147/* 64 bit BIC shifted register setting flags. */
9148static void
9149bics64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9150{
ef0d8ffc
NC
9151 unsigned rm = INSTR (20, 16);
9152 unsigned rn = INSTR (9, 5);
9153 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9154
9155 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9156 uint64_t value2 = ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
9157 shift, count);
9158
9159 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
9160 set_flags_for_binop64 (cpu, value1 & value2);
9161}
9162
9163/* 32 bit EON shifted register. */
9164static void
9165eon32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9166{
ef0d8ffc
NC
9167 unsigned rm = INSTR (20, 16);
9168 unsigned rn = INSTR (9, 5);
9169 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9170
9171 aarch64_set_reg_u64
9172 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9173 ^ ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9174}
9175
9176/* 64 bit EON shifted register. */
9177static void
9178eon64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9179{
ef0d8ffc
NC
9180 unsigned rm = INSTR (20, 16);
9181 unsigned rn = INSTR (9, 5);
9182 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9183
9184 aarch64_set_reg_u64
9185 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9186 ^ ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9187}
9188
9189/* 32 bit EOR shifted register. */
9190static void
9191eor32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9192{
ef0d8ffc
NC
9193 unsigned rm = INSTR (20, 16);
9194 unsigned rn = INSTR (9, 5);
9195 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9196
9197 aarch64_set_reg_u64
9198 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9199 ^ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9200}
9201
9202/* 64 bit EOR shifted register. */
9203static void
9204eor64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9205{
ef0d8ffc
NC
9206 unsigned rm = INSTR (20, 16);
9207 unsigned rn = INSTR (9, 5);
9208 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9209
9210 aarch64_set_reg_u64
9211 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9212 ^ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9213}
9214
9215/* 32 bit ORR shifted register. */
9216static void
9217orr32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9218{
ef0d8ffc
NC
9219 unsigned rm = INSTR (20, 16);
9220 unsigned rn = INSTR (9, 5);
9221 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9222
9223 aarch64_set_reg_u64
9224 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9225 | shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9226}
9227
9228/* 64 bit ORR shifted register. */
9229static void
9230orr64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9231{
ef0d8ffc
NC
9232 unsigned rm = INSTR (20, 16);
9233 unsigned rn = INSTR (9, 5);
9234 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9235
9236 aarch64_set_reg_u64
9237 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9238 | shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9239}
9240
9241/* 32 bit ORN shifted register. */
9242static void
9243orn32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9244{
ef0d8ffc
NC
9245 unsigned rm = INSTR (20, 16);
9246 unsigned rn = INSTR (9, 5);
9247 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9248
9249 aarch64_set_reg_u64
9250 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
9251 | ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
9252}
9253
9254/* 64 bit ORN shifted register. */
9255static void
9256orn64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
9257{
ef0d8ffc
NC
9258 unsigned rm = INSTR (20, 16);
9259 unsigned rn = INSTR (9, 5);
9260 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9261
9262 aarch64_set_reg_u64
9263 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
9264 | ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
9265}
9266
9267static void
9268dexLogicalImmediate (sim_cpu *cpu)
9269{
9270 /* assert instr[28,23] = 1001000
9271 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9272 instr[30,29] = op : 0 ==> AND, 1 ==> ORR, 2 ==> EOR, 3 ==> ANDS
9273 instr[22] = N : used to construct immediate mask
9274 instr[21,16] = immr
9275 instr[15,10] = imms
9276 instr[9,5] = Rn
9277 instr[4,0] = Rd */
9278
9279 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
ef0d8ffc
NC
9280 uint32_t size = INSTR (31, 31);
9281 uint32_t N = INSTR (22, 22);
9282 /* uint32_t immr = INSTR (21, 16);. */
9283 /* uint32_t imms = INSTR (15, 10);. */
9284 uint32_t index = INSTR (22, 10);
2e8cf49e 9285 uint64_t bimm64 = LITable [index];
ef0d8ffc 9286 uint32_t dispatch = INSTR (30, 29);
2e8cf49e
NC
9287
9288 if (~size & N)
9289 HALT_UNALLOC;
9290
9291 if (!bimm64)
9292 HALT_UNALLOC;
9293
9294 if (size == 0)
9295 {
9296 uint32_t bimm = (uint32_t) bimm64;
9297
9298 switch (dispatch)
9299 {
9300 case 0: and32 (cpu, bimm); return;
9301 case 1: orr32 (cpu, bimm); return;
9302 case 2: eor32 (cpu, bimm); return;
9303 case 3: ands32 (cpu, bimm); return;
9304 }
9305 }
9306 else
9307 {
9308 switch (dispatch)
9309 {
9310 case 0: and64 (cpu, bimm64); return;
9311 case 1: orr64 (cpu, bimm64); return;
9312 case 2: eor64 (cpu, bimm64); return;
9313 case 3: ands64 (cpu, bimm64); return;
9314 }
9315 }
9316 HALT_UNALLOC;
9317}
9318
9319/* Immediate move.
9320 The uimm argument is a 16 bit value to be inserted into the
9321 target register the pos argument locates the 16 bit word in the
9322 dest register i.e. it is in {0, 1} for 32 bit and {0, 1, 2,
9323 3} for 64 bit.
9324 N.B register arg may not be SP so it should be.
9325 accessed using the setGZRegisterXXX accessors. */
9326
9327/* 32 bit move 16 bit immediate zero remaining shorts. */
9328static void
9329movz32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9330{
ef0d8ffc 9331 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9332
9333 aarch64_set_reg_u64 (cpu, rd, NO_SP, val << (pos * 16));
9334}
9335
9336/* 64 bit move 16 bit immediate zero remaining shorts. */
9337static void
9338movz64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9339{
ef0d8ffc 9340 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9341
9342 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((uint64_t) val) << (pos * 16));
9343}
9344
9345/* 32 bit move 16 bit immediate negated. */
9346static void
9347movn32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9348{
ef0d8ffc 9349 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9350
9351 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((val << (pos * 16)) ^ 0xffffffffU));
9352}
9353
9354/* 64 bit move 16 bit immediate negated. */
9355static void
9356movn64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9357{
ef0d8ffc 9358 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9359
9360 aarch64_set_reg_u64
9361 (cpu, rd, NO_SP, ((((uint64_t) val) << (pos * 16))
9362 ^ 0xffffffffffffffffULL));
9363}
9364
9365/* 32 bit move 16 bit immediate keep remaining shorts. */
9366static void
9367movk32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9368{
ef0d8ffc 9369 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9370 uint32_t current = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9371 uint32_t value = val << (pos * 16);
9372 uint32_t mask = ~(0xffffU << (pos * 16));
9373
9374 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
9375}
9376
9377/* 64 bit move 16 it immediate keep remaining shorts. */
9378static void
9379movk64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
9380{
ef0d8ffc 9381 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
9382 uint64_t current = aarch64_get_reg_u64 (cpu, rd, NO_SP);
9383 uint64_t value = (uint64_t) val << (pos * 16);
9384 uint64_t mask = ~(0xffffULL << (pos * 16));
9385
9386 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
9387}
9388
9389static void
9390dexMoveWideImmediate (sim_cpu *cpu)
9391{
9392 /* assert instr[28:23] = 100101
9393 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9394 instr[30,29] = op : 0 ==> MOVN, 1 ==> UNALLOC, 2 ==> MOVZ, 3 ==> MOVK
9395 instr[22,21] = shift : 00 == LSL#0, 01 = LSL#16, 10 = LSL#32, 11 = LSL#48
9396 instr[20,5] = uimm16
9397 instr[4,0] = Rd */
9398
9399 /* N.B. the (multiple of 16) shift is applied by the called routine,
9400 we just pass the multiplier. */
9401
9402 uint32_t imm;
ef0d8ffc
NC
9403 uint32_t size = INSTR (31, 31);
9404 uint32_t op = INSTR (30, 29);
9405 uint32_t shift = INSTR (22, 21);
2e8cf49e
NC
9406
9407 /* 32 bit can only shift 0 or 1 lot of 16.
9408 anything else is an unallocated instruction. */
9409 if (size == 0 && (shift > 1))
9410 HALT_UNALLOC;
9411
9412 if (op == 1)
9413 HALT_UNALLOC;
9414
ef0d8ffc 9415 imm = INSTR (20, 5);
2e8cf49e
NC
9416
9417 if (size == 0)
9418 {
9419 if (op == 0)
9420 movn32 (cpu, imm, shift);
9421 else if (op == 2)
9422 movz32 (cpu, imm, shift);
9423 else
9424 movk32 (cpu, imm, shift);
9425 }
9426 else
9427 {
9428 if (op == 0)
9429 movn64 (cpu, imm, shift);
9430 else if (op == 2)
9431 movz64 (cpu, imm, shift);
9432 else
9433 movk64 (cpu, imm, shift);
9434 }
9435}
9436
9437/* Bitfield operations.
9438 These take a pair of bit positions r and s which are in {0..31}
9439 or {0..63} depending on the instruction word size.
9440 N.B register args may not be SP. */
9441
9442/* OK, we start with ubfm which just needs to pick
9443 some bits out of source zero the rest and write
9444 the result to dest. Just need two logical shifts. */
9445
9446/* 32 bit bitfield move, left and right of affected zeroed
9447 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9448static void
9449ubfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9450{
9451 unsigned rd;
ef0d8ffc 9452 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9453 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9454
9455 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
9456 if (r <= s)
9457 {
9458 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
9459 We want only bits s:xxx:r at the bottom of the word
9460 so we LSL bit s up to bit 31 i.e. by 31 - s
9461 and then we LSR to bring bit 31 down to bit s - r
9462 i.e. by 31 + r - s. */
9463 value <<= 31 - s;
9464 value >>= 31 + r - s;
9465 }
9466 else
9467 {
9468 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0
9469 We want only bits s:xxx:0 starting at it 31-(r-1)
9470 so we LSL bit s up to bit 31 i.e. by 31 - s
9471 and then we LSL to bring bit 31 down to 31-(r-1)+s
9472 i.e. by r - (s + 1). */
9473 value <<= 31 - s;
9474 value >>= r - (s + 1);
9475 }
9476
ef0d8ffc 9477 rd = INSTR (4, 0);
2e8cf49e
NC
9478 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
9479}
9480
9481/* 64 bit bitfield move, left and right of affected zeroed
9482 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9483static void
9484ubfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9485{
9486 unsigned rd;
ef0d8ffc 9487 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9488 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9489
9490 if (r <= s)
9491 {
9492 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9493 We want only bits s:xxx:r at the bottom of the word.
9494 So we LSL bit s up to bit 63 i.e. by 63 - s
9495 and then we LSR to bring bit 63 down to bit s - r
9496 i.e. by 63 + r - s. */
9497 value <<= 63 - s;
9498 value >>= 63 + r - s;
9499 }
9500 else
9501 {
9502 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0.
9503 We want only bits s:xxx:0 starting at it 63-(r-1).
9504 So we LSL bit s up to bit 63 i.e. by 63 - s
9505 and then we LSL to bring bit 63 down to 63-(r-1)+s
9506 i.e. by r - (s + 1). */
9507 value <<= 63 - s;
9508 value >>= r - (s + 1);
9509 }
9510
ef0d8ffc 9511 rd = INSTR (4, 0);
2e8cf49e
NC
9512 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
9513}
9514
9515/* The signed versions need to insert sign bits
9516 on the left of the inserted bit field. so we do
9517 much the same as the unsigned version except we
9518 use an arithmetic shift right -- this just means
9519 we need to operate on signed values. */
9520
9521/* 32 bit bitfield move, left of affected sign-extended, right zeroed. */
9522/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9523static void
9524sbfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9525{
9526 unsigned rd;
ef0d8ffc 9527 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9528 /* as per ubfm32 but use an ASR instead of an LSR. */
9529 int32_t value = aarch64_get_reg_s32 (cpu, rn, NO_SP);
9530
9531 if (r <= s)
9532 {
9533 value <<= 31 - s;
9534 value >>= 31 + r - s;
9535 }
9536 else
9537 {
9538 value <<= 31 - s;
9539 value >>= r - (s + 1);
9540 }
9541
ef0d8ffc 9542 rd = INSTR (4, 0);
2e8cf49e
NC
9543 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
9544}
9545
9546/* 64 bit bitfield move, left of affected sign-extended, right zeroed. */
9547/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9548static void
9549sbfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9550{
9551 unsigned rd;
ef0d8ffc 9552 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9553 /* acpu per ubfm but use an ASR instead of an LSR. */
9554 int64_t value = aarch64_get_reg_s64 (cpu, rn, NO_SP);
9555
9556 if (r <= s)
9557 {
9558 value <<= 63 - s;
9559 value >>= 63 + r - s;
9560 }
9561 else
9562 {
9563 value <<= 63 - s;
9564 value >>= r - (s + 1);
9565 }
9566
ef0d8ffc 9567 rd = INSTR (4, 0);
2e8cf49e
NC
9568 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
9569}
9570
9571/* Finally, these versions leave non-affected bits
9572 as is. so we need to generate the bits as per
9573 ubfm and also generate a mask to pick the
9574 bits from the original and computed values. */
9575
9576/* 32 bit bitfield move, non-affected bits left as is.
9577 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9578static void
9579bfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9580{
ef0d8ffc 9581 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9582 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9583 uint32_t mask = -1;
9584 unsigned rd;
9585 uint32_t value2;
9586
9587 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
9588 if (r <= s)
9589 {
9590 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
9591 We want only bits s:xxx:r at the bottom of the word
9592 so we LSL bit s up to bit 31 i.e. by 31 - s
9593 and then we LSR to bring bit 31 down to bit s - r
9594 i.e. by 31 + r - s. */
9595 value <<= 31 - s;
9596 value >>= 31 + r - s;
9597 /* the mask must include the same bits. */
9598 mask <<= 31 - s;
9599 mask >>= 31 + r - s;
9600 }
9601 else
9602 {
9603 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0.
9604 We want only bits s:xxx:0 starting at it 31-(r-1)
9605 so we LSL bit s up to bit 31 i.e. by 31 - s
9606 and then we LSL to bring bit 31 down to 31-(r-1)+s
9607 i.e. by r - (s + 1). */
9608 value <<= 31 - s;
9609 value >>= r - (s + 1);
9610 /* The mask must include the same bits. */
9611 mask <<= 31 - s;
9612 mask >>= r - (s + 1);
9613 }
9614
ef0d8ffc 9615 rd = INSTR (4, 0);
2e8cf49e
NC
9616 value2 = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9617
9618 value2 &= ~mask;
9619 value2 |= value;
9620
9621 aarch64_set_reg_u64
9622 (cpu, rd, NO_SP, (aarch64_get_reg_u32 (cpu, rd, NO_SP) & ~mask) | value);
9623}
9624
9625/* 64 bit bitfield move, non-affected bits left as is.
9626 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9627static void
9628bfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9629{
9630 unsigned rd;
ef0d8ffc 9631 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9632 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9633 uint64_t mask = 0xffffffffffffffffULL;
9634
9635 if (r <= s)
9636 {
9637 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9638 We want only bits s:xxx:r at the bottom of the word
9639 so we LSL bit s up to bit 63 i.e. by 63 - s
9640 and then we LSR to bring bit 63 down to bit s - r
9641 i.e. by 63 + r - s. */
9642 value <<= 63 - s;
9643 value >>= 63 + r - s;
9644 /* The mask must include the same bits. */
9645 mask <<= 63 - s;
9646 mask >>= 63 + r - s;
9647 }
9648 else
9649 {
9650 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0
9651 We want only bits s:xxx:0 starting at it 63-(r-1)
9652 so we LSL bit s up to bit 63 i.e. by 63 - s
9653 and then we LSL to bring bit 63 down to 63-(r-1)+s
9654 i.e. by r - (s + 1). */
9655 value <<= 63 - s;
9656 value >>= r - (s + 1);
9657 /* The mask must include the same bits. */
9658 mask <<= 63 - s;
9659 mask >>= r - (s + 1);
9660 }
9661
ef0d8ffc 9662 rd = INSTR (4, 0);
2e8cf49e
NC
9663 aarch64_set_reg_u64
9664 (cpu, rd, NO_SP, (aarch64_get_reg_u64 (cpu, rd, NO_SP) & ~mask) | value);
9665}
9666
9667static void
9668dexBitfieldImmediate (sim_cpu *cpu)
9669{
9670 /* assert instr[28:23] = 100110
9671 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9672 instr[30,29] = op : 0 ==> SBFM, 1 ==> BFM, 2 ==> UBFM, 3 ==> UNALLOC
9673 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit ow UNALLOC
9674 instr[21,16] = immr : 0xxxxx for 32 bit, xxxxxx for 64 bit
9675 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9676 instr[9,5] = Rn
9677 instr[4,0] = Rd */
9678
9679 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9680 uint32_t dispatch;
9681 uint32_t imms;
ef0d8ffc
NC
9682 uint32_t size = INSTR (31, 31);
9683 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
9684 /* 32 bit operations must have immr[5] = 0 and imms[5] = 0. */
9685 /* or else we have an UNALLOC. */
ef0d8ffc 9686 uint32_t immr = INSTR (21, 16);
2e8cf49e
NC
9687
9688 if (~size & N)
9689 HALT_UNALLOC;
9690
9691 if (!size && uimm (immr, 5, 5))
9692 HALT_UNALLOC;
9693
ef0d8ffc 9694 imms = INSTR (15, 10);
2e8cf49e
NC
9695 if (!size && uimm (imms, 5, 5))
9696 HALT_UNALLOC;
9697
9698 /* Switch on combined size and op. */
ef0d8ffc 9699 dispatch = INSTR (31, 29);
2e8cf49e
NC
9700 switch (dispatch)
9701 {
9702 case 0: sbfm32 (cpu, immr, imms); return;
9703 case 1: bfm32 (cpu, immr, imms); return;
9704 case 2: ubfm32 (cpu, immr, imms); return;
9705 case 4: sbfm (cpu, immr, imms); return;
9706 case 5: bfm (cpu, immr, imms); return;
9707 case 6: ubfm (cpu, immr, imms); return;
9708 default: HALT_UNALLOC;
9709 }
9710}
9711
9712static void
9713do_EXTR_32 (sim_cpu *cpu)
9714{
9715 /* instr[31:21] = 00010011100
9716 instr[20,16] = Rm
9717 instr[15,10] = imms : 0xxxxx for 32 bit
9718 instr[9,5] = Rn
9719 instr[4,0] = Rd */
ef0d8ffc
NC
9720 unsigned rm = INSTR (20, 16);
9721 unsigned imms = INSTR (15, 10) & 31;
9722 unsigned rn = INSTR ( 9, 5);
9723 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
9724 uint64_t val1;
9725 uint64_t val2;
9726
9727 val1 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
9728 val1 >>= imms;
9729 val2 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9730 val2 <<= (32 - imms);
9731
9732 aarch64_set_reg_u64 (cpu, rd, NO_SP, val1 | val2);
9733}
9734
9735static void
9736do_EXTR_64 (sim_cpu *cpu)
9737{
9738 /* instr[31:21] = 10010011100
9739 instr[20,16] = Rm
9740 instr[15,10] = imms
9741 instr[9,5] = Rn
9742 instr[4,0] = Rd */
ef0d8ffc
NC
9743 unsigned rm = INSTR (20, 16);
9744 unsigned imms = INSTR (15, 10) & 63;
9745 unsigned rn = INSTR ( 9, 5);
9746 unsigned rd = INSTR ( 4, 0);
2e8cf49e
NC
9747 uint64_t val;
9748
9749 val = aarch64_get_reg_u64 (cpu, rm, NO_SP);
9750 val >>= imms;
9751 val |= (aarch64_get_reg_u64 (cpu, rn, NO_SP) << (64 - imms));
9752
9753 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
9754}
9755
9756static void
9757dexExtractImmediate (sim_cpu *cpu)
9758{
9759 /* assert instr[28:23] = 100111
9760 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9761 instr[30,29] = op21 : 0 ==> EXTR, 1,2,3 ==> UNALLOC
9762 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit or UNALLOC
9763 instr[21] = op0 : must be 0 or UNALLOC
9764 instr[20,16] = Rm
9765 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9766 instr[9,5] = Rn
9767 instr[4,0] = Rd */
9768
9769 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9770 /* 64 bit operations must have N = 1 or else we have an UNALLOC. */
9771 uint32_t dispatch;
ef0d8ffc
NC
9772 uint32_t size = INSTR (31, 31);
9773 uint32_t N = INSTR (22, 22);
2e8cf49e
NC
9774 /* 32 bit operations must have imms[5] = 0
9775 or else we have an UNALLOC. */
ef0d8ffc 9776 uint32_t imms = INSTR (15, 10);
2e8cf49e
NC
9777
9778 if (size ^ N)
9779 HALT_UNALLOC;
9780
9781 if (!size && uimm (imms, 5, 5))
9782 HALT_UNALLOC;
9783
9784 /* Switch on combined size and op. */
ef0d8ffc 9785 dispatch = INSTR (31, 29);
2e8cf49e
NC
9786
9787 if (dispatch == 0)
9788 do_EXTR_32 (cpu);
9789
9790 else if (dispatch == 4)
9791 do_EXTR_64 (cpu);
9792
9793 else if (dispatch == 1)
9794 HALT_NYI;
9795 else
9796 HALT_UNALLOC;
9797}
9798
9799static void
9800dexDPImm (sim_cpu *cpu)
9801{
9802 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
9803 assert group == GROUP_DPIMM_1000 || grpoup == GROUP_DPIMM_1001
9804 bits [25,23] of a DPImm are the secondary dispatch vector. */
9805 uint32_t group2 = dispatchDPImm (aarch64_get_instr (cpu));
9806
9807 switch (group2)
9808 {
9809 case DPIMM_PCADR_000:
9810 case DPIMM_PCADR_001:
9811 dexPCRelAddressing (cpu);
9812 return;
9813
9814 case DPIMM_ADDSUB_010:
9815 case DPIMM_ADDSUB_011:
9816 dexAddSubtractImmediate (cpu);
9817 return;
9818
9819 case DPIMM_LOG_100:
9820 dexLogicalImmediate (cpu);
9821 return;
9822
9823 case DPIMM_MOV_101:
9824 dexMoveWideImmediate (cpu);
9825 return;
9826
9827 case DPIMM_BITF_110:
9828 dexBitfieldImmediate (cpu);
9829 return;
9830
9831 case DPIMM_EXTR_111:
9832 dexExtractImmediate (cpu);
9833 return;
9834
9835 default:
9836 /* Should never reach here. */
9837 HALT_NYI;
9838 }
9839}
9840
9841static void
9842dexLoadUnscaledImmediate (sim_cpu *cpu)
9843{
9844 /* instr[29,24] == 111_00
9845 instr[21] == 0
9846 instr[11,10] == 00
9847 instr[31,30] = size
9848 instr[26] = V
9849 instr[23,22] = opc
9850 instr[20,12] = simm9
9851 instr[9,5] = rn may be SP. */
ef0d8ffc
NC
9852 /* unsigned rt = INSTR (4, 0); */
9853 uint32_t V = INSTR (26, 26);
7517e550 9854 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
2e8cf49e
NC
9855 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
9856
9857 if (!V)
9858 {
9859 /* GReg operations. */
9860 switch (dispatch)
9861 {
9862 case 0: sturb (cpu, imm); return;
9863 case 1: ldurb32 (cpu, imm); return;
9864 case 2: ldursb64 (cpu, imm); return;
9865 case 3: ldursb32 (cpu, imm); return;
9866 case 4: sturh (cpu, imm); return;
9867 case 5: ldurh32 (cpu, imm); return;
9868 case 6: ldursh64 (cpu, imm); return;
9869 case 7: ldursh32 (cpu, imm); return;
9870 case 8: stur32 (cpu, imm); return;
9871 case 9: ldur32 (cpu, imm); return;
9872 case 10: ldursw (cpu, imm); return;
9873 case 12: stur64 (cpu, imm); return;
9874 case 13: ldur64 (cpu, imm); return;
9875
9876 case 14:
9877 /* PRFUM NYI. */
9878 HALT_NYI;
9879
9880 default:
9881 case 11:
9882 case 15:
9883 HALT_UNALLOC;
9884 }
9885 }
9886
9887 /* FReg operations. */
9888 switch (dispatch)
9889 {
9890 case 2: fsturq (cpu, imm); return;
9891 case 3: fldurq (cpu, imm); return;
9892 case 8: fsturs (cpu, imm); return;
9893 case 9: fldurs (cpu, imm); return;
9894 case 12: fsturd (cpu, imm); return;
9895 case 13: fldurd (cpu, imm); return;
9896
9897 case 0: /* STUR 8 bit FP. */
9898 case 1: /* LDUR 8 bit FP. */
9899 case 4: /* STUR 16 bit FP. */
9900 case 5: /* LDUR 8 bit FP. */
9901 HALT_NYI;
9902
9903 default:
9904 case 6:
9905 case 7:
9906 case 10:
9907 case 11:
9908 case 14:
9909 case 15:
9910 HALT_UNALLOC;
9911 }
9912}
9913
9914/* N.B. A preliminary note regarding all the ldrs<x>32
9915 instructions
9916
9917 The signed value loaded by these instructions is cast to unsigned
9918 before being assigned to aarch64_get_reg_u64 (cpu, N) i.e. to the
9919 64 bit element of the GReg union. this performs a 32 bit sign extension
9920 (as required) but avoids 64 bit sign extension, thus ensuring that the
9921 top half of the register word is zero. this is what the spec demands
9922 when a 32 bit load occurs. */
9923
9924/* 32 bit load sign-extended byte scaled unsigned 12 bit. */
9925static void
9926ldrsb32_abs (sim_cpu *cpu, uint32_t offset)
9927{
ef0d8ffc
NC
9928 unsigned int rn = INSTR (9, 5);
9929 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
9930
9931 /* The target register may not be SP but the source may be
9932 there is no scaling required for a byte load. */
9933 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
9934 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9935 (int64_t) aarch64_get_mem_s8 (cpu, address));
9936}
9937
9938/* 32 bit load sign-extended byte scaled or unscaled zero-
9939 or sign-extended 32-bit register offset. */
9940static void
9941ldrsb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9942{
ef0d8ffc
NC
9943 unsigned int rm = INSTR (20, 16);
9944 unsigned int rn = INSTR (9, 5);
9945 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
9946
9947 /* rn may reference SP, rm and rt must reference ZR. */
9948
9949 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9950 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9951 extension);
9952
9953 /* There is no scaling required for a byte load. */
9954 aarch64_set_reg_u64
9955 (cpu, rt, NO_SP, (int64_t) aarch64_get_mem_s8 (cpu, address
9956 + displacement));
9957}
9958
9959/* 32 bit load sign-extended byte unscaled signed 9 bit with
9960 pre- or post-writeback. */
9961static void
9962ldrsb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9963{
9964 uint64_t address;
ef0d8ffc
NC
9965 unsigned int rn = INSTR (9, 5);
9966 unsigned int rt = INSTR (4, 0);
2e8cf49e
NC
9967
9968 if (rn == rt && wb != NoWriteBack)
9969 HALT_UNALLOC;
9970
9971 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9972
9973 if (wb == Pre)
9974 address += offset;
9975
9976 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9977 (int64_t) aarch64_get_mem_s8 (cpu, address));
9978
9979 if (wb == Post)
9980 address += offset;
9981
9982 if (wb != NoWriteBack)
9983 aarch64_set_reg_u64 (cpu, rn, NO_SP, address);
9984}
9985
9986/* 8 bit store scaled. */
9987static void
9988fstrb_abs (sim_cpu *cpu, uint32_t offset)
9989{
ef0d8ffc
NC
9990 unsigned st = INSTR (4, 0);
9991 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
9992
9993 aarch64_set_mem_u8 (cpu,
9994 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
9995 aarch64_get_vec_u8 (cpu, st, 0));
9996}
9997
9998/* 8 bit store scaled or unscaled zero- or
9999 sign-extended 8-bit register offset. */
10000static void
10001fstrb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10002{
ef0d8ffc
NC
10003 unsigned rm = INSTR (20, 16);
10004 unsigned rn = INSTR (9, 5);
10005 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10006
10007 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10008 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10009 extension);
7517e550 10010 uint64_t displacement = scaling == Scaled ? extended : 0;
2e8cf49e
NC
10011
10012 aarch64_set_mem_u8
10013 (cpu, address + displacement, aarch64_get_vec_u8 (cpu, st, 0));
10014}
10015
10016/* 16 bit store scaled. */
10017static void
10018fstrh_abs (sim_cpu *cpu, uint32_t offset)
10019{
ef0d8ffc
NC
10020 unsigned st = INSTR (4, 0);
10021 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10022
10023 aarch64_set_mem_u16
10024 (cpu,
10025 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16),
10026 aarch64_get_vec_u16 (cpu, st, 0));
10027}
10028
10029/* 16 bit store scaled or unscaled zero-
10030 or sign-extended 16-bit register offset. */
10031static void
10032fstrh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10033{
ef0d8ffc
NC
10034 unsigned rm = INSTR (20, 16);
10035 unsigned rn = INSTR (9, 5);
10036 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10037
10038 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10039 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10040 extension);
7517e550 10041 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
2e8cf49e
NC
10042
10043 aarch64_set_mem_u16
10044 (cpu, address + displacement, aarch64_get_vec_u16 (cpu, st, 0));
10045}
10046
10047/* 32 bit store scaled unsigned 12 bit. */
10048static void
10049fstrs_abs (sim_cpu *cpu, uint32_t offset)
10050{
ef0d8ffc
NC
10051 unsigned st = INSTR (4, 0);
10052 unsigned rn = INSTR (9, 5);
2e8cf49e 10053
e101a78b 10054 aarch64_set_mem_u32
2e8cf49e
NC
10055 (cpu,
10056 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
e101a78b 10057 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10058}
10059
10060/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
10061static void
10062fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10063{
ef0d8ffc
NC
10064 unsigned rn = INSTR (9, 5);
10065 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10066
10067 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10068
10069 if (wb != Post)
10070 address += offset;
10071
e101a78b 10072 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10073
10074 if (wb == Post)
10075 address += offset;
10076
10077 if (wb != NoWriteBack)
10078 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10079}
10080
10081/* 32 bit store scaled or unscaled zero-
10082 or sign-extended 32-bit register offset. */
10083static void
10084fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10085{
ef0d8ffc
NC
10086 unsigned rm = INSTR (20, 16);
10087 unsigned rn = INSTR (9, 5);
10088 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10089
10090 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10091 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10092 extension);
10093 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
10094
e101a78b
NC
10095 aarch64_set_mem_u32
10096 (cpu, address + displacement, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
10097}
10098
10099/* 64 bit store scaled unsigned 12 bit. */
10100static void
10101fstrd_abs (sim_cpu *cpu, uint32_t offset)
10102{
ef0d8ffc
NC
10103 unsigned st = INSTR (4, 0);
10104 unsigned rn = INSTR (9, 5);
2e8cf49e 10105
e101a78b 10106 aarch64_set_mem_u64
2e8cf49e
NC
10107 (cpu,
10108 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
e101a78b 10109 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10110}
10111
10112/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
10113static void
10114fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10115{
ef0d8ffc
NC
10116 unsigned rn = INSTR (9, 5);
10117 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10118
10119 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10120
10121 if (wb != Post)
10122 address += offset;
10123
e101a78b 10124 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10125
10126 if (wb == Post)
10127 address += offset;
10128
10129 if (wb != NoWriteBack)
10130 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10131}
10132
10133/* 64 bit store scaled or unscaled zero-
10134 or sign-extended 32-bit register offset. */
10135static void
10136fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10137{
ef0d8ffc
NC
10138 unsigned rm = INSTR (20, 16);
10139 unsigned rn = INSTR (9, 5);
10140 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10141
10142 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10143 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10144 extension);
10145 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
10146
e101a78b
NC
10147 aarch64_set_mem_u64
10148 (cpu, address + displacement, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
10149}
10150
10151/* 128 bit store scaled unsigned 12 bit. */
10152static void
10153fstrq_abs (sim_cpu *cpu, uint32_t offset)
10154{
10155 FRegister a;
ef0d8ffc
NC
10156 unsigned st = INSTR (4, 0);
10157 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
10158 uint64_t addr;
10159
10160 aarch64_get_FP_long_double (cpu, st, & a);
10161
10162 addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
10163 aarch64_set_mem_long_double (cpu, addr, a);
10164}
10165
10166/* 128 bit store unscaled signed 9 bit with pre- or post-writeback. */
10167static void
10168fstrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
10169{
10170 FRegister a;
ef0d8ffc
NC
10171 unsigned rn = INSTR (9, 5);
10172 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10173 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10174
10175 if (wb != Post)
10176 address += offset;
10177
10178 aarch64_get_FP_long_double (cpu, st, & a);
10179 aarch64_set_mem_long_double (cpu, address, a);
10180
10181 if (wb == Post)
10182 address += offset;
10183
10184 if (wb != NoWriteBack)
10185 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
10186}
10187
10188/* 128 bit store scaled or unscaled zero-
10189 or sign-extended 32-bit register offset. */
10190static void
10191fstrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
10192{
ef0d8ffc
NC
10193 unsigned rm = INSTR (20, 16);
10194 unsigned rn = INSTR (9, 5);
10195 unsigned st = INSTR (4, 0);
2e8cf49e
NC
10196
10197 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
10198 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
10199 extension);
10200 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
10201
10202 FRegister a;
10203
10204 aarch64_get_FP_long_double (cpu, st, & a);
10205 aarch64_set_mem_long_double (cpu, address + displacement, a);
10206}
10207
10208static void
10209dexLoadImmediatePrePost (sim_cpu *cpu)
10210{
ef0d8ffc
NC
10211 /* instr[31,30] = size
10212 instr[29,27] = 111
10213 instr[26] = V
10214 instr[25,24] = 00
2e8cf49e 10215 instr[23,22] = opc
ef0d8ffc 10216 instr[21] = 0
2e8cf49e 10217 instr[20,12] = simm9
ef0d8ffc
NC
10218 instr[11] = wb : 0 ==> Post, 1 ==> Pre
10219 instr[10] = 0
10220 instr[9,5] = Rn may be SP.
10221 instr[4,0] = Rt */
10222
10223 uint32_t V = INSTR (26, 26);
10224 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10225 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
10226 WriteBack wb = INSTR (11, 11);
2e8cf49e
NC
10227
10228 if (!V)
10229 {
10230 /* GReg operations. */
10231 switch (dispatch)
10232 {
10233 case 0: strb_wb (cpu, imm, wb); return;
10234 case 1: ldrb32_wb (cpu, imm, wb); return;
10235 case 2: ldrsb_wb (cpu, imm, wb); return;
10236 case 3: ldrsb32_wb (cpu, imm, wb); return;
10237 case 4: strh_wb (cpu, imm, wb); return;
10238 case 5: ldrh32_wb (cpu, imm, wb); return;
10239 case 6: ldrsh64_wb (cpu, imm, wb); return;
10240 case 7: ldrsh32_wb (cpu, imm, wb); return;
10241 case 8: str32_wb (cpu, imm, wb); return;
10242 case 9: ldr32_wb (cpu, imm, wb); return;
10243 case 10: ldrsw_wb (cpu, imm, wb); return;
10244 case 12: str_wb (cpu, imm, wb); return;
10245 case 13: ldr_wb (cpu, imm, wb); return;
10246
10247 default:
10248 case 11:
10249 case 14:
10250 case 15:
10251 HALT_UNALLOC;
10252 }
10253 }
10254
10255 /* FReg operations. */
10256 switch (dispatch)
10257 {
10258 case 2: fstrq_wb (cpu, imm, wb); return;
10259 case 3: fldrq_wb (cpu, imm, wb); return;
10260 case 8: fstrs_wb (cpu, imm, wb); return;
10261 case 9: fldrs_wb (cpu, imm, wb); return;
10262 case 12: fstrd_wb (cpu, imm, wb); return;
10263 case 13: fldrd_wb (cpu, imm, wb); return;
10264
10265 case 0: /* STUR 8 bit FP. */
10266 case 1: /* LDUR 8 bit FP. */
10267 case 4: /* STUR 16 bit FP. */
10268 case 5: /* LDUR 8 bit FP. */
10269 HALT_NYI;
10270
10271 default:
10272 case 6:
10273 case 7:
10274 case 10:
10275 case 11:
10276 case 14:
10277 case 15:
10278 HALT_UNALLOC;
10279 }
10280}
10281
10282static void
10283dexLoadRegisterOffset (sim_cpu *cpu)
10284{
10285 /* instr[31,30] = size
10286 instr[29,27] = 111
10287 instr[26] = V
10288 instr[25,24] = 00
10289 instr[23,22] = opc
10290 instr[21] = 1
10291 instr[20,16] = rm
10292 instr[15,13] = option : 010 ==> UXTW, 011 ==> UXTX/LSL,
10293 110 ==> SXTW, 111 ==> SXTX,
10294 ow ==> RESERVED
10295 instr[12] = scaled
10296 instr[11,10] = 10
10297 instr[9,5] = rn
10298 instr[4,0] = rt. */
10299
ef0d8ffc
NC
10300 uint32_t V = INSTR (26, 26);
10301 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
10302 Scaling scale = INSTR (12, 12);
10303 Extension extensionType = INSTR (15, 13);
2e8cf49e
NC
10304
10305 /* Check for illegal extension types. */
10306 if (uimm (extensionType, 1, 1) == 0)
10307 HALT_UNALLOC;
10308
10309 if (extensionType == UXTX || extensionType == SXTX)
10310 extensionType = NoExtension;
10311
10312 if (!V)
10313 {
10314 /* GReg operations. */
10315 switch (dispatch)
10316 {
10317 case 0: strb_scale_ext (cpu, scale, extensionType); return;
10318 case 1: ldrb32_scale_ext (cpu, scale, extensionType); return;
10319 case 2: ldrsb_scale_ext (cpu, scale, extensionType); return;
10320 case 3: ldrsb32_scale_ext (cpu, scale, extensionType); return;
10321 case 4: strh_scale_ext (cpu, scale, extensionType); return;
10322 case 5: ldrh32_scale_ext (cpu, scale, extensionType); return;
10323 case 6: ldrsh_scale_ext (cpu, scale, extensionType); return;
10324 case 7: ldrsh32_scale_ext (cpu, scale, extensionType); return;
10325 case 8: str32_scale_ext (cpu, scale, extensionType); return;
10326 case 9: ldr32_scale_ext (cpu, scale, extensionType); return;
10327 case 10: ldrsw_scale_ext (cpu, scale, extensionType); return;
10328 case 12: str_scale_ext (cpu, scale, extensionType); return;
10329 case 13: ldr_scale_ext (cpu, scale, extensionType); return;
10330 case 14: prfm_scale_ext (cpu, scale, extensionType); return;
10331
10332 default:
10333 case 11:
10334 case 15:
10335 HALT_UNALLOC;
10336 }
10337 }
10338
10339 /* FReg operations. */
10340 switch (dispatch)
10341 {
10342 case 1: /* LDUR 8 bit FP. */
10343 HALT_NYI;
10344 case 3: fldrq_scale_ext (cpu, scale, extensionType); return;
10345 case 5: /* LDUR 8 bit FP. */
10346 HALT_NYI;
10347 case 9: fldrs_scale_ext (cpu, scale, extensionType); return;
10348 case 13: fldrd_scale_ext (cpu, scale, extensionType); return;
10349
10350 case 0: fstrb_scale_ext (cpu, scale, extensionType); return;
10351 case 2: fstrq_scale_ext (cpu, scale, extensionType); return;
10352 case 4: fstrh_scale_ext (cpu, scale, extensionType); return;
10353 case 8: fstrs_scale_ext (cpu, scale, extensionType); return;
10354 case 12: fstrd_scale_ext (cpu, scale, extensionType); return;
10355
10356 default:
10357 case 6:
10358 case 7:
10359 case 10:
10360 case 11:
10361 case 14:
10362 case 15:
10363 HALT_UNALLOC;
10364 }
10365}
10366
10367static void
10368dexLoadUnsignedImmediate (sim_cpu *cpu)
10369{
5ab6d79e 10370 /* instr[29,24] == 111_01
2e8cf49e 10371 instr[31,30] = size
5ab6d79e 10372 instr[26] = V
2e8cf49e
NC
10373 instr[23,22] = opc
10374 instr[21,10] = uimm12 : unsigned immediate offset
5ab6d79e
NC
10375 instr[9,5] = rn may be SP.
10376 instr[4,0] = rt. */
ef0d8ffc
NC
10377
10378 uint32_t V = INSTR (26,26);
7517e550 10379 uint32_t dispatch = ((INSTR (31, 30) << 2) | INSTR (23, 22));
ef0d8ffc 10380 uint32_t imm = INSTR (21, 10);
2e8cf49e
NC
10381
10382 if (!V)
10383 {
10384 /* GReg operations. */
10385 switch (dispatch)
10386 {
10387 case 0: strb_abs (cpu, imm); return;
10388 case 1: ldrb32_abs (cpu, imm); return;
10389 case 2: ldrsb_abs (cpu, imm); return;
10390 case 3: ldrsb32_abs (cpu, imm); return;
10391 case 4: strh_abs (cpu, imm); return;
10392 case 5: ldrh32_abs (cpu, imm); return;
10393 case 6: ldrsh_abs (cpu, imm); return;
10394 case 7: ldrsh32_abs (cpu, imm); return;
10395 case 8: str32_abs (cpu, imm); return;
10396 case 9: ldr32_abs (cpu, imm); return;
10397 case 10: ldrsw_abs (cpu, imm); return;
10398 case 12: str_abs (cpu, imm); return;
10399 case 13: ldr_abs (cpu, imm); return;
10400 case 14: prfm_abs (cpu, imm); return;
10401
10402 default:
10403 case 11:
10404 case 15:
10405 HALT_UNALLOC;
10406 }
10407 }
10408
10409 /* FReg operations. */
10410 switch (dispatch)
10411 {
2e8cf49e 10412 case 0: fstrb_abs (cpu, imm); return;
2e8cf49e
NC
10413 case 4: fstrh_abs (cpu, imm); return;
10414 case 8: fstrs_abs (cpu, imm); return;
10415 case 12: fstrd_abs (cpu, imm); return;
5ab6d79e 10416 case 2: fstrq_abs (cpu, imm); return;
2e8cf49e 10417
5ab6d79e
NC
10418 case 1: fldrb_abs (cpu, imm); return;
10419 case 5: fldrh_abs (cpu, imm); return;
10420 case 9: fldrs_abs (cpu, imm); return;
10421 case 13: fldrd_abs (cpu, imm); return;
10422 case 3: fldrq_abs (cpu, imm); return;
2e8cf49e
NC
10423
10424 default:
10425 case 6:
10426 case 7:
10427 case 10:
10428 case 11:
10429 case 14:
10430 case 15:
10431 HALT_UNALLOC;
10432 }
10433}
10434
10435static void
10436dexLoadExclusive (sim_cpu *cpu)
10437{
10438 /* assert instr[29:24] = 001000;
10439 instr[31,30] = size
10440 instr[23] = 0 if exclusive
10441 instr[22] = L : 1 if load, 0 if store
10442 instr[21] = 1 if pair
10443 instr[20,16] = Rs
10444 instr[15] = o0 : 1 if ordered
10445 instr[14,10] = Rt2
10446 instr[9,5] = Rn
10447 instr[4.0] = Rt. */
10448
ef0d8ffc 10449 switch (INSTR (22, 21))
2e8cf49e
NC
10450 {
10451 case 2: ldxr (cpu); return;
10452 case 0: stxr (cpu); return;
10453 default: HALT_NYI;
10454 }
10455}
10456
10457static void
10458dexLoadOther (sim_cpu *cpu)
10459{
10460 uint32_t dispatch;
10461
10462 /* instr[29,25] = 111_0
10463 instr[24] == 0 ==> dispatch, 1 ==> ldst reg unsigned immediate
10464 instr[21:11,10] is the secondary dispatch. */
ef0d8ffc 10465 if (INSTR (24, 24))
2e8cf49e
NC
10466 {
10467 dexLoadUnsignedImmediate (cpu);
10468 return;
10469 }
10470
7517e550 10471 dispatch = ((INSTR (21, 21) << 2) | INSTR (11, 10));
2e8cf49e
NC
10472 switch (dispatch)
10473 {
10474 case 0: dexLoadUnscaledImmediate (cpu); return;
10475 case 1: dexLoadImmediatePrePost (cpu); return;
10476 case 3: dexLoadImmediatePrePost (cpu); return;
10477 case 6: dexLoadRegisterOffset (cpu); return;
10478
10479 default:
10480 case 2:
10481 case 4:
10482 case 5:
10483 case 7:
10484 HALT_NYI;
10485 }
10486}
10487
10488static void
10489store_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10490{
ef0d8ffc
NC
10491 unsigned rn = INSTR (14, 10);
10492 unsigned rd = INSTR (9, 5);
10493 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10494 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10495
10496 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10497 HALT_UNALLOC; /* ??? */
10498
10499 offset <<= 2;
10500
10501 if (wb != Post)
10502 address += offset;
10503
10504 aarch64_set_mem_u32 (cpu, address,
10505 aarch64_get_reg_u32 (cpu, rm, NO_SP));
10506 aarch64_set_mem_u32 (cpu, address + 4,
10507 aarch64_get_reg_u32 (cpu, rn, NO_SP));
10508
10509 if (wb == Post)
10510 address += offset;
10511
10512 if (wb != NoWriteBack)
10513 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10514}
10515
10516static void
10517store_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10518{
ef0d8ffc
NC
10519 unsigned rn = INSTR (14, 10);
10520 unsigned rd = INSTR (9, 5);
10521 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10522 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10523
10524 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10525 HALT_UNALLOC; /* ??? */
10526
10527 offset <<= 3;
10528
10529 if (wb != Post)
10530 address += offset;
10531
10532 aarch64_set_mem_u64 (cpu, address,
7517e550 10533 aarch64_get_reg_u64 (cpu, rm, NO_SP));
2e8cf49e 10534 aarch64_set_mem_u64 (cpu, address + 8,
7517e550 10535 aarch64_get_reg_u64 (cpu, rn, NO_SP));
2e8cf49e
NC
10536
10537 if (wb == Post)
10538 address += offset;
10539
10540 if (wb != NoWriteBack)
10541 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10542}
10543
10544static void
10545load_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10546{
ef0d8ffc
NC
10547 unsigned rn = INSTR (14, 10);
10548 unsigned rd = INSTR (9, 5);
10549 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10550 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10551
7517e550 10552 /* Treat this as unalloc to make sure we don't do it. */
2e8cf49e
NC
10553 if (rn == rm)
10554 HALT_UNALLOC;
10555
10556 offset <<= 2;
10557
10558 if (wb != Post)
10559 address += offset;
10560
10561 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u32 (cpu, address));
10562 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u32 (cpu, address + 4));
10563
10564 if (wb == Post)
10565 address += offset;
10566
10567 if (wb != NoWriteBack)
10568 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10569}
10570
10571static void
10572load_pair_s32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10573{
ef0d8ffc
NC
10574 unsigned rn = INSTR (14, 10);
10575 unsigned rd = INSTR (9, 5);
10576 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10577 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10578
10579 /* Treat this as unalloc to make sure we don't do it. */
10580 if (rn == rm)
10581 HALT_UNALLOC;
10582
10583 offset <<= 2;
10584
10585 if (wb != Post)
10586 address += offset;
10587
10588 aarch64_set_reg_s64 (cpu, rm, SP_OK, aarch64_get_mem_s32 (cpu, address));
10589 aarch64_set_reg_s64 (cpu, rn, SP_OK, aarch64_get_mem_s32 (cpu, address + 4));
10590
10591 if (wb == Post)
10592 address += offset;
10593
10594 if (wb != NoWriteBack)
10595 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10596}
10597
10598static void
10599load_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10600{
ef0d8ffc
NC
10601 unsigned rn = INSTR (14, 10);
10602 unsigned rd = INSTR (9, 5);
10603 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10604 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10605
10606 /* Treat this as unalloc to make sure we don't do it. */
10607 if (rn == rm)
10608 HALT_UNALLOC;
10609
10610 offset <<= 3;
10611
10612 if (wb != Post)
10613 address += offset;
10614
10615 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u64 (cpu, address));
10616 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u64 (cpu, address + 8));
10617
10618 if (wb == Post)
10619 address += offset;
10620
10621 if (wb != NoWriteBack)
10622 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10623}
10624
10625static void
10626dex_load_store_pair_gr (sim_cpu *cpu)
10627{
10628 /* instr[31,30] = size (10=> 64-bit, 01=> signed 32-bit, 00=> 32-bit)
10629 instr[29,25] = instruction encoding: 101_0
10630 instr[26] = V : 1 if fp 0 if gp
10631 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10632 instr[22] = load/store (1=> load)
10633 instr[21,15] = signed, scaled, offset
10634 instr[14,10] = Rn
10635 instr[ 9, 5] = Rd
10636 instr[ 4, 0] = Rm. */
10637
7517e550 10638 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
10639 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10640
10641 switch (dispatch)
10642 {
10643 case 2: store_pair_u32 (cpu, offset, Post); return;
10644 case 3: load_pair_u32 (cpu, offset, Post); return;
10645 case 4: store_pair_u32 (cpu, offset, NoWriteBack); return;
10646 case 5: load_pair_u32 (cpu, offset, NoWriteBack); return;
10647 case 6: store_pair_u32 (cpu, offset, Pre); return;
10648 case 7: load_pair_u32 (cpu, offset, Pre); return;
10649
10650 case 11: load_pair_s32 (cpu, offset, Post); return;
10651 case 13: load_pair_s32 (cpu, offset, NoWriteBack); return;
10652 case 15: load_pair_s32 (cpu, offset, Pre); return;
10653
10654 case 18: store_pair_u64 (cpu, offset, Post); return;
10655 case 19: load_pair_u64 (cpu, offset, Post); return;
10656 case 20: store_pair_u64 (cpu, offset, NoWriteBack); return;
10657 case 21: load_pair_u64 (cpu, offset, NoWriteBack); return;
10658 case 22: store_pair_u64 (cpu, offset, Pre); return;
10659 case 23: load_pair_u64 (cpu, offset, Pre); return;
10660
10661 default:
10662 HALT_UNALLOC;
10663 }
10664}
10665
10666static void
10667store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10668{
ef0d8ffc
NC
10669 unsigned rn = INSTR (14, 10);
10670 unsigned rd = INSTR (9, 5);
10671 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10672 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10673
10674 offset <<= 2;
10675
10676 if (wb != Post)
10677 address += offset;
10678
e101a78b
NC
10679 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, rm, 0));
10680 aarch64_set_mem_u32 (cpu, address + 4, aarch64_get_vec_u32 (cpu, rn, 0));
2e8cf49e
NC
10681
10682 if (wb == Post)
10683 address += offset;
10684
10685 if (wb != NoWriteBack)
10686 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10687}
10688
10689static void
10690store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10691{
ef0d8ffc
NC
10692 unsigned rn = INSTR (14, 10);
10693 unsigned rd = INSTR (9, 5);
10694 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10695 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10696
10697 offset <<= 3;
10698
10699 if (wb != Post)
10700 address += offset;
10701
e101a78b
NC
10702 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, rm, 0));
10703 aarch64_set_mem_u64 (cpu, address + 8, aarch64_get_vec_u64 (cpu, rn, 0));
2e8cf49e
NC
10704
10705 if (wb == Post)
10706 address += offset;
10707
10708 if (wb != NoWriteBack)
10709 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10710}
10711
10712static void
10713store_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10714{
10715 FRegister a;
ef0d8ffc
NC
10716 unsigned rn = INSTR (14, 10);
10717 unsigned rd = INSTR (9, 5);
10718 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10719 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10720
10721 offset <<= 4;
10722
10723 if (wb != Post)
10724 address += offset;
10725
10726 aarch64_get_FP_long_double (cpu, rm, & a);
10727 aarch64_set_mem_long_double (cpu, address, a);
10728 aarch64_get_FP_long_double (cpu, rn, & a);
10729 aarch64_set_mem_long_double (cpu, address + 16, a);
10730
10731 if (wb == Post)
10732 address += offset;
10733
10734 if (wb != NoWriteBack)
10735 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10736}
10737
10738static void
10739load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10740{
ef0d8ffc
NC
10741 unsigned rn = INSTR (14, 10);
10742 unsigned rd = INSTR (9, 5);
10743 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10744 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10745
10746 if (rm == rn)
10747 HALT_UNALLOC;
10748
10749 offset <<= 2;
10750
10751 if (wb != Post)
10752 address += offset;
10753
e101a78b
NC
10754 aarch64_set_vec_u32 (cpu, rm, 0, aarch64_get_mem_u32 (cpu, address));
10755 aarch64_set_vec_u32 (cpu, rn, 0, aarch64_get_mem_u32 (cpu, address + 4));
2e8cf49e
NC
10756
10757 if (wb == Post)
10758 address += offset;
10759
10760 if (wb != NoWriteBack)
10761 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10762}
10763
10764static void
10765load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10766{
ef0d8ffc
NC
10767 unsigned rn = INSTR (14, 10);
10768 unsigned rd = INSTR (9, 5);
10769 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10770 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10771
10772 if (rm == rn)
10773 HALT_UNALLOC;
10774
10775 offset <<= 3;
10776
10777 if (wb != Post)
10778 address += offset;
10779
e101a78b
NC
10780 aarch64_set_vec_u64 (cpu, rm, 0, aarch64_get_mem_u64 (cpu, address));
10781 aarch64_set_vec_u64 (cpu, rn, 0, aarch64_get_mem_u64 (cpu, address + 8));
2e8cf49e
NC
10782
10783 if (wb == Post)
10784 address += offset;
10785
10786 if (wb != NoWriteBack)
10787 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10788}
10789
10790static void
10791load_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10792{
10793 FRegister a;
ef0d8ffc
NC
10794 unsigned rn = INSTR (14, 10);
10795 unsigned rd = INSTR (9, 5);
10796 unsigned rm = INSTR (4, 0);
2e8cf49e
NC
10797 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10798
10799 if (rm == rn)
10800 HALT_UNALLOC;
10801
10802 offset <<= 4;
10803
10804 if (wb != Post)
10805 address += offset;
10806
10807 aarch64_get_mem_long_double (cpu, address, & a);
10808 aarch64_set_FP_long_double (cpu, rm, a);
10809 aarch64_get_mem_long_double (cpu, address + 16, & a);
10810 aarch64_set_FP_long_double (cpu, rn, a);
10811
10812 if (wb == Post)
10813 address += offset;
10814
10815 if (wb != NoWriteBack)
10816 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10817}
10818
10819static void
10820dex_load_store_pair_fp (sim_cpu *cpu)
10821{
10822 /* instr[31,30] = size (10=> 128-bit, 01=> 64-bit, 00=> 32-bit)
10823 instr[29,25] = instruction encoding
10824 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10825 instr[22] = load/store (1=> load)
10826 instr[21,15] = signed, scaled, offset
10827 instr[14,10] = Rn
10828 instr[ 9, 5] = Rd
10829 instr[ 4, 0] = Rm */
10830
7517e550 10831 uint32_t dispatch = ((INSTR (31, 30) << 3) | INSTR (24, 22));
2e8cf49e
NC
10832 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10833
10834 switch (dispatch)
10835 {
10836 case 2: store_pair_float (cpu, offset, Post); return;
10837 case 3: load_pair_float (cpu, offset, Post); return;
10838 case 4: store_pair_float (cpu, offset, NoWriteBack); return;
10839 case 5: load_pair_float (cpu, offset, NoWriteBack); return;
10840 case 6: store_pair_float (cpu, offset, Pre); return;
10841 case 7: load_pair_float (cpu, offset, Pre); return;
10842
10843 case 10: store_pair_double (cpu, offset, Post); return;
10844 case 11: load_pair_double (cpu, offset, Post); return;
10845 case 12: store_pair_double (cpu, offset, NoWriteBack); return;
10846 case 13: load_pair_double (cpu, offset, NoWriteBack); return;
10847 case 14: store_pair_double (cpu, offset, Pre); return;
10848 case 15: load_pair_double (cpu, offset, Pre); return;
10849
10850 case 18: store_pair_long_double (cpu, offset, Post); return;
10851 case 19: load_pair_long_double (cpu, offset, Post); return;
10852 case 20: store_pair_long_double (cpu, offset, NoWriteBack); return;
10853 case 21: load_pair_long_double (cpu, offset, NoWriteBack); return;
10854 case 22: store_pair_long_double (cpu, offset, Pre); return;
10855 case 23: load_pair_long_double (cpu, offset, Pre); return;
10856
10857 default:
10858 HALT_UNALLOC;
10859 }
10860}
10861
10862static inline unsigned
10863vec_reg (unsigned v, unsigned o)
10864{
10865 return (v + o) & 0x3F;
10866}
10867
10868/* Load multiple N-element structures to N consecutive registers. */
10869static void
10870vec_load (sim_cpu *cpu, uint64_t address, unsigned N)
10871{
ef0d8ffc
NC
10872 int all = INSTR (30, 30);
10873 unsigned size = INSTR (11, 10);
10874 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
10875 unsigned i;
10876
10877 switch (size)
10878 {
10879 case 0: /* 8-bit operations. */
10880 if (all)
10881 for (i = 0; i < (16 * N); i++)
10882 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15,
10883 aarch64_get_mem_u8 (cpu, address + i));
10884 else
10885 for (i = 0; i < (8 * N); i++)
10886 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7,
10887 aarch64_get_mem_u8 (cpu, address + i));
10888 return;
10889
10890 case 1: /* 16-bit operations. */
10891 if (all)
10892 for (i = 0; i < (8 * N); i++)
10893 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7,
10894 aarch64_get_mem_u16 (cpu, address + i * 2));
10895 else
10896 for (i = 0; i < (4 * N); i++)
10897 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3,
10898 aarch64_get_mem_u16 (cpu, address + i * 2));
10899 return;
10900
10901 case 2: /* 32-bit operations. */
10902 if (all)
10903 for (i = 0; i < (4 * N); i++)
10904 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3,
10905 aarch64_get_mem_u32 (cpu, address + i * 4));
10906 else
10907 for (i = 0; i < (2 * N); i++)
10908 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1,
10909 aarch64_get_mem_u32 (cpu, address + i * 4));
10910 return;
10911
10912 case 3: /* 64-bit operations. */
10913 if (all)
10914 for (i = 0; i < (2 * N); i++)
10915 aarch64_set_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1,
10916 aarch64_get_mem_u64 (cpu, address + i * 8));
10917 else
10918 for (i = 0; i < N; i++)
10919 aarch64_set_vec_u64 (cpu, vec_reg (vd, i), 0,
10920 aarch64_get_mem_u64 (cpu, address + i * 8));
10921 return;
2e8cf49e
NC
10922 }
10923}
10924
10925/* LD4: load multiple 4-element to four consecutive registers. */
10926static void
10927LD4 (sim_cpu *cpu, uint64_t address)
10928{
10929 vec_load (cpu, address, 4);
10930}
10931
10932/* LD3: load multiple 3-element structures to three consecutive registers. */
10933static void
10934LD3 (sim_cpu *cpu, uint64_t address)
10935{
10936 vec_load (cpu, address, 3);
10937}
10938
10939/* LD2: load multiple 2-element structures to two consecutive registers. */
10940static void
10941LD2 (sim_cpu *cpu, uint64_t address)
10942{
10943 vec_load (cpu, address, 2);
10944}
10945
10946/* Load multiple 1-element structures into one register. */
10947static void
10948LD1_1 (sim_cpu *cpu, uint64_t address)
10949{
ef0d8ffc
NC
10950 int all = INSTR (30, 30);
10951 unsigned size = INSTR (11, 10);
10952 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
10953 unsigned i;
10954
10955 switch (size)
10956 {
10957 case 0:
10958 /* LD1 {Vd.16b}, addr, #16 */
10959 /* LD1 {Vd.8b}, addr, #8 */
10960 for (i = 0; i < (all ? 16 : 8); i++)
10961 aarch64_set_vec_u8 (cpu, vd, i,
10962 aarch64_get_mem_u8 (cpu, address + i));
10963 return;
10964
10965 case 1:
10966 /* LD1 {Vd.8h}, addr, #16 */
10967 /* LD1 {Vd.4h}, addr, #8 */
10968 for (i = 0; i < (all ? 8 : 4); i++)
10969 aarch64_set_vec_u16 (cpu, vd, i,
10970 aarch64_get_mem_u16 (cpu, address + i * 2));
10971 return;
10972
10973 case 2:
10974 /* LD1 {Vd.4s}, addr, #16 */
10975 /* LD1 {Vd.2s}, addr, #8 */
10976 for (i = 0; i < (all ? 4 : 2); i++)
10977 aarch64_set_vec_u32 (cpu, vd, i,
10978 aarch64_get_mem_u32 (cpu, address + i * 4));
10979 return;
10980
10981 case 3:
10982 /* LD1 {Vd.2d}, addr, #16 */
10983 /* LD1 {Vd.1d}, addr, #8 */
10984 for (i = 0; i < (all ? 2 : 1); i++)
10985 aarch64_set_vec_u64 (cpu, vd, i,
10986 aarch64_get_mem_u64 (cpu, address + i * 8));
10987 return;
2e8cf49e
NC
10988 }
10989}
10990
10991/* Load multiple 1-element structures into two registers. */
10992static void
10993LD1_2 (sim_cpu *cpu, uint64_t address)
10994{
10995 /* FIXME: This algorithm is *exactly* the same as the LD2 version.
10996 So why have two different instructions ? There must be something
10997 wrong somewhere. */
10998 vec_load (cpu, address, 2);
10999}
11000
11001/* Load multiple 1-element structures into three registers. */
11002static void
11003LD1_3 (sim_cpu *cpu, uint64_t address)
11004{
11005 /* FIXME: This algorithm is *exactly* the same as the LD3 version.
11006 So why have two different instructions ? There must be something
11007 wrong somewhere. */
11008 vec_load (cpu, address, 3);
11009}
11010
11011/* Load multiple 1-element structures into four registers. */
11012static void
11013LD1_4 (sim_cpu *cpu, uint64_t address)
11014{
11015 /* FIXME: This algorithm is *exactly* the same as the LD4 version.
11016 So why have two different instructions ? There must be something
11017 wrong somewhere. */
11018 vec_load (cpu, address, 4);
11019}
11020
11021/* Store multiple N-element structures to N consecutive registers. */
11022static void
11023vec_store (sim_cpu *cpu, uint64_t address, unsigned N)
11024{
ef0d8ffc
NC
11025 int all = INSTR (30, 30);
11026 unsigned size = INSTR (11, 10);
11027 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11028 unsigned i;
11029
11030 switch (size)
11031 {
11032 case 0: /* 8-bit operations. */
11033 if (all)
11034 for (i = 0; i < (16 * N); i++)
11035 aarch64_set_mem_u8
11036 (cpu, address + i,
11037 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15));
11038 else
11039 for (i = 0; i < (8 * N); i++)
11040 aarch64_set_mem_u8
11041 (cpu, address + i,
11042 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7));
11043 return;
11044
11045 case 1: /* 16-bit operations. */
11046 if (all)
11047 for (i = 0; i < (8 * N); i++)
11048 aarch64_set_mem_u16
11049 (cpu, address + i * 2,
11050 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7));
11051 else
11052 for (i = 0; i < (4 * N); i++)
11053 aarch64_set_mem_u16
11054 (cpu, address + i * 2,
11055 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3));
11056 return;
11057
11058 case 2: /* 32-bit operations. */
11059 if (all)
11060 for (i = 0; i < (4 * N); i++)
11061 aarch64_set_mem_u32
11062 (cpu, address + i * 4,
11063 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3));
11064 else
11065 for (i = 0; i < (2 * N); i++)
11066 aarch64_set_mem_u32
11067 (cpu, address + i * 4,
11068 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1));
11069 return;
11070
11071 case 3: /* 64-bit operations. */
11072 if (all)
11073 for (i = 0; i < (2 * N); i++)
11074 aarch64_set_mem_u64
11075 (cpu, address + i * 8,
11076 aarch64_get_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1));
11077 else
11078 for (i = 0; i < N; i++)
11079 aarch64_set_mem_u64
11080 (cpu, address + i * 8,
11081 aarch64_get_vec_u64 (cpu, vec_reg (vd, i), 0));
11082 return;
2e8cf49e
NC
11083 }
11084}
11085
11086/* Store multiple 4-element structure to four consecutive registers. */
11087static void
11088ST4 (sim_cpu *cpu, uint64_t address)
11089{
11090 vec_store (cpu, address, 4);
11091}
11092
11093/* Store multiple 3-element structures to three consecutive registers. */
11094static void
11095ST3 (sim_cpu *cpu, uint64_t address)
11096{
11097 vec_store (cpu, address, 3);
11098}
11099
11100/* Store multiple 2-element structures to two consecutive registers. */
11101static void
11102ST2 (sim_cpu *cpu, uint64_t address)
11103{
11104 vec_store (cpu, address, 2);
11105}
11106
11107/* Store multiple 1-element structures into one register. */
11108static void
11109ST1_1 (sim_cpu *cpu, uint64_t address)
11110{
ef0d8ffc
NC
11111 int all = INSTR (30, 30);
11112 unsigned size = INSTR (11, 10);
11113 unsigned vd = INSTR (4, 0);
2e8cf49e
NC
11114 unsigned i;
11115
11116 switch (size)
11117 {
11118 case 0:
11119 for (i = 0; i < (all ? 16 : 8); i++)
11120 aarch64_set_mem_u8 (cpu, address + i,
11121 aarch64_get_vec_u8 (cpu, vd, i));
11122 return;
11123
11124 case 1:
11125 for (i = 0; i < (all ? 8 : 4); i++)
11126 aarch64_set_mem_u16 (cpu, address + i * 2,
11127 aarch64_get_vec_u16 (cpu, vd, i));
11128 return;
11129
11130 case 2:
11131 for (i = 0; i < (all ? 4 : 2); i++)
11132 aarch64_set_mem_u32 (cpu, address + i * 4,
11133 aarch64_get_vec_u32 (cpu, vd, i));
11134 return;
11135
11136 case 3:
11137 for (i = 0; i < (all ? 2 : 1); i++)
11138 aarch64_set_mem_u64 (cpu, address + i * 8,
11139 aarch64_get_vec_u64 (cpu, vd, i));
11140 return;
2e8cf49e
NC
11141 }
11142}
11143
11144/* Store multiple 1-element structures into two registers. */
11145static void
11146ST1_2 (sim_cpu *cpu, uint64_t address)
11147{
11148 /* FIXME: This algorithm is *exactly* the same as the ST2 version.
11149 So why have two different instructions ? There must be
11150 something wrong somewhere. */
11151 vec_store (cpu, address, 2);
11152}
11153
11154/* Store multiple 1-element structures into three registers. */
11155static void
11156ST1_3 (sim_cpu *cpu, uint64_t address)
11157{
11158 /* FIXME: This algorithm is *exactly* the same as the ST3 version.
11159 So why have two different instructions ? There must be
11160 something wrong somewhere. */
11161 vec_store (cpu, address, 3);
11162}
11163
11164/* Store multiple 1-element structures into four registers. */
11165static void
11166ST1_4 (sim_cpu *cpu, uint64_t address)
11167{
11168 /* FIXME: This algorithm is *exactly* the same as the ST4 version.
11169 So why have two different instructions ? There must be
11170 something wrong somewhere. */
11171 vec_store (cpu, address, 4);
11172}
11173
11174static void
11175do_vec_LDnR (sim_cpu *cpu, uint64_t address)
11176{
11177 /* instr[31] = 0
11178 instr[30] = element selector 0=>half, 1=>all elements
11179 instr[29,24] = 00 1101
11180 instr[23] = 0=>simple, 1=>post
11181 instr[22] = 1
11182 instr[21] = width: LD1R-or-LD3R (0) / LD2R-or-LD4R (1)
11183 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
11184 11111 (immediate post inc)
11185 instr[15,14] = 11
11186 instr[13] = width: LD1R-or-LD2R (0) / LD3R-or-LD4R (1)
11187 instr[12] = 0
11188 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11189 10=> word(s), 11=> double(d)
11190 instr[9,5] = address
11191 instr[4,0] = Vd */
11192
ef0d8ffc
NC
11193 unsigned full = INSTR (30, 30);
11194 unsigned vd = INSTR (4, 0);
11195 unsigned size = INSTR (11, 10);
2e8cf49e
NC
11196 int i;
11197
11198 NYI_assert (29, 24, 0x0D);
11199 NYI_assert (22, 22, 1);
11200 NYI_assert (15, 14, 3);
11201 NYI_assert (12, 12, 0);
11202
7517e550 11203 switch ((INSTR (13, 13) << 1) | INSTR (21, 21))
2e8cf49e
NC
11204 {
11205 case 0: /* LD1R. */
11206 switch (size)
11207 {
11208 case 0:
11209 {
11210 uint8_t val = aarch64_get_mem_u8 (cpu, address);
11211 for (i = 0; i < (full ? 16 : 8); i++)
11212 aarch64_set_vec_u8 (cpu, vd, i, val);
11213 break;
11214 }
11215
11216 case 1:
11217 {
11218 uint16_t val = aarch64_get_mem_u16 (cpu, address);
11219 for (i = 0; i < (full ? 8 : 4); i++)
11220 aarch64_set_vec_u16 (cpu, vd, i, val);
11221 break;
11222 }
11223
11224 case 2:
11225 {
11226 uint32_t val = aarch64_get_mem_u32 (cpu, address);
11227 for (i = 0; i < (full ? 4 : 2); i++)
11228 aarch64_set_vec_u32 (cpu, vd, i, val);
11229 break;
11230 }
11231
11232 case 3:
11233 {
11234 uint64_t val = aarch64_get_mem_u64 (cpu, address);
11235 for (i = 0; i < (full ? 2 : 1); i++)
11236 aarch64_set_vec_u64 (cpu, vd, i, val);
11237 break;
11238 }
11239
11240 default:
11241 HALT_UNALLOC;
11242 }
11243 break;
11244
11245 case 1: /* LD2R. */
11246 switch (size)
11247 {
11248 case 0:
11249 {
11250 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11251 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11252
11253 for (i = 0; i < (full ? 16 : 8); i++)
11254 {
11255 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11256 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11257 }
11258 break;
11259 }
11260
11261 case 1:
11262 {
11263 uint16_t val1 = aarch64_get_mem_u16 (cpu, address);
11264 uint16_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11265
11266 for (i = 0; i < (full ? 8 : 4); i++)
11267 {
11268 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11269 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11270 }
11271 break;
11272 }
11273
11274 case 2:
11275 {
11276 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11277 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11278
11279 for (i = 0; i < (full ? 4 : 2); i++)
11280 {
11281 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11282 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11283 }
11284 break;
11285 }
11286
11287 case 3:
11288 {
11289 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11290 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11291
11292 for (i = 0; i < (full ? 2 : 1); i++)
11293 {
11294 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11295 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11296 }
11297 break;
11298 }
11299
11300 default:
11301 HALT_UNALLOC;
11302 }
11303 break;
11304
11305 case 2: /* LD3R. */
11306 switch (size)
11307 {
11308 case 0:
11309 {
11310 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11311 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11312 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
11313
11314 for (i = 0; i < (full ? 16 : 8); i++)
11315 {
11316 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11317 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11318 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
11319 }
11320 }
11321 break;
11322
11323 case 1:
11324 {
11325 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
11326 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11327 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
11328
11329 for (i = 0; i < (full ? 8 : 4); i++)
11330 {
11331 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11332 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11333 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
11334 }
11335 }
11336 break;
11337
11338 case 2:
11339 {
11340 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11341 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11342 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
11343
11344 for (i = 0; i < (full ? 4 : 2); i++)
11345 {
11346 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11347 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11348 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
11349 }
11350 }
11351 break;
11352
11353 case 3:
11354 {
11355 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11356 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11357 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
11358
11359 for (i = 0; i < (full ? 2 : 1); i++)
11360 {
11361 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11362 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11363 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
11364 }
11365 }
11366 break;
11367
11368 default:
11369 HALT_UNALLOC;
11370 }
11371 break;
11372
11373 case 3: /* LD4R. */
11374 switch (size)
11375 {
11376 case 0:
11377 {
11378 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
11379 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
11380 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
11381 uint8_t val4 = aarch64_get_mem_u8 (cpu, address + 3);
11382
11383 for (i = 0; i < (full ? 16 : 8); i++)
11384 {
11385 aarch64_set_vec_u8 (cpu, vd, 0, val1);
11386 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
11387 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
11388 aarch64_set_vec_u8 (cpu, vd + 3, 0, val4);
11389 }
11390 }
11391 break;
11392
11393 case 1:
11394 {
11395 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
11396 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
11397 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
11398 uint32_t val4 = aarch64_get_mem_u16 (cpu, address + 6);
11399
11400 for (i = 0; i < (full ? 8 : 4); i++)
11401 {
11402 aarch64_set_vec_u16 (cpu, vd, 0, val1);
11403 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
11404 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
11405 aarch64_set_vec_u16 (cpu, vd + 3, 0, val4);
11406 }
11407 }
11408 break;
11409
11410 case 2:
11411 {
11412 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
11413 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
11414 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
11415 uint32_t val4 = aarch64_get_mem_u32 (cpu, address + 12);
11416
11417 for (i = 0; i < (full ? 4 : 2); i++)
11418 {
11419 aarch64_set_vec_u32 (cpu, vd, 0, val1);
11420 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
11421 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
11422 aarch64_set_vec_u32 (cpu, vd + 3, 0, val4);
11423 }
11424 }
11425 break;
11426
11427 case 3:
11428 {
11429 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
11430 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
11431 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
11432 uint64_t val4 = aarch64_get_mem_u64 (cpu, address + 24);
11433
11434 for (i = 0; i < (full ? 2 : 1); i++)
11435 {
11436 aarch64_set_vec_u64 (cpu, vd, 0, val1);
11437 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
11438 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
11439 aarch64_set_vec_u64 (cpu, vd + 3, 0, val4);
11440 }
11441 }
11442 break;
11443
11444 default:
11445 HALT_UNALLOC;
11446 }
11447 break;
11448
11449 default:
11450 HALT_UNALLOC;
11451 }
11452}
11453
11454static void
11455do_vec_load_store (sim_cpu *cpu)
11456{
11457 /* {LD|ST}<N> {Vd..Vd+N}, vaddr
11458
11459 instr[31] = 0
11460 instr[30] = element selector 0=>half, 1=>all elements
11461 instr[29,25] = 00110
11462 instr[24] = ?
11463 instr[23] = 0=>simple, 1=>post
11464 instr[22] = 0=>store, 1=>load
11465 instr[21] = 0 (LDn) / small(0)-large(1) selector (LDnR)
11466 instr[20,16] = 00000 (simple), Vinc (reg-post-inc, no SP),
11467 11111 (immediate post inc)
11468 instr[15,12] = elements and destinations. eg for load:
11469 0000=>LD4 => load multiple 4-element to
11470 four consecutive registers
11471 0100=>LD3 => load multiple 3-element to
11472 three consecutive registers
11473 1000=>LD2 => load multiple 2-element to
11474 two consecutive registers
11475 0010=>LD1 => load multiple 1-element to
11476 four consecutive registers
11477 0110=>LD1 => load multiple 1-element to
11478 three consecutive registers
11479 1010=>LD1 => load multiple 1-element to
11480 two consecutive registers
11481 0111=>LD1 => load multiple 1-element to
11482 one register
11483 1100=>LDR1,LDR2
11484 1110=>LDR3,LDR4
11485 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11486 10=> word(s), 11=> double(d)
11487 instr[9,5] = Vn, can be SP
11488 instr[4,0] = Vd */
11489
11490 int post;
11491 int load;
11492 unsigned vn;
11493 uint64_t address;
11494 int type;
11495
7517e550 11496 if (INSTR (31, 31) != 0 || INSTR (29, 25) != 0x06)
2e8cf49e
NC
11497 HALT_NYI;
11498
ef0d8ffc
NC
11499 type = INSTR (15, 12);
11500 if (type != 0xE && type != 0xE && INSTR (21, 21) != 0)
2e8cf49e
NC
11501 HALT_NYI;
11502
ef0d8ffc
NC
11503 post = INSTR (23, 23);
11504 load = INSTR (22, 22);
11505 vn = INSTR (9, 5);
2e8cf49e
NC
11506 address = aarch64_get_reg_u64 (cpu, vn, SP_OK);
11507
11508 if (post)
11509 {
ef0d8ffc 11510 unsigned vm = INSTR (20, 16);
2e8cf49e
NC
11511
11512 if (vm == R31)
11513 {
11514 unsigned sizeof_operation;
11515
11516 switch (type)
11517 {
11518 case 0: sizeof_operation = 32; break;
11519 case 4: sizeof_operation = 24; break;
11520 case 8: sizeof_operation = 16; break;
11521
11522 case 0xC:
ef0d8ffc
NC
11523 sizeof_operation = INSTR (21, 21) ? 2 : 1;
11524 sizeof_operation <<= INSTR (11, 10);
2e8cf49e
NC
11525 break;
11526
11527 case 0xE:
ef0d8ffc
NC
11528 sizeof_operation = INSTR (21, 21) ? 8 : 4;
11529 sizeof_operation <<= INSTR (11, 10);
2e8cf49e
NC
11530 break;
11531
2e8cf49e 11532 case 7:
57aa1742
NC
11533 /* One register, immediate offset variant. */
11534 sizeof_operation = 8;
11535 break;
ef0d8ffc 11536
57aa1742
NC
11537 case 10:
11538 /* Two registers, immediate offset variant. */
11539 sizeof_operation = 16;
11540 break;
11541
11542 case 6:
11543 /* Three registers, immediate offset variant. */
11544 sizeof_operation = 24;
11545 break;
11546
11547 case 2:
11548 /* Four registers, immediate offset variant. */
11549 sizeof_operation = 32;
2e8cf49e
NC
11550 break;
11551
11552 default:
11553 HALT_UNALLOC;
11554 }
11555
ef0d8ffc 11556 if (INSTR (30, 30))
2e8cf49e
NC
11557 sizeof_operation *= 2;
11558
11559 aarch64_set_reg_u64 (cpu, vn, SP_OK, address + sizeof_operation);
11560 }
11561 else
11562 aarch64_set_reg_u64 (cpu, vn, SP_OK,
11563 address + aarch64_get_reg_u64 (cpu, vm, NO_SP));
11564 }
11565 else
11566 {
11567 NYI_assert (20, 16, 0);
11568 }
11569
11570 if (load)
11571 {
11572 switch (type)
11573 {
11574 case 0: LD4 (cpu, address); return;
11575 case 4: LD3 (cpu, address); return;
11576 case 8: LD2 (cpu, address); return;
11577 case 2: LD1_4 (cpu, address); return;
11578 case 6: LD1_3 (cpu, address); return;
11579 case 10: LD1_2 (cpu, address); return;
11580 case 7: LD1_1 (cpu, address); return;
11581
11582 case 0xE:
11583 case 0xC: do_vec_LDnR (cpu, address); return;
11584
11585 default:
11586 HALT_NYI;
11587 }
11588 }
11589
11590 /* Stores. */
11591 switch (type)
11592 {
11593 case 0: ST4 (cpu, address); return;
11594 case 4: ST3 (cpu, address); return;
11595 case 8: ST2 (cpu, address); return;
11596 case 2: ST1_4 (cpu, address); return;
11597 case 6: ST1_3 (cpu, address); return;
11598 case 10: ST1_2 (cpu, address); return;
11599 case 7: ST1_1 (cpu, address); return;
11600 default:
11601 HALT_NYI;
11602 }
11603}
11604
11605static void
11606dexLdSt (sim_cpu *cpu)
11607{
11608 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
11609 assert group == GROUP_LDST_0100 || group == GROUP_LDST_0110 ||
11610 group == GROUP_LDST_1100 || group == GROUP_LDST_1110
11611 bits [29,28:26] of a LS are the secondary dispatch vector. */
11612 uint32_t group2 = dispatchLS (aarch64_get_instr (cpu));
11613
11614 switch (group2)
11615 {
11616 case LS_EXCL_000:
11617 dexLoadExclusive (cpu); return;
11618
11619 case LS_LIT_010:
11620 case LS_LIT_011:
11621 dexLoadLiteral (cpu); return;
11622
11623 case LS_OTHER_110:
11624 case LS_OTHER_111:
11625 dexLoadOther (cpu); return;
11626
11627 case LS_ADVSIMD_001:
11628 do_vec_load_store (cpu); return;
11629
11630 case LS_PAIR_100:
11631 dex_load_store_pair_gr (cpu); return;
11632
11633 case LS_PAIR_101:
11634 dex_load_store_pair_fp (cpu); return;
11635
11636 default:
11637 /* Should never reach here. */
11638 HALT_NYI;
11639 }
11640}
11641
11642/* Specific decode and execute for group Data Processing Register. */
11643
11644static void
11645dexLogicalShiftedRegister (sim_cpu *cpu)
11646{
ef0d8ffc
NC
11647 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11648 instr[30,29] = op
11649 instr[28:24] = 01010
2e8cf49e 11650 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> ROR
ef0d8ffc
NC
11651 instr[21] = N
11652 instr[20,16] = Rm
2e8cf49e 11653 instr[15,10] = count : must be 0xxxxx for 32 bit
ef0d8ffc
NC
11654 instr[9,5] = Rn
11655 instr[4,0] = Rd */
2e8cf49e 11656
ef0d8ffc
NC
11657 uint32_t size = INSTR (31, 31);
11658 Shift shiftType = INSTR (23, 22);
11659 uint32_t count = INSTR (15, 10);
2e8cf49e 11660
ef0d8ffc
NC
11661 /* 32 bit operations must have count[5] = 0.
11662 or else we have an UNALLOC. */
11663 if (size == 0 && uimm (count, 5, 5))
2e8cf49e
NC
11664 HALT_UNALLOC;
11665
ef0d8ffc
NC
11666 /* Dispatch on size:op:N. */
11667 switch ((INSTR (31, 29) << 1) | INSTR (21, 21))
2e8cf49e
NC
11668 {
11669 case 0: and32_shift (cpu, shiftType, count); return;
11670 case 1: bic32_shift (cpu, shiftType, count); return;
11671 case 2: orr32_shift (cpu, shiftType, count); return;
11672 case 3: orn32_shift (cpu, shiftType, count); return;
11673 case 4: eor32_shift (cpu, shiftType, count); return;
11674 case 5: eon32_shift (cpu, shiftType, count); return;
11675 case 6: ands32_shift (cpu, shiftType, count); return;
11676 case 7: bics32_shift (cpu, shiftType, count); return;
11677 case 8: and64_shift (cpu, shiftType, count); return;
11678 case 9: bic64_shift (cpu, shiftType, count); return;
11679 case 10:orr64_shift (cpu, shiftType, count); return;
11680 case 11:orn64_shift (cpu, shiftType, count); return;
11681 case 12:eor64_shift (cpu, shiftType, count); return;
11682 case 13:eon64_shift (cpu, shiftType, count); return;
11683 case 14:ands64_shift (cpu, shiftType, count); return;
11684 case 15:bics64_shift (cpu, shiftType, count); return;
2e8cf49e
NC
11685 }
11686}
11687
11688/* 32 bit conditional select. */
11689static void
11690csel32 (sim_cpu *cpu, CondCode cc)
11691{
ef0d8ffc
NC
11692 unsigned rm = INSTR (20, 16);
11693 unsigned rn = INSTR (9, 5);
11694 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11695
11696 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11697 testConditionCode (cpu, cc)
11698 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11699 : aarch64_get_reg_u32 (cpu, rm, NO_SP));
11700}
11701
11702/* 64 bit conditional select. */
11703static void
11704csel64 (sim_cpu *cpu, CondCode cc)
11705{
ef0d8ffc
NC
11706 unsigned rm = INSTR (20, 16);
11707 unsigned rn = INSTR (9, 5);
11708 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11709
11710 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11711 testConditionCode (cpu, cc)
11712 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11713 : aarch64_get_reg_u64 (cpu, rm, NO_SP));
11714}
11715
11716/* 32 bit conditional increment. */
11717static void
11718csinc32 (sim_cpu *cpu, CondCode cc)
11719{
ef0d8ffc
NC
11720 unsigned rm = INSTR (20, 16);
11721 unsigned rn = INSTR (9, 5);
11722 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11723
11724 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11725 testConditionCode (cpu, cc)
11726 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11727 : aarch64_get_reg_u32 (cpu, rm, NO_SP) + 1);
11728}
11729
11730/* 64 bit conditional increment. */
11731static void
11732csinc64 (sim_cpu *cpu, CondCode cc)
11733{
ef0d8ffc
NC
11734 unsigned rm = INSTR (20, 16);
11735 unsigned rn = INSTR (9, 5);
11736 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11737
11738 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11739 testConditionCode (cpu, cc)
11740 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11741 : aarch64_get_reg_u64 (cpu, rm, NO_SP) + 1);
11742}
11743
11744/* 32 bit conditional invert. */
11745static void
11746csinv32 (sim_cpu *cpu, CondCode cc)
11747{
ef0d8ffc
NC
11748 unsigned rm = INSTR (20, 16);
11749 unsigned rn = INSTR (9, 5);
11750 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11751
11752 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11753 testConditionCode (cpu, cc)
11754 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11755 : ~ aarch64_get_reg_u32 (cpu, rm, NO_SP));
11756}
11757
11758/* 64 bit conditional invert. */
11759static void
11760csinv64 (sim_cpu *cpu, CondCode cc)
11761{
ef0d8ffc
NC
11762 unsigned rm = INSTR (20, 16);
11763 unsigned rn = INSTR (9, 5);
11764 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11765
11766 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11767 testConditionCode (cpu, cc)
11768 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11769 : ~ aarch64_get_reg_u64 (cpu, rm, NO_SP));
11770}
11771
11772/* 32 bit conditional negate. */
11773static void
11774csneg32 (sim_cpu *cpu, CondCode cc)
11775{
ef0d8ffc
NC
11776 unsigned rm = INSTR (20, 16);
11777 unsigned rn = INSTR (9, 5);
11778 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11779
11780 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11781 testConditionCode (cpu, cc)
11782 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11783 : - aarch64_get_reg_u32 (cpu, rm, NO_SP));
11784}
11785
11786/* 64 bit conditional negate. */
11787static void
11788csneg64 (sim_cpu *cpu, CondCode cc)
11789{
ef0d8ffc
NC
11790 unsigned rm = INSTR (20, 16);
11791 unsigned rn = INSTR (9, 5);
11792 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11793
11794 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11795 testConditionCode (cpu, cc)
11796 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11797 : - aarch64_get_reg_u64 (cpu, rm, NO_SP));
11798}
11799
11800static void
11801dexCondSelect (sim_cpu *cpu)
11802{
ef0d8ffc
NC
11803 /* instr[28,21] = 11011011
11804 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2e8cf49e
NC
11805 instr[30:11,10] = op : 000 ==> CSEL, 001 ==> CSINC,
11806 100 ==> CSINV, 101 ==> CSNEG,
11807 _1_ ==> UNALLOC
11808 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11809 instr[15,12] = cond
11810 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC */
11811
ef0d8ffc
NC
11812 CondCode cc = INSTR (15, 12);
11813 uint32_t S = INSTR (29, 29);
11814 uint32_t op2 = INSTR (11, 10);
2e8cf49e
NC
11815
11816 if (S == 1)
11817 HALT_UNALLOC;
11818
11819 if (op2 & 0x2)
11820 HALT_UNALLOC;
11821
ef0d8ffc 11822 switch ((INSTR (31, 30) << 1) | op2)
2e8cf49e
NC
11823 {
11824 case 0: csel32 (cpu, cc); return;
11825 case 1: csinc32 (cpu, cc); return;
11826 case 2: csinv32 (cpu, cc); return;
11827 case 3: csneg32 (cpu, cc); return;
11828 case 4: csel64 (cpu, cc); return;
11829 case 5: csinc64 (cpu, cc); return;
11830 case 6: csinv64 (cpu, cc); return;
11831 case 7: csneg64 (cpu, cc); return;
2e8cf49e
NC
11832 }
11833}
11834
11835/* Some helpers for counting leading 1 or 0 bits. */
11836
11837/* Counts the number of leading bits which are the same
11838 in a 32 bit value in the range 1 to 32. */
11839static uint32_t
11840leading32 (uint32_t value)
11841{
11842 int32_t mask= 0xffff0000;
11843 uint32_t count= 16; /* Counts number of bits set in mask. */
11844 uint32_t lo = 1; /* Lower bound for number of sign bits. */
11845 uint32_t hi = 32; /* Upper bound for number of sign bits. */
11846
11847 while (lo + 1 < hi)
11848 {
11849 int32_t test = (value & mask);
11850
11851 if (test == 0 || test == mask)
11852 {
11853 lo = count;
11854 count = (lo + hi) / 2;
11855 mask >>= (count - lo);
11856 }
11857 else
11858 {
11859 hi = count;
11860 count = (lo + hi) / 2;
11861 mask <<= hi - count;
11862 }
11863 }
11864
11865 if (lo != hi)
11866 {
11867 int32_t test;
11868
11869 mask >>= 1;
11870 test = (value & mask);
11871
11872 if (test == 0 || test == mask)
11873 count = hi;
11874 else
11875 count = lo;
11876 }
11877
11878 return count;
11879}
11880
11881/* Counts the number of leading bits which are the same
11882 in a 64 bit value in the range 1 to 64. */
11883static uint64_t
11884leading64 (uint64_t value)
11885{
11886 int64_t mask= 0xffffffff00000000LL;
11887 uint64_t count = 32; /* Counts number of bits set in mask. */
11888 uint64_t lo = 1; /* Lower bound for number of sign bits. */
11889 uint64_t hi = 64; /* Upper bound for number of sign bits. */
11890
11891 while (lo + 1 < hi)
11892 {
11893 int64_t test = (value & mask);
11894
11895 if (test == 0 || test == mask)
11896 {
11897 lo = count;
11898 count = (lo + hi) / 2;
11899 mask >>= (count - lo);
11900 }
11901 else
11902 {
11903 hi = count;
11904 count = (lo + hi) / 2;
11905 mask <<= hi - count;
11906 }
11907 }
11908
11909 if (lo != hi)
11910 {
11911 int64_t test;
11912
11913 mask >>= 1;
11914 test = (value & mask);
11915
11916 if (test == 0 || test == mask)
11917 count = hi;
11918 else
11919 count = lo;
11920 }
11921
11922 return count;
11923}
11924
11925/* Bit operations. */
11926/* N.B register args may not be SP. */
11927
11928/* 32 bit count leading sign bits. */
11929static void
11930cls32 (sim_cpu *cpu)
11931{
ef0d8ffc
NC
11932 unsigned rn = INSTR (9, 5);
11933 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11934
11935 /* N.B. the result needs to exclude the leading bit. */
11936 aarch64_set_reg_u64
11937 (cpu, rd, NO_SP, leading32 (aarch64_get_reg_u32 (cpu, rn, NO_SP)) - 1);
11938}
11939
11940/* 64 bit count leading sign bits. */
11941static void
11942cls64 (sim_cpu *cpu)
11943{
ef0d8ffc
NC
11944 unsigned rn = INSTR (9, 5);
11945 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11946
11947 /* N.B. the result needs to exclude the leading bit. */
11948 aarch64_set_reg_u64
11949 (cpu, rd, NO_SP, leading64 (aarch64_get_reg_u64 (cpu, rn, NO_SP)) - 1);
11950}
11951
11952/* 32 bit count leading zero bits. */
11953static void
11954clz32 (sim_cpu *cpu)
11955{
ef0d8ffc
NC
11956 unsigned rn = INSTR (9, 5);
11957 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11958 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11959
11960 /* if the sign (top) bit is set then the count is 0. */
11961 if (pick32 (value, 31, 31))
11962 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11963 else
11964 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading32 (value));
11965}
11966
11967/* 64 bit count leading zero bits. */
11968static void
11969clz64 (sim_cpu *cpu)
11970{
ef0d8ffc
NC
11971 unsigned rn = INSTR (9, 5);
11972 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11973 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11974
11975 /* if the sign (top) bit is set then the count is 0. */
11976 if (pick64 (value, 63, 63))
11977 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11978 else
11979 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading64 (value));
11980}
11981
11982/* 32 bit reverse bits. */
11983static void
11984rbit32 (sim_cpu *cpu)
11985{
ef0d8ffc
NC
11986 unsigned rn = INSTR (9, 5);
11987 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
11988 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11989 uint32_t result = 0;
11990 int i;
11991
11992 for (i = 0; i < 32; i++)
11993 {
11994 result <<= 1;
11995 result |= (value & 1);
11996 value >>= 1;
11997 }
11998 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11999}
12000
12001/* 64 bit reverse bits. */
12002static void
12003rbit64 (sim_cpu *cpu)
12004{
ef0d8ffc
NC
12005 unsigned rn = INSTR (9, 5);
12006 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12007 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12008 uint64_t result = 0;
12009 int i;
12010
12011 for (i = 0; i < 64; i++)
12012 {
12013 result <<= 1;
57aa1742 12014 result |= (value & 1UL);
2e8cf49e
NC
12015 value >>= 1;
12016 }
12017 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12018}
12019
12020/* 32 bit reverse bytes. */
12021static void
12022rev32 (sim_cpu *cpu)
12023{
ef0d8ffc
NC
12024 unsigned rn = INSTR (9, 5);
12025 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12026 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12027 uint32_t result = 0;
12028 int i;
12029
12030 for (i = 0; i < 4; i++)
12031 {
12032 result <<= 8;
12033 result |= (value & 0xff);
12034 value >>= 8;
12035 }
12036 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12037}
12038
12039/* 64 bit reverse bytes. */
12040static void
12041rev64 (sim_cpu *cpu)
12042{
ef0d8ffc
NC
12043 unsigned rn = INSTR (9, 5);
12044 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12045 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12046 uint64_t result = 0;
12047 int i;
12048
12049 for (i = 0; i < 8; i++)
12050 {
12051 result <<= 8;
12052 result |= (value & 0xffULL);
12053 value >>= 8;
12054 }
12055 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12056}
12057
12058/* 32 bit reverse shorts. */
12059/* N.B.this reverses the order of the bytes in each half word. */
12060static void
12061revh32 (sim_cpu *cpu)
12062{
ef0d8ffc
NC
12063 unsigned rn = INSTR (9, 5);
12064 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12065 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12066 uint32_t result = 0;
12067 int i;
12068
12069 for (i = 0; i < 2; i++)
12070 {
12071 result <<= 8;
12072 result |= (value & 0x00ff00ff);
12073 value >>= 8;
12074 }
12075 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12076}
12077
12078/* 64 bit reverse shorts. */
12079/* N.B.this reverses the order of the bytes in each half word. */
12080static void
12081revh64 (sim_cpu *cpu)
12082{
ef0d8ffc
NC
12083 unsigned rn = INSTR (9, 5);
12084 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12085 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12086 uint64_t result = 0;
12087 int i;
12088
12089 for (i = 0; i < 2; i++)
12090 {
12091 result <<= 8;
12092 result |= (value & 0x00ff00ff00ff00ffULL);
12093 value >>= 8;
12094 }
12095 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
12096}
12097
12098static void
12099dexDataProc1Source (sim_cpu *cpu)
12100{
ef0d8ffc
NC
12101 /* instr[30] = 1
12102 instr[28,21] = 111010110
12103 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12104 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
2e8cf49e
NC
12105 instr[20,16] = opcode2 : 00000 ==> ok, ow ==> UNALLOC
12106 instr[15,10] = opcode : 000000 ==> RBIT, 000001 ==> REV16,
12107 000010 ==> REV, 000011 ==> UNALLOC
12108 000100 ==> CLZ, 000101 ==> CLS
12109 ow ==> UNALLOC
ef0d8ffc
NC
12110 instr[9,5] = rn : may not be SP
12111 instr[4,0] = rd : may not be SP. */
2e8cf49e 12112
ef0d8ffc
NC
12113 uint32_t S = INSTR (29, 29);
12114 uint32_t opcode2 = INSTR (20, 16);
12115 uint32_t opcode = INSTR (15, 10);
12116 uint32_t dispatch = ((INSTR (31, 31) << 3) | opcode);
2e8cf49e
NC
12117
12118 if (S == 1)
12119 HALT_UNALLOC;
12120
12121 if (opcode2 != 0)
12122 HALT_UNALLOC;
12123
12124 if (opcode & 0x38)
12125 HALT_UNALLOC;
12126
12127 switch (dispatch)
12128 {
12129 case 0: rbit32 (cpu); return;
12130 case 1: revh32 (cpu); return;
12131 case 2: rev32 (cpu); return;
12132 case 4: clz32 (cpu); return;
12133 case 5: cls32 (cpu); return;
12134 case 8: rbit64 (cpu); return;
12135 case 9: revh64 (cpu); return;
12136 case 10:rev32 (cpu); return;
12137 case 11:rev64 (cpu); return;
12138 case 12:clz64 (cpu); return;
12139 case 13:cls64 (cpu); return;
12140 default: HALT_UNALLOC;
12141 }
12142}
12143
12144/* Variable shift.
12145 Shifts by count supplied in register.
12146 N.B register args may not be SP.
12147 These all use the shifted auxiliary function for
12148 simplicity and clarity. Writing the actual shift
12149 inline would avoid a branch and so be faster but
12150 would also necessitate getting signs right. */
12151
12152/* 32 bit arithmetic shift right. */
12153static void
12154asrv32 (sim_cpu *cpu)
12155{
ef0d8ffc
NC
12156 unsigned rm = INSTR (20, 16);
12157 unsigned rn = INSTR (9, 5);
12158 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12159
12160 aarch64_set_reg_u64
12161 (cpu, rd, NO_SP,
12162 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ASR,
12163 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12164}
12165
12166/* 64 bit arithmetic shift right. */
12167static void
12168asrv64 (sim_cpu *cpu)
12169{
ef0d8ffc
NC
12170 unsigned rm = INSTR (20, 16);
12171 unsigned rn = INSTR (9, 5);
12172 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12173
12174 aarch64_set_reg_u64
12175 (cpu, rd, NO_SP,
12176 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ASR,
12177 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12178}
12179
12180/* 32 bit logical shift left. */
12181static void
12182lslv32 (sim_cpu *cpu)
12183{
ef0d8ffc
NC
12184 unsigned rm = INSTR (20, 16);
12185 unsigned rn = INSTR (9, 5);
12186 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12187
12188 aarch64_set_reg_u64
12189 (cpu, rd, NO_SP,
12190 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSL,
12191 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12192}
12193
12194/* 64 bit arithmetic shift left. */
12195static void
12196lslv64 (sim_cpu *cpu)
12197{
ef0d8ffc
NC
12198 unsigned rm = INSTR (20, 16);
12199 unsigned rn = INSTR (9, 5);
12200 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12201
12202 aarch64_set_reg_u64
12203 (cpu, rd, NO_SP,
12204 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSL,
12205 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12206}
12207
12208/* 32 bit logical shift right. */
12209static void
12210lsrv32 (sim_cpu *cpu)
12211{
ef0d8ffc
NC
12212 unsigned rm = INSTR (20, 16);
12213 unsigned rn = INSTR (9, 5);
12214 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12215
12216 aarch64_set_reg_u64
12217 (cpu, rd, NO_SP,
12218 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSR,
12219 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12220}
12221
12222/* 64 bit logical shift right. */
12223static void
12224lsrv64 (sim_cpu *cpu)
12225{
ef0d8ffc
NC
12226 unsigned rm = INSTR (20, 16);
12227 unsigned rn = INSTR (9, 5);
12228 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12229
12230 aarch64_set_reg_u64
12231 (cpu, rd, NO_SP,
12232 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSR,
12233 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12234}
12235
12236/* 32 bit rotate right. */
12237static void
12238rorv32 (sim_cpu *cpu)
12239{
ef0d8ffc
NC
12240 unsigned rm = INSTR (20, 16);
12241 unsigned rn = INSTR (9, 5);
12242 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12243
12244 aarch64_set_reg_u64
12245 (cpu, rd, NO_SP,
12246 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ROR,
12247 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
12248}
12249
12250/* 64 bit rotate right. */
12251static void
12252rorv64 (sim_cpu *cpu)
12253{
ef0d8ffc
NC
12254 unsigned rm = INSTR (20, 16);
12255 unsigned rn = INSTR (9, 5);
12256 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12257
12258 aarch64_set_reg_u64
12259 (cpu, rd, NO_SP,
12260 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ROR,
12261 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
12262}
12263
12264
12265/* divide. */
12266
12267/* 32 bit signed divide. */
12268static void
12269cpuiv32 (sim_cpu *cpu)
12270{
ef0d8ffc
NC
12271 unsigned rm = INSTR (20, 16);
12272 unsigned rn = INSTR (9, 5);
12273 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12274 /* N.B. the pseudo-code does the divide using 64 bit data. */
12275 /* TODO : check that this rounds towards zero as required. */
12276 int64_t dividend = aarch64_get_reg_s32 (cpu, rn, NO_SP);
12277 int64_t divisor = aarch64_get_reg_s32 (cpu, rm, NO_SP);
12278
12279 aarch64_set_reg_s64 (cpu, rd, NO_SP,
12280 divisor ? ((int32_t) (dividend / divisor)) : 0);
12281}
12282
12283/* 64 bit signed divide. */
12284static void
12285cpuiv64 (sim_cpu *cpu)
12286{
ef0d8ffc
NC
12287 unsigned rm = INSTR (20, 16);
12288 unsigned rn = INSTR (9, 5);
12289 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12290
12291 /* TODO : check that this rounds towards zero as required. */
12292 int64_t divisor = aarch64_get_reg_s64 (cpu, rm, NO_SP);
12293
12294 aarch64_set_reg_s64
12295 (cpu, rd, NO_SP,
12296 divisor ? (aarch64_get_reg_s64 (cpu, rn, NO_SP) / divisor) : 0);
12297}
12298
12299/* 32 bit unsigned divide. */
12300static void
12301udiv32 (sim_cpu *cpu)
12302{
ef0d8ffc
NC
12303 unsigned rm = INSTR (20, 16);
12304 unsigned rn = INSTR (9, 5);
12305 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12306
12307 /* N.B. the pseudo-code does the divide using 64 bit data. */
12308 uint64_t dividend = aarch64_get_reg_u32 (cpu, rn, NO_SP);
12309 uint64_t divisor = aarch64_get_reg_u32 (cpu, rm, NO_SP);
12310
12311 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12312 divisor ? (uint32_t) (dividend / divisor) : 0);
12313}
12314
12315/* 64 bit unsigned divide. */
12316static void
12317udiv64 (sim_cpu *cpu)
12318{
ef0d8ffc
NC
12319 unsigned rm = INSTR (20, 16);
12320 unsigned rn = INSTR (9, 5);
12321 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12322
12323 /* TODO : check that this rounds towards zero as required. */
12324 uint64_t divisor = aarch64_get_reg_u64 (cpu, rm, NO_SP);
12325
12326 aarch64_set_reg_u64
12327 (cpu, rd, NO_SP,
12328 divisor ? (aarch64_get_reg_u64 (cpu, rn, NO_SP) / divisor) : 0);
12329}
12330
12331static void
12332dexDataProc2Source (sim_cpu *cpu)
12333{
12334 /* assert instr[30] == 0
12335 instr[28,21] == 11010110
12336 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
12337 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
12338 instr[15,10] = opcode : 000010 ==> UDIV, 000011 ==> CPUIV,
12339 001000 ==> LSLV, 001001 ==> LSRV
12340 001010 ==> ASRV, 001011 ==> RORV
12341 ow ==> UNALLOC. */
12342
12343 uint32_t dispatch;
ef0d8ffc
NC
12344 uint32_t S = INSTR (29, 29);
12345 uint32_t opcode = INSTR (15, 10);
2e8cf49e
NC
12346
12347 if (S == 1)
12348 HALT_UNALLOC;
12349
12350 if (opcode & 0x34)
12351 HALT_UNALLOC;
12352
ef0d8ffc 12353 dispatch = ( (INSTR (31, 31) << 3)
2e8cf49e
NC
12354 | (uimm (opcode, 3, 3) << 2)
12355 | uimm (opcode, 1, 0));
12356 switch (dispatch)
12357 {
12358 case 2: udiv32 (cpu); return;
12359 case 3: cpuiv32 (cpu); return;
12360 case 4: lslv32 (cpu); return;
12361 case 5: lsrv32 (cpu); return;
12362 case 6: asrv32 (cpu); return;
12363 case 7: rorv32 (cpu); return;
12364 case 10: udiv64 (cpu); return;
12365 case 11: cpuiv64 (cpu); return;
12366 case 12: lslv64 (cpu); return;
12367 case 13: lsrv64 (cpu); return;
12368 case 14: asrv64 (cpu); return;
12369 case 15: rorv64 (cpu); return;
12370 default: HALT_UNALLOC;
12371 }
12372}
12373
12374
12375/* Multiply. */
12376
12377/* 32 bit multiply and add. */
12378static void
12379madd32 (sim_cpu *cpu)
12380{
ef0d8ffc
NC
12381 unsigned rm = INSTR (20, 16);
12382 unsigned ra = INSTR (14, 10);
12383 unsigned rn = INSTR (9, 5);
12384 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12385
12386 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12387 aarch64_get_reg_u32 (cpu, ra, NO_SP)
12388 + aarch64_get_reg_u32 (cpu, rn, NO_SP)
12389 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
12390}
12391
12392/* 64 bit multiply and add. */
12393static void
12394madd64 (sim_cpu *cpu)
12395{
ef0d8ffc
NC
12396 unsigned rm = INSTR (20, 16);
12397 unsigned ra = INSTR (14, 10);
12398 unsigned rn = INSTR (9, 5);
12399 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12400
12401 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12402 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12403 + aarch64_get_reg_u64 (cpu, rn, NO_SP)
12404 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
12405}
12406
12407/* 32 bit multiply and sub. */
12408static void
12409msub32 (sim_cpu *cpu)
12410{
ef0d8ffc
NC
12411 unsigned rm = INSTR (20, 16);
12412 unsigned ra = INSTR (14, 10);
12413 unsigned rn = INSTR (9, 5);
12414 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12415
12416 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12417 aarch64_get_reg_u32 (cpu, ra, NO_SP)
12418 - aarch64_get_reg_u32 (cpu, rn, NO_SP)
12419 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
12420}
12421
12422/* 64 bit multiply and sub. */
12423static void
12424msub64 (sim_cpu *cpu)
12425{
ef0d8ffc
NC
12426 unsigned rm = INSTR (20, 16);
12427 unsigned ra = INSTR (14, 10);
12428 unsigned rn = INSTR (9, 5);
12429 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12430
12431 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12432 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12433 - aarch64_get_reg_u64 (cpu, rn, NO_SP)
12434 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
12435}
12436
12437/* Signed multiply add long -- source, source2 : 32 bit, source3 : 64 bit. */
12438static void
12439smaddl (sim_cpu *cpu)
12440{
ef0d8ffc
NC
12441 unsigned rm = INSTR (20, 16);
12442 unsigned ra = INSTR (14, 10);
12443 unsigned rn = INSTR (9, 5);
12444 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12445
12446 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12447 obtain a 64 bit product. */
12448 aarch64_set_reg_s64
12449 (cpu, rd, NO_SP,
12450 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12451 + ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12452 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12453}
12454
12455/* Signed multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12456static void
12457smsubl (sim_cpu *cpu)
12458{
ef0d8ffc
NC
12459 unsigned rm = INSTR (20, 16);
12460 unsigned ra = INSTR (14, 10);
12461 unsigned rn = INSTR (9, 5);
12462 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12463
12464 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12465 obtain a 64 bit product. */
12466 aarch64_set_reg_s64
12467 (cpu, rd, NO_SP,
12468 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12469 - ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12470 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12471}
12472
12473/* Integer Multiply/Divide. */
12474
12475/* First some macros and a helper function. */
12476/* Macros to test or access elements of 64 bit words. */
12477
12478/* Mask used to access lo 32 bits of 64 bit unsigned int. */
12479#define LOW_WORD_MASK ((1ULL << 32) - 1)
12480/* Return the lo 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12481#define lowWordToU64(_value_u64) ((_value_u64) & LOW_WORD_MASK)
12482/* Return the hi 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12483#define highWordToU64(_value_u64) ((_value_u64) >> 32)
12484
12485/* Offset of sign bit in 64 bit signed integger. */
12486#define SIGN_SHIFT_U64 63
12487/* The sign bit itself -- also identifies the minimum negative int value. */
12488#define SIGN_BIT_U64 (1UL << SIGN_SHIFT_U64)
12489/* Return true if a 64 bit signed int presented as an unsigned int is the
12490 most negative value. */
12491#define isMinimumU64(_value_u64) ((_value_u64) == SIGN_BIT_U64)
12492/* Return true (non-zero) if a 64 bit signed int presented as an unsigned
12493 int has its sign bit set to false. */
12494#define isSignSetU64(_value_u64) ((_value_u64) & SIGN_BIT_U64)
12495/* Return 1L or -1L according to whether a 64 bit signed int presented as
12496 an unsigned int has its sign bit set or not. */
12497#define signOfU64(_value_u64) (1L + (((value_u64) >> SIGN_SHIFT_U64) * -2L)
12498/* Clear the sign bit of a 64 bit signed int presented as an unsigned int. */
12499#define clearSignU64(_value_u64) ((_value_u64) &= ~SIGN_BIT_U64)
12500
12501/* Multiply two 64 bit ints and return.
12502 the hi 64 bits of the 128 bit product. */
12503
12504static uint64_t
12505mul64hi (uint64_t value1, uint64_t value2)
12506{
12507 uint64_t resultmid1;
12508 uint64_t result;
12509 uint64_t value1_lo = lowWordToU64 (value1);
12510 uint64_t value1_hi = highWordToU64 (value1) ;
12511 uint64_t value2_lo = lowWordToU64 (value2);
12512 uint64_t value2_hi = highWordToU64 (value2);
12513
12514 /* Cross-multiply and collect results. */
12515
12516 uint64_t xproductlo = value1_lo * value2_lo;
12517 uint64_t xproductmid1 = value1_lo * value2_hi;
12518 uint64_t xproductmid2 = value1_hi * value2_lo;
12519 uint64_t xproducthi = value1_hi * value2_hi;
12520 uint64_t carry = 0;
12521 /* Start accumulating 64 bit results. */
12522 /* Drop bottom half of lowest cross-product. */
12523 uint64_t resultmid = xproductlo >> 32;
12524 /* Add in middle products. */
12525 resultmid = resultmid + xproductmid1;
12526
12527 /* Check for overflow. */
12528 if (resultmid < xproductmid1)
12529 /* Carry over 1 into top cross-product. */
12530 carry++;
12531
12532 resultmid1 = resultmid + xproductmid2;
12533
12534 /* Check for overflow. */
12535 if (resultmid1 < xproductmid2)
12536 /* Carry over 1 into top cross-product. */
12537 carry++;
12538
12539 /* Drop lowest 32 bits of middle cross-product. */
12540 result = resultmid1 >> 32;
12541
12542 /* Add top cross-product plus and any carry. */
12543 result += xproducthi + carry;
12544
12545 return result;
12546}
12547
12548/* Signed multiply high, source, source2 :
12549 64 bit, dest <-- high 64-bit of result. */
12550static void
12551smulh (sim_cpu *cpu)
12552{
12553 uint64_t uresult;
ef0d8ffc
NC
12554 int64_t result;
12555 unsigned rm = INSTR (20, 16);
12556 unsigned rn = INSTR (9, 5);
12557 unsigned rd = INSTR (4, 0);
12558 GReg ra = INSTR (14, 10);
12559 int64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12560 int64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2e8cf49e
NC
12561 uint64_t uvalue1;
12562 uint64_t uvalue2;
ef0d8ffc 12563 int64_t signum = 1;
2e8cf49e
NC
12564
12565 if (ra != R31)
12566 HALT_UNALLOC;
12567
12568 /* Convert to unsigned and use the unsigned mul64hi routine
12569 the fix the sign up afterwards. */
12570 if (value1 < 0)
12571 {
12572 signum *= -1L;
12573 uvalue1 = -value1;
12574 }
12575 else
12576 {
12577 uvalue1 = value1;
12578 }
12579
12580 if (value2 < 0)
12581 {
12582 signum *= -1L;
12583 uvalue2 = -value2;
12584 }
12585 else
12586 {
12587 uvalue2 = value2;
12588 }
12589
12590 uresult = mul64hi (uvalue1, uvalue2);
12591 result = uresult;
12592 result *= signum;
12593
12594 aarch64_set_reg_s64 (cpu, rd, NO_SP, result);
12595}
12596
12597/* Unsigned multiply add long -- source, source2 :
12598 32 bit, source3 : 64 bit. */
12599static void
12600umaddl (sim_cpu *cpu)
12601{
ef0d8ffc
NC
12602 unsigned rm = INSTR (20, 16);
12603 unsigned ra = INSTR (14, 10);
12604 unsigned rn = INSTR (9, 5);
12605 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12606
12607 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12608 obtain a 64 bit product. */
12609 aarch64_set_reg_u64
12610 (cpu, rd, NO_SP,
12611 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12612 + ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12613 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12614}
12615
12616/* Unsigned multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12617static void
12618umsubl (sim_cpu *cpu)
12619{
ef0d8ffc
NC
12620 unsigned rm = INSTR (20, 16);
12621 unsigned ra = INSTR (14, 10);
12622 unsigned rn = INSTR (9, 5);
12623 unsigned rd = INSTR (4, 0);
2e8cf49e
NC
12624
12625 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12626 obtain a 64 bit product. */
12627 aarch64_set_reg_u64
12628 (cpu, rd, NO_SP,
12629 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12630 - ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12631 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12632}
12633
12634/* Unsigned multiply high, source, source2 :
12635 64 bit, dest <-- high 64-bit of result. */
12636static void
12637umulh (sim_cpu *cpu)
12638{
ef0d8ffc
NC
12639 unsigned rm = INSTR (20, 16);
12640 unsigned rn = INSTR (9, 5);
12641 unsigned rd = INSTR (4, 0);
12642 GReg ra = INSTR (14, 10);
2e8cf49e
NC
12643
12644 if (ra != R31)
12645 HALT_UNALLOC;
12646
12647 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12648 mul64hi (aarch64_get_reg_u64 (cpu, rn, NO_SP),
12649 aarch64_get_reg_u64 (cpu, rm, NO_SP)));
12650}
12651
12652static void
12653dexDataProc3Source (sim_cpu *cpu)
12654{
12655 /* assert instr[28,24] == 11011. */
12656 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit (for rd at least)
12657 instr[30,29] = op54 : 00 ==> ok, ow ==> UNALLOC
12658 instr[23,21] = op31 : 111 ==> UNALLOC, o2 ==> ok
12659 instr[15] = o0 : 0/1 ==> ok
12660 instr[23,21:15] ==> op : 0000 ==> MADD, 0001 ==> MSUB, (32/64 bit)
12661 0010 ==> SMADDL, 0011 ==> SMSUBL, (64 bit only)
12662 0100 ==> SMULH, (64 bit only)
12663 1010 ==> UMADDL, 1011 ==> UNSUBL, (64 bit only)
12664 1100 ==> UMULH (64 bit only)
12665 ow ==> UNALLOC. */
12666
12667 uint32_t dispatch;
ef0d8ffc
NC
12668 uint32_t size = INSTR (31, 31);
12669 uint32_t op54 = INSTR (30, 29);
12670 uint32_t op31 = INSTR (23, 21);
12671 uint32_t o0 = INSTR (15, 15);
2e8cf49e
NC
12672
12673 if (op54 != 0)
12674 HALT_UNALLOC;
12675
12676 if (size == 0)
12677 {
12678 if (op31 != 0)
12679 HALT_UNALLOC;
12680
12681 if (o0 == 0)
12682 madd32 (cpu);
12683 else
12684 msub32 (cpu);
12685 return;
12686 }
12687
12688 dispatch = (op31 << 1) | o0;
12689
12690 switch (dispatch)
12691 {
12692 case 0: madd64 (cpu); return;
12693 case 1: msub64 (cpu); return;
12694 case 2: smaddl (cpu); return;
12695 case 3: smsubl (cpu); return;
12696 case 4: smulh (cpu); return;
12697 case 10: umaddl (cpu); return;
12698 case 11: umsubl (cpu); return;
12699 case 12: umulh (cpu); return;
12700 default: HALT_UNALLOC;
12701 }
12702}
12703
12704static void
12705dexDPReg (sim_cpu *cpu)
12706{
12707 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12708 assert group == GROUP_DPREG_0101 || group == GROUP_DPREG_1101
12709 bits [28:24:21] of a DPReg are the secondary dispatch vector. */
12710 uint32_t group2 = dispatchDPReg (aarch64_get_instr (cpu));
12711
12712 switch (group2)
12713 {
12714 case DPREG_LOG_000:
12715 case DPREG_LOG_001:
12716 dexLogicalShiftedRegister (cpu); return;
12717
12718 case DPREG_ADDSHF_010:
12719 dexAddSubtractShiftedRegister (cpu); return;
12720
12721 case DPREG_ADDEXT_011:
12722 dexAddSubtractExtendedRegister (cpu); return;
12723
12724 case DPREG_ADDCOND_100:
12725 {
12726 /* This set bundles a variety of different operations. */
12727 /* Check for. */
12728 /* 1) add/sub w carry. */
12729 uint32_t mask1 = 0x1FE00000U;
12730 uint32_t val1 = 0x1A000000U;
12731 /* 2) cond compare register/immediate. */
12732 uint32_t mask2 = 0x1FE00000U;
12733 uint32_t val2 = 0x1A400000U;
12734 /* 3) cond select. */
12735 uint32_t mask3 = 0x1FE00000U;
12736 uint32_t val3 = 0x1A800000U;
12737 /* 4) data proc 1/2 source. */
12738 uint32_t mask4 = 0x1FE00000U;
12739 uint32_t val4 = 0x1AC00000U;
12740
12741 if ((aarch64_get_instr (cpu) & mask1) == val1)
12742 dexAddSubtractWithCarry (cpu);
12743
12744 else if ((aarch64_get_instr (cpu) & mask2) == val2)
12745 CondCompare (cpu);
12746
12747 else if ((aarch64_get_instr (cpu) & mask3) == val3)
12748 dexCondSelect (cpu);
12749
12750 else if ((aarch64_get_instr (cpu) & mask4) == val4)
12751 {
12752 /* Bit 30 is clear for data proc 2 source
12753 and set for data proc 1 source. */
12754 if (aarch64_get_instr (cpu) & (1U << 30))
12755 dexDataProc1Source (cpu);
12756 else
12757 dexDataProc2Source (cpu);
12758 }
12759
12760 else
12761 /* Should not reach here. */
12762 HALT_NYI;
12763
12764 return;
12765 }
12766
12767 case DPREG_3SRC_110:
12768 dexDataProc3Source (cpu); return;
12769
12770 case DPREG_UNALLOC_101:
12771 HALT_UNALLOC;
12772
12773 case DPREG_3SRC_111:
12774 dexDataProc3Source (cpu); return;
12775
12776 default:
12777 /* Should never reach here. */
12778 HALT_NYI;
12779 }
12780}
12781
12782/* Unconditional Branch immediate.
12783 Offset is a PC-relative byte offset in the range +/- 128MiB.
12784 The offset is assumed to be raw from the decode i.e. the
12785 simulator is expected to scale them from word offsets to byte. */
12786
12787/* Unconditional branch. */
12788static void
12789buc (sim_cpu *cpu, int32_t offset)
12790{
12791 aarch64_set_next_PC_by_offset (cpu, offset);
12792}
12793
12794static unsigned stack_depth = 0;
12795
12796/* Unconditional branch and link -- writes return PC to LR. */
12797static void
12798bl (sim_cpu *cpu, int32_t offset)
12799{
12800 aarch64_save_LR (cpu);
12801 aarch64_set_next_PC_by_offset (cpu, offset);
12802
12803 if (TRACE_BRANCH_P (cpu))
12804 {
12805 ++ stack_depth;
12806 TRACE_BRANCH (cpu,
12807 " %*scall %" PRIx64 " [%s]"
12808 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12809 stack_depth, " ", aarch64_get_next_PC (cpu),
12810 aarch64_get_func (aarch64_get_next_PC (cpu)),
12811 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12812 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12813 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12814 );
12815 }
12816}
12817
12818/* Unconditional Branch register.
12819 Branch/return address is in source register. */
12820
12821/* Unconditional branch. */
12822static void
12823br (sim_cpu *cpu)
12824{
ef0d8ffc 12825 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
12826 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12827}
12828
12829/* Unconditional branch and link -- writes return PC to LR. */
12830static void
12831blr (sim_cpu *cpu)
12832{
ef0d8ffc 12833 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
12834
12835 /* The pseudo code in the spec says we update LR before fetching.
12836 the value from the rn. */
12837 aarch64_save_LR (cpu);
12838 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12839
12840 if (TRACE_BRANCH_P (cpu))
12841 {
12842 ++ stack_depth;
12843 TRACE_BRANCH (cpu,
12844 " %*scall %" PRIx64 " [%s]"
12845 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12846 stack_depth, " ", aarch64_get_next_PC (cpu),
12847 aarch64_get_func (aarch64_get_next_PC (cpu)),
12848 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12849 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12850 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12851 );
12852 }
12853}
12854
12855/* Return -- assembler will default source to LR this is functionally
12856 equivalent to br but, presumably, unlike br it side effects the
12857 branch predictor. */
12858static void
12859ret (sim_cpu *cpu)
12860{
ef0d8ffc 12861 unsigned rn = INSTR (9, 5);
2e8cf49e
NC
12862 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12863
12864 if (TRACE_BRANCH_P (cpu))
12865 {
12866 TRACE_BRANCH (cpu,
12867 " %*sreturn [result: %" PRIx64 "]",
12868 stack_depth, " ", aarch64_get_reg_u64 (cpu, 0, NO_SP));
12869 -- stack_depth;
12870 }
12871}
12872
12873/* NOP -- we implement this and call it from the decode in case we
12874 want to intercept it later. */
12875
12876static void
12877nop (sim_cpu *cpu)
12878{
12879}
12880
12881/* Data synchronization barrier. */
12882
12883static void
12884dsb (sim_cpu *cpu)
12885{
12886}
12887
12888/* Data memory barrier. */
12889
12890static void
12891dmb (sim_cpu *cpu)
12892{
12893}
12894
12895/* Instruction synchronization barrier. */
12896
12897static void
12898isb (sim_cpu *cpu)
12899{
12900}
12901
12902static void
12903dexBranchImmediate (sim_cpu *cpu)
12904{
12905 /* assert instr[30,26] == 00101
12906 instr[31] ==> 0 == B, 1 == BL
12907 instr[25,0] == imm26 branch offset counted in words. */
12908
ef0d8ffc 12909 uint32_t top = INSTR (31, 31);
2e8cf49e
NC
12910 /* We have a 26 byte signed word offset which we need to pass to the
12911 execute routine as a signed byte offset. */
12912 int32_t offset = simm32 (aarch64_get_instr (cpu), 25, 0) << 2;
12913
12914 if (top)
12915 bl (cpu, offset);
12916 else
12917 buc (cpu, offset);
12918}
12919
12920/* Control Flow. */
12921
12922/* Conditional branch
12923
12924 Offset is a PC-relative byte offset in the range +/- 1MiB pos is
12925 a bit position in the range 0 .. 63
12926
12927 cc is a CondCode enum value as pulled out of the decode
12928
12929 N.B. any offset register (source) can only be Xn or Wn. */
12930
12931static void
12932bcc (sim_cpu *cpu, int32_t offset, CondCode cc)
12933{
12934 /* the test returns TRUE if CC is met. */
12935 if (testConditionCode (cpu, cc))
12936 aarch64_set_next_PC_by_offset (cpu, offset);
12937}
12938
12939/* 32 bit branch on register non-zero. */
12940static void
12941cbnz32 (sim_cpu *cpu, int32_t offset)
12942{
ef0d8ffc 12943 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
12944
12945 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) != 0)
12946 aarch64_set_next_PC_by_offset (cpu, offset);
12947}
12948
12949/* 64 bit branch on register zero. */
12950static void
12951cbnz (sim_cpu *cpu, int32_t offset)
12952{
ef0d8ffc 12953 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
12954
12955 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) != 0)
12956 aarch64_set_next_PC_by_offset (cpu, offset);
12957}
12958
12959/* 32 bit branch on register non-zero. */
12960static void
12961cbz32 (sim_cpu *cpu, int32_t offset)
12962{
ef0d8ffc 12963 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
12964
12965 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) == 0)
12966 aarch64_set_next_PC_by_offset (cpu, offset);
12967}
12968
12969/* 64 bit branch on register zero. */
12970static void
12971cbz (sim_cpu *cpu, int32_t offset)
12972{
ef0d8ffc 12973 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
12974
12975 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) == 0)
12976 aarch64_set_next_PC_by_offset (cpu, offset);
12977}
12978
12979/* Branch on register bit test non-zero -- one size fits all. */
12980static void
12981tbnz (sim_cpu *cpu, uint32_t pos, int32_t offset)
12982{
ef0d8ffc 12983 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
12984
12985 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) & (1 << pos))
12986 aarch64_set_next_PC_by_offset (cpu, offset);
12987}
12988
12989/* branch on register bit test zero -- one size fits all. */
12990static void
12991tbz (sim_cpu *cpu, uint32_t pos, int32_t offset)
12992{
ef0d8ffc 12993 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
12994
12995 if (!(aarch64_get_reg_u64 (cpu, rt, NO_SP) & (1 << pos)))
12996 aarch64_set_next_PC_by_offset (cpu, offset);
12997}
12998
12999static void
13000dexCompareBranchImmediate (sim_cpu *cpu)
13001{
13002 /* instr[30,25] = 01 1010
13003 instr[31] = size : 0 ==> 32, 1 ==> 64
13004 instr[24] = op : 0 ==> CBZ, 1 ==> CBNZ
13005 instr[23,5] = simm19 branch offset counted in words
13006 instr[4,0] = rt */
13007
ef0d8ffc
NC
13008 uint32_t size = INSTR (31, 31);
13009 uint32_t op = INSTR (24, 24);
2e8cf49e
NC
13010 int32_t offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
13011
13012 if (size == 0)
13013 {
13014 if (op == 0)
13015 cbz32 (cpu, offset);
13016 else
13017 cbnz32 (cpu, offset);
13018 }
13019 else
13020 {
13021 if (op == 0)
13022 cbz (cpu, offset);
13023 else
13024 cbnz (cpu, offset);
13025 }
13026}
13027
13028static void
13029dexTestBranchImmediate (sim_cpu *cpu)
13030{
13031 /* instr[31] = b5 : bit 5 of test bit idx
13032 instr[30,25] = 01 1011
13033 instr[24] = op : 0 ==> TBZ, 1 == TBNZ
13034 instr[23,19] = b40 : bits 4 to 0 of test bit idx
13035 instr[18,5] = simm14 : signed offset counted in words
13036 instr[4,0] = uimm5 */
13037
7517e550 13038 uint32_t pos = ((INSTR (31, 31) << 4) | INSTR (23, 19));
2e8cf49e
NC
13039 int32_t offset = simm32 (aarch64_get_instr (cpu), 18, 5) << 2;
13040
13041 NYI_assert (30, 25, 0x1b);
13042
ef0d8ffc 13043 if (INSTR (24, 24) == 0)
2e8cf49e
NC
13044 tbz (cpu, pos, offset);
13045 else
13046 tbnz (cpu, pos, offset);
13047}
13048
13049static void
13050dexCondBranchImmediate (sim_cpu *cpu)
13051{
13052 /* instr[31,25] = 010 1010
13053 instr[24] = op1; op => 00 ==> B.cond
13054 instr[23,5] = simm19 : signed offset counted in words
13055 instr[4] = op0
13056 instr[3,0] = cond */
13057
13058 int32_t offset;
ef0d8ffc 13059 uint32_t op = ((INSTR (24, 24) << 1) | INSTR (4, 4));
2e8cf49e
NC
13060
13061 NYI_assert (31, 25, 0x2a);
13062
13063 if (op != 0)
13064 HALT_UNALLOC;
13065
13066 offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
2e8cf49e 13067
ef0d8ffc 13068 bcc (cpu, offset, INSTR (3, 0));
2e8cf49e
NC
13069}
13070
13071static void
13072dexBranchRegister (sim_cpu *cpu)
13073{
13074 /* instr[31,25] = 110 1011
13075 instr[24,21] = op : 0 ==> BR, 1 => BLR, 2 => RET, 3 => ERET, 4 => DRPS
13076 instr[20,16] = op2 : must be 11111
13077 instr[15,10] = op3 : must be 000000
13078 instr[4,0] = op2 : must be 11111. */
13079
ef0d8ffc
NC
13080 uint32_t op = INSTR (24, 21);
13081 uint32_t op2 = INSTR (20, 16);
13082 uint32_t op3 = INSTR (15, 10);
13083 uint32_t op4 = INSTR (4, 0);
2e8cf49e
NC
13084
13085 NYI_assert (31, 25, 0x6b);
13086
13087 if (op2 != 0x1F || op3 != 0 || op4 != 0)
13088 HALT_UNALLOC;
13089
13090 if (op == 0)
13091 br (cpu);
13092
13093 else if (op == 1)
13094 blr (cpu);
13095
13096 else if (op == 2)
13097 ret (cpu);
13098
13099 else
13100 {
ef0d8ffc 13101 /* ERET and DRPS accept 0b11111 for rn = instr [4,0]. */
2e8cf49e 13102 /* anything else is unallocated. */
ef0d8ffc 13103 uint32_t rn = INSTR (4, 0);
2e8cf49e
NC
13104
13105 if (rn != 0x1f)
13106 HALT_UNALLOC;
13107
13108 if (op == 4 || op == 5)
13109 HALT_NYI;
13110
13111 HALT_UNALLOC;
13112 }
13113}
13114
13115/* FIXME: We should get the Angel SWI values from ../../libgloss/aarch64/svc.h
13116 but this may not be available. So instead we define the values we need
13117 here. */
13118#define AngelSVC_Reason_Open 0x01
13119#define AngelSVC_Reason_Close 0x02
13120#define AngelSVC_Reason_Write 0x05
13121#define AngelSVC_Reason_Read 0x06
13122#define AngelSVC_Reason_IsTTY 0x09
13123#define AngelSVC_Reason_Seek 0x0A
13124#define AngelSVC_Reason_FLen 0x0C
13125#define AngelSVC_Reason_Remove 0x0E
13126#define AngelSVC_Reason_Rename 0x0F
13127#define AngelSVC_Reason_Clock 0x10
13128#define AngelSVC_Reason_Time 0x11
13129#define AngelSVC_Reason_System 0x12
13130#define AngelSVC_Reason_Errno 0x13
13131#define AngelSVC_Reason_GetCmdLine 0x15
13132#define AngelSVC_Reason_HeapInfo 0x16
13133#define AngelSVC_Reason_ReportException 0x18
13134#define AngelSVC_Reason_Elapsed 0x30
13135
13136
13137static void
13138handle_halt (sim_cpu *cpu, uint32_t val)
13139{
13140 uint64_t result = 0;
13141
13142 if (val != 0xf000)
13143 {
13144 TRACE_SYSCALL (cpu, " HLT [0x%x]", val);
13145 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13146 sim_stopped, SIM_SIGTRAP);
13147 }
13148
13149 /* We have encountered an Angel SVC call. See if we can process it. */
13150 switch (aarch64_get_reg_u32 (cpu, 0, NO_SP))
13151 {
13152 case AngelSVC_Reason_HeapInfo:
13153 {
13154 /* Get the values. */
13155 uint64_t stack_top = aarch64_get_stack_start (cpu);
13156 uint64_t heap_base = aarch64_get_heap_start (cpu);
13157
13158 /* Get the pointer */
13159 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13160 ptr = aarch64_get_mem_u64 (cpu, ptr);
13161
13162 /* Fill in the memory block. */
13163 /* Start addr of heap. */
13164 aarch64_set_mem_u64 (cpu, ptr + 0, heap_base);
13165 /* End addr of heap. */
13166 aarch64_set_mem_u64 (cpu, ptr + 8, stack_top);
13167 /* Lowest stack addr. */
13168 aarch64_set_mem_u64 (cpu, ptr + 16, heap_base);
13169 /* Initial stack addr. */
13170 aarch64_set_mem_u64 (cpu, ptr + 24, stack_top);
13171
13172 TRACE_SYSCALL (cpu, " AngelSVC: Get Heap Info");
13173 }
13174 break;
13175
13176 case AngelSVC_Reason_Open:
13177 {
13178 /* Get the pointer */
13179 /* uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);. */
13180 /* FIXME: For now we just assume that we will only be asked
13181 to open the standard file descriptors. */
13182 static int fd = 0;
13183 result = fd ++;
13184
13185 TRACE_SYSCALL (cpu, " AngelSVC: Open file %d", fd - 1);
13186 }
13187 break;
13188
13189 case AngelSVC_Reason_Close:
13190 {
13191 uint64_t fh = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13192 TRACE_SYSCALL (cpu, " AngelSVC: Close file %d", (int) fh);
13193 result = 0;
13194 }
13195 break;
13196
13197 case AngelSVC_Reason_Errno:
13198 result = 0;
13199 TRACE_SYSCALL (cpu, " AngelSVC: Get Errno");
13200 break;
13201
13202 case AngelSVC_Reason_Clock:
13203 result =
13204#ifdef CLOCKS_PER_SEC
13205 (CLOCKS_PER_SEC >= 100)
13206 ? (clock () / (CLOCKS_PER_SEC / 100))
13207 : ((clock () * 100) / CLOCKS_PER_SEC)
13208#else
13209 /* Presume unix... clock() returns microseconds. */
13210 (clock () / 10000)
13211#endif
13212 ;
13213 TRACE_SYSCALL (cpu, " AngelSVC: Get Clock");
13214 break;
13215
13216 case AngelSVC_Reason_GetCmdLine:
13217 {
13218 /* Get the pointer */
13219 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13220 ptr = aarch64_get_mem_u64 (cpu, ptr);
13221
13222 /* FIXME: No command line for now. */
13223 aarch64_set_mem_u64 (cpu, ptr, 0);
13224 TRACE_SYSCALL (cpu, " AngelSVC: Get Command Line");
13225 }
13226 break;
13227
13228 case AngelSVC_Reason_IsTTY:
13229 result = 1;
13230 TRACE_SYSCALL (cpu, " AngelSVC: IsTTY ?");
13231 break;
13232
13233 case AngelSVC_Reason_Write:
13234 {
13235 /* Get the pointer */
13236 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13237 /* Get the write control block. */
13238 uint64_t fd = aarch64_get_mem_u64 (cpu, ptr);
13239 uint64_t buf = aarch64_get_mem_u64 (cpu, ptr + 8);
13240 uint64_t len = aarch64_get_mem_u64 (cpu, ptr + 16);
13241
13242 TRACE_SYSCALL (cpu, "write of %" PRIx64 " bytes from %"
13243 PRIx64 " on descriptor %" PRIx64,
13244 len, buf, fd);
13245
13246 if (len > 1280)
13247 {
13248 TRACE_SYSCALL (cpu,
13249 " AngelSVC: Write: Suspiciously long write: %ld",
13250 (long) len);
13251 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13252 sim_stopped, SIM_SIGBUS);
13253 }
13254 else if (fd == 1)
13255 {
13256 printf ("%.*s", (int) len, aarch64_get_mem_ptr (cpu, buf));
2e8cf49e
NC
13257 }
13258 else if (fd == 2)
13259 {
13260 TRACE (cpu, 0, "\n");
13261 sim_io_eprintf (CPU_STATE (cpu), "%.*s",
13262 (int) len, aarch64_get_mem_ptr (cpu, buf));
13263 TRACE (cpu, 0, "\n");
13264 }
13265 else
13266 {
13267 TRACE_SYSCALL (cpu,
13268 " AngelSVC: Write: Unexpected file handle: %d",
13269 (int) fd);
13270 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13271 sim_stopped, SIM_SIGABRT);
13272 }
13273 }
13274 break;
13275
13276 case AngelSVC_Reason_ReportException:
13277 {
13278 /* Get the pointer */
13279 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
13280 /*ptr = aarch64_get_mem_u64 (cpu, ptr);. */
13281 uint64_t type = aarch64_get_mem_u64 (cpu, ptr);
13282 uint64_t state = aarch64_get_mem_u64 (cpu, ptr + 8);
13283
13284 TRACE_SYSCALL (cpu,
13285 "Angel Exception: type 0x%" PRIx64 " state %" PRIx64,
13286 type, state);
13287
13288 if (type == 0x20026)
13289 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13290 sim_exited, state);
13291 else
13292 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13293 sim_stopped, SIM_SIGINT);
13294 }
13295 break;
13296
13297 case AngelSVC_Reason_Read:
13298 case AngelSVC_Reason_FLen:
13299 case AngelSVC_Reason_Seek:
13300 case AngelSVC_Reason_Remove:
13301 case AngelSVC_Reason_Time:
13302 case AngelSVC_Reason_System:
13303 case AngelSVC_Reason_Rename:
13304 case AngelSVC_Reason_Elapsed:
13305 default:
13306 TRACE_SYSCALL (cpu, " HLT [Unknown angel %x]",
13307 aarch64_get_reg_u32 (cpu, 0, NO_SP));
13308 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13309 sim_stopped, SIM_SIGTRAP);
13310 }
13311
13312 aarch64_set_reg_u64 (cpu, 0, NO_SP, result);
13313}
13314
13315static void
13316dexExcpnGen (sim_cpu *cpu)
13317{
13318 /* instr[31:24] = 11010100
13319 instr[23,21] = opc : 000 ==> GEN EXCPN, 001 ==> BRK
13320 010 ==> HLT, 101 ==> DBG GEN EXCPN
13321 instr[20,5] = imm16
13322 instr[4,2] = opc2 000 ==> OK, ow ==> UNALLOC
13323 instr[1,0] = LL : discriminates opc */
13324
ef0d8ffc
NC
13325 uint32_t opc = INSTR (23, 21);
13326 uint32_t imm16 = INSTR (20, 5);
13327 uint32_t opc2 = INSTR (4, 2);
2e8cf49e
NC
13328 uint32_t LL;
13329
13330 NYI_assert (31, 24, 0xd4);
13331
13332 if (opc2 != 0)
13333 HALT_UNALLOC;
13334
ef0d8ffc 13335 LL = INSTR (1, 0);
2e8cf49e
NC
13336
13337 /* We only implement HLT and BRK for now. */
13338 if (opc == 1 && LL == 0)
13339 {
13340 TRACE_EVENTS (cpu, " BRK [0x%x]", imm16);
13341 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
13342 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13343 }
13344
13345 if (opc == 2 && LL == 0)
13346 handle_halt (cpu, imm16);
13347
13348 else if (opc == 0 || opc == 5)
13349 HALT_NYI;
13350
13351 else
13352 HALT_UNALLOC;
13353}
13354
5ab6d79e 13355/* Stub for accessing system registers. */
caa8d700
NC
13356
13357static uint64_t
13358system_get (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
13359 unsigned crm, unsigned op2)
13360{
13361 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 7)
13362 /* DCZID_EL0 - the Data Cache Zero ID register.
13363 We do not support DC ZVA at the moment, so
5ab6d79e
NC
13364 we return a value with the disable bit set.
13365 We implement support for the DCZID register since
13366 it is used by the C library's memset function. */
caa8d700
NC
13367 return ((uint64_t) 1) << 4;
13368
5ab6d79e
NC
13369 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 1)
13370 /* Cache Type Register. */
13371 return 0x80008000UL;
13372
13373 if (crn == 13 && op1 == 3 && crm == 0 && op2 == 2)
13374 /* TPIDR_EL0 - thread pointer id. */
13375 return aarch64_get_thread_id (cpu);
13376
13377 if (op1 == 3 && crm == 4 && op2 == 0)
13378 return aarch64_get_FPCR (cpu);
13379
13380 if (op1 == 3 && crm == 4 && op2 == 1)
13381 return aarch64_get_FPSR (cpu);
13382
13383 else if (op1 == 3 && crm == 2 && op2 == 0)
13384 return aarch64_get_CPSR (cpu);
13385
caa8d700
NC
13386 HALT_NYI;
13387}
13388
5ab6d79e
NC
13389static void
13390system_set (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
13391 unsigned crm, unsigned op2, uint64_t val)
13392{
13393 if (op1 == 3 && crm == 4 && op2 == 0)
13394 aarch64_set_FPCR (cpu, val);
13395
13396 else if (op1 == 3 && crm == 4 && op2 == 1)
13397 aarch64_set_FPSR (cpu, val);
13398
13399 else if (op1 == 3 && crm == 2 && op2 == 0)
13400 aarch64_set_CPSR (cpu, val);
13401
13402 else
13403 HALT_NYI;
13404}
ef0d8ffc 13405
caa8d700
NC
13406static void
13407do_mrs (sim_cpu *cpu)
13408{
5ab6d79e 13409 /* instr[31:20] = 1101 0101 0001 1
caa8d700
NC
13410 instr[19] = op0
13411 instr[18,16] = op1
13412 instr[15,12] = CRn
13413 instr[11,8] = CRm
13414 instr[7,5] = op2
13415 instr[4,0] = Rt */
ef0d8ffc
NC
13416 unsigned sys_op0 = INSTR (19, 19) + 2;
13417 unsigned sys_op1 = INSTR (18, 16);
13418 unsigned sys_crn = INSTR (15, 12);
13419 unsigned sys_crm = INSTR (11, 8);
13420 unsigned sys_op2 = INSTR (7, 5);
13421 unsigned rt = INSTR (4, 0);
caa8d700
NC
13422
13423 aarch64_set_reg_u64 (cpu, rt, NO_SP,
13424 system_get (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2));
13425}
13426
5ab6d79e
NC
13427static void
13428do_MSR_immediate (sim_cpu *cpu)
13429{
13430 /* instr[31:19] = 1101 0101 0000 0
13431 instr[18,16] = op1
13432 instr[15,12] = 0100
13433 instr[11,8] = CRm
13434 instr[7,5] = op2
13435 instr[4,0] = 1 1111 */
13436
ef0d8ffc
NC
13437 unsigned op1 = INSTR (18, 16);
13438 /*unsigned crm = INSTR (11, 8);*/
13439 unsigned op2 = INSTR (7, 5);
5ab6d79e
NC
13440
13441 NYI_assert (31, 19, 0x1AA0);
13442 NYI_assert (15, 12, 0x4);
13443 NYI_assert (4, 0, 0x1F);
13444
13445 if (op1 == 0)
13446 {
13447 if (op2 == 5)
13448 HALT_NYI; /* set SPSel. */
13449 else
13450 HALT_UNALLOC;
13451 }
13452 else if (op1 == 3)
13453 {
13454 if (op2 == 6)
13455 HALT_NYI; /* set DAIFset. */
13456 else if (op2 == 7)
13457 HALT_NYI; /* set DAIFclr. */
13458 else
13459 HALT_UNALLOC;
13460 }
13461 else
13462 HALT_UNALLOC;
13463}
13464
13465static void
13466do_MSR_reg (sim_cpu *cpu)
13467{
13468 /* instr[31:20] = 1101 0101 0001
13469 instr[19] = op0
13470 instr[18,16] = op1
13471 instr[15,12] = CRn
13472 instr[11,8] = CRm
13473 instr[7,5] = op2
13474 instr[4,0] = Rt */
13475
ef0d8ffc
NC
13476 unsigned sys_op0 = INSTR (19, 19) + 2;
13477 unsigned sys_op1 = INSTR (18, 16);
13478 unsigned sys_crn = INSTR (15, 12);
13479 unsigned sys_crm = INSTR (11, 8);
13480 unsigned sys_op2 = INSTR (7, 5);
13481 unsigned rt = INSTR (4, 0);
5ab6d79e
NC
13482
13483 NYI_assert (31, 20, 0xD51);
ef0d8ffc 13484
5ab6d79e
NC
13485 system_set (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2,
13486 aarch64_get_reg_u64 (cpu, rt, NO_SP));
13487}
13488
13489static void
ef0d8ffc 13490do_SYS (sim_cpu *cpu)
5ab6d79e
NC
13491{
13492 /* instr[31,19] = 1101 0101 0000 1
13493 instr[18,16] = op1
13494 instr[15,12] = CRn
13495 instr[11,8] = CRm
13496 instr[7,5] = op2
13497 instr[4,0] = Rt */
13498 NYI_assert (31, 19, 0x1AA1);
13499
13500 /* FIXME: For now we just silently accept system ops. */
13501}
ef0d8ffc 13502
2e8cf49e
NC
13503static void
13504dexSystem (sim_cpu *cpu)
13505{
13506 /* instr[31:22] = 1101 01010 0
13507 instr[21] = L
13508 instr[20,19] = op0
13509 instr[18,16] = op1
13510 instr[15,12] = CRn
13511 instr[11,8] = CRm
13512 instr[7,5] = op2
13513 instr[4,0] = uimm5 */
13514
13515 /* We are interested in HINT, DSB, DMB and ISB
13516
13517 Hint #0 encodes NOOP (this is the only hint we care about)
13518 L == 0, op0 == 0, op1 = 011, CRn = 0010, Rt = 11111,
13519 CRm op2 != 0000 000 OR CRm op2 == 0000 000 || CRm op > 0000 101
13520
13521 DSB, DMB, ISB are data store barrier, data memory barrier and
13522 instruction store barrier, respectively, where
13523
13524 L == 0, op0 == 0, op1 = 011, CRn = 0011, Rt = 11111,
13525 op2 : DSB ==> 100, DMB ==> 101, ISB ==> 110
13526 CRm<3:2> ==> domain, CRm<1:0> ==> types,
13527 domain : 00 ==> OuterShareable, 01 ==> Nonshareable,
13528 10 ==> InerShareable, 11 ==> FullSystem
13529 types : 01 ==> Reads, 10 ==> Writes,
13530 11 ==> All, 00 ==> All (domain == FullSystem). */
13531
ef0d8ffc 13532 unsigned rt = INSTR (4, 0);
2e8cf49e
NC
13533
13534 NYI_assert (31, 22, 0x354);
13535
5ab6d79e 13536 switch (INSTR (21, 12))
2e8cf49e
NC
13537 {
13538 case 0x032:
13539 if (rt == 0x1F)
13540 {
13541 /* NOP has CRm != 0000 OR. */
13542 /* (CRm == 0000 AND (op2 == 000 OR op2 > 101)). */
ef0d8ffc
NC
13543 uint32_t crm = INSTR (11, 8);
13544 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
13545
13546 if (crm != 0 || (op2 == 0 || op2 > 5))
13547 {
13548 /* Actually call nop method so we can reimplement it later. */
13549 nop (cpu);
13550 return;
13551 }
13552 }
13553 HALT_NYI;
13554
13555 case 0x033:
13556 {
ef0d8ffc 13557 uint32_t op2 = INSTR (7, 5);
2e8cf49e
NC
13558
13559 switch (op2)
13560 {
caa8d700 13561 case 2: HALT_NYI;
2e8cf49e
NC
13562 case 4: dsb (cpu); return;
13563 case 5: dmb (cpu); return;
13564 case 6: isb (cpu); return;
2e8cf49e
NC
13565 default: HALT_UNALLOC;
13566 }
13567 }
13568
13569 case 0x3B0:
2e8cf49e
NC
13570 case 0x3B4:
13571 case 0x3BD:
caa8d700 13572 do_mrs (cpu);
2e8cf49e
NC
13573 return;
13574
13575 case 0x0B7:
5ab6d79e 13576 do_SYS (cpu); /* DC is an alias of SYS. */
2e8cf49e
NC
13577 return;
13578
13579 default:
ef0d8ffc 13580 if (INSTR (21, 20) == 0x1)
5ab6d79e
NC
13581 do_MSR_reg (cpu);
13582 else if (INSTR (21, 19) == 0 && INSTR (15, 12) == 0x4)
13583 do_MSR_immediate (cpu);
13584 else
13585 HALT_NYI;
caa8d700 13586 return;
2e8cf49e
NC
13587 }
13588}
13589
13590static void
13591dexBr (sim_cpu *cpu)
13592{
13593 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
13594 assert group == GROUP_BREXSYS_1010 || group == GROUP_BREXSYS_1011
13595 bits [31,29] of a BrExSys are the secondary dispatch vector. */
13596 uint32_t group2 = dispatchBrExSys (aarch64_get_instr (cpu));
13597
13598 switch (group2)
13599 {
13600 case BR_IMM_000:
13601 return dexBranchImmediate (cpu);
13602
13603 case BR_IMMCMP_001:
13604 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 13605 if (!INSTR (25, 25))
2e8cf49e
NC
13606 dexCompareBranchImmediate (cpu);
13607 else
13608 dexTestBranchImmediate (cpu);
13609 return;
13610
13611 case BR_IMMCOND_010:
13612 /* This is a conditional branch if bit 25 is clear otherwise
13613 unallocated. */
ef0d8ffc 13614 if (!INSTR (25, 25))
2e8cf49e
NC
13615 dexCondBranchImmediate (cpu);
13616 else
13617 HALT_UNALLOC;
13618 return;
13619
13620 case BR_UNALLOC_011:
13621 HALT_UNALLOC;
13622
13623 case BR_IMM_100:
13624 dexBranchImmediate (cpu);
13625 return;
13626
13627 case BR_IMMCMP_101:
13628 /* Compare has bit 25 clear while test has it set. */
ef0d8ffc 13629 if (!INSTR (25, 25))
2e8cf49e
NC
13630 dexCompareBranchImmediate (cpu);
13631 else
13632 dexTestBranchImmediate (cpu);
13633 return;
13634
13635 case BR_REG_110:
13636 /* Unconditional branch reg has bit 25 set. */
ef0d8ffc 13637 if (INSTR (25, 25))
2e8cf49e
NC
13638 dexBranchRegister (cpu);
13639
13640 /* This includes both Excpn Gen, System and unalloc operations.
13641 We need to decode the Excpn Gen operation BRK so we can plant
13642 debugger entry points.
ef0d8ffc 13643 Excpn Gen operations have instr [24] = 0.
2e8cf49e
NC
13644 we need to decode at least one of the System operations NOP
13645 which is an alias for HINT #0.
ef0d8ffc
NC
13646 System operations have instr [24,22] = 100. */
13647 else if (INSTR (24, 24) == 0)
2e8cf49e
NC
13648 dexExcpnGen (cpu);
13649
ef0d8ffc 13650 else if (INSTR (24, 22) == 4)
2e8cf49e
NC
13651 dexSystem (cpu);
13652
13653 else
13654 HALT_UNALLOC;
13655
13656 return;
13657
13658 case BR_UNALLOC_111:
13659 HALT_UNALLOC;
13660
13661 default:
13662 /* Should never reach here. */
13663 HALT_NYI;
13664 }
13665}
13666
13667static void
13668aarch64_decode_and_execute (sim_cpu *cpu, uint64_t pc)
13669{
13670 /* We need to check if gdb wants an in here. */
13671 /* checkBreak (cpu);. */
13672
13673 uint64_t group = dispatchGroup (aarch64_get_instr (cpu));
13674
13675 switch (group)
13676 {
13677 case GROUP_PSEUDO_0000: dexPseudo (cpu); break;
13678 case GROUP_LDST_0100: dexLdSt (cpu); break;
13679 case GROUP_DPREG_0101: dexDPReg (cpu); break;
13680 case GROUP_LDST_0110: dexLdSt (cpu); break;
13681 case GROUP_ADVSIMD_0111: dexAdvSIMD0 (cpu); break;
13682 case GROUP_DPIMM_1000: dexDPImm (cpu); break;
13683 case GROUP_DPIMM_1001: dexDPImm (cpu); break;
13684 case GROUP_BREXSYS_1010: dexBr (cpu); break;
13685 case GROUP_BREXSYS_1011: dexBr (cpu); break;
13686 case GROUP_LDST_1100: dexLdSt (cpu); break;
13687 case GROUP_DPREG_1101: dexDPReg (cpu); break;
13688 case GROUP_LDST_1110: dexLdSt (cpu); break;
13689 case GROUP_ADVSIMD_1111: dexAdvSIMD1 (cpu); break;
13690
13691 case GROUP_UNALLOC_0001:
13692 case GROUP_UNALLOC_0010:
13693 case GROUP_UNALLOC_0011:
13694 HALT_UNALLOC;
13695
13696 default:
13697 /* Should never reach here. */
13698 HALT_NYI;
13699 }
13700}
13701
13702static bfd_boolean
13703aarch64_step (sim_cpu *cpu)
13704{
13705 uint64_t pc = aarch64_get_PC (cpu);
13706
13707 if (pc == TOP_LEVEL_RETURN_PC)
13708 return FALSE;
13709
13710 aarch64_set_next_PC (cpu, pc + 4);
13711 aarch64_get_instr (cpu) = aarch64_get_mem_u32 (cpu, pc);
13712
57aa1742 13713 TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %08x", pc,
1a846c62
MF
13714 aarch64_get_instr (cpu));
13715 TRACE_DISASM (cpu, pc);
2e8cf49e
NC
13716
13717 aarch64_decode_and_execute (cpu, pc);
13718
13719 return TRUE;
13720}
13721
13722void
13723aarch64_run (SIM_DESC sd)
13724{
13725 sim_cpu *cpu = STATE_CPU (sd, 0);
13726
13727 while (aarch64_step (cpu))
13728 aarch64_update_PC (cpu);
13729
13730 sim_engine_halt (sd, NULL, NULL, aarch64_get_PC (cpu),
13731 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13732}
13733
13734void
13735aarch64_init (sim_cpu *cpu, uint64_t pc)
13736{
13737 uint64_t sp = aarch64_get_stack_start (cpu);
13738
13739 /* Install SP, FP and PC and set LR to -20
13740 so we can detect a top-level return. */
13741 aarch64_set_reg_u64 (cpu, SP, SP_OK, sp);
13742 aarch64_set_reg_u64 (cpu, FP, SP_OK, sp);
13743 aarch64_set_reg_u64 (cpu, LR, SP_OK, TOP_LEVEL_RETURN_PC);
13744 aarch64_set_next_PC (cpu, pc);
13745 aarch64_update_PC (cpu);
13746 aarch64_init_LIT_table ();
13747}
This page took 0.608457 seconds and 4 git commands to generate.