Fix thinko in new GET_VEC_ELEMENT macro.
[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
NC
41
42#define HALT_UNALLOC \
43 do \
44 { \
1a846c62
MF
45 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
46 TRACE_INSN (cpu, \
47 "Unallocated instruction detected at sim line %d," \
48 " exe addr %" PRIx64, \
49 __LINE__, aarch64_get_PC (cpu)); \
2e8cf49e
NC
50 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
51 sim_stopped, SIM_SIGILL); \
52 } \
53 while (0)
54
55#define HALT_NYI \
56 do \
57 { \
1a846c62
MF
58 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
59 TRACE_INSN (cpu, \
60 "Unimplemented instruction detected at sim line %d," \
61 " exe addr %" PRIx64, \
62 __LINE__, aarch64_get_PC (cpu)); \
2e8cf49e
NC
63 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
64 sim_stopped, SIM_SIGABRT); \
65 } \
66 while (0)
67
68#define NYI_assert(HI, LO, EXPECTED) \
69 do \
70 { \
71 if (uimm (aarch64_get_instr (cpu), (HI), (LO)) != (EXPECTED)) \
72 HALT_NYI; \
73 } \
74 while (0)
75
76#define HALT_UNREACHABLE \
77 do \
78 { \
79 TRACE_EVENTS (cpu, "ISE: unreachable code point"); \
80 sim_engine_abort (NULL, cpu, aarch64_get_PC (cpu), "Internal Error"); \
81 } \
82 while (0)
83
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. */
182 uint32_t type = uimm (aarch64_get_instr (cpu), 14, 0);
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
237 dispatch = uimm (aarch64_get_instr (cpu), 31, 15);
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{
265 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
266 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
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{
277 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
278 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
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{
289 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
290 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
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{
301 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
302 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
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{
313 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
314 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
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{
325 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
326 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
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{
337 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
338 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
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{
349 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
350 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
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{
361 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
362 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
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{
376 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
377 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
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{
388 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
389 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
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{
400 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
401 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
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{
412 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
413 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
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{
428 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
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{
439 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
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{
450 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
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{
461 unsigned int rd = uimm (aarch64_get_instr (cpu), 4, 0);
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{
472 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
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{
483 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
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
500 argument. the second argument is either Byte, Short, Word
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{
541 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
542 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
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
556/* Load 32 bit scaled unsigned 12 bit. */
557static void
558fldrs_abs (sim_cpu *cpu, uint32_t offset)
559{
560 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
561 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
562
e101a78b
NC
563 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
564 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
565 + SCALE (offset, 32)));
2e8cf49e
NC
566}
567
568/* Load 32 bit scaled or unscaled zero- or sign-extended
569 32-bit register offset. */
570static void
571fldrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
572{
573 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
574 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
575 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
576 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
577 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
578 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
579
e101a78b
NC
580 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
581 (cpu, address + displacement));
2e8cf49e
NC
582}
583
584/* Load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
585static void
586fldrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
587{
588 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
589 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
590 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
591
592 if (wb != Post)
593 address += offset;
594
e101a78b 595 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64 (cpu, address));
2e8cf49e
NC
596
597 if (wb == Post)
598 address += offset;
599
600 if (wb != NoWriteBack)
601 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
602}
603
604/* Load 64 bit scaled unsigned 12 bit. */
605static void
606fldrd_abs (sim_cpu *cpu, uint32_t offset)
607{
608 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
609 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
610 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64);
611
e101a78b 612 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64 (cpu, address));
2e8cf49e
NC
613}
614
615/* Load 64 bit scaled or unscaled zero- or sign-extended 32-bit register offset. */
616static void
617fldrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
618{
619 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
620 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
621 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
622
623 fldrd_wb (cpu, displacement, NoWriteBack);
624}
625
626/* Load 128 bit unscaled signed 9 bit with pre- or post-writeback. */
627static void
628fldrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
629{
630 FRegister a;
631 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
632 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
633 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
634
635 if (wb != Post)
636 address += offset;
637
638 aarch64_get_mem_long_double (cpu, address, & a);
639 aarch64_set_FP_long_double (cpu, st, a);
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
648/* Load 128 bit scaled unsigned 12 bit. */
649static void
650fldrq_abs (sim_cpu *cpu, uint32_t offset)
651{
652 FRegister a;
653 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
654 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
655 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
656
657 aarch64_get_mem_long_double (cpu, address, & a);
658 aarch64_set_FP_long_double (cpu, st, a);
659}
660
661/* Load 128 bit scaled or unscaled zero- or sign-extended 32-bit register offset */
662static void
663fldrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
664{
665 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
666 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
667 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
668
669 fldrq_wb (cpu, displacement, NoWriteBack);
670}
671
672/* Memory Access
673
674 load-store single register
675 There are four addressing modes available here which all employ a
676 64 bit source (base) register.
677
678 N.B. the base register (source) can be the stack pointer.
679 The secondary source register (source2)can only be an Xn register.
680
681 Scaled, 12-bit, unsigned immediate offset, without pre- and
682 post-index options.
683 Unscaled, 9-bit, signed immediate offset with pre- or post-index
684 writeback.
685 scaled or unscaled 64-bit register offset.
686 scaled or unscaled 32-bit extended register offset.
687
688 All offsets are assumed to be raw from the decode i.e. the
689 simulator is expected to adjust scaled offsets based on the
690 accessed data size with register or extended register offset
691 versions the same applies except that in the latter case the
692 operation may also require a sign extend.
693
694 A separate method is provided for each possible addressing mode. */
695
696/* 32 bit load 32 bit scaled unsigned 12 bit */
697static void
698ldr32_abs (sim_cpu *cpu, uint32_t offset)
699{
700 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
701 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
702
703 /* The target register may not be SP but the source may be. */
704 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
705 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
706 + SCALE (offset, 32)));
707}
708
709/* 32 bit load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
710static void
711ldr32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
712{
713 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
714 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
715 uint64_t address;
716
717 if (rn == rt && wb != NoWriteBack)
718 HALT_UNALLOC;
719
720 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
721
722 if (wb != Post)
723 address += offset;
724
725 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
726
727 if (wb == Post)
728 address += offset;
729
730 if (wb != NoWriteBack)
731 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
732}
733
734/* 32 bit load 32 bit scaled or unscaled
735 zero- or sign-extended 32-bit register offset */
736static void
737ldr32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
738{
739 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
740 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
741 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
742 /* rn may reference SP, rm and rt must reference ZR */
743
744 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
745 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
746 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
747
748 aarch64_set_reg_u64 (cpu, rt, NO_SP,
749 aarch64_get_mem_u32 (cpu, address + displacement));
750}
751
752/* 64 bit load 64 bit scaled unsigned 12 bit */
753static void
754ldr_abs (sim_cpu *cpu, uint32_t offset)
755{
756 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
757 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
758
759 /* The target register may not be SP but the source may be. */
760 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
761 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
762 + SCALE (offset, 64)));
763}
764
765/* 64 bit load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
766static void
767ldr_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
768{
769 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
770 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
771 uint64_t address;
772
773 if (rn == rt && wb != NoWriteBack)
774 HALT_UNALLOC;
775
776 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
777
778 if (wb != Post)
779 address += offset;
780
781 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
782
783 if (wb == Post)
784 address += offset;
785
786 if (wb != NoWriteBack)
787 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
788}
789
790/* 64 bit load 64 bit scaled or unscaled zero-
791 or sign-extended 32-bit register offset. */
792static void
793ldr_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
794{
795 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
796 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
797 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
798 /* rn may reference SP, rm and rt must reference ZR */
799
800 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
801 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
802 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
803
804 aarch64_set_reg_u64 (cpu, rt, NO_SP,
805 aarch64_get_mem_u64 (cpu, address + displacement));
806}
807
808/* 32 bit load zero-extended byte scaled unsigned 12 bit. */
809static void
810ldrb32_abs (sim_cpu *cpu, uint32_t offset)
811{
812 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
813 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
814
815 /* The target register may not be SP but the source may be
816 there is no scaling required for a byte load. */
817 aarch64_set_reg_u64 (cpu, rt, NO_SP,
818 aarch64_get_mem_u8
819 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
820}
821
822/* 32 bit load zero-extended byte unscaled signed 9 bit with pre- or post-writeback. */
823static void
824ldrb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
825{
826 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
827 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
828 uint64_t address;
829
830 if (rn == rt && wb != NoWriteBack)
831 HALT_UNALLOC;
832
833 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
834
835 if (wb != Post)
836 address += offset;
837
838 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
839
840 if (wb == Post)
841 address += offset;
842
843 if (wb != NoWriteBack)
844 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
845}
846
847/* 32 bit load zero-extended byte scaled or unscaled zero-
848 or sign-extended 32-bit register offset. */
849static void
850ldrb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
851{
852 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
853 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
854 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
855 /* rn may reference SP, rm and rt must reference ZR */
856
857 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
858 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
859 extension);
860
861 /* There is no scaling required for a byte load. */
862 aarch64_set_reg_u64 (cpu, rt, NO_SP,
863 aarch64_get_mem_u8 (cpu, address + displacement));
864}
865
866/* 64 bit load sign-extended byte unscaled signed 9 bit
867 with pre- or post-writeback. */
868static void
869ldrsb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
870{
871 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
872 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
873 uint64_t address;
874
875 if (rn == rt && wb != NoWriteBack)
876 HALT_UNALLOC;
877
878 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
879
880 if (wb != Post)
881 address += offset;
882
883 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s8 (cpu, address));
884
885 if (wb == Post)
886 address += offset;
887
888 if (wb != NoWriteBack)
889 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
890}
891
892/* 64 bit load sign-extended byte scaled unsigned 12 bit. */
893static void
894ldrsb_abs (sim_cpu *cpu, uint32_t offset)
895{
896 ldrsb_wb (cpu, offset, NoWriteBack);
897}
898
899/* 64 bit load sign-extended byte scaled or unscaled zero-
900 or sign-extended 32-bit register offset. */
901static void
902ldrsb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
903{
904 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
905 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
906 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
907 /* rn may reference SP, rm and rt must reference ZR */
908
909 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
910 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
911 extension);
912 /* There is no scaling required for a byte load. */
913 aarch64_set_reg_u64 (cpu, rt, NO_SP,
914 aarch64_get_mem_s8 (cpu, address + displacement));
915}
916
917/* 32 bit load zero-extended short scaled unsigned 12 bit. */
918static void
919ldrh32_abs (sim_cpu *cpu, uint32_t offset)
920{
921 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
922 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
923
924 /* The target register may not be SP but the source may be. */
925 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16
926 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
927 + SCALE (offset, 16)));
928}
929
930/* 32 bit load zero-extended short unscaled signed 9 bit
931 with pre- or post-writeback. */
932static void
933ldrh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
934{
935 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
936 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
937 uint64_t address;
938
939 if (rn == rt && wb != NoWriteBack)
940 HALT_UNALLOC;
941
942 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
943
944 if (wb != Post)
945 address += offset;
946
947 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
948
949 if (wb == Post)
950 address += offset;
951
952 if (wb != NoWriteBack)
953 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
954}
955
956/* 32 bit load zero-extended short scaled or unscaled zero-
957 or sign-extended 32-bit register offset. */
958static void
959ldrh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
960{
961 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
962 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
963 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
964 /* rn may reference SP, rm and rt must reference ZR */
965
966 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
967 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
968 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
969
970 aarch64_set_reg_u64 (cpu, rt, NO_SP,
971 aarch64_get_mem_u16 (cpu, address + displacement));
972}
973
974/* 32 bit load sign-extended short scaled unsigned 12 bit. */
975static void
976ldrsh32_abs (sim_cpu *cpu, uint32_t offset)
977{
978 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
979 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
980
981 /* The target register may not be SP but the source may be. */
982 aarch64_set_reg_u64 (cpu, rt, NO_SP, (uint32_t) aarch64_get_mem_s16
983 (cpu,
984 aarch64_get_reg_u64 (cpu, rn, SP_OK)
985 + SCALE (offset, 16)));
986}
987
988/* 32 bit load sign-extended short unscaled signed 9 bit
989 with pre- or post-writeback. */
990static void
991ldrsh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
992{
993 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
994 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
995 uint64_t address;
996
997 if (rn == rt && wb != NoWriteBack)
998 HALT_UNALLOC;
999
1000 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1001
1002 if (wb != Post)
1003 address += offset;
1004
1005 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1006 (uint32_t) aarch64_get_mem_s16 (cpu, address));
1007
1008 if (wb == Post)
1009 address += offset;
1010
1011 if (wb != NoWriteBack)
1012 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1013}
1014
1015/* 32 bit load sign-extended short scaled or unscaled zero-
1016 or sign-extended 32-bit register offset. */
1017static void
1018ldrsh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1019{
1020 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1021 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1022 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1023 /* rn may reference SP, rm and rt must reference ZR */
1024
1025 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1026 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1027 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1028
1029 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1030 (uint32_t) aarch64_get_mem_s16
1031 (cpu, address + displacement));
1032}
1033
1034/* 64 bit load sign-extended short scaled unsigned 12 bit. */
1035static void
1036ldrsh_abs (sim_cpu *cpu, uint32_t offset)
1037{
1038 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1039 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1040
1041 /* The target register may not be SP but the source may be. */
1042 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s16
1043 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1044 + SCALE (offset, 16)));
1045}
1046
1047/* 64 bit load sign-extended short unscaled signed 9 bit
1048 with pre- or post-writeback. */
1049static void
1050ldrsh64_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1051{
1052 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1053 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1054 uint64_t address;
1055
1056 if (rn == rt && wb != NoWriteBack)
1057 HALT_UNALLOC;
1058
1059 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1060
1061 if (wb != Post)
1062 address += offset;
1063
1064 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s16 (cpu, address));
1065
1066 if (wb == Post)
1067 address += offset;
1068
1069 if (wb != NoWriteBack)
1070 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1071}
1072
1073/* 64 bit load sign-extended short scaled or unscaled zero-
1074 or sign-extended 32-bit register offset. */
1075static void
1076ldrsh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1077{
1078 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1079 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1080 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1081 /* rn may reference SP, rm and rt must reference ZR */
1082
1083 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1084 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1085 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1086
1087 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1088 aarch64_get_mem_s16 (cpu, address + displacement));
1089}
1090
1091/* 64 bit load sign-extended 32 bit scaled unsigned 12 bit. */
1092static void
1093ldrsw_abs (sim_cpu *cpu, uint32_t offset)
1094{
1095 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1096 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1097
1098 /* The target register may not be SP but the source may be. */
1099 return aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32
1100 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1101 + SCALE (offset, 32)));
1102}
1103
1104/* 64 bit load sign-extended 32 bit unscaled signed 9 bit
1105 with pre- or post-writeback. */
1106static void
1107ldrsw_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1108{
1109 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1110 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1111 uint64_t address;
1112
1113 if (rn == rt && wb != NoWriteBack)
1114 HALT_UNALLOC;
1115
1116 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1117
1118 if (wb != Post)
1119 address += offset;
1120
1121 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32 (cpu, address));
1122
1123 if (wb == Post)
1124 address += offset;
1125
1126 if (wb != NoWriteBack)
1127 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1128}
1129
1130/* 64 bit load sign-extended 32 bit scaled or unscaled zero-
1131 or sign-extended 32-bit register offset. */
1132static void
1133ldrsw_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1134{
1135 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1136 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1137 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1138 /* rn may reference SP, rm and rt must reference ZR */
1139
1140 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1141 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1142 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1143
1144 aarch64_set_reg_s64 (cpu, rt, NO_SP,
1145 aarch64_get_mem_s32 (cpu, address + displacement));
1146}
1147
1148/* N.B. with stores the value in source is written to the
1149 address identified by source2 modified by source3/offset. */
1150
1151/* 32 bit store scaled unsigned 12 bit. */
1152static void
1153str32_abs (sim_cpu *cpu, uint32_t offset)
1154{
1155 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1156 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1157
1158 /* The target register may not be SP but the source may be. */
1159 aarch64_set_mem_u32 (cpu, (aarch64_get_reg_u64 (cpu, rn, SP_OK)
1160 + SCALE (offset, 32)),
1161 aarch64_get_reg_u32 (cpu, rt, NO_SP));
1162}
1163
1164/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
1165static void
1166str32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1167{
1168 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1169 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1170 uint64_t address;
1171
1172 if (rn == rt && wb != NoWriteBack)
1173 HALT_UNALLOC;
1174
1175 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1176 if (wb != Post)
1177 address += offset;
1178
1179 aarch64_set_mem_u32 (cpu, address, aarch64_get_reg_u32 (cpu, rt, NO_SP));
1180
1181 if (wb == Post)
1182 address += offset;
1183
1184 if (wb != NoWriteBack)
1185 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1186}
1187
1188/* 32 bit store scaled or unscaled zero- or
1189 sign-extended 32-bit register offset. */
1190static void
1191str32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1192{
1193 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1194 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1195 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1196
1197 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1198 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1199 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1200
1201 aarch64_set_mem_u32 (cpu, address + displacement,
1202 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1203}
1204
1205/* 64 bit store scaled unsigned 12 bit. */
1206static void
1207str_abs (sim_cpu *cpu, uint32_t offset)
1208{
1209 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1210 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1211
1212 aarch64_set_mem_u64 (cpu,
1213 aarch64_get_reg_u64 (cpu, rn, SP_OK)
1214 + SCALE (offset, 64),
1215 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1216}
1217
1218/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
1219static void
1220str_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1221{
1222 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1223 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1224 uint64_t address;
1225
1226 if (rn == rt && wb != NoWriteBack)
1227 HALT_UNALLOC;
1228
1229 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1230
1231 if (wb != Post)
1232 address += offset;
1233
1234 aarch64_set_mem_u64 (cpu, address, aarch64_get_reg_u64 (cpu, rt, NO_SP));
1235
1236 if (wb == Post)
1237 address += offset;
1238
1239 if (wb != NoWriteBack)
1240 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1241}
1242
1243/* 64 bit store scaled or unscaled zero-
1244 or sign-extended 32-bit register offset. */
1245static void
1246str_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1247{
1248 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1249 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1250 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1251 /* rn may reference SP, rm and rt must reference ZR */
1252
1253 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1254 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1255 extension);
1256 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1257
1258 aarch64_set_mem_u64 (cpu, address + displacement,
1259 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1260}
1261
1262/* 32 bit store byte scaled unsigned 12 bit. */
1263static void
1264strb_abs (sim_cpu *cpu, uint32_t offset)
1265{
1266 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1267 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1268
1269 /* The target register may not be SP but the source may be.
1270 There is no scaling required for a byte load. */
1271 aarch64_set_mem_u8 (cpu,
1272 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
1273 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1274}
1275
1276/* 32 bit store byte unscaled signed 9 bit with pre- or post-writeback. */
1277static void
1278strb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1279{
1280 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1281 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1282 uint64_t address;
1283
1284 if (rn == rt && wb != NoWriteBack)
1285 HALT_UNALLOC;
1286
1287 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1288
1289 if (wb != Post)
1290 address += offset;
1291
1292 aarch64_set_mem_u8 (cpu, address, aarch64_get_reg_u8 (cpu, rt, NO_SP));
1293
1294 if (wb == Post)
1295 address += offset;
1296
1297 if (wb != NoWriteBack)
1298 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1299}
1300
1301/* 32 bit store byte scaled or unscaled zero-
1302 or sign-extended 32-bit register offset. */
1303static void
1304strb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1305{
1306 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1307 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1308 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1309 /* rn may reference SP, rm and rt must reference ZR */
1310
1311 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1312 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1313 extension);
1314
1315 /* There is no scaling required for a byte load. */
1316 aarch64_set_mem_u8 (cpu, address + displacement,
1317 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1318}
1319
1320/* 32 bit store short scaled unsigned 12 bit. */
1321static void
1322strh_abs (sim_cpu *cpu, uint32_t offset)
1323{
1324 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1325 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1326
1327 /* The target register may not be SP but the source may be. */
1328 aarch64_set_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1329 + SCALE (offset, 16),
1330 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1331}
1332
1333/* 32 bit store short unscaled signed 9 bit with pre- or post-writeback. */
1334static void
1335strh_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1336{
1337 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1338 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1339 uint64_t address;
1340
1341 if (rn == rt && wb != NoWriteBack)
1342 HALT_UNALLOC;
1343
1344 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1345
1346 if (wb != Post)
1347 address += offset;
1348
1349 aarch64_set_mem_u16 (cpu, address, aarch64_get_reg_u16 (cpu, rt, NO_SP));
1350
1351 if (wb == Post)
1352 address += offset;
1353
1354 if (wb != NoWriteBack)
1355 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1356}
1357
1358/* 32 bit store short scaled or unscaled zero-
1359 or sign-extended 32-bit register offset. */
1360static void
1361strh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1362{
1363 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1364 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1365 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1366 /* rn may reference SP, rm and rt must reference ZR */
1367
1368 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1369 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1370 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1371
1372 aarch64_set_mem_u16 (cpu, address + displacement,
1373 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1374}
1375
1376/* Prefetch unsigned 12 bit. */
1377static void
1378prfm_abs (sim_cpu *cpu, uint32_t offset)
1379{
1380 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1381 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1382 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1383 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1384 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1385 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1386 ow ==> UNALLOC
1387 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1388 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK)
1389 + SCALE (offset, 64). */
1390
1391 /* TODO : implement prefetch of address. */
1392}
1393
1394/* Prefetch scaled or unscaled zero- or sign-extended 32-bit register offset. */
1395static void
1396prfm_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1397{
1398 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1399 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1400 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1401 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1402 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1403 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1404 ow ==> UNALLOC
1405 rn may reference SP, rm may only reference ZR
1406 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1407 uint64_t base = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1408 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1409 extension);
1410 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1411 uint64_t address = base + displacement. */
1412
1413 /* TODO : implement prefetch of address */
1414}
1415
1416/* 64 bit pc-relative prefetch. */
1417static void
1418prfm_pcrel (sim_cpu *cpu, int32_t offset)
1419{
1420 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1421 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1422 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1423 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1424 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1425 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1426 ow ==> UNALLOC
1427 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1428 uint64_t address = aarch64_get_PC (cpu) + offset. */
1429
1430 /* TODO : implement this */
1431}
1432
1433/* Load-store exclusive. */
1434
1435static void
1436ldxr (sim_cpu *cpu)
1437{
1438 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1439 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1440 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1441 int size = uimm (aarch64_get_instr (cpu), 31, 30);
1442 /* int ordered = uimm (aarch64_get_instr (cpu), 15, 15); */
1443 /* int exclusive = ! uimm (aarch64_get_instr (cpu), 23, 23); */
1444
1445 switch (size)
1446 {
1447 case 0:
1448 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
1449 break;
1450 case 1:
1451 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
1452 break;
1453 case 2:
1454 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
1455 break;
1456 case 3:
1457 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
1458 break;
1459 default:
1460 HALT_UNALLOC;
1461 }
1462}
1463
1464static void
1465stxr (sim_cpu *cpu)
1466{
1467 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1468 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1469 unsigned rs = uimm (aarch64_get_instr (cpu), 20, 16);
1470 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1471 int size = uimm (aarch64_get_instr (cpu), 31, 30);
1472 uint64_t data = aarch64_get_reg_u64 (cpu, rt, NO_SP);
1473
1474 switch (size)
1475 {
1476 case 0: aarch64_set_mem_u8 (cpu, address, data); break;
1477 case 1: aarch64_set_mem_u16 (cpu, address, data); break;
1478 case 2: aarch64_set_mem_u32 (cpu, address, data); break;
1479 case 3: aarch64_set_mem_u64 (cpu, address, data); break;
1480 default: HALT_UNALLOC;
1481 }
1482
1483 aarch64_set_reg_u64 (cpu, rs, NO_SP, 0); /* Always exclusive... */
1484}
1485
1486static void
1487dexLoadLiteral (sim_cpu *cpu)
1488{
1489 /* instr[29,27] == 011
1490 instr[25,24] == 00
1491 instr[31,30:26] = opc: 000 ==> LDRW, 001 ==> FLDRS
1492 010 ==> LDRX, 011 ==> FLDRD
1493 100 ==> LDRSW, 101 ==> FLDRQ
1494 110 ==> PRFM, 111 ==> UNALLOC
1495 instr[26] ==> V : 0 ==> GReg, 1 ==> FReg
1496 instr[23, 5] == simm19 */
1497
1498 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
1499 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 1)
1500 | uimm (aarch64_get_instr (cpu), 26, 26));
1501 int32_t imm = simm32 (aarch64_get_instr (cpu), 23, 5);
1502
1503 switch (dispatch)
1504 {
1505 case 0: ldr32_pcrel (cpu, imm); break;
1506 case 1: fldrs_pcrel (cpu, imm); break;
1507 case 2: ldr_pcrel (cpu, imm); break;
1508 case 3: fldrd_pcrel (cpu, imm); break;
1509 case 4: ldrsw_pcrel (cpu, imm); break;
1510 case 5: fldrq_pcrel (cpu, imm); break;
1511 case 6: prfm_pcrel (cpu, imm); break;
1512 case 7:
1513 default:
1514 HALT_UNALLOC;
1515 }
1516}
1517
1518/* Immediate arithmetic
1519 The aimm argument is a 12 bit unsigned value or a 12 bit unsigned
1520 value left shifted by 12 bits (done at decode).
1521
1522 N.B. the register args (dest, source) can normally be Xn or SP.
1523 the exception occurs for flag setting instructions which may
1524 only use Xn for the output (dest). */
1525
1526/* 32 bit add immediate. */
1527static void
1528add32 (sim_cpu *cpu, uint32_t aimm)
1529{
1530 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1531 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1532
1533 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1534 aarch64_get_reg_u32 (cpu, rn, SP_OK) + aimm);
1535}
1536
1537/* 64 bit add immediate. */
1538static void
1539add64 (sim_cpu *cpu, uint32_t aimm)
1540{
1541 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1542 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1543
1544 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1545 aarch64_get_reg_u64 (cpu, rn, SP_OK) + aimm);
1546}
1547
1548static void
1549set_flags_for_add32 (sim_cpu *cpu, int32_t value1, int32_t value2)
1550{
1551 int32_t result = value1 + value2;
1552 int64_t sresult = (int64_t) value1 + (int64_t) value2;
1553 uint64_t uresult = (uint64_t)(uint32_t) value1
1554 + (uint64_t)(uint32_t) value2;
1555 uint32_t flags = 0;
1556
1557 if (result == 0)
1558 flags |= Z;
1559
1560 if (result & (1 << 31))
1561 flags |= N;
1562
1563 if (uresult != result)
1564 flags |= C;
1565
1566 if (sresult != result)
1567 flags |= V;
1568
1569 aarch64_set_CPSR (cpu, flags);
1570}
1571
1572static void
1573set_flags_for_add64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1574{
1575 int64_t sval1 = value1;
1576 int64_t sval2 = value2;
1577 uint64_t result = value1 + value2;
1578 int64_t sresult = sval1 + sval2;
1579 uint32_t flags = 0;
1580
1581 if (result == 0)
1582 flags |= Z;
1583
1584 if (result & (1ULL << 63))
1585 flags |= N;
1586
1587 if (sval1 < 0)
1588 {
1589 if (sval2 < 0)
1590 {
1591 /* Negative plus a negative. Overflow happens if
1592 the result is greater than either of the operands. */
1593 if (sresult > sval1 || sresult > sval2)
1594 flags |= V;
1595 }
1596 /* else Negative plus a positive. Overflow cannot happen. */
1597 }
1598 else /* value1 is +ve. */
1599 {
1600 if (sval2 < 0)
1601 {
1602 /* Overflow can only occur if we computed "0 - MININT". */
1603 if (sval1 == 0 && sval2 == (1LL << 63))
1604 flags |= V;
1605 }
1606 else
1607 {
1608 /* Postive plus positive - overflow has happened if the
1609 result is smaller than either of the operands. */
1610 if (result < value1 || result < value2)
1611 flags |= V | C;
1612 }
1613 }
1614
1615 aarch64_set_CPSR (cpu, flags);
1616}
1617
1618#define NEG(a) (((a) & signbit) == signbit)
1619#define POS(a) (((a) & signbit) == 0)
1620
1621static void
1622set_flags_for_sub32 (sim_cpu *cpu, uint32_t value1, uint32_t value2)
1623{
1624 uint32_t result = value1 - value2;
1625 uint32_t flags = 0;
57aa1742 1626 uint32_t signbit = 1U << 31;
2e8cf49e
NC
1627
1628 if (result == 0)
1629 flags |= Z;
1630
1631 if (NEG (result))
1632 flags |= N;
1633
1634 if ( (NEG (value1) && POS (value2))
1635 || (NEG (value1) && POS (result))
1636 || (POS (value2) && POS (result)))
1637 flags |= C;
1638
1639 if ( (NEG (value1) && POS (value2) && POS (result))
1640 || (POS (value1) && NEG (value2) && NEG (result)))
1641 flags |= V;
1642
1643 aarch64_set_CPSR (cpu, flags);
1644}
1645
1646static void
1647set_flags_for_sub64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1648{
1649 uint64_t result = value1 - value2;
1650 uint32_t flags = 0;
1651 uint64_t signbit = 1ULL << 63;
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_binop32 (sim_cpu *cpu, uint32_t result)
1673{
1674 uint32_t flags = 0;
1675
1676 if (result == 0)
1677 flags |= Z;
1678 else
1679 flags &= ~ Z;
1680
1681 if (result & (1 << 31))
1682 flags |= N;
1683 else
1684 flags &= ~ N;
1685
1686 aarch64_set_CPSR (cpu, flags);
1687}
1688
1689static void
1690set_flags_for_binop64 (sim_cpu *cpu, uint64_t result)
1691{
1692 uint32_t flags = 0;
1693
1694 if (result == 0)
1695 flags |= Z;
1696 else
1697 flags &= ~ Z;
1698
1699 if (result & (1ULL << 63))
1700 flags |= N;
1701 else
1702 flags &= ~ N;
1703
1704 aarch64_set_CPSR (cpu, flags);
1705}
1706
1707/* 32 bit add immediate set flags. */
1708static void
1709adds32 (sim_cpu *cpu, uint32_t aimm)
1710{
1711 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1712 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1713 /* TODO : do we need to worry about signs here? */
1714 int32_t value1 = aarch64_get_reg_s32 (cpu, rn, SP_OK);
1715
1716 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + aimm);
1717 set_flags_for_add32 (cpu, value1, aimm);
1718}
1719
1720/* 64 bit add immediate set flags. */
1721static void
1722adds64 (sim_cpu *cpu, uint32_t aimm)
1723{
1724 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1725 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1726 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1727 uint64_t value2 = aimm;
1728
1729 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1730 set_flags_for_add64 (cpu, value1, value2);
1731}
1732
1733/* 32 bit sub immediate. */
1734static void
1735sub32 (sim_cpu *cpu, uint32_t aimm)
1736{
1737 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1738 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1739
1740 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1741 aarch64_get_reg_u32 (cpu, rn, SP_OK) - aimm);
1742}
1743
1744/* 64 bit sub immediate. */
1745static void
1746sub64 (sim_cpu *cpu, uint32_t aimm)
1747{
1748 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1749 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1750
1751 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1752 aarch64_get_reg_u64 (cpu, rn, SP_OK) - aimm);
1753}
1754
1755/* 32 bit sub immediate set flags. */
1756static void
1757subs32 (sim_cpu *cpu, uint32_t aimm)
1758{
1759 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1760 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1761 uint32_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1762 uint32_t value2 = aimm;
1763
1764 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1765 set_flags_for_sub32 (cpu, value1, value2);
1766}
1767
1768/* 64 bit sub immediate set flags. */
1769static void
1770subs64 (sim_cpu *cpu, uint32_t aimm)
1771{
1772 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1773 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1774 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1775 uint32_t value2 = aimm;
1776
1777 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1778 set_flags_for_sub64 (cpu, value1, value2);
1779}
1780
1781/* Data Processing Register. */
1782
1783/* First two helpers to perform the shift operations. */
1784
1785static inline uint32_t
1786shifted32 (uint32_t value, Shift shift, uint32_t count)
1787{
1788 switch (shift)
1789 {
1790 default:
1791 case LSL:
1792 return (value << count);
1793 case LSR:
1794 return (value >> count);
1795 case ASR:
1796 {
1797 int32_t svalue = value;
1798 return (svalue >> count);
1799 }
1800 case ROR:
1801 {
1802 uint32_t top = value >> count;
1803 uint32_t bottom = value << (32 - count);
1804 return (bottom | top);
1805 }
1806 }
1807}
1808
1809static inline uint64_t
1810shifted64 (uint64_t value, Shift shift, uint32_t count)
1811{
1812 switch (shift)
1813 {
1814 default:
1815 case LSL:
1816 return (value << count);
1817 case LSR:
1818 return (value >> count);
1819 case ASR:
1820 {
1821 int64_t svalue = value;
1822 return (svalue >> count);
1823 }
1824 case ROR:
1825 {
1826 uint64_t top = value >> count;
1827 uint64_t bottom = value << (64 - count);
1828 return (bottom | top);
1829 }
1830 }
1831}
1832
1833/* Arithmetic shifted register.
1834 These allow an optional LSL, ASR or LSR to the second source
1835 register with a count up to the register bit count.
1836
1837 N.B register args may not be SP. */
1838
1839/* 32 bit ADD shifted register. */
1840static void
1841add32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1842{
1843 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1844 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1845 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1846
1847 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1848 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1849 + shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1850 shift, count));
1851}
1852
1853/* 64 bit ADD shifted register. */
1854static void
1855add64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1856{
1857 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1858 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1859 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1860
1861 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1862 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1863 + shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1864 shift, count));
1865}
1866
1867/* 32 bit ADD shifted register setting flags. */
1868static void
1869adds32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1870{
1871 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1872 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1873 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1874
1875 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1876 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1877 shift, count);
1878
1879 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1880 set_flags_for_add32 (cpu, value1, value2);
1881}
1882
1883/* 64 bit ADD shifted register setting flags. */
1884static void
1885adds64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1886{
1887 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1888 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1889 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1890
1891 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1892 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1893 shift, count);
1894
1895 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1896 set_flags_for_add64 (cpu, value1, value2);
1897}
1898
1899/* 32 bit SUB shifted register. */
1900static void
1901sub32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1902{
1903 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1904 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1905 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1906
1907 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1908 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1909 - shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1910 shift, count));
1911}
1912
1913/* 64 bit SUB shifted register. */
1914static void
1915sub64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1916{
1917 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1918 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1919 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1920
1921 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1922 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1923 - shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1924 shift, count));
1925}
1926
1927/* 32 bit SUB shifted register setting flags. */
1928static void
1929subs32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1930{
1931 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1932 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1933 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1934
1935 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1936 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1937 shift, count);
1938
1939 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1940 set_flags_for_sub32 (cpu, value1, value2);
1941}
1942
1943/* 64 bit SUB shifted register setting flags. */
1944static void
1945subs64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1946{
1947 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1948 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1949 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1950
1951 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1952 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1953 shift, count);
1954
1955 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1956 set_flags_for_sub64 (cpu, value1, value2);
1957}
1958
1959/* First a couple more helpers to fetch the
1960 relevant source register element either
1961 sign or zero extended as required by the
1962 extension value. */
1963
1964static uint32_t
1965extreg32 (sim_cpu *cpu, unsigned int lo, Extension extension)
1966{
1967 switch (extension)
1968 {
1969 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
1970 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
1971 case UXTW: /* Fall through. */
1972 case UXTX: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
1973 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
1974 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
1975 case SXTW: /* Fall through. */
1976 case SXTX: /* Fall through. */
1977 default: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
1978 }
1979}
1980
1981static uint64_t
1982extreg64 (sim_cpu *cpu, unsigned int lo, Extension extension)
1983{
1984 switch (extension)
1985 {
1986 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
1987 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
1988 case UXTW: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
1989 case UXTX: return aarch64_get_reg_u64 (cpu, lo, NO_SP);
1990 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
1991 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
1992 case SXTW: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
1993 case SXTX:
1994 default: return aarch64_get_reg_s64 (cpu, lo, NO_SP);
1995 }
1996}
1997
1998/* Arithmetic extending register
1999 These allow an optional sign extension of some portion of the
2000 second source register followed by an optional left shift of
2001 between 1 and 4 bits (i.e. a shift of 0-4 bits???)
2002
2003 N.B output (dest) and first input arg (source) may normally be Xn
2004 or SP. However, for flag setting operations dest can only be
2005 Xn. Second input registers are always Xn. */
2006
2007/* 32 bit ADD extending register. */
2008static void
2009add32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2010{
2011 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2012 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2013 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2014
2015 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2016 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2017 + (extreg32 (cpu, rm, extension) << shift));
2018}
2019
2020/* 64 bit ADD extending register.
2021 N.B. This subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2022static void
2023add64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2024{
2025 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2026 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2027 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2028
2029 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2030 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2031 + (extreg64 (cpu, rm, extension) << shift));
2032}
2033
2034/* 32 bit ADD extending register setting flags. */
2035static void
2036adds32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2037{
2038 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2039 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2040 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2041
2042 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2043 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2044
2045 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2046 set_flags_for_add32 (cpu, value1, value2);
2047}
2048
2049/* 64 bit ADD extending register setting flags */
2050/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2051static void
2052adds64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2053{
2054 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2055 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2056 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2057
2058 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2059 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2060
2061 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2062 set_flags_for_add64 (cpu, value1, value2);
2063}
2064
2065/* 32 bit SUB extending register. */
2066static void
2067sub32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2068{
2069 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2070 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2071 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2072
2073 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2074 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2075 - (extreg32 (cpu, rm, extension) << shift));
2076}
2077
2078/* 64 bit SUB extending register. */
2079/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2080static void
2081sub64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2082{
2083 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2084 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2085 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2086
2087 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2088 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2089 - (extreg64 (cpu, rm, extension) << shift));
2090}
2091
2092/* 32 bit SUB extending register setting flags. */
2093static void
2094subs32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2095{
2096 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2097 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2098 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2099
2100 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2101 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2102
2103 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2104 set_flags_for_sub32 (cpu, value1, value2);
2105}
2106
2107/* 64 bit SUB extending register setting flags */
2108/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2109static void
2110subs64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2111{
2112 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2113 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2114 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2115
2116 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2117 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2118
2119 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2120 set_flags_for_sub64 (cpu, value1, value2);
2121}
2122
2123static void
2124dexAddSubtractImmediate (sim_cpu *cpu)
2125{
2126 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2127 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2128 instr[29] = set : 0 ==> no flags, 1 ==> set flags
2129 instr[28,24] = 10001
2130 instr[23,22] = shift : 00 == LSL#0, 01 = LSL#12 1x = UNALLOC
2131 instr[21,10] = uimm12
2132 instr[9,5] = Rn
2133 instr[4,0] = Rd */
2134
2135 /* N.B. the shift is applied at decode before calling the add/sub routine. */
2136 uint32_t shift = uimm (aarch64_get_instr (cpu), 23, 22);
2137 uint32_t imm = uimm (aarch64_get_instr (cpu), 21, 10);
2138 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2139
2140 NYI_assert (28, 24, 0x11);
2141
2142 if (shift > 1)
2143 HALT_UNALLOC;
2144
2145 if (shift)
2146 imm <<= 12;
2147
2148 switch (dispatch)
2149 {
2150 case 0: add32 (cpu, imm); break;
2151 case 1: adds32 (cpu, imm); break;
2152 case 2: sub32 (cpu, imm); break;
2153 case 3: subs32 (cpu, imm); break;
2154 case 4: add64 (cpu, imm); break;
2155 case 5: adds64 (cpu, imm); break;
2156 case 6: sub64 (cpu, imm); break;
2157 case 7: subs64 (cpu, imm); break;
2158 default:
2159 HALT_UNALLOC;
2160 }
2161}
2162
2163static void
2164dexAddSubtractShiftedRegister (sim_cpu *cpu)
2165{
2166 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2167 instr[30,29] = op : 00 ==> ADD, 01 ==> ADDS, 10 ==> SUB, 11 ==> SUBS
2168 instr[28,24] = 01011
2169 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> UNALLOC
2170 instr[21] = 0
2171 instr[20,16] = Rm
2172 instr[15,10] = count : must be 0xxxxx for 32 bit
2173 instr[9,5] = Rn
2174 instr[4,0] = Rd */
2175
2176 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
2177 /* 32 bit operations must have count[5] = 0
2178 or else we have an UNALLOC. */
2179 uint32_t count = uimm (aarch64_get_instr (cpu), 15, 10);
2180 /* Shift encoded as ROR is unallocated. */
2181 Shift shiftType = shift (aarch64_get_instr (cpu), 22);
2182 /* Dispatch on size:op i.e aarch64_get_instr (cpu)[31,29]. */
2183 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2184
2185 NYI_assert (28, 24, 0x0B);
2186 NYI_assert (21, 21, 0);
2187
2188 if (shiftType == ROR)
2189 HALT_UNALLOC;
2190
2191 if (!size && uimm (count, 5, 5))
2192 HALT_UNALLOC;
2193
2194 switch (dispatch)
2195 {
2196 case 0: add32_shift (cpu, shiftType, count); break;
2197 case 1: adds32_shift (cpu, shiftType, count); break;
2198 case 2: sub32_shift (cpu, shiftType, count); break;
2199 case 3: subs32_shift (cpu, shiftType, count); break;
2200 case 4: add64_shift (cpu, shiftType, count); break;
2201 case 5: adds64_shift (cpu, shiftType, count); break;
2202 case 6: sub64_shift (cpu, shiftType, count); break;
2203 case 7: subs64_shift (cpu, shiftType, count); break;
2204 default:
2205 HALT_UNALLOC;
2206 }
2207}
2208
2209static void
2210dexAddSubtractExtendedRegister (sim_cpu *cpu)
2211{
2212 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2213 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2214 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2215 instr[28,24] = 01011
2216 instr[23,22] = opt : 0 ==> ok, 1,2,3 ==> UNALLOC
2217 instr[21] = 1
2218 instr[20,16] = Rm
2219 instr[15,13] = option : 000 ==> UXTB, 001 ==> UXTH,
2220 000 ==> LSL|UXTW, 001 ==> UXTZ,
2221 000 ==> SXTB, 001 ==> SXTH,
2222 000 ==> SXTW, 001 ==> SXTX,
2223 instr[12,10] = shift : 0,1,2,3,4 ==> ok, 5,6,7 ==> UNALLOC
2224 instr[9,5] = Rn
2225 instr[4,0] = Rd */
2226
2227 Extension extensionType = extension (aarch64_get_instr (cpu), 13);
2228 uint32_t shift = uimm (aarch64_get_instr (cpu), 12, 10);
2229 /* dispatch on size:op:set? i.e aarch64_get_instr (cpu)[31,29] */
2230 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2231
2232 NYI_assert (28, 24, 0x0B);
2233 NYI_assert (21, 21, 1);
2234
2235 /* Shift may not exceed 4. */
2236 if (shift > 4)
2237 HALT_UNALLOC;
2238
2239 switch (dispatch)
2240 {
2241 case 0: add32_ext (cpu, extensionType, shift); break;
2242 case 1: adds32_ext (cpu, extensionType, shift); break;
2243 case 2: sub32_ext (cpu, extensionType, shift); break;
2244 case 3: subs32_ext (cpu, extensionType, shift); break;
2245 case 4: add64_ext (cpu, extensionType, shift); break;
2246 case 5: adds64_ext (cpu, extensionType, shift); break;
2247 case 6: sub64_ext (cpu, extensionType, shift); break;
2248 case 7: subs64_ext (cpu, extensionType, shift); break;
2249 default: HALT_UNALLOC;
2250 }
2251}
2252
2253/* Conditional data processing
2254 Condition register is implicit 3rd source. */
2255
2256/* 32 bit add with carry. */
2257/* N.B register args may not be SP. */
2258
2259static void
2260adc32 (sim_cpu *cpu)
2261{
2262 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2263 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2264 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2265
2266 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2267 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2268 + aarch64_get_reg_u32 (cpu, rm, NO_SP)
2269 + IS_SET (C));
2270}
2271
2272/* 64 bit add with carry */
2273static void
2274adc64 (sim_cpu *cpu)
2275{
2276 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2277 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2278 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2279
2280 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2281 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2282 + aarch64_get_reg_u64 (cpu, rm, NO_SP)
2283 + IS_SET (C));
2284}
2285
2286/* 32 bit add with carry setting flags. */
2287static void
2288adcs32 (sim_cpu *cpu)
2289{
2290 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2291 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2292 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2293
2294 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2295 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2296 uint32_t carry = IS_SET (C);
2297
2298 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2299 set_flags_for_add32 (cpu, value1, value2 + carry);
2300}
2301
2302/* 64 bit add with carry setting flags. */
2303static void
2304adcs64 (sim_cpu *cpu)
2305{
2306 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2307 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2308 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2309
2310 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2311 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2312 uint64_t carry = IS_SET (C);
2313
2314 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2315 set_flags_for_add64 (cpu, value1, value2 + carry);
2316}
2317
2318/* 32 bit sub with carry. */
2319static void
2320sbc32 (sim_cpu *cpu)
2321{
2322 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
e101a78b 2323 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5); /* ngc iff rn == 31. */
2e8cf49e
NC
2324 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2325
2326 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2327 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2328 - aarch64_get_reg_u32 (cpu, rm, NO_SP)
2329 - 1 + IS_SET (C));
2330}
2331
2332/* 64 bit sub with carry */
2333static void
2334sbc64 (sim_cpu *cpu)
2335{
2336 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2337 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2338 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2339
2340 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2341 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2342 - aarch64_get_reg_u64 (cpu, rm, NO_SP)
2343 - 1 + IS_SET (C));
2344}
2345
2346/* 32 bit sub with carry setting flags */
2347static void
2348sbcs32 (sim_cpu *cpu)
2349{
2350 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2351 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2352 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2353
2354 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2355 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2356 uint32_t carry = IS_SET (C);
2357 uint32_t result = value1 - value2 + 1 - carry;
2358
2359 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2360 set_flags_for_sub32 (cpu, value1, value2 + 1 - carry);
2361}
2362
2363/* 64 bit sub with carry setting flags */
2364static void
2365sbcs64 (sim_cpu *cpu)
2366{
2367 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2368 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2369 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2370
2371 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2372 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2373 uint64_t carry = IS_SET (C);
2374 uint64_t result = value1 - value2 + 1 - carry;
2375
2376 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2377 set_flags_for_sub64 (cpu, value1, value2 + 1 - carry);
2378}
2379
2380static void
2381dexAddSubtractWithCarry (sim_cpu *cpu)
2382{
2383 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2384 instr[30] = op : 0 ==> ADC, 1 ==> SBC
2385 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2386 instr[28,21] = 1 1010 000
2387 instr[20,16] = Rm
2388 instr[15,10] = op2 : 00000 ==> ok, ow ==> UNALLOC
2389 instr[9,5] = Rn
2390 instr[4,0] = Rd */
2391
2392 uint32_t op2 = uimm (aarch64_get_instr (cpu), 15, 10);
2393 /* Dispatch on size:op:set? i.e aarch64_get_instr (cpu)[31,29] */
2394 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2395
2396 NYI_assert (28, 21, 0xD0);
2397
2398 if (op2 != 0)
2399 HALT_UNALLOC;
2400
2401 switch (dispatch)
2402 {
2403 case 0: adc32 (cpu); break;
2404 case 1: adcs32 (cpu); break;
2405 case 2: sbc32 (cpu); break;
2406 case 3: sbcs32 (cpu); break;
2407 case 4: adc64 (cpu); break;
2408 case 5: adcs64 (cpu); break;
2409 case 6: sbc64 (cpu); break;
2410 case 7: sbcs64 (cpu); break;
2411 default: HALT_UNALLOC;
2412 }
2413}
2414
2415static uint32_t
2416testConditionCode (sim_cpu *cpu, CondCode cc)
2417{
2418 /* This should be reduceable to branchless logic
2419 by some careful testing of bits in CC followed
2420 by the requisite masking and combining of bits
2421 from the flag register.
2422
2423 For now we do it with a switch. */
2424 int res;
2425
2426 switch (cc)
2427 {
2428 case EQ: res = IS_SET (Z); break;
2429 case NE: res = IS_CLEAR (Z); break;
2430 case CS: res = IS_SET (C); break;
2431 case CC: res = IS_CLEAR (C); break;
2432 case MI: res = IS_SET (N); break;
2433 case PL: res = IS_CLEAR (N); break;
2434 case VS: res = IS_SET (V); break;
2435 case VC: res = IS_CLEAR (V); break;
2436 case HI: res = IS_SET (C) && IS_CLEAR (Z); break;
2437 case LS: res = IS_CLEAR (C) || IS_SET (Z); break;
2438 case GE: res = IS_SET (N) == IS_SET (V); break;
2439 case LT: res = IS_SET (N) != IS_SET (V); break;
2440 case GT: res = IS_CLEAR (Z) && (IS_SET (N) == IS_SET (V)); break;
2441 case LE: res = IS_SET (Z) || (IS_SET (N) != IS_SET (V)); break;
2442 case AL:
2443 case NV:
2444 default:
2445 res = 1;
2446 break;
2447 }
2448 return res;
2449}
2450
2451static void
2452CondCompare (sim_cpu *cpu) /* aka: ccmp and ccmn */
2453{
2454 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
57aa1742 2455 instr[30] = compare with positive (1) or negative value (0)
2e8cf49e
NC
2456 instr[29,21] = 1 1101 0010
2457 instr[20,16] = Rm or const
2458 instr[15,12] = cond
2459 instr[11] = compare reg (0) or const (1)
2460 instr[10] = 0
2461 instr[9,5] = Rn
2462 instr[4] = 0
2463 instr[3,0] = value for CPSR bits if the comparison does not take place. */
2464 signed int negate;
2465 unsigned rm;
2466 unsigned rn;
2467
2468 NYI_assert (29, 21, 0x1d2);
2469 NYI_assert (10, 10, 0);
2470 NYI_assert (4, 4, 0);
2471
2472 if (! testConditionCode (cpu, uimm (aarch64_get_instr (cpu), 15, 12)))
2473 {
2474 aarch64_set_CPSR (cpu, uimm (aarch64_get_instr (cpu), 3, 0));
2475 return;
2476 }
2477
57aa1742 2478 negate = uimm (aarch64_get_instr (cpu), 30, 30) ? 1 : -1;
2e8cf49e
NC
2479 rm = uimm (aarch64_get_instr (cpu), 20, 16);
2480 rn = uimm (aarch64_get_instr (cpu), 9, 5);
2481
2482 if (uimm (aarch64_get_instr (cpu), 31, 31))
2483 {
2484 if (uimm (aarch64_get_instr (cpu), 11, 11))
2485 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2486 negate * (uint64_t) rm);
2487 else
2488 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2489 negate * aarch64_get_reg_u64 (cpu, rm, SP_OK));
2490 }
2491 else
2492 {
2493 if (uimm (aarch64_get_instr (cpu), 11, 11))
2494 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2495 negate * rm);
2496 else
2497 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2498 negate * aarch64_get_reg_u32 (cpu, rm, SP_OK));
2499 }
2500}
2501
2502static void
2503do_vec_MOV_whole_vector (sim_cpu *cpu)
2504{
2505 /* MOV Vd.T, Vs.T (alias for ORR Vd.T, Vn.T, Vm.T where Vn == Vm)
2506
2507 instr[31] = 0
2508 instr[30] = half(0)/full(1)
2509 instr[29,21] = 001110101
2510 instr[20,16] = Vs
2511 instr[15,10] = 000111
2512 instr[9,5] = Vs
2513 instr[4,0] = Vd */
2514
2515 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2516 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2517
2518 NYI_assert (29, 21, 0x075);
2519 NYI_assert (15, 10, 0x07);
2520
2521 if (uimm (aarch64_get_instr (cpu), 20, 16) != vs)
2522 HALT_NYI;
2523
2524 if (uimm (aarch64_get_instr (cpu), 30, 30))
2525 aarch64_set_vec_u64 (cpu, vd, 1, aarch64_get_vec_u64 (cpu, vs, 1));
2526
2527 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vs, 0));
2528}
2529
2530static void
2531do_vec_MOV_into_scalar (sim_cpu *cpu)
2532{
2533 /* instr[31] = 0
2534 instr[30] = word(0)/long(1)
2535 instr[29,21] = 00 1110 000
2536 instr[20,18] = element size and index
2537 instr[17,10] = 00 0011 11
2538 instr[9,5] = V source
2539 instr[4,0] = R dest */
2540
2541 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2542 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2543
2544 NYI_assert (29, 21, 0x070);
2545 NYI_assert (17, 10, 0x0F);
2546
2547 switch (uimm (aarch64_get_instr (cpu), 20, 18))
2548 {
2549 case 0x2:
2550 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 0));
2551 break;
2552
2553 case 0x6:
2554 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 1));
2555 break;
2556
2557 case 0x1:
2558 case 0x3:
2559 case 0x5:
2560 case 0x7:
2561 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u32
2562 (cpu, vs, uimm (aarch64_get_instr (cpu), 20, 19)));
2563 break;
2564
2565 default:
2566 HALT_NYI;
2567 }
2568}
2569
2570static void
2571do_vec_INS (sim_cpu *cpu)
2572{
2573 /* instr[31,21] = 01001110000
2574 instr[20,16] = element size and index
2575 instr[15,10] = 000111
2576 instr[9,5] = W source
2577 instr[4,0] = V dest */
2578
2579 int index;
2580 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
2581 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2582
2583 NYI_assert (31, 21, 0x270);
2584 NYI_assert (15, 10, 0x07);
2585
2586 if (uimm (aarch64_get_instr (cpu), 16, 16))
2587 {
2588 index = uimm (aarch64_get_instr (cpu), 20, 17);
2589 aarch64_set_vec_u8 (cpu, vd, index,
2590 aarch64_get_reg_u8 (cpu, rs, NO_SP));
2591 }
2592 else if (uimm (aarch64_get_instr (cpu), 17, 17))
2593 {
2594 index = uimm (aarch64_get_instr (cpu), 20, 18);
2595 aarch64_set_vec_u16 (cpu, vd, index,
2596 aarch64_get_reg_u16 (cpu, rs, NO_SP));
2597 }
2598 else if (uimm (aarch64_get_instr (cpu), 18, 18))
2599 {
2600 index = uimm (aarch64_get_instr (cpu), 20, 19);
2601 aarch64_set_vec_u32 (cpu, vd, index,
2602 aarch64_get_reg_u32 (cpu, rs, NO_SP));
2603 }
2604 else if (uimm (aarch64_get_instr (cpu), 19, 19))
2605 {
2606 index = uimm (aarch64_get_instr (cpu), 20, 20);
2607 aarch64_set_vec_u64 (cpu, vd, index,
2608 aarch64_get_reg_u64 (cpu, rs, NO_SP));
2609 }
2610 else
2611 HALT_NYI;
2612}
2613
2614static void
2615do_vec_DUP_vector_into_vector (sim_cpu *cpu)
2616{
2617 /* instr[31] = 0
2618 instr[30] = half(0)/full(1)
2619 instr[29,21] = 00 1110 000
2620 instr[20,16] = element size and index
2621 instr[15,10] = 0000 01
2622 instr[9,5] = V source
2623 instr[4,0] = V dest. */
2624
2625 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
2626 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2627 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2628 int i, index;
2629
2630 NYI_assert (29, 21, 0x070);
2631 NYI_assert (15, 10, 0x01);
2632
2633 if (uimm (aarch64_get_instr (cpu), 16, 16))
2634 {
2635 index = uimm (aarch64_get_instr (cpu), 20, 17);
2636
2637 for (i = 0; i < (full ? 16 : 8); i++)
2638 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, index));
2639 }
2640 else if (uimm (aarch64_get_instr (cpu), 17, 17))
2641 {
2642 index = uimm (aarch64_get_instr (cpu), 20, 18);
2643
2644 for (i = 0; i < (full ? 8 : 4); i++)
2645 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, index));
2646 }
2647 else if (uimm (aarch64_get_instr (cpu), 18, 18))
2648 {
2649 index = uimm (aarch64_get_instr (cpu), 20, 19);
2650
2651 for (i = 0; i < (full ? 4 : 2); i++)
2652 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, index));
2653 }
2654 else
2655 {
2656 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
2657 HALT_UNALLOC;
2658
2659 if (! full)
2660 HALT_UNALLOC;
2661
2662 index = uimm (aarch64_get_instr (cpu), 20, 20);
2663
2664 for (i = 0; i < 2; i++)
2665 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, index));
2666 }
2667}
2668
2669static void
2670do_vec_TBL (sim_cpu *cpu)
2671{
2672 /* instr[31] = 0
2673 instr[30] = half(0)/full(1)
2674 instr[29,21] = 00 1110 000
2675 instr[20,16] = Vm
2676 instr[15] = 0
2677 instr[14,13] = vec length
2678 instr[12,10] = 000
2679 instr[9,5] = V start
2680 instr[4,0] = V dest */
2681
2682 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2683 int len = uimm (aarch64_get_instr (cpu), 14, 13) + 1;
2684 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2685 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2686 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2687 unsigned i;
2688
2689 NYI_assert (29, 21, 0x070);
2690 NYI_assert (12, 10, 0);
2691
2692 for (i = 0; i < (full ? 16 : 8); i++)
2693 {
2694 unsigned int selector = aarch64_get_vec_u8 (cpu, vm, i);
2695 uint8_t val;
2696
2697 if (selector < 16)
2698 val = aarch64_get_vec_u8 (cpu, vn, selector);
2699 else if (selector < 32)
2700 val = len < 2 ? 0 : aarch64_get_vec_u8 (cpu, vn + 1, selector - 16);
2701 else if (selector < 48)
2702 val = len < 3 ? 0 : aarch64_get_vec_u8 (cpu, vn + 2, selector - 32);
2703 else if (selector < 64)
2704 val = len < 4 ? 0 : aarch64_get_vec_u8 (cpu, vn + 3, selector - 48);
2705 else
2706 val = 0;
2707
2708 aarch64_set_vec_u8 (cpu, vd, i, val);
2709 }
2710}
2711
2712static void
2713do_vec_TRN (sim_cpu *cpu)
2714{
2715 /* instr[31] = 0
2716 instr[30] = half(0)/full(1)
2717 instr[29,24] = 00 1110
2718 instr[23,22] = size
2719 instr[21] = 0
2720 instr[20,16] = Vm
2721 instr[15] = 0
2722 instr[14] = TRN1 (0) / TRN2 (1)
2723 instr[13,10] = 1010
2724 instr[9,5] = V source
2725 instr[4,0] = V dest. */
2726
2727 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2728 int second = uimm (aarch64_get_instr (cpu), 14, 14);
2729 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2730 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2731 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2732 unsigned i;
2733
2734 NYI_assert (29, 24, 0x0E);
2735 NYI_assert (13, 10, 0xA);
2736
2737 switch (uimm (aarch64_get_instr (cpu), 23, 22))
2738 {
2739 case 0:
2740 for (i = 0; i < (full ? 8 : 4); i++)
2741 {
2742 aarch64_set_vec_u8
2743 (cpu, vd, i * 2,
2744 aarch64_get_vec_u8 (cpu, second ? vm : vn, i * 2));
2745 aarch64_set_vec_u8
2746 (cpu, vd, 1 * 2 + 1,
2747 aarch64_get_vec_u8 (cpu, second ? vn : vm, i * 2 + 1));
2748 }
2749 break;
2750
2751 case 1:
2752 for (i = 0; i < (full ? 4 : 2); i++)
2753 {
2754 aarch64_set_vec_u16
2755 (cpu, vd, i * 2,
2756 aarch64_get_vec_u16 (cpu, second ? vm : vn, i * 2));
2757 aarch64_set_vec_u16
2758 (cpu, vd, 1 * 2 + 1,
2759 aarch64_get_vec_u16 (cpu, second ? vn : vm, i * 2 + 1));
2760 }
2761 break;
2762
2763 case 2:
2764 aarch64_set_vec_u32
2765 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, second ? vm : vn, 0));
2766 aarch64_set_vec_u32
2767 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, second ? vn : vm, 1));
2768 aarch64_set_vec_u32
2769 (cpu, vd, 2, aarch64_get_vec_u32 (cpu, second ? vm : vn, 2));
2770 aarch64_set_vec_u32
2771 (cpu, vd, 3, aarch64_get_vec_u32 (cpu, second ? vn : vm, 3));
2772 break;
2773
2774 case 3:
2775 if (! full)
2776 HALT_UNALLOC;
2777
2778 aarch64_set_vec_u64 (cpu, vd, 0,
2779 aarch64_get_vec_u64 (cpu, second ? vm : vn, 0));
2780 aarch64_set_vec_u64 (cpu, vd, 1,
2781 aarch64_get_vec_u64 (cpu, second ? vn : vm, 1));
2782 break;
2783
2784 default:
2785 HALT_UNALLOC;
2786 }
2787}
2788
2789static void
2790do_vec_DUP_scalar_into_vector (sim_cpu *cpu)
2791{
2792 /* instr[31] = 0
2793 instr[30] = 0=> zero top 64-bits, 1=> duplicate into top 64-bits
2794 [must be 1 for 64-bit xfer]
2795 instr[29,20] = 00 1110 0000
2796 instr[19,16] = element size: 0001=> 8-bits, 0010=> 16-bits,
2797 0100=> 32-bits. 1000=>64-bits
2798 instr[15,10] = 0000 11
2799 instr[9,5] = W source
2800 instr[4,0] = V dest. */
2801
2802 unsigned i;
2803 unsigned Vd = uimm (aarch64_get_instr (cpu), 4, 0);
2804 unsigned Rs = uimm (aarch64_get_instr (cpu), 9, 5);
2805 int both = uimm (aarch64_get_instr (cpu), 30, 30);
2806
2807 NYI_assert (29, 20, 0x0E0);
2808 NYI_assert (15, 10, 0x03);
2809
2810 switch (uimm (aarch64_get_instr (cpu), 19, 16))
2811 {
2812 case 1:
2813 for (i = 0; i < (both ? 16 : 8); i++)
2814 aarch64_set_vec_u8 (cpu, Vd, i, aarch64_get_reg_u8 (cpu, Rs, NO_SP));
2815 break;
2816
2817 case 2:
2818 for (i = 0; i < (both ? 8 : 4); i++)
2819 aarch64_set_vec_u16 (cpu, Vd, i, aarch64_get_reg_u16 (cpu, Rs, NO_SP));
2820 break;
2821
2822 case 4:
2823 for (i = 0; i < (both ? 4 : 2); i++)
2824 aarch64_set_vec_u32 (cpu, Vd, i, aarch64_get_reg_u32 (cpu, Rs, NO_SP));
2825 break;
2826
2827 case 8:
2828 if (!both)
2829 HALT_NYI;
2830 aarch64_set_vec_u64 (cpu, Vd, 0, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2831 aarch64_set_vec_u64 (cpu, Vd, 1, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2832 break;
2833
2834 default:
2835 HALT_NYI;
2836 }
2837}
2838
2839static void
2840do_vec_UZP (sim_cpu *cpu)
2841{
2842 /* instr[31] = 0
2843 instr[30] = half(0)/full(1)
2844 instr[29,24] = 00 1110
2845 instr[23,22] = size: byte(00), half(01), word (10), long (11)
2846 instr[21] = 0
2847 instr[20,16] = Vm
2848 instr[15] = 0
2849 instr[14] = lower (0) / upper (1)
2850 instr[13,10] = 0110
2851 instr[9,5] = Vn
2852 instr[4,0] = Vd. */
2853
2854 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2855 int upper = uimm (aarch64_get_instr (cpu), 14, 14);
2856
2857 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2858 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2859 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2860
2861 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2862 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2863 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2864 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2865
2866 uint64_t val1 = 0;
2867 uint64_t val2 = 0;
2868
2869 uint64_t input1 = upper ? val_n1 : val_m1;
2870 uint64_t input2 = upper ? val_n2 : val_m2;
2871 unsigned i;
2872
2873 NYI_assert (29, 24, 0x0E);
2874 NYI_assert (21, 21, 0);
2875 NYI_assert (15, 15, 0);
2876 NYI_assert (13, 10, 6);
2877
2878 switch (uimm (aarch64_get_instr (cpu), 23, 23))
2879 {
2880 case 0:
2881 for (i = 0; i < 8; i++)
2882 {
2883 val1 |= (input1 >> (i * 8)) & (0xFFULL << (i * 8));
2884 val2 |= (input2 >> (i * 8)) & (0xFFULL << (i * 8));
2885 }
2886 break;
2887
2888 case 1:
2889 for (i = 0; i < 4; i++)
2890 {
2891 val1 |= (input1 >> (i * 16)) & (0xFFFFULL << (i * 16));
2892 val2 |= (input2 >> (i * 16)) & (0xFFFFULL << (i * 16));
2893 }
2894 break;
2895
2896 case 2:
2897 val1 = ((input1 & 0xFFFFFFFF) | ((input1 >> 32) & 0xFFFFFFFF00000000ULL));
2898 val2 = ((input2 & 0xFFFFFFFF) | ((input2 >> 32) & 0xFFFFFFFF00000000ULL));
2899
2900 case 3:
2901 val1 = input1;
2902 val2 = input2;
2903 break;
2904 }
2905
2906 aarch64_set_vec_u64 (cpu, vd, 0, val1);
2907 if (full)
2908 aarch64_set_vec_u64 (cpu, vd, 1, val2);
2909}
2910
2911static void
2912do_vec_ZIP (sim_cpu *cpu)
2913{
2914 /* instr[31] = 0
2915 instr[30] = half(0)/full(1)
2916 instr[29,24] = 00 1110
2917 instr[23,22] = size: byte(00), hald(01), word (10), long (11)
2918 instr[21] = 0
2919 instr[20,16] = Vm
2920 instr[15] = 0
2921 instr[14] = lower (0) / upper (1)
2922 instr[13,10] = 1110
2923 instr[9,5] = Vn
2924 instr[4,0] = Vd. */
2925
2926 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2927 int upper = uimm (aarch64_get_instr (cpu), 14, 14);
2928
2929 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2930 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2931 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2932
2933 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2934 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2935 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2936 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2937
2938 uint64_t val1 = 0;
2939 uint64_t val2 = 0;
2940
2941 uint64_t input1 = upper ? val_n1 : val_m1;
2942 uint64_t input2 = upper ? val_n2 : val_m2;
2943
2944 NYI_assert (29, 24, 0x0E);
2945 NYI_assert (21, 21, 0);
2946 NYI_assert (15, 15, 0);
2947 NYI_assert (13, 10, 0xE);
2948
2949 switch (uimm (aarch64_get_instr (cpu), 23, 23))
2950 {
2951 case 0:
2952 val1 =
2953 ((input1 << 0) & (0xFF << 0))
2954 | ((input2 << 8) & (0xFF << 8))
2955 | ((input1 << 8) & (0xFF << 16))
2956 | ((input2 << 16) & (0xFF << 24))
2957 | ((input1 << 16) & (0xFFULL << 32))
2958 | ((input2 << 24) & (0xFFULL << 40))
2959 | ((input1 << 24) & (0xFFULL << 48))
2960 | ((input2 << 32) & (0xFFULL << 56));
2961
2962 val2 =
2963 ((input1 >> 32) & (0xFF << 0))
2964 | ((input2 >> 24) & (0xFF << 8))
2965 | ((input1 >> 24) & (0xFF << 16))
2966 | ((input2 >> 16) & (0xFF << 24))
2967 | ((input1 >> 16) & (0xFFULL << 32))
2968 | ((input2 >> 8) & (0xFFULL << 40))
2969 | ((input1 >> 8) & (0xFFULL << 48))
2970 | ((input2 >> 0) & (0xFFULL << 56));
2971 break;
2972
2973 case 1:
2974 val1 =
2975 ((input1 << 0) & (0xFFFF << 0))
2976 | ((input2 << 16) & (0xFFFF << 16))
2977 | ((input1 << 16) & (0xFFFFULL << 32))
2978 | ((input2 << 32) & (0xFFFFULL << 48));
2979
2980 val2 =
2981 ((input1 >> 32) & (0xFFFF << 0))
2982 | ((input2 >> 16) & (0xFFFF << 16))
2983 | ((input1 >> 16) & (0xFFFFULL << 32))
2984 | ((input2 >> 0) & (0xFFFFULL << 48));
2985 break;
2986
2987 case 2:
2988 val1 = (input1 & 0xFFFFFFFFULL) | (input2 << 32);
2989 val2 = (input2 & 0xFFFFFFFFULL) | (input1 << 32);
2990 break;
2991
2992 case 3:
2993 val1 = input1;
2994 val2 = input2;
2995 break;
2996 }
2997
2998 aarch64_set_vec_u64 (cpu, vd, 0, val1);
2999 if (full)
3000 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3001}
3002
3003/* Floating point immediates are encoded in 8 bits.
3004 fpimm[7] = sign bit.
3005 fpimm[6:4] = signed exponent.
3006 fpimm[3:0] = fraction (assuming leading 1).
3007 i.e. F = s * 1.f * 2^(e - b). */
3008
3009static float
3010fp_immediate_for_encoding_32 (uint32_t imm8)
3011{
3012 float u;
3013 uint32_t s, e, f, i;
3014
3015 s = (imm8 >> 7) & 0x1;
3016 e = (imm8 >> 4) & 0x7;
3017 f = imm8 & 0xf;
3018
3019 /* The fp value is s * n/16 * 2r where n is 16+e. */
3020 u = (16.0 + f) / 16.0;
3021
3022 /* N.B. exponent is signed. */
3023 if (e < 4)
3024 {
3025 int epos = e;
3026
3027 for (i = 0; i <= epos; i++)
3028 u *= 2.0;
3029 }
3030 else
3031 {
3032 int eneg = 7 - e;
3033
3034 for (i = 0; i < eneg; i++)
3035 u /= 2.0;
3036 }
3037
3038 if (s)
3039 u = - u;
3040
3041 return u;
3042}
3043
3044static double
3045fp_immediate_for_encoding_64 (uint32_t imm8)
3046{
3047 double u;
3048 uint32_t s, e, f, i;
3049
3050 s = (imm8 >> 7) & 0x1;
3051 e = (imm8 >> 4) & 0x7;
3052 f = imm8 & 0xf;
3053
3054 /* The fp value is s * n/16 * 2r where n is 16+e. */
3055 u = (16.0 + f) / 16.0;
3056
3057 /* N.B. exponent is signed. */
3058 if (e < 4)
3059 {
3060 int epos = e;
3061
3062 for (i = 0; i <= epos; i++)
3063 u *= 2.0;
3064 }
3065 else
3066 {
3067 int eneg = 7 - e;
3068
3069 for (i = 0; i < eneg; i++)
3070 u /= 2.0;
3071 }
3072
3073 if (s)
3074 u = - u;
3075
3076 return u;
3077}
3078
3079static void
3080do_vec_MOV_immediate (sim_cpu *cpu)
3081{
3082 /* instr[31] = 0
3083 instr[30] = full/half selector
3084 instr[29,19] = 00111100000
3085 instr[18,16] = high 3 bits of uimm8
3086 instr[15,12] = size & shift:
3087 0000 => 32-bit
3088 0010 => 32-bit + LSL#8
3089 0100 => 32-bit + LSL#16
3090 0110 => 32-bit + LSL#24
3091 1010 => 16-bit + LSL#8
3092 1000 => 16-bit
3093 1101 => 32-bit + MSL#16
3094 1100 => 32-bit + MSL#8
3095 1110 => 8-bit
3096 1111 => double
3097 instr[11,10] = 01
3098 instr[9,5] = low 5-bits of uimm8
3099 instr[4,0] = Vd. */
3100
3101 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3102 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3103 unsigned val = uimm (aarch64_get_instr (cpu), 18, 16) << 5
3104 | uimm (aarch64_get_instr (cpu), 9, 5);
3105 unsigned i;
3106
3107 NYI_assert (29, 19, 0x1E0);
3108 NYI_assert (11, 10, 1);
3109
3110 switch (uimm (aarch64_get_instr (cpu), 15, 12))
3111 {
3112 case 0x0: /* 32-bit, no shift. */
3113 case 0x2: /* 32-bit, shift by 8. */
3114 case 0x4: /* 32-bit, shift by 16. */
3115 case 0x6: /* 32-bit, shift by 24. */
3116 val <<= (8 * uimm (aarch64_get_instr (cpu), 14, 13));
3117 for (i = 0; i < (full ? 4 : 2); i++)
3118 aarch64_set_vec_u32 (cpu, vd, i, val);
3119 break;
3120
3121 case 0xa: /* 16-bit, shift by 8. */
3122 val <<= 8;
3123 /* Fall through. */
3124 case 0x8: /* 16-bit, no shift. */
3125 for (i = 0; i < (full ? 8 : 4); i++)
3126 aarch64_set_vec_u16 (cpu, vd, i, val);
3127 /* Fall through. */
3128 case 0xd: /* 32-bit, mask shift by 16. */
3129 val <<= 8;
3130 val |= 0xFF;
3131 /* Fall through. */
3132 case 0xc: /* 32-bit, mask shift by 8. */
3133 val <<= 8;
3134 val |= 0xFF;
3135 for (i = 0; i < (full ? 4 : 2); i++)
3136 aarch64_set_vec_u32 (cpu, vd, i, val);
3137 break;
3138
3139 case 0xe: /* 8-bit, no shift. */
3140 for (i = 0; i < (full ? 16 : 8); i++)
3141 aarch64_set_vec_u8 (cpu, vd, i, val);
3142 break;
3143
3144 case 0xf: /* FMOV Vs.{2|4}S, #fpimm. */
3145 {
3146 float u = fp_immediate_for_encoding_32 (val);
3147 for (i = 0; i < (full ? 4 : 2); i++)
3148 aarch64_set_vec_float (cpu, vd, i, u);
3149 break;
3150 }
3151
3152 default:
3153 HALT_NYI;
3154 }
3155}
3156
3157static void
3158do_vec_MVNI (sim_cpu *cpu)
3159{
3160 /* instr[31] = 0
3161 instr[30] = full/half selector
3162 instr[29,19] = 10111100000
3163 instr[18,16] = high 3 bits of uimm8
3164 instr[15,12] = selector
3165 instr[11,10] = 01
3166 instr[9,5] = low 5-bits of uimm8
3167 instr[4,0] = Vd. */
3168
3169 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3170 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3171 unsigned val = uimm (aarch64_get_instr (cpu), 18, 16) << 5
3172 | uimm (aarch64_get_instr (cpu), 9, 5);
3173 unsigned i;
3174
3175 NYI_assert (29, 19, 0x5E0);
3176 NYI_assert (11, 10, 1);
3177
3178 switch (uimm (aarch64_get_instr (cpu), 15, 12))
3179 {
3180 case 0x0: /* 32-bit, no shift. */
3181 case 0x2: /* 32-bit, shift by 8. */
3182 case 0x4: /* 32-bit, shift by 16. */
3183 case 0x6: /* 32-bit, shift by 24. */
3184 val <<= (8 * uimm (aarch64_get_instr (cpu), 14, 13));
3185 val = ~ val;
3186 for (i = 0; i < (full ? 4 : 2); i++)
3187 aarch64_set_vec_u32 (cpu, vd, i, val);
3188 return;
3189
3190 case 0xa: /* 16-bit, 8 bit shift. */
3191 val <<= 8;
3192 case 0x8: /* 16-bit, no shift. */
3193 val = ~ val;
3194 for (i = 0; i < (full ? 8 : 4); i++)
3195 aarch64_set_vec_u16 (cpu, vd, i, val);
3196 return;
3197
3198 case 0xd: /* 32-bit, mask shift by 16. */
3199 val <<= 8;
3200 val |= 0xFF;
3201 case 0xc: /* 32-bit, mask shift by 8. */
3202 val <<= 8;
3203 val |= 0xFF;
3204 val = ~ val;
3205 for (i = 0; i < (full ? 4 : 2); i++)
3206 aarch64_set_vec_u32 (cpu, vd, i, val);
3207 return;
3208
3209 case 0xE: /* MOVI Dn, #mask64 */
3210 {
3211 uint64_t mask = 0;
3212
3213 for (i = 0; i < 8; i++)
3214 if (val & (1 << i))
3215 mask |= (0xF << (i * 4));
3216 aarch64_set_vec_u64 (cpu, vd, 0, mask);
3217 aarch64_set_vec_u64 (cpu, vd, 1, 0);
3218 return;
3219 }
3220
3221 case 0xf: /* FMOV Vd.2D, #fpimm. */
3222 {
3223 double u = fp_immediate_for_encoding_64 (val);
3224
3225 if (! full)
3226 HALT_UNALLOC;
3227
3228 aarch64_set_vec_double (cpu, vd, 0, u);
3229 aarch64_set_vec_double (cpu, vd, 1, u);
3230 return;
3231 }
3232
3233 default:
3234 HALT_NYI;
3235 }
3236}
3237
3238#define ABS(A) ((A) < 0 ? - (A) : (A))
3239
3240static void
3241do_vec_ABS (sim_cpu *cpu)
3242{
3243 /* instr[31] = 0
3244 instr[30] = half(0)/full(1)
3245 instr[29,24] = 00 1110
3246 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3247 instr[21,10] = 10 0000 1011 10
3248 instr[9,5] = Vn
3249 instr[4.0] = Vd. */
3250
3251 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3252 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3253 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
3254 unsigned i;
3255
3256 NYI_assert (29, 24, 0x0E);
3257 NYI_assert (21, 10, 0x82E);
3258
3259 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3260 {
3261 case 0:
3262 for (i = 0; i < (full ? 16 : 8); i++)
3263 aarch64_set_vec_s8 (cpu, vd, i,
3264 ABS (aarch64_get_vec_s8 (cpu, vn, i)));
3265 break;
3266
3267 case 1:
3268 for (i = 0; i < (full ? 8 : 4); i++)
3269 aarch64_set_vec_s16 (cpu, vd, i,
3270 ABS (aarch64_get_vec_s16 (cpu, vn, i)));
3271 break;
3272
3273 case 2:
3274 for (i = 0; i < (full ? 4 : 2); i++)
3275 aarch64_set_vec_s32 (cpu, vd, i,
3276 ABS (aarch64_get_vec_s32 (cpu, vn, i)));
3277 break;
3278
3279 case 3:
3280 if (! full)
3281 HALT_NYI;
3282 for (i = 0; i < 2; i++)
3283 aarch64_set_vec_s64 (cpu, vd, i,
3284 ABS (aarch64_get_vec_s64 (cpu, vn, i)));
3285 break;
3286 }
3287}
3288
3289static void
3290do_vec_ADDV (sim_cpu *cpu)
3291{
3292 /* instr[31] = 0
3293 instr[30] = full/half selector
3294 instr[29,24] = 00 1110
3295 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3296 instr[21,10] = 11 0001 1011 10
3297 instr[9,5] = Vm
3298 instr[4.0] = Rd. */
3299
3300 unsigned vm = uimm (aarch64_get_instr (cpu), 9, 5);
3301 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
3302 unsigned i;
3303 uint64_t val = 0;
3304 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3305
3306 NYI_assert (29, 24, 0x0E);
3307 NYI_assert (21, 10, 0xC6E);
3308
3309 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3310 {
3311 case 0:
3312 for (i = 0; i < (full ? 16 : 8); i++)
3313 val += aarch64_get_vec_u8 (cpu, vm, i);
3314 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3315 return;
3316
3317 case 1:
3318 for (i = 0; i < (full ? 8 : 4); i++)
3319 val += aarch64_get_vec_u16 (cpu, vm, i);
3320 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3321 return;
3322
3323 case 2:
3324 for (i = 0; i < (full ? 4 : 2); i++)
3325 val += aarch64_get_vec_u32 (cpu, vm, i);
3326 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3327 return;
3328
3329 case 3:
3330 if (! full)
3331 HALT_UNALLOC;
3332 val = aarch64_get_vec_u64 (cpu, vm, 0);
3333 val += aarch64_get_vec_u64 (cpu, vm, 1);
3334 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3335 return;
3336
3337 default:
3338 HALT_UNREACHABLE;
3339 }
3340}
3341
3342static void
3343do_vec_ins_2 (sim_cpu *cpu)
3344{
3345 /* instr[31,21] = 01001110000
3346 instr[20,18] = size & element selector
3347 instr[17,14] = 0000
3348 instr[13] = direction: to vec(0), from vec (1)
3349 instr[12,10] = 111
3350 instr[9,5] = Vm
3351 instr[4,0] = Vd. */
3352
3353 unsigned elem;
3354 unsigned vm = uimm (aarch64_get_instr (cpu), 9, 5);
3355 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3356
3357 NYI_assert (31, 21, 0x270);
3358 NYI_assert (17, 14, 0);
3359 NYI_assert (12, 10, 7);
3360
3361 if (uimm (aarch64_get_instr (cpu), 13, 13) == 1)
3362 {
3363 if (uimm (aarch64_get_instr (cpu), 18, 18) == 1)
3364 {
3365 /* 32-bit moves. */
3366 elem = uimm (aarch64_get_instr (cpu), 20, 19);
3367 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3368 aarch64_get_vec_u32 (cpu, vm, elem));
3369 }
3370 else
3371 {
3372 /* 64-bit moves. */
3373 if (uimm (aarch64_get_instr (cpu), 19, 19) != 1)
3374 HALT_NYI;
3375
3376 elem = uimm (aarch64_get_instr (cpu), 20, 20);
3377 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3378 aarch64_get_vec_u64 (cpu, vm, elem));
3379 }
3380 }
3381 else
3382 {
3383 if (uimm (aarch64_get_instr (cpu), 18, 18) == 1)
3384 {
3385 /* 32-bit moves. */
3386 elem = uimm (aarch64_get_instr (cpu), 20, 19);
3387 aarch64_set_vec_u32 (cpu, vd, elem,
3388 aarch64_get_reg_u32 (cpu, vm, NO_SP));
3389 }
3390 else
3391 {
3392 /* 64-bit moves. */
3393 if (uimm (aarch64_get_instr (cpu), 19, 19) != 1)
3394 HALT_NYI;
3395
3396 elem = uimm (aarch64_get_instr (cpu), 20, 20);
3397 aarch64_set_vec_u64 (cpu, vd, elem,
3398 aarch64_get_reg_u64 (cpu, vm, NO_SP));
3399 }
3400 }
3401}
3402
3403static void
3404do_vec_mull (sim_cpu *cpu)
3405{
3406 /* instr[31] = 0
3407 instr[30] = lower(0)/upper(1) selector
3408 instr[29] = signed(0)/unsigned(1)
3409 instr[28,24] = 0 1110
3410 instr[23,22] = size: 8-bit (00), 16-bit (01), 32-bit (10)
3411 instr[21] = 1
3412 instr[20,16] = Vm
3413 instr[15,10] = 11 0000
3414 instr[9,5] = Vn
3415 instr[4.0] = Vd. */
3416
3417 int unsign = uimm (aarch64_get_instr (cpu), 29, 29);
3418 int bias = uimm (aarch64_get_instr (cpu), 30, 30);
3419 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3420 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3421 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3422 unsigned i;
3423
3424 NYI_assert (28, 24, 0x0E);
3425 NYI_assert (15, 10, 0x30);
3426
3427 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3428 {
3429 case 0:
3430 if (bias)
3431 bias = 8;
3432 if (unsign)
3433 for (i = 0; i < 8; i++)
3434 aarch64_set_vec_u16 (cpu, vd, i,
3435 aarch64_get_vec_u8 (cpu, vn, i + bias)
3436 * aarch64_get_vec_u8 (cpu, vm, i + bias));
3437 else
3438 for (i = 0; i < 8; i++)
3439 aarch64_set_vec_s16 (cpu, vd, i,
3440 aarch64_get_vec_s8 (cpu, vn, i + bias)
3441 * aarch64_get_vec_s8 (cpu, vm, i + bias));
3442 return;
3443
3444 case 1:
3445 if (bias)
3446 bias = 4;
3447 if (unsign)
3448 for (i = 0; i < 4; i++)
3449 aarch64_set_vec_u32 (cpu, vd, i,
3450 aarch64_get_vec_u16 (cpu, vn, i + bias)
3451 * aarch64_get_vec_u16 (cpu, vm, i + bias));
3452 else
3453 for (i = 0; i < 4; i++)
3454 aarch64_set_vec_s32 (cpu, vd, i,
3455 aarch64_get_vec_s16 (cpu, vn, i + bias)
3456 * aarch64_get_vec_s16 (cpu, vm, i + bias));
3457 return;
3458
3459 case 2:
3460 if (bias)
3461 bias = 2;
3462 if (unsign)
3463 for (i = 0; i < 2; i++)
3464 aarch64_set_vec_u64 (cpu, vd, i,
3465 (uint64_t) aarch64_get_vec_u32 (cpu, vn,
3466 i + bias)
3467 * (uint64_t) aarch64_get_vec_u32 (cpu, vm,
3468 i + bias));
3469 else
3470 for (i = 0; i < 2; i++)
3471 aarch64_set_vec_s64 (cpu, vd, i,
3472 aarch64_get_vec_s32 (cpu, vn, i + bias)
3473 * aarch64_get_vec_s32 (cpu, vm, i + bias));
3474 return;
3475
3476 case 3:
3477 default:
3478 HALT_NYI;
3479 }
3480}
3481
3482static void
3483do_vec_fadd (sim_cpu *cpu)
3484{
3485 /* instr[31] = 0
3486 instr[30] = half(0)/full(1)
3487 instr[29,24] = 001110
3488 instr[23] = FADD(0)/FSUB(1)
3489 instr[22] = float (0)/double(1)
3490 instr[21] = 1
3491 instr[20,16] = Vm
3492 instr[15,10] = 110101
3493 instr[9,5] = Vn
3494 instr[4.0] = Vd. */
3495
3496 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3497 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3498 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3499 unsigned i;
3500 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3501
3502 NYI_assert (29, 24, 0x0E);
3503 NYI_assert (21, 21, 1);
3504 NYI_assert (15, 10, 0x35);
3505
3506 if (uimm (aarch64_get_instr (cpu), 23, 23))
3507 {
3508 if (uimm (aarch64_get_instr (cpu), 22, 22))
3509 {
3510 if (! full)
3511 HALT_NYI;
3512
3513 for (i = 0; i < 2; i++)
3514 aarch64_set_vec_double (cpu, vd, i,
3515 aarch64_get_vec_double (cpu, vn, i)
3516 - aarch64_get_vec_double (cpu, vm, i));
3517 }
3518 else
3519 {
3520 for (i = 0; i < (full ? 4 : 2); i++)
3521 aarch64_set_vec_float (cpu, vd, i,
3522 aarch64_get_vec_float (cpu, vn, i)
3523 - aarch64_get_vec_float (cpu, vm, i));
3524 }
3525 }
3526 else
3527 {
3528 if (uimm (aarch64_get_instr (cpu), 22, 22))
3529 {
3530 if (! full)
3531 HALT_NYI;
3532
3533 for (i = 0; i < 2; i++)
3534 aarch64_set_vec_double (cpu, vd, i,
3535 aarch64_get_vec_double (cpu, vm, i)
3536 + aarch64_get_vec_double (cpu, vn, i));
3537 }
3538 else
3539 {
3540 for (i = 0; i < (full ? 4 : 2); i++)
3541 aarch64_set_vec_float (cpu, vd, i,
3542 aarch64_get_vec_float (cpu, vm, i)
3543 + aarch64_get_vec_float (cpu, vn, i));
3544 }
3545 }
3546}
3547
3548static void
3549do_vec_add (sim_cpu *cpu)
3550{
3551 /* instr[31] = 0
3552 instr[30] = full/half selector
3553 instr[29,24] = 001110
3554 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3555 instr[21] = 1
3556 instr[20,16] = Vn
3557 instr[15,10] = 100001
3558 instr[9,5] = Vm
3559 instr[4.0] = Vd. */
3560
3561 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3562 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3563 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3564 unsigned i;
3565 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3566
3567 NYI_assert (29, 24, 0x0E);
3568 NYI_assert (21, 21, 1);
3569 NYI_assert (15, 10, 0x21);
3570
3571 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3572 {
3573 case 0:
3574 for (i = 0; i < (full ? 16 : 8); i++)
3575 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
3576 + aarch64_get_vec_u8 (cpu, vm, i));
3577 return;
3578
3579 case 1:
3580 for (i = 0; i < (full ? 8 : 4); i++)
3581 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
3582 + aarch64_get_vec_u16 (cpu, vm, i));
3583 return;
3584
3585 case 2:
3586 for (i = 0; i < (full ? 4 : 2); i++)
3587 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
3588 + aarch64_get_vec_u32 (cpu, vm, i));
3589 return;
3590
3591 case 3:
3592 if (! full)
3593 HALT_UNALLOC;
3594 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vn, 0)
3595 + aarch64_get_vec_u64 (cpu, vm, 0));
3596 aarch64_set_vec_u64 (cpu, vd, 1,
3597 aarch64_get_vec_u64 (cpu, vn, 1)
3598 + aarch64_get_vec_u64 (cpu, vm, 1));
3599 return;
3600
3601 default:
3602 HALT_UNREACHABLE;
3603 }
3604}
3605
3606static void
3607do_vec_mul (sim_cpu *cpu)
3608{
3609 /* instr[31] = 0
3610 instr[30] = full/half selector
3611 instr[29,24] = 00 1110
3612 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3613 instr[21] = 1
3614 instr[20,16] = Vn
3615 instr[15,10] = 10 0111
3616 instr[9,5] = Vm
3617 instr[4.0] = Vd. */
3618
3619 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3620 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3621 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3622 unsigned i;
3623 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3624
3625 NYI_assert (29, 24, 0x0E);
3626 NYI_assert (21, 21, 1);
3627 NYI_assert (15, 10, 0x27);
3628
3629 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3630 {
3631 case 0:
3632 for (i = 0; i < (full ? 16 : 8); i++)
3633 {
3634 uint16_t val = aarch64_get_vec_u8 (cpu, vn, i);
3635 val *= aarch64_get_vec_u8 (cpu, vm, i);
3636
3637 aarch64_set_vec_u16 (cpu, vd, i, val);
3638 }
3639 return;
3640
3641 case 1:
3642 for (i = 0; i < (full ? 8 : 4); i++)
3643 {
3644 uint32_t val = aarch64_get_vec_u16 (cpu, vn, i);
3645 val *= aarch64_get_vec_u16 (cpu, vm, i);
3646
3647 aarch64_set_vec_u32 (cpu, vd, i, val);
3648 }
3649 return;
3650
3651 case 2:
3652 for (i = 0; i < (full ? 4 : 2); i++)
3653 {
3654 uint64_t val = aarch64_get_vec_u32 (cpu, vn, i);
3655 val *= aarch64_get_vec_u32 (cpu, vm, i);
3656
3657 aarch64_set_vec_u64 (cpu, vd, i, val);
3658 }
3659 return;
3660
3661 default:
3662 case 3:
3663 HALT_UNALLOC;
3664 }
3665}
3666
3667static void
3668do_vec_MLA (sim_cpu *cpu)
3669{
3670 /* instr[31] = 0
3671 instr[30] = full/half selector
3672 instr[29,24] = 00 1110
3673 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3674 instr[21] = 1
3675 instr[20,16] = Vn
3676 instr[15,10] = 1001 01
3677 instr[9,5] = Vm
3678 instr[4.0] = Vd. */
3679
3680 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3681 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3682 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3683 unsigned i;
3684 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3685
3686 NYI_assert (29, 24, 0x0E);
3687 NYI_assert (21, 21, 1);
3688 NYI_assert (15, 10, 0x25);
3689
3690 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3691 {
3692 case 0:
3693 for (i = 0; i < (full ? 16 : 8); i++)
3694 {
3695 uint16_t val = aarch64_get_vec_u8 (cpu, vn, i);
3696 val *= aarch64_get_vec_u8 (cpu, vm, i);
3697 val += aarch64_get_vec_u8 (cpu, vd, i);
3698
3699 aarch64_set_vec_u16 (cpu, vd, i, val);
3700 }
3701 return;
3702
3703 case 1:
3704 for (i = 0; i < (full ? 8 : 4); i++)
3705 {
3706 uint32_t val = aarch64_get_vec_u16 (cpu, vn, i);
3707 val *= aarch64_get_vec_u16 (cpu, vm, i);
3708 val += aarch64_get_vec_u16 (cpu, vd, i);
3709
3710 aarch64_set_vec_u32 (cpu, vd, i, val);
3711 }
3712 return;
3713
3714 case 2:
3715 for (i = 0; i < (full ? 4 : 2); i++)
3716 {
3717 uint64_t val = aarch64_get_vec_u32 (cpu, vn, i);
3718 val *= aarch64_get_vec_u32 (cpu, vm, i);
3719 val += aarch64_get_vec_u32 (cpu, vd, i);
3720
3721 aarch64_set_vec_u64 (cpu, vd, i, val);
3722 }
3723 return;
3724
3725 default:
3726 case 3:
3727 HALT_UNALLOC;
3728 }
3729}
3730
3731static float
3732fmaxnm (float a, float b)
3733{
3734 if (fpclassify (a) == FP_NORMAL)
3735 {
3736 if (fpclassify (b) == FP_NORMAL)
3737 return a > b ? a : b;
3738 return a;
3739 }
3740 else if (fpclassify (b) == FP_NORMAL)
3741 return b;
3742 return a;
3743}
3744
3745static float
3746fminnm (float a, float b)
3747{
3748 if (fpclassify (a) == FP_NORMAL)
3749 {
3750 if (fpclassify (b) == FP_NORMAL)
3751 return a < b ? a : b;
3752 return a;
3753 }
3754 else if (fpclassify (b) == FP_NORMAL)
3755 return b;
3756 return a;
3757}
3758
3759static double
3760dmaxnm (double a, double b)
3761{
3762 if (fpclassify (a) == FP_NORMAL)
3763 {
3764 if (fpclassify (b) == FP_NORMAL)
3765 return a > b ? a : b;
3766 return a;
3767 }
3768 else if (fpclassify (b) == FP_NORMAL)
3769 return b;
3770 return a;
3771}
3772
3773static double
3774dminnm (double a, double b)
3775{
3776 if (fpclassify (a) == FP_NORMAL)
3777 {
3778 if (fpclassify (b) == FP_NORMAL)
3779 return a < b ? a : b;
3780 return a;
3781 }
3782 else if (fpclassify (b) == FP_NORMAL)
3783 return b;
3784 return a;
3785}
3786
3787static void
3788do_vec_FminmaxNMP (sim_cpu *cpu)
3789{
3790 /* aarch64_get_instr (cpu)[31] = 0
3791 aarch64_get_instr (cpu)[30] = half (0)/full (1)
3792 aarch64_get_instr (cpu)[29,24] = 10 1110
3793 aarch64_get_instr (cpu)[23] = max(0)/min(1)
3794 aarch64_get_instr (cpu)[22] = float (0)/double (1)
3795 aarch64_get_instr (cpu)[21] = 1
3796 aarch64_get_instr (cpu)[20,16] = Vn
3797 aarch64_get_instr (cpu)[15,10] = 1100 01
3798 aarch64_get_instr (cpu)[9,5] = Vm
3799 aarch64_get_instr (cpu)[4.0] = Vd. */
3800
3801 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3802 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3803 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3804 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3805
3806 NYI_assert (29, 24, 0x2E);
3807 NYI_assert (21, 21, 1);
3808 NYI_assert (15, 10, 0x31);
3809
3810 if (uimm (aarch64_get_instr (cpu), 22, 22))
3811 {
3812 double (* fn)(double, double) = uimm (aarch64_get_instr (cpu), 23, 23)
3813 ? dminnm : dmaxnm;
3814
3815 if (! full)
3816 HALT_NYI;
3817 aarch64_set_vec_double (cpu, vd, 0,
3818 fn (aarch64_get_vec_double (cpu, vn, 0),
3819 aarch64_get_vec_double (cpu, vn, 1)));
3820 aarch64_set_vec_double (cpu, vd, 0,
3821 fn (aarch64_get_vec_double (cpu, vm, 0),
3822 aarch64_get_vec_double (cpu, vm, 1)));
3823 }
3824 else
3825 {
3826 float (* fn)(float, float) = uimm (aarch64_get_instr (cpu), 23, 23)
3827 ? fminnm : fmaxnm;
3828
3829 aarch64_set_vec_float (cpu, vd, 0,
3830 fn (aarch64_get_vec_float (cpu, vn, 0),
3831 aarch64_get_vec_float (cpu, vn, 1)));
3832 if (full)
3833 aarch64_set_vec_float (cpu, vd, 1,
3834 fn (aarch64_get_vec_float (cpu, vn, 2),
3835 aarch64_get_vec_float (cpu, vn, 3)));
3836
3837 aarch64_set_vec_float (cpu, vd, (full ? 2 : 1),
3838 fn (aarch64_get_vec_float (cpu, vm, 0),
3839 aarch64_get_vec_float (cpu, vm, 1)));
3840 if (full)
3841 aarch64_set_vec_float (cpu, vd, 3,
3842 fn (aarch64_get_vec_float (cpu, vm, 2),
3843 aarch64_get_vec_float (cpu, vm, 3)));
3844 }
3845}
3846
3847static void
3848do_vec_AND (sim_cpu *cpu)
3849{
3850 /* instr[31] = 0
3851 instr[30] = half (0)/full (1)
3852 instr[29,21] = 001110001
3853 instr[20,16] = Vm
3854 instr[15,10] = 000111
3855 instr[9,5] = Vn
3856 instr[4.0] = Vd. */
3857
3858 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3859 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3860 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3861 unsigned i;
3862 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3863
3864 NYI_assert (29, 21, 0x071);
3865 NYI_assert (15, 10, 0x07);
3866
3867 for (i = 0; i < (full ? 4 : 2); i++)
3868 aarch64_set_vec_u32 (cpu, vd, i,
3869 aarch64_get_vec_u32 (cpu, vn, i)
3870 & aarch64_get_vec_u32 (cpu, vm, i));
3871}
3872
3873static void
3874do_vec_BSL (sim_cpu *cpu)
3875{
3876 /* instr[31] = 0
3877 instr[30] = half (0)/full (1)
3878 instr[29,21] = 101110011
3879 instr[20,16] = Vm
3880 instr[15,10] = 000111
3881 instr[9,5] = Vn
3882 instr[4.0] = Vd. */
3883
3884 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3885 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3886 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3887 unsigned i;
3888 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3889
3890 NYI_assert (29, 21, 0x173);
3891 NYI_assert (15, 10, 0x07);
3892
3893 for (i = 0; i < (full ? 16 : 8); i++)
3894 aarch64_set_vec_u8 (cpu, vd, i,
3895 ( aarch64_get_vec_u8 (cpu, vd, i)
3896 & aarch64_get_vec_u8 (cpu, vn, i))
3897 | ((~ aarch64_get_vec_u8 (cpu, vd, i))
3898 & aarch64_get_vec_u8 (cpu, vm, i)));
3899}
3900
3901static void
3902do_vec_EOR (sim_cpu *cpu)
3903{
3904 /* instr[31] = 0
3905 instr[30] = half (0)/full (1)
3906 instr[29,21] = 10 1110 001
3907 instr[20,16] = Vm
3908 instr[15,10] = 000111
3909 instr[9,5] = Vn
3910 instr[4.0] = Vd. */
3911
3912 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3913 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3914 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3915 unsigned i;
3916 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3917
3918 NYI_assert (29, 21, 0x171);
3919 NYI_assert (15, 10, 0x07);
3920
3921 for (i = 0; i < (full ? 4 : 2); i++)
3922 aarch64_set_vec_u32 (cpu, vd, i,
3923 aarch64_get_vec_u32 (cpu, vn, i)
3924 ^ aarch64_get_vec_u32 (cpu, vm, i));
3925}
3926
3927static void
3928do_vec_bit (sim_cpu *cpu)
3929{
3930 /* instr[31] = 0
3931 instr[30] = half (0)/full (1)
3932 instr[29,23] = 10 1110 1
3933 instr[22] = BIT (0) / BIF (1)
3934 instr[21] = 1
3935 instr[20,16] = Vm
3936 instr[15,10] = 0001 11
3937 instr[9,5] = Vn
3938 instr[4.0] = Vd. */
3939
3940 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3941 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3942 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3943 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
3944 unsigned test_false = uimm (aarch64_get_instr (cpu), 22, 22);
3945 unsigned i;
3946
3947 NYI_assert (29, 23, 0x5D);
3948 NYI_assert (21, 21, 1);
3949 NYI_assert (15, 10, 0x07);
3950
3951 if (test_false)
3952 {
3953 for (i = 0; i < (full ? 16 : 8); i++)
3954 if (aarch64_get_vec_u32 (cpu, vn, i) == 0)
3955 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
3956 }
3957 else
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}
3964
3965static void
3966do_vec_ORN (sim_cpu *cpu)
3967{
3968 /* instr[31] = 0
3969 instr[30] = half (0)/full (1)
3970 instr[29,21] = 00 1110 111
3971 instr[20,16] = Vm
3972 instr[15,10] = 00 0111
3973 instr[9,5] = Vn
3974 instr[4.0] = Vd. */
3975
3976 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3977 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3978 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3979 unsigned i;
3980 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3981
3982 NYI_assert (29, 21, 0x077);
3983 NYI_assert (15, 10, 0x07);
3984
3985 for (i = 0; i < (full ? 16 : 8); i++)
3986 aarch64_set_vec_u8 (cpu, vd, i,
3987 aarch64_get_vec_u8 (cpu, vn, i)
3988 | ~ aarch64_get_vec_u8 (cpu, vm, i));
3989}
3990
3991static void
3992do_vec_ORR (sim_cpu *cpu)
3993{
3994 /* instr[31] = 0
3995 instr[30] = half (0)/full (1)
3996 instr[29,21] = 00 1110 101
3997 instr[20,16] = Vm
3998 instr[15,10] = 0001 11
3999 instr[9,5] = Vn
4000 instr[4.0] = Vd. */
4001
4002 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4003 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4004 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4005 unsigned i;
4006 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4007
4008 NYI_assert (29, 21, 0x075);
4009 NYI_assert (15, 10, 0x07);
4010
4011 for (i = 0; i < (full ? 16 : 8); i++)
4012 aarch64_set_vec_u8 (cpu, vd, i,
4013 aarch64_get_vec_u8 (cpu, vn, i)
4014 | aarch64_get_vec_u8 (cpu, vm, i));
4015}
4016
4017static void
4018do_vec_BIC (sim_cpu *cpu)
4019{
4020 /* instr[31] = 0
4021 instr[30] = half (0)/full (1)
4022 instr[29,21] = 00 1110 011
4023 instr[20,16] = Vm
4024 instr[15,10] = 00 0111
4025 instr[9,5] = Vn
4026 instr[4.0] = Vd. */
4027
4028 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4029 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4030 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4031 unsigned i;
4032 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4033
4034 NYI_assert (29, 21, 0x073);
4035 NYI_assert (15, 10, 0x07);
4036
4037 for (i = 0; i < (full ? 16 : 8); i++)
4038 aarch64_set_vec_u8 (cpu, vd, i,
4039 aarch64_get_vec_u8 (cpu, vn, i)
4040 & ~ aarch64_get_vec_u8 (cpu, vm, i));
4041}
4042
4043static void
4044do_vec_XTN (sim_cpu *cpu)
4045{
4046 /* instr[31] = 0
4047 instr[30] = first part (0)/ second part (1)
4048 instr[29,24] = 00 1110
4049 instr[23,22] = size: byte(00), half(01), word (10)
4050 instr[21,10] = 1000 0100 1010
4051 instr[9,5] = Vs
4052 instr[4,0] = Vd. */
4053
4054 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4055 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4056 unsigned bias = uimm (aarch64_get_instr (cpu), 30, 30);
4057 unsigned i;
4058
4059 NYI_assert (29, 24, 0x0E);
4060 NYI_assert (21, 10, 0x84A);
4061
4062 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4063 {
4064 case 0:
4065 if (bias)
4066 for (i = 0; i < 8; i++)
4067 aarch64_set_vec_u8 (cpu, vd, i + 8,
4068 aarch64_get_vec_u16 (cpu, vs, i) >> 8);
4069 else
4070 for (i = 0; i < 8; i++)
4071 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i));
4072 return;
4073
4074 case 1:
4075 if (bias)
4076 for (i = 0; i < 4; i++)
4077 aarch64_set_vec_u16 (cpu, vd, i + 4,
4078 aarch64_get_vec_u32 (cpu, vs, i) >> 16);
4079 else
4080 for (i = 0; i < 4; i++)
4081 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, i));
4082 return;
4083
4084 case 2:
4085 if (bias)
4086 for (i = 0; i < 2; i++)
4087 aarch64_set_vec_u32 (cpu, vd, i + 4,
4088 aarch64_get_vec_u64 (cpu, vs, i) >> 32);
4089 else
4090 for (i = 0; i < 2; i++)
4091 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, i));
4092 return;
4093
4094 default:
4095 HALT_UNALLOC;
4096 }
4097}
4098
2e8cf49e
NC
4099static void
4100do_vec_maxv (sim_cpu *cpu)
4101{
4102 /* instr[31] = 0
4103 instr[30] = half(0)/full(1)
4104 instr[29] = signed (0)/unsigned(1)
4105 instr[28,24] = 0 1110
4106 instr[23,22] = size: byte(00), half(01), word (10)
4107 instr[21] = 1
4108 instr[20,17] = 1 000
4109 instr[16] = max(0)/min(1)
4110 instr[15,10] = 1010 10
4111 instr[9,5] = V source
4112 instr[4.0] = R dest. */
4113
4114 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4115 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
4116 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4117 unsigned i;
4118
4119 NYI_assert (28, 24, 0x0E);
4120 NYI_assert (21, 21, 1);
4121 NYI_assert (20, 17, 8);
4122 NYI_assert (15, 10, 0x2A);
4123
4124 switch ((uimm (aarch64_get_instr (cpu), 29, 29) << 1)
4125 | uimm (aarch64_get_instr (cpu), 16, 16))
4126 {
4127 case 0: /* SMAXV. */
4128 {
4129 int64_t smax;
4130 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4131 {
4132 case 0:
4133 smax = aarch64_get_vec_s8 (cpu, vs, 0);
4134 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4135 smax = max (smax, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4136 break;
4137 case 1:
4138 smax = aarch64_get_vec_s16 (cpu, vs, 0);
4139 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4140 smax = max (smax, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4141 break;
4142 case 2:
4143 smax = aarch64_get_vec_s32 (cpu, vs, 0);
4144 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4145 smax = max (smax, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e
NC
4146 break;
4147 default:
4148 case 3:
4149 HALT_UNALLOC;
4150 }
4151 aarch64_set_reg_s64 (cpu, rd, NO_SP, smax);
4152 return;
4153 }
4154
4155 case 1: /* SMINV. */
4156 {
4157 int64_t smin;
4158 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4159 {
4160 case 0:
4161 smin = aarch64_get_vec_s8 (cpu, vs, 0);
4162 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4163 smin = min (smin, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4164 break;
4165 case 1:
4166 smin = aarch64_get_vec_s16 (cpu, vs, 0);
4167 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4168 smin = min (smin, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4169 break;
4170 case 2:
4171 smin = aarch64_get_vec_s32 (cpu, vs, 0);
4172 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4173 smin = min (smin, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e
NC
4174 break;
4175 default:
4176 case 3:
4177 HALT_UNALLOC;
4178 }
4179 aarch64_set_reg_s64 (cpu, rd, NO_SP, smin);
4180 return;
4181 }
4182
4183 case 2: /* UMAXV. */
4184 {
4185 uint64_t umax;
4186 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4187 {
4188 case 0:
4189 umax = aarch64_get_vec_u8 (cpu, vs, 0);
4190 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4191 umax = max (umax, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4192 break;
4193 case 1:
4194 umax = aarch64_get_vec_u16 (cpu, vs, 0);
4195 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4196 umax = max (umax, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4197 break;
4198 case 2:
4199 umax = aarch64_get_vec_u32 (cpu, vs, 0);
4200 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4201 umax = max (umax, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e
NC
4202 break;
4203 default:
4204 case 3:
4205 HALT_UNALLOC;
4206 }
4207 aarch64_set_reg_u64 (cpu, rd, NO_SP, umax);
4208 return;
4209 }
4210
4211 case 3: /* UMINV. */
4212 {
4213 uint64_t umin;
4214 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4215 {
4216 case 0:
4217 umin = aarch64_get_vec_u8 (cpu, vs, 0);
4218 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4219 umin = min (umin, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4220 break;
4221 case 1:
4222 umin = aarch64_get_vec_u16 (cpu, vs, 0);
4223 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4224 umin = min (umin, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4225 break;
4226 case 2:
4227 umin = aarch64_get_vec_u32 (cpu, vs, 0);
4228 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4229 umin = min (umin, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e
NC
4230 break;
4231 default:
4232 case 3:
4233 HALT_UNALLOC;
4234 }
4235 aarch64_set_reg_u64 (cpu, rd, NO_SP, umin);
4236 return;
4237 }
4238
4239 default:
4240 HALT_UNALLOC;
4241 }
4242}
4243
4244static void
4245do_vec_fminmaxV (sim_cpu *cpu)
4246{
4247 /* instr[31,24] = 0110 1110
4248 instr[23] = max(0)/min(1)
4249 instr[22,14] = 011 0000 11
4250 instr[13,12] = nm(00)/normal(11)
4251 instr[11,10] = 10
4252 instr[9,5] = V source
4253 instr[4.0] = R dest. */
4254
4255 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4256 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
4257 unsigned i;
4258 float res = aarch64_get_vec_float (cpu, vs, 0);
4259
4260 NYI_assert (31, 24, 0x6E);
4261 NYI_assert (22, 14, 0x0C3);
4262 NYI_assert (11, 10, 2);
4263
4264 if (uimm (aarch64_get_instr (cpu), 23, 23))
4265 {
4266 switch (uimm (aarch64_get_instr (cpu), 13, 12))
4267 {
4268 case 0: /* FMNINNMV. */
4269 for (i = 1; i < 4; i++)
4270 res = fminnm (res, aarch64_get_vec_float (cpu, vs, i));
4271 break;
4272
4273 case 3: /* FMINV. */
4274 for (i = 1; i < 4; i++)
bc273e17 4275 res = min (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4276 break;
4277
4278 default:
4279 HALT_NYI;
4280 }
4281 }
4282 else
4283 {
4284 switch (uimm (aarch64_get_instr (cpu), 13, 12))
4285 {
4286 case 0: /* FMNAXNMV. */
4287 for (i = 1; i < 4; i++)
4288 res = fmaxnm (res, aarch64_get_vec_float (cpu, vs, i));
4289 break;
4290
4291 case 3: /* FMAXV. */
4292 for (i = 1; i < 4; i++)
bc273e17 4293 res = max (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4294 break;
4295
4296 default:
4297 HALT_NYI;
4298 }
4299 }
4300
4301 aarch64_set_FP_float (cpu, rd, res);
4302}
4303
4304static void
4305do_vec_Fminmax (sim_cpu *cpu)
4306{
4307 /* instr[31] = 0
4308 instr[30] = half(0)/full(1)
4309 instr[29,24] = 00 1110
4310 instr[23] = max(0)/min(1)
4311 instr[22] = float(0)/double(1)
4312 instr[21] = 1
4313 instr[20,16] = Vm
4314 instr[15,14] = 11
4315 instr[13,12] = nm(00)/normal(11)
4316 instr[11,10] = 01
4317 instr[9,5] = Vn
4318 instr[4,0] = Vd. */
4319
4320 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4321 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4322 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4323 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4324 unsigned min = uimm (aarch64_get_instr (cpu), 23, 23);
4325 unsigned i;
4326
4327 NYI_assert (29, 24, 0x0E);
4328 NYI_assert (21, 21, 1);
4329 NYI_assert (15, 14, 3);
4330 NYI_assert (11, 10, 1);
4331
4332 if (uimm (aarch64_get_instr (cpu), 22, 22))
4333 {
4334 double (* func)(double, double);
4335
4336 if (! full)
4337 HALT_NYI;
4338
4339 if (uimm (aarch64_get_instr (cpu), 13, 12) == 0)
4340 func = min ? dminnm : dmaxnm;
4341 else if (uimm (aarch64_get_instr (cpu), 13, 12) == 3)
4342 func = min ? fmin : fmax;
4343 else
4344 HALT_NYI;
4345
4346 for (i = 0; i < 2; i++)
4347 aarch64_set_vec_double (cpu, vd, i,
4348 func (aarch64_get_vec_double (cpu, vn, i),
4349 aarch64_get_vec_double (cpu, vm, i)));
4350 }
4351 else
4352 {
4353 float (* func)(float, float);
4354
4355 if (uimm (aarch64_get_instr (cpu), 13, 12) == 0)
4356 func = min ? fminnm : fmaxnm;
4357 else if (uimm (aarch64_get_instr (cpu), 13, 12) == 3)
4358 func = min ? fminf : fmaxf;
4359 else
4360 HALT_NYI;
4361
4362 for (i = 0; i < (full ? 4 : 2); i++)
4363 aarch64_set_vec_float (cpu, vd, i,
4364 func (aarch64_get_vec_float (cpu, vn, i),
4365 aarch64_get_vec_float (cpu, vm, i)));
4366 }
4367}
4368
4369static void
4370do_vec_SCVTF (sim_cpu *cpu)
4371{
4372 /* instr[31] = 0
4373 instr[30] = Q
4374 instr[29,23] = 00 1110 0
4375 instr[22] = float(0)/double(1)
4376 instr[21,10] = 10 0001 1101 10
4377 instr[9,5] = Vn
4378 instr[4,0] = Vd. */
4379
4380 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4381 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4382 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4383 unsigned size = uimm (aarch64_get_instr (cpu), 22, 22);
4384 unsigned i;
4385
4386 NYI_assert (29, 23, 0x1C);
4387 NYI_assert (21, 10, 0x876);
4388
4389 if (size)
4390 {
4391 if (! full)
4392 HALT_UNALLOC;
4393
4394 for (i = 0; i < 2; i++)
4395 {
4396 double val = (double) aarch64_get_vec_u64 (cpu, vn, i);
4397 aarch64_set_vec_double (cpu, vd, i, val);
4398 }
4399 }
4400 else
4401 {
4402 for (i = 0; i < (full ? 4 : 2); i++)
4403 {
4404 float val = (float) aarch64_get_vec_u32 (cpu, vn, i);
4405 aarch64_set_vec_float (cpu, vd, i, val);
4406 }
4407 }
4408}
4409
4410#define VEC_CMP(SOURCE, CMP) \
4411 do \
4412 { \
4413 switch (size) \
4414 { \
4415 case 0: \
4416 for (i = 0; i < (full ? 16 : 8); i++) \
4417 aarch64_set_vec_u8 (cpu, vd, i, \
4418 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4419 CMP \
4420 aarch64_get_vec_##SOURCE##8 (cpu, vm, i) \
4421 ? -1 : 0); \
4422 return; \
4423 case 1: \
4424 for (i = 0; i < (full ? 8 : 4); i++) \
4425 aarch64_set_vec_u16 (cpu, vd, i, \
4426 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4427 CMP \
4428 aarch64_get_vec_##SOURCE##16 (cpu, vm, i) \
4429 ? -1 : 0); \
4430 return; \
4431 case 2: \
4432 for (i = 0; i < (full ? 4 : 2); i++) \
4433 aarch64_set_vec_u32 (cpu, vd, i, \
4434 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4435 CMP \
4436 aarch64_get_vec_##SOURCE##32 (cpu, vm, i) \
4437 ? -1 : 0); \
4438 return; \
4439 case 3: \
4440 if (! full) \
4441 HALT_UNALLOC; \
4442 for (i = 0; i < 2; i++) \
4443 aarch64_set_vec_u64 (cpu, vd, i, \
4444 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4445 CMP \
4446 aarch64_get_vec_##SOURCE##64 (cpu, vm, i) \
4447 ? -1ULL : 0); \
4448 return; \
4449 default: \
4450 HALT_UNALLOC; \
4451 } \
4452 } \
4453 while (0)
4454
4455#define VEC_CMP0(SOURCE, CMP) \
4456 do \
4457 { \
4458 switch (size) \
4459 { \
4460 case 0: \
4461 for (i = 0; i < (full ? 16 : 8); i++) \
4462 aarch64_set_vec_u8 (cpu, vd, i, \
4463 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4464 CMP 0 ? -1 : 0); \
4465 return; \
4466 case 1: \
4467 for (i = 0; i < (full ? 8 : 4); i++) \
4468 aarch64_set_vec_u16 (cpu, vd, i, \
4469 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4470 CMP 0 ? -1 : 0); \
4471 return; \
4472 case 2: \
4473 for (i = 0; i < (full ? 4 : 2); i++) \
4474 aarch64_set_vec_u32 (cpu, vd, i, \
4475 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4476 CMP 0 ? -1 : 0); \
4477 return; \
4478 case 3: \
4479 if (! full) \
4480 HALT_UNALLOC; \
4481 for (i = 0; i < 2; i++) \
4482 aarch64_set_vec_u64 (cpu, vd, i, \
4483 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4484 CMP 0 ? -1ULL : 0); \
4485 return; \
4486 default: \
4487 HALT_UNALLOC; \
4488 } \
4489 } \
4490 while (0)
4491
4492#define VEC_FCMP0(CMP) \
4493 do \
4494 { \
4495 if (vm != 0) \
4496 HALT_NYI; \
4497 if (uimm (aarch64_get_instr (cpu), 22, 22)) \
4498 { \
4499 if (! full) \
4500 HALT_NYI; \
4501 for (i = 0; i < 2; i++) \
4502 aarch64_set_vec_u64 (cpu, vd, i, \
4503 aarch64_get_vec_double (cpu, vn, i) \
4504 CMP 0.0 ? -1 : 0); \
4505 } \
4506 else \
4507 { \
4508 for (i = 0; i < (full ? 4 : 2); i++) \
4509 aarch64_set_vec_u32 (cpu, vd, i, \
4510 aarch64_get_vec_float (cpu, vn, i) \
4511 CMP 0.0 ? -1 : 0); \
4512 } \
4513 return; \
4514 } \
4515 while (0)
4516
4517#define VEC_FCMP(CMP) \
4518 do \
4519 { \
4520 if (uimm (aarch64_get_instr (cpu), 22, 22)) \
4521 { \
4522 if (! full) \
4523 HALT_NYI; \
4524 for (i = 0; i < 2; i++) \
4525 aarch64_set_vec_u64 (cpu, vd, i, \
4526 aarch64_get_vec_double (cpu, vn, i) \
4527 CMP \
4528 aarch64_get_vec_double (cpu, vm, i) \
4529 ? -1 : 0); \
4530 } \
4531 else \
4532 { \
4533 for (i = 0; i < (full ? 4 : 2); i++) \
4534 aarch64_set_vec_u32 (cpu, vd, i, \
4535 aarch64_get_vec_float (cpu, vn, i) \
4536 CMP \
4537 aarch64_get_vec_float (cpu, vm, i) \
4538 ? -1 : 0); \
4539 } \
4540 return; \
4541 } \
4542 while (0)
4543
4544static void
4545do_vec_compare (sim_cpu *cpu)
4546{
4547 /* instr[31] = 0
4548 instr[30] = half(0)/full(1)
4549 instr[29] = part-of-comparison-type
4550 instr[28,24] = 0 1110
4551 instr[23,22] = size of integer compares: byte(00), half(01), word (10), long (11)
4552 type of float compares: single (-0) / double (-1)
4553 instr[21] = 1
4554 instr[20,16] = Vm or 00000 (compare vs 0)
4555 instr[15,10] = part-of-comparison-type
4556 instr[9,5] = Vn
4557 instr[4.0] = Vd. */
4558
4559 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4560 int size = uimm (aarch64_get_instr (cpu), 23, 22);
4561 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4562 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4563 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4564 unsigned i;
4565
4566 NYI_assert (28, 24, 0x0E);
4567 NYI_assert (21, 21, 1);
4568
4569 if ((uimm (aarch64_get_instr (cpu), 11, 11)
4570 && uimm (aarch64_get_instr (cpu), 14, 14))
4571 || ((uimm (aarch64_get_instr (cpu), 11, 11) == 0
4572 && uimm (aarch64_get_instr (cpu), 10, 10) == 0)))
4573 {
4574 /* A compare vs 0. */
4575 if (vm != 0)
4576 {
4577 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x2A)
4578 do_vec_maxv (cpu);
4579 else if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x32
4580 || uimm (aarch64_get_instr (cpu), 15, 10) == 0x3E)
4581 do_vec_fminmaxV (cpu);
4582 else if (uimm (aarch64_get_instr (cpu), 29, 23) == 0x1C
4583 && uimm (aarch64_get_instr (cpu), 21, 10) == 0x876)
4584 do_vec_SCVTF (cpu);
4585 else
4586 HALT_NYI;
4587 return;
4588 }
4589 }
4590
4591 if (uimm (aarch64_get_instr (cpu), 14, 14))
4592 {
4593 /* A floating point compare. */
4594 unsigned decode = (uimm (aarch64_get_instr (cpu), 29, 29) << 5)
4595 | (uimm (aarch64_get_instr (cpu), 23, 23) << 4)
4596 | uimm (aarch64_get_instr (cpu), 13, 10);
4597
4598 NYI_assert (15, 15, 1);
4599
4600 switch (decode)
4601 {
4602 case /* 0b010010: GT#0 */ 0x12: VEC_FCMP0 (>);
4603 case /* 0b110010: GE#0 */ 0x32: VEC_FCMP0 (>=);
4604 case /* 0b010110: EQ#0 */ 0x16: VEC_FCMP0 (==);
4605 case /* 0b110110: LE#0 */ 0x36: VEC_FCMP0 (<=);
4606 case /* 0b011010: LT#0 */ 0x1A: VEC_FCMP0 (<);
4607 case /* 0b111001: GT */ 0x39: VEC_FCMP (>);
4608 case /* 0b101001: GE */ 0x29: VEC_FCMP (>=);
4609 case /* 0b001001: EQ */ 0x09: VEC_FCMP (==);
4610
4611 default:
4612 HALT_NYI;
4613 }
4614 }
4615 else
4616 {
4617 unsigned decode = (uimm (aarch64_get_instr (cpu), 29, 29) << 6)
4618 | uimm (aarch64_get_instr (cpu), 15, 10);
4619
4620 switch (decode)
4621 {
4622 case 0x0D: /* 0001101 GT */ VEC_CMP (s, > );
4623 case 0x0F: /* 0001111 GE */ VEC_CMP (s, >= );
4624 case 0x22: /* 0100010 GT #0 */ VEC_CMP0 (s, > );
4625 case 0x26: /* 0100110 EQ #0 */ VEC_CMP0 (s, == );
4626 case 0x2A: /* 0101010 LT #0 */ VEC_CMP0 (s, < );
4627 case 0x4D: /* 1001101 HI */ VEC_CMP (u, > );
4628 case 0x4F: /* 1001111 HS */ VEC_CMP (u, >= );
4629 case 0x62: /* 1100010 GE #0 */ VEC_CMP0 (s, >= );
4630 case 0x63: /* 1100011 EQ */ VEC_CMP (u, == );
4631 case 0x66: /* 1100110 LE #0 */ VEC_CMP0 (s, <= );
4632 default:
4633 if (vm == 0)
4634 HALT_NYI;
4635 do_vec_maxv (cpu);
4636 }
4637 }
4638}
4639
4640static void
4641do_vec_SSHL (sim_cpu *cpu)
4642{
4643 /* instr[31] = 0
4644 instr[30] = first part (0)/ second part (1)
4645 instr[29,24] = 00 1110
4646 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4647 instr[21] = 1
4648 instr[20,16] = Vm
4649 instr[15,10] = 0100 01
4650 instr[9,5] = Vn
4651 instr[4,0] = Vd. */
4652
4653 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4654 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4655 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4656 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4657 unsigned i;
4658
4659 NYI_assert (29, 24, 0x0E);
4660 NYI_assert (21, 21, 1);
4661 NYI_assert (15, 10, 0x11);
4662
4663 /* FIXME: What is a signed shift left in this context ?. */
4664
4665 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4666 {
4667 case 0:
4668 for (i = 0; i < (full ? 16 : 8); i++)
4669 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4670 << aarch64_get_vec_s8 (cpu, vm, i));
4671 return;
4672
4673 case 1:
4674 for (i = 0; i < (full ? 8 : 4); i++)
4675 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4676 << aarch64_get_vec_s16 (cpu, vm, i));
4677 return;
4678
4679 case 2:
4680 for (i = 0; i < (full ? 4 : 2); i++)
4681 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4682 << aarch64_get_vec_s32 (cpu, vm, i));
4683 return;
4684
4685 case 3:
4686 if (! full)
4687 HALT_UNALLOC;
4688 for (i = 0; i < 2; i++)
4689 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4690 << aarch64_get_vec_s64 (cpu, vm, i));
4691 return;
4692
4693 default:
4694 HALT_NYI;
4695 }
4696}
4697
4698static void
4699do_vec_USHL (sim_cpu *cpu)
4700{
4701 /* instr[31] = 0
4702 instr[30] = first part (0)/ second part (1)
4703 instr[29,24] = 10 1110
4704 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4705 instr[21] = 1
4706 instr[20,16] = Vm
4707 instr[15,10] = 0100 01
4708 instr[9,5] = Vn
4709 instr[4,0] = Vd */
4710
4711 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4712 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4713 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4714 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4715 unsigned i;
4716
4717 NYI_assert (29, 24, 0x2E);
4718 NYI_assert (15, 10, 0x11);
4719
4720 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4721 {
4722 case 0:
4723 for (i = 0; i < (full ? 16 : 8); i++)
4724 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4725 << aarch64_get_vec_u8 (cpu, vm, i));
4726 return;
4727
4728 case 1:
4729 for (i = 0; i < (full ? 8 : 4); i++)
4730 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4731 << aarch64_get_vec_u16 (cpu, vm, i));
4732 return;
4733
4734 case 2:
4735 for (i = 0; i < (full ? 4 : 2); i++)
4736 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4737 << aarch64_get_vec_u32 (cpu, vm, i));
4738 return;
4739
4740 case 3:
4741 if (! full)
4742 HALT_UNALLOC;
4743 for (i = 0; i < 2; i++)
4744 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4745 << aarch64_get_vec_u64 (cpu, vm, i));
4746 return;
4747
4748 default:
4749 HALT_NYI;
4750 }
4751}
4752
4753static void
4754do_vec_FMLA (sim_cpu *cpu)
4755{
4756 /* instr[31] = 0
4757 instr[30] = full/half selector
4758 instr[29,23] = 0011100
4759 instr[22] = size: 0=>float, 1=>double
4760 instr[21] = 1
4761 instr[20,16] = Vn
4762 instr[15,10] = 1100 11
4763 instr[9,5] = Vm
4764 instr[4.0] = Vd. */
4765
4766 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4767 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4768 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4769 unsigned i;
4770 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4771
4772 NYI_assert (29, 23, 0x1C);
4773 NYI_assert (21, 21, 1);
4774 NYI_assert (15, 10, 0x33);
4775
4776 if (uimm (aarch64_get_instr (cpu), 22, 22))
4777 {
4778 if (! full)
4779 HALT_UNALLOC;
4780 for (i = 0; i < 2; i++)
4781 aarch64_set_vec_double (cpu, vd, i,
4782 aarch64_get_vec_double (cpu, vn, i) *
4783 aarch64_get_vec_double (cpu, vm, i) +
4784 aarch64_get_vec_double (cpu, vd, i));
4785 }
4786 else
4787 {
4788 for (i = 0; i < (full ? 4 : 2); i++)
4789 aarch64_set_vec_float (cpu, vd, i,
4790 aarch64_get_vec_float (cpu, vn, i) *
4791 aarch64_get_vec_float (cpu, vm, i) +
4792 aarch64_get_vec_float (cpu, vd, i));
4793 }
4794}
4795
4796static void
4797do_vec_max (sim_cpu *cpu)
4798{
4799 /* instr[31] = 0
4800 instr[30] = full/half selector
4801 instr[29] = SMAX (0) / UMAX (1)
4802 instr[28,24] = 0 1110
4803 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4804 instr[21] = 1
4805 instr[20,16] = Vn
4806 instr[15,10] = 0110 01
4807 instr[9,5] = Vm
4808 instr[4.0] = Vd. */
4809
4810 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4811 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4812 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4813 unsigned i;
4814 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4815
4816 NYI_assert (28, 24, 0x0E);
4817 NYI_assert (21, 21, 1);
4818 NYI_assert (15, 10, 0x19);
4819
4820 if (uimm (aarch64_get_instr (cpu), 29, 29))
4821 {
4822 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4823 {
4824 case 0:
4825 for (i = 0; i < (full ? 16 : 8); i++)
4826 aarch64_set_vec_u8 (cpu, vd, i,
4827 aarch64_get_vec_u8 (cpu, vn, i)
4828 > aarch64_get_vec_u8 (cpu, vm, i)
4829 ? aarch64_get_vec_u8 (cpu, vn, i)
4830 : aarch64_get_vec_u8 (cpu, vm, i));
4831 return;
4832
4833 case 1:
4834 for (i = 0; i < (full ? 8 : 4); i++)
4835 aarch64_set_vec_u16 (cpu, vd, i,
4836 aarch64_get_vec_u16 (cpu, vn, i)
4837 > aarch64_get_vec_u16 (cpu, vm, i)
4838 ? aarch64_get_vec_u16 (cpu, vn, i)
4839 : aarch64_get_vec_u16 (cpu, vm, i));
4840 return;
4841
4842 case 2:
4843 for (i = 0; i < (full ? 4 : 2); i++)
4844 aarch64_set_vec_u32 (cpu, vd, i,
4845 aarch64_get_vec_u32 (cpu, vn, i)
4846 > aarch64_get_vec_u32 (cpu, vm, i)
4847 ? aarch64_get_vec_u32 (cpu, vn, i)
4848 : aarch64_get_vec_u32 (cpu, vm, i));
4849 return;
4850
4851 default:
4852 case 3:
4853 HALT_UNALLOC;
4854 }
4855 }
4856 else
4857 {
4858 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4859 {
4860 case 0:
4861 for (i = 0; i < (full ? 16 : 8); i++)
4862 aarch64_set_vec_s8 (cpu, vd, i,
4863 aarch64_get_vec_s8 (cpu, vn, i)
4864 > aarch64_get_vec_s8 (cpu, vm, i)
4865 ? aarch64_get_vec_s8 (cpu, vn, i)
4866 : aarch64_get_vec_s8 (cpu, vm, i));
4867 return;
4868
4869 case 1:
4870 for (i = 0; i < (full ? 8 : 4); i++)
4871 aarch64_set_vec_s16 (cpu, vd, i,
4872 aarch64_get_vec_s16 (cpu, vn, i)
4873 > aarch64_get_vec_s16 (cpu, vm, i)
4874 ? aarch64_get_vec_s16 (cpu, vn, i)
4875 : aarch64_get_vec_s16 (cpu, vm, i));
4876 return;
4877
4878 case 2:
4879 for (i = 0; i < (full ? 4 : 2); i++)
4880 aarch64_set_vec_s32 (cpu, vd, i,
4881 aarch64_get_vec_s32 (cpu, vn, i)
4882 > aarch64_get_vec_s32 (cpu, vm, i)
4883 ? aarch64_get_vec_s32 (cpu, vn, i)
4884 : aarch64_get_vec_s32 (cpu, vm, i));
4885 return;
4886
4887 default:
4888 case 3:
4889 HALT_UNALLOC;
4890 }
4891 }
4892}
4893
4894static void
4895do_vec_min (sim_cpu *cpu)
4896{
4897 /* instr[31] = 0
4898 instr[30] = full/half selector
4899 instr[29] = SMIN (0) / UMIN (1)
4900 instr[28,24] = 0 1110
4901 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4902 instr[21] = 1
4903 instr[20,16] = Vn
4904 instr[15,10] = 0110 11
4905 instr[9,5] = Vm
4906 instr[4.0] = Vd. */
4907
4908 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4909 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4910 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4911 unsigned i;
4912 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4913
4914 NYI_assert (28, 24, 0x0E);
4915 NYI_assert (21, 21, 1);
4916 NYI_assert (15, 10, 0x1B);
4917
4918 if (uimm (aarch64_get_instr (cpu), 29, 29))
4919 {
4920 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4921 {
4922 case 0:
4923 for (i = 0; i < (full ? 16 : 8); i++)
4924 aarch64_set_vec_u8 (cpu, vd, i,
4925 aarch64_get_vec_u8 (cpu, vn, i)
4926 < aarch64_get_vec_u8 (cpu, vm, i)
4927 ? aarch64_get_vec_u8 (cpu, vn, i)
4928 : aarch64_get_vec_u8 (cpu, vm, i));
4929 return;
4930
4931 case 1:
4932 for (i = 0; i < (full ? 8 : 4); i++)
4933 aarch64_set_vec_u16 (cpu, vd, i,
4934 aarch64_get_vec_u16 (cpu, vn, i)
4935 < aarch64_get_vec_u16 (cpu, vm, i)
4936 ? aarch64_get_vec_u16 (cpu, vn, i)
4937 : aarch64_get_vec_u16 (cpu, vm, i));
4938 return;
4939
4940 case 2:
4941 for (i = 0; i < (full ? 4 : 2); i++)
4942 aarch64_set_vec_u32 (cpu, vd, i,
4943 aarch64_get_vec_u32 (cpu, vn, i)
4944 < aarch64_get_vec_u32 (cpu, vm, i)
4945 ? aarch64_get_vec_u32 (cpu, vn, i)
4946 : aarch64_get_vec_u32 (cpu, vm, i));
4947 return;
4948
4949 default:
4950 case 3:
4951 HALT_UNALLOC;
4952 }
4953 }
4954 else
4955 {
4956 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4957 {
4958 case 0:
4959 for (i = 0; i < (full ? 16 : 8); i++)
4960 aarch64_set_vec_s8 (cpu, vd, i,
4961 aarch64_get_vec_s8 (cpu, vn, i)
4962 < aarch64_get_vec_s8 (cpu, vm, i)
4963 ? aarch64_get_vec_s8 (cpu, vn, i)
4964 : aarch64_get_vec_s8 (cpu, vm, i));
4965 return;
4966
4967 case 1:
4968 for (i = 0; i < (full ? 8 : 4); i++)
4969 aarch64_set_vec_s16 (cpu, vd, i,
4970 aarch64_get_vec_s16 (cpu, vn, i)
4971 < aarch64_get_vec_s16 (cpu, vm, i)
4972 ? aarch64_get_vec_s16 (cpu, vn, i)
4973 : aarch64_get_vec_s16 (cpu, vm, i));
4974 return;
4975
4976 case 2:
4977 for (i = 0; i < (full ? 4 : 2); i++)
4978 aarch64_set_vec_s32 (cpu, vd, i,
4979 aarch64_get_vec_s32 (cpu, vn, i)
4980 < aarch64_get_vec_s32 (cpu, vm, i)
4981 ? aarch64_get_vec_s32 (cpu, vn, i)
4982 : aarch64_get_vec_s32 (cpu, vm, i));
4983 return;
4984
4985 default:
4986 case 3:
4987 HALT_UNALLOC;
4988 }
4989 }
4990}
4991
4992static void
4993do_vec_sub_long (sim_cpu *cpu)
4994{
4995 /* instr[31] = 0
4996 instr[30] = lower (0) / upper (1)
4997 instr[29] = signed (0) / unsigned (1)
4998 instr[28,24] = 0 1110
4999 instr[23,22] = size: bytes (00), half (01), word (10)
5000 instr[21] = 1
5001 insrt[20,16] = Vm
5002 instr[15,10] = 0010 00
5003 instr[9,5] = Vn
5004 instr[4,0] = V dest. */
5005
5006 unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
5007 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5008 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5009 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5010 unsigned bias = 0;
5011 unsigned i;
5012
5013 NYI_assert (28, 24, 0x0E);
5014 NYI_assert (21, 21, 1);
5015 NYI_assert (15, 10, 0x08);
5016
5017 if (size == 3)
5018 HALT_UNALLOC;
5019
5020 switch (uimm (aarch64_get_instr (cpu), 30, 29))
5021 {
5022 case 2: /* SSUBL2. */
5023 bias = 2;
5024 case 0: /* SSUBL. */
5025 switch (size)
5026 {
5027 case 0:
5028 bias *= 3;
5029 for (i = 0; i < 8; i++)
5030 aarch64_set_vec_s16 (cpu, vd, i,
5031 aarch64_get_vec_s8 (cpu, vn, i + bias)
5032 - aarch64_get_vec_s8 (cpu, vm, i + bias));
5033 break;
5034
5035 case 1:
5036 bias *= 2;
5037 for (i = 0; i < 4; i++)
5038 aarch64_set_vec_s32 (cpu, vd, i,
5039 aarch64_get_vec_s16 (cpu, vn, i + bias)
5040 - aarch64_get_vec_s16 (cpu, vm, i + bias));
5041 break;
5042
5043 case 2:
5044 for (i = 0; i < 2; i++)
5045 aarch64_set_vec_s64 (cpu, vd, i,
5046 aarch64_get_vec_s32 (cpu, vn, i + bias)
5047 - aarch64_get_vec_s32 (cpu, vm, i + bias));
5048 break;
5049
5050 default:
5051 HALT_UNALLOC;
5052 }
5053 break;
5054
5055 case 3: /* USUBL2. */
5056 bias = 2;
5057 case 1: /* USUBL. */
5058 switch (size)
5059 {
5060 case 0:
5061 bias *= 3;
5062 for (i = 0; i < 8; i++)
5063 aarch64_set_vec_u16 (cpu, vd, i,
5064 aarch64_get_vec_u8 (cpu, vn, i + bias)
5065 - aarch64_get_vec_u8 (cpu, vm, i + bias));
5066 break;
5067
5068 case 1:
5069 bias *= 2;
5070 for (i = 0; i < 4; i++)
5071 aarch64_set_vec_u32 (cpu, vd, i,
5072 aarch64_get_vec_u16 (cpu, vn, i + bias)
5073 - aarch64_get_vec_u16 (cpu, vm, i + bias));
5074 break;
5075
5076 case 2:
5077 for (i = 0; i < 2; i++)
5078 aarch64_set_vec_u64 (cpu, vd, i,
5079 aarch64_get_vec_u32 (cpu, vn, i + bias)
5080 - aarch64_get_vec_u32 (cpu, vm, i + bias));
5081 break;
5082
5083 default:
5084 HALT_UNALLOC;
5085 }
5086 break;
5087 }
5088}
5089
2e8cf49e
NC
5090static void
5091do_vec_ADDP (sim_cpu *cpu)
5092{
5093 /* instr[31] = 0
5094 instr[30] = half(0)/full(1)
5095 instr[29,24] = 00 1110
5096 instr[23,22] = size: bytes (00), half (01), word (10), long (11)
5097 instr[21] = 1
5098 insrt[20,16] = Vm
5099 instr[15,10] = 1011 11
5100 instr[9,5] = Vn
5101 instr[4,0] = V dest. */
5102
57aa1742
NC
5103 FRegister copy_vn;
5104 FRegister copy_vm;
2e8cf49e
NC
5105 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5106 unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
5107 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5108 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5109 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5110 unsigned i, range;
5111
5112 NYI_assert (29, 24, 0x0E);
5113 NYI_assert (21, 21, 1);
5114 NYI_assert (15, 10, 0x2F);
5115
57aa1742
NC
5116 /* Make copies of the source registers in case vd == vn/vm. */
5117 copy_vn = cpu->fr[vn];
5118 copy_vm = cpu->fr[vm];
5119
2e8cf49e
NC
5120 switch (size)
5121 {
5122 case 0:
5123 range = full ? 8 : 4;
57aa1742
NC
5124 for (i = 0; i < range; i++)
5125 {
5126 aarch64_set_vec_u8 (cpu, vd, i,
5127 copy_vn.b[i * 2] + copy_vn.b[i * 2 + 1]);
5128 aarch64_set_vec_u8 (cpu, vd, i + range,
5129 copy_vm.b[i * 2] + copy_vm.b[i * 2 + 1]);
5130 }
2e8cf49e
NC
5131 return;
5132
5133 case 1:
5134 range = full ? 4 : 2;
57aa1742
NC
5135 for (i = 0; i < range; i++)
5136 {
5137 aarch64_set_vec_u16 (cpu, vd, i,
5138 copy_vn.h[i * 2] + copy_vn.h[i * 2 + 1]);
5139 aarch64_set_vec_u16 (cpu, vd, i + range,
5140 copy_vm.h[i * 2] + copy_vm.h[i * 2 + 1]);
5141 }
2e8cf49e
NC
5142 return;
5143
5144 case 2:
5145 range = full ? 2 : 1;
57aa1742
NC
5146 for (i = 0; i < range; i++)
5147 {
5148 aarch64_set_vec_u32 (cpu, vd, i,
5149 copy_vn.w[i * 2] + copy_vn.w[i * 2 + 1]);
5150 aarch64_set_vec_u32 (cpu, vd, i + range,
5151 copy_vm.w[i * 2] + copy_vm.w[i * 2 + 1]);
5152 }
2e8cf49e
NC
5153 return;
5154
5155 case 3:
5156 if (! full)
5157 HALT_UNALLOC;
57aa1742
NC
5158 aarch64_set_vec_u64 (cpu, vd, 0, copy_vn.v[0] + copy_vn.v[1]);
5159 aarch64_set_vec_u64 (cpu, vd, 1, copy_vm.v[0] + copy_vm.v[1]);
2e8cf49e
NC
5160 return;
5161
5162 default:
5163 HALT_NYI;
5164 }
5165}
5166
5167static void
5168do_vec_UMOV (sim_cpu *cpu)
5169{
5170 /* instr[31] = 0
5171 instr[30] = 32-bit(0)/64-bit(1)
5172 instr[29,21] = 00 1110 000
5173 insrt[20,16] = size & index
5174 instr[15,10] = 0011 11
5175 instr[9,5] = V source
5176 instr[4,0] = R dest. */
5177
5178 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5179 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
5180 unsigned index;
5181
5182 NYI_assert (29, 21, 0x070);
5183 NYI_assert (15, 10, 0x0F);
5184
5185 if (uimm (aarch64_get_instr (cpu), 16, 16))
5186 {
5187 /* Byte transfer. */
5188 index = uimm (aarch64_get_instr (cpu), 20, 17);
5189 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5190 aarch64_get_vec_u8 (cpu, vs, index));
5191 }
5192 else if (uimm (aarch64_get_instr (cpu), 17, 17))
5193 {
5194 index = uimm (aarch64_get_instr (cpu), 20, 18);
5195 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5196 aarch64_get_vec_u16 (cpu, vs, index));
5197 }
5198 else if (uimm (aarch64_get_instr (cpu), 18, 18))
5199 {
5200 index = uimm (aarch64_get_instr (cpu), 20, 19);
5201 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5202 aarch64_get_vec_u32 (cpu, vs, index));
5203 }
5204 else
5205 {
5206 if (uimm (aarch64_get_instr (cpu), 30, 30) != 1)
5207 HALT_UNALLOC;
5208
5209 index = uimm (aarch64_get_instr (cpu), 20, 20);
5210 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5211 aarch64_get_vec_u64 (cpu, vs, index));
5212 }
5213}
5214
5215static void
5216do_vec_FABS (sim_cpu *cpu)
5217{
5218 /* instr[31] = 0
5219 instr[30] = half(0)/full(1)
5220 instr[29,23] = 00 1110 1
5221 instr[22] = float(0)/double(1)
5222 instr[21,16] = 10 0000
5223 instr[15,10] = 1111 10
5224 instr[9,5] = Vn
5225 instr[4,0] = Vd. */
5226
5227 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5228 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5229 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5230 unsigned i;
5231
5232 NYI_assert (29, 23, 0x1D);
5233 NYI_assert (21, 10, 0x83E);
5234
5235 if (uimm (aarch64_get_instr (cpu), 22, 22))
5236 {
5237 if (! full)
5238 HALT_NYI;
5239
5240 for (i = 0; i < 2; i++)
5241 aarch64_set_vec_double (cpu, vd, i,
5242 fabs (aarch64_get_vec_double (cpu, vn, i)));
5243 }
5244 else
5245 {
5246 for (i = 0; i < (full ? 4 : 2); i++)
5247 aarch64_set_vec_float (cpu, vd, i,
5248 fabsf (aarch64_get_vec_float (cpu, vn, i)));
5249 }
5250}
5251
5252static void
5253do_vec_FCVTZS (sim_cpu *cpu)
5254{
5255 /* instr[31] = 0
5256 instr[30] = half (0) / all (1)
5257 instr[29,23] = 00 1110 1
5258 instr[22] = single (0) / double (1)
5259 instr[21,10] = 10 0001 1011 10
5260 instr[9,5] = Rn
5261 instr[4,0] = Rd. */
5262
5263 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
5264 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
5265 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5266 unsigned i;
5267
5268 NYI_assert (31, 31, 0);
5269 NYI_assert (29, 23, 0x1D);
5270 NYI_assert (21, 10, 0x86E);
5271
5272 if (uimm (aarch64_get_instr (cpu), 22, 22))
5273 {
5274 if (! full)
5275 HALT_UNALLOC;
5276
5277 for (i = 0; i < 2; i++)
5278 aarch64_set_vec_s64 (cpu, rd, i,
5279 (int64_t) aarch64_get_vec_double (cpu, rn, i));
5280 }
5281 else
5282 for (i = 0; i < (full ? 4 : 2); i++)
5283 aarch64_set_vec_s32 (cpu, rd, i,
5284 (int32_t) aarch64_get_vec_float (cpu, rn, i));
5285}
5286
5287static void
5288do_vec_op1 (sim_cpu *cpu)
5289{
5290 /* instr[31] = 0
5291 instr[30] = half/full
5292 instr[29,24] = 00 1110
5293 instr[23,21] = ???
5294 instr[20,16] = Vm
5295 instr[15,10] = sub-opcode
5296 instr[9,5] = Vn
5297 instr[4,0] = Vd */
5298 NYI_assert (29, 24, 0x0E);
5299
5300 if (uimm (aarch64_get_instr (cpu), 21, 21) == 0)
5301 {
5302 if (uimm (aarch64_get_instr (cpu), 23, 22) == 0)
5303 {
5304 if (uimm (aarch64_get_instr (cpu), 30, 30) == 1
5305 && uimm (aarch64_get_instr (cpu), 17, 14) == 0
5306 && uimm (aarch64_get_instr (cpu), 12, 10) == 7)
5307 return do_vec_ins_2 (cpu);
5308
5309 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5310 {
5311 case 0x01: do_vec_DUP_vector_into_vector (cpu); return;
5312 case 0x03: do_vec_DUP_scalar_into_vector (cpu); return;
5313 case 0x07: do_vec_INS (cpu); return;
5314 case 0x0A: do_vec_TRN (cpu); return;
5315
5316 case 0x0F:
5317 if (uimm (aarch64_get_instr (cpu), 17, 16) == 0)
5318 {
5319 do_vec_MOV_into_scalar (cpu);
5320 return;
5321 }
5322 break;
5323
5324 case 0x00:
5325 case 0x08:
5326 case 0x10:
5327 case 0x18:
5328 do_vec_TBL (cpu); return;
5329
5330 case 0x06:
5331 case 0x16:
5332 do_vec_UZP (cpu); return;
5333
5334 case 0x0E:
5335 case 0x1E:
5336 do_vec_ZIP (cpu); return;
5337
5338 default:
5339 HALT_NYI;
5340 }
5341 }
5342
5343 switch (uimm (aarch64_get_instr (cpu), 13, 10))
5344 {
5345 case 0x6: do_vec_UZP (cpu); return;
5346 case 0xE: do_vec_ZIP (cpu); return;
5347 case 0xA: do_vec_TRN (cpu); return;
5348 case 0xF: do_vec_UMOV (cpu); return;
5349 default: HALT_NYI;
5350 }
5351 }
5352
5353 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5354 {
5355 case 0x07:
5356 switch (uimm (aarch64_get_instr (cpu), 23, 21))
5357 {
5358 case 1: do_vec_AND (cpu); return;
5359 case 3: do_vec_BIC (cpu); return;
5360 case 5: do_vec_ORR (cpu); return;
5361 case 7: do_vec_ORN (cpu); return;
5362 default: HALT_NYI;
5363 }
5364
5365 case 0x08: do_vec_sub_long (cpu); return;
5366 case 0x0a: do_vec_XTN (cpu); return;
5367 case 0x11: do_vec_SSHL (cpu); return;
5368 case 0x19: do_vec_max (cpu); return;
5369 case 0x1B: do_vec_min (cpu); return;
5370 case 0x21: do_vec_add (cpu); return;
5371 case 0x25: do_vec_MLA (cpu); return;
5372 case 0x27: do_vec_mul (cpu); return;
5373 case 0x2F: do_vec_ADDP (cpu); return;
5374 case 0x30: do_vec_mull (cpu); return;
5375 case 0x33: do_vec_FMLA (cpu); return;
5376 case 0x35: do_vec_fadd (cpu); return;
5377
5378 case 0x2E:
5379 switch (uimm (aarch64_get_instr (cpu), 20, 16))
5380 {
5381 case 0x00: do_vec_ABS (cpu); return;
5382 case 0x01: do_vec_FCVTZS (cpu); return;
5383 case 0x11: do_vec_ADDV (cpu); return;
5384 default: HALT_NYI;
5385 }
5386
5387 case 0x31:
5388 case 0x3B:
5389 do_vec_Fminmax (cpu); return;
5390
5391 case 0x0D:
5392 case 0x0F:
5393 case 0x22:
5394 case 0x23:
5395 case 0x26:
5396 case 0x2A:
5397 case 0x32:
5398 case 0x36:
5399 case 0x39:
5400 case 0x3A:
5401 do_vec_compare (cpu); return;
5402
5403 case 0x3E:
5404 do_vec_FABS (cpu); return;
5405
5406 default:
5407 HALT_NYI;
5408 }
5409}
5410
5411static void
5412do_vec_xtl (sim_cpu *cpu)
5413{
5414 /* instr[31] = 0
5415 instr[30,29] = SXTL (00), UXTL (01), SXTL2 (10), UXTL2 (11)
5416 instr[28,22] = 0 1111 00
5417 instr[21,16] = size & shift (USHLL, SSHLL, USHLL2, SSHLL2)
5418 instr[15,10] = 1010 01
5419 instr[9,5] = V source
5420 instr[4,0] = V dest. */
5421
5422 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5423 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5424 unsigned i, shift, bias = 0;
5425
5426 NYI_assert (28, 22, 0x3C);
5427 NYI_assert (15, 10, 0x29);
5428
5429 switch (uimm (aarch64_get_instr (cpu), 30, 29))
5430 {
5431 case 2: /* SXTL2, SSHLL2. */
5432 bias = 2;
5433 case 0: /* SXTL, SSHLL. */
5434 if (uimm (aarch64_get_instr (cpu), 21, 21))
5435 {
5436 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5437 aarch64_set_vec_s64
5438 (cpu, vd, 0, aarch64_get_vec_s32 (cpu, vs, bias) << shift);
5439 aarch64_set_vec_s64
5440 (cpu, vd, 1, aarch64_get_vec_s32 (cpu, vs, bias + 1) << shift);
5441 }
5442 else if (uimm (aarch64_get_instr (cpu), 20, 20))
5443 {
5444 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5445 bias *= 2;
5446 for (i = 0; i < 4; i++)
5447 aarch64_set_vec_s32
5448 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vs, i + bias) << shift);
5449 }
5450 else
5451 {
5452 NYI_assert (19, 19, 1);
5453
5454 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5455 bias *= 3;
5456 for (i = 0; i < 8; i++)
5457 aarch64_set_vec_s16
5458 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vs, i + bias) << shift);
5459 }
5460 return;
5461
5462 case 3: /* UXTL2, USHLL2. */
5463 bias = 2;
5464 case 1: /* UXTL, USHLL. */
5465 if (uimm (aarch64_get_instr (cpu), 21, 21))
5466 {
5467 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5468 aarch64_set_vec_u64
5469 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, vs, bias) << shift);
5470 aarch64_set_vec_u64
5471 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, vs, bias + 1) << shift);
5472 }
5473 else if (uimm (aarch64_get_instr (cpu), 20, 20))
5474 {
5475 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5476 bias *= 2;
5477 for (i = 0; i < 4; i++)
5478 aarch64_set_vec_u32
5479 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i + bias) << shift);
5480 }
5481 else
5482 {
5483 NYI_assert (19, 19, 1);
5484
5485 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5486 bias *= 3;
5487 for (i = 0; i < 8; i++)
5488 aarch64_set_vec_u16
5489 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, i + bias) << shift);
5490 }
5491 return;
5492
5493 default:
5494 HALT_NYI;
5495 }
5496}
5497
5498static void
5499do_vec_SHL (sim_cpu *cpu)
5500{
5501 /* instr [31] = 0
5502 instr [30] = half(0)/full(1)
5503 instr [29,23] = 001 1110
5504 instr [22,16] = size and shift amount
5505 instr [15,10] = 01 0101
5506 instr [9, 5] = Vs
5507 instr [4, 0] = Vd. */
5508
5509 int shift;
5510 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5511 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5512 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5513 unsigned i;
5514
5515 NYI_assert (29, 23, 0x1E);
5516 NYI_assert (15, 10, 0x15);
5517
5518 if (uimm (aarch64_get_instr (cpu), 22, 22))
5519 {
5520 shift = uimm (aarch64_get_instr (cpu), 21, 16) - 1;
5521
5522 if (full == 0)
5523 HALT_UNALLOC;
5524
5525 for (i = 0; i < 2; i++)
5526 {
5527 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5528 aarch64_set_vec_u64 (cpu, vd, i, val << shift);
5529 }
5530
5531 return;
5532 }
5533
5534 if (uimm (aarch64_get_instr (cpu), 21, 21))
5535 {
5536 shift = uimm (aarch64_get_instr (cpu), 20, 16) - 1;
5537
5538 for (i = 0; i < (full ? 4 : 2); i++)
5539 {
5540 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5541 aarch64_set_vec_u32 (cpu, vd, i, val << shift);
5542 }
5543
5544 return;
5545 }
5546
5547 if (uimm (aarch64_get_instr (cpu), 20, 20))
5548 {
5549 shift = uimm (aarch64_get_instr (cpu), 19, 16) - 1;
5550
5551 for (i = 0; i < (full ? 8 : 4); i++)
5552 {
5553 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5554 aarch64_set_vec_u16 (cpu, vd, i, val << shift);
5555 }
5556
5557 return;
5558 }
5559
5560 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
5561 HALT_UNALLOC;
5562
5563 shift = uimm (aarch64_get_instr (cpu), 18, 16) - 1;
5564
5565 for (i = 0; i < (full ? 16 : 8); i++)
5566 {
5567 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5568 aarch64_set_vec_u8 (cpu, vd, i, val << shift);
5569 }
5570}
5571
5572static void
5573do_vec_SSHR_USHR (sim_cpu *cpu)
5574{
5575 /* instr [31] = 0
5576 instr [30] = half(0)/full(1)
5577 instr [29] = signed(0)/unsigned(1)
5578 instr [28,23] = 01 1110
5579 instr [22,16] = size and shift amount
5580 instr [15,10] = 0000 01
5581 instr [9, 5] = Vs
5582 instr [4, 0] = Vd. */
5583
5584 int shift;
5585 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5586 int sign = uimm (aarch64_get_instr (cpu), 29, 29);
5587 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5588 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5589 unsigned i;
5590
5591 NYI_assert (28, 23, 0x1E);
5592 NYI_assert (15, 10, 0x01);
5593
5594 if (uimm (aarch64_get_instr (cpu), 22, 22))
5595 {
5596 shift = uimm (aarch64_get_instr (cpu), 21, 16);
5597
5598 if (full == 0)
5599 HALT_UNALLOC;
5600
5601 if (sign)
5602 for (i = 0; i < 2; i++)
5603 {
5604 int64_t val = aarch64_get_vec_s64 (cpu, vs, i);
5605 aarch64_set_vec_s64 (cpu, vd, i, val >> shift);
5606 }
5607 else
5608 for (i = 0; i < 2; i++)
5609 {
5610 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5611 aarch64_set_vec_u64 (cpu, vd, i, val >> shift);
5612 }
5613
5614 return;
5615 }
5616
5617 if (uimm (aarch64_get_instr (cpu), 21, 21))
5618 {
5619 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5620
5621 if (sign)
5622 for (i = 0; i < (full ? 4 : 2); i++)
5623 {
5624 int32_t val = aarch64_get_vec_s32 (cpu, vs, i);
5625 aarch64_set_vec_s32 (cpu, vd, i, val >> shift);
5626 }
5627 else
5628 for (i = 0; i < (full ? 4 : 2); i++)
5629 {
5630 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5631 aarch64_set_vec_u32 (cpu, vd, i, val >> shift);
5632 }
5633
5634 return;
5635 }
5636
5637 if (uimm (aarch64_get_instr (cpu), 20, 20))
5638 {
5639 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5640
5641 if (sign)
5642 for (i = 0; i < (full ? 8 : 4); i++)
5643 {
5644 int16_t val = aarch64_get_vec_s16 (cpu, vs, i);
5645 aarch64_set_vec_s16 (cpu, vd, i, val >> shift);
5646 }
5647 else
5648 for (i = 0; i < (full ? 8 : 4); i++)
5649 {
5650 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5651 aarch64_set_vec_u16 (cpu, vd, i, val >> shift);
5652 }
5653
5654 return;
5655 }
5656
5657 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
5658 HALT_UNALLOC;
5659
5660 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5661
5662 if (sign)
5663 for (i = 0; i < (full ? 16 : 8); i++)
5664 {
5665 int8_t val = aarch64_get_vec_s8 (cpu, vs, i);
5666 aarch64_set_vec_s8 (cpu, vd, i, val >> shift);
5667 }
5668 else
5669 for (i = 0; i < (full ? 16 : 8); i++)
5670 {
5671 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5672 aarch64_set_vec_u8 (cpu, vd, i, val >> shift);
5673 }
5674}
5675
e101a78b
NC
5676static void
5677do_vec_MUL_by_element (sim_cpu *cpu)
5678{
5679 /* instr[31] = 0
5680 instr[30] = half/full
5681 instr[29,24] = 00 1111
5682 instr[23,22] = size
5683 instr[21] = L
5684 instr[20] = M
5685 instr[19,16] = m
5686 instr[15,12] = 1000
5687 instr[11] = H
5688 instr[10] = 0
5689 instr[9,5] = Vn
5690 instr[4,0] = Vd */
5691
5692 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5693 unsigned L = uimm (aarch64_get_instr (cpu), 21, 21);
5694 unsigned H = uimm (aarch64_get_instr (cpu), 11, 11);
5695 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5696 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5697 unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
5698 unsigned index;
5699 unsigned vm;
5700 unsigned e;
5701
5702 NYI_assert (29, 24, 0x0F);
5703 NYI_assert (15, 12, 0x8);
5704 NYI_assert (10, 10, 0);
5705
5706 switch (size)
5707 {
5708 case 1:
5709 {
5710 /* 16 bit products. */
5711 uint16_t product;
5712 uint16_t element1;
5713 uint16_t element2;
5714
5715 index = (H << 2) | (L << 1) | uimm (aarch64_get_instr (cpu), 20, 20);
5716 vm = uimm (aarch64_get_instr (cpu), 19, 16);
5717 element2 = aarch64_get_vec_u16 (cpu, vm, index);
5718
5719 for (e = 0; e < (full ? 8 : 4); e ++)
5720 {
5721 element1 = aarch64_get_vec_u16 (cpu, vn, e);
5722 product = element1 * element2;
5723 aarch64_set_vec_u16 (cpu, vd, e, product);
5724 }
5725 }
5726 break;
5727
5728 case 2:
5729 {
5730 /* 32 bit products. */
5731 uint32_t product;
5732 uint32_t element1;
5733 uint32_t element2;
5734
5735 index = (H << 1) | L;
5736 vm = uimm (aarch64_get_instr (cpu), 20, 16);
5737 element2 = aarch64_get_vec_u32 (cpu, vm, index);
5738
5739 for (e = 0; e < (full ? 4 : 2); e ++)
5740 {
5741 element1 = aarch64_get_vec_u32 (cpu, vn, e);
5742 product = element1 * element2;
5743 aarch64_set_vec_u32 (cpu, vd, e, product);
5744 }
5745 }
5746 break;
5747
5748 default:
5749 HALT_UNALLOC;
5750 }
5751}
5752
2e8cf49e
NC
5753static void
5754do_vec_op2 (sim_cpu *cpu)
5755{
5756 /* instr[31] = 0
5757 instr[30] = half/full
5758 instr[29,24] = 00 1111
5759 instr[23] = ?
5760 instr[22,16] = element size & index
5761 instr[15,10] = sub-opcode
5762 instr[9,5] = Vm
e101a78b 5763 instr[4,0] = Vd */
2e8cf49e
NC
5764
5765 NYI_assert (29, 24, 0x0F);
5766
5767 if (uimm (aarch64_get_instr (cpu), 23, 23) != 0)
2e8cf49e 5768 {
e101a78b
NC
5769 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5770 {
5771 case 0x20:
5772 case 0x22: do_vec_MUL_by_element (cpu); return;
5773 default: HALT_NYI;
5774 }
5775 }
5776 else
5777 {
5778 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5779 {
5780 case 0x01: do_vec_SSHR_USHR (cpu); return;
5781 case 0x15: do_vec_SHL (cpu); return;
5782 case 0x20:
5783 case 0x22: do_vec_MUL_by_element (cpu); return;
5784 case 0x29: do_vec_xtl (cpu); return;
5785 default: HALT_NYI;
5786 }
2e8cf49e
NC
5787 }
5788}
5789
5790static void
5791do_vec_neg (sim_cpu *cpu)
5792{
5793 /* instr[31] = 0
5794 instr[30] = full(1)/half(0)
5795 instr[29,24] = 10 1110
5796 instr[23,22] = size: byte(00), half (01), word (10), long (11)
5797 instr[21,10] = 1000 0010 1110
5798 instr[9,5] = Vs
5799 instr[4,0] = Vd */
5800
5801 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5802 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5803 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5804 unsigned i;
5805
5806 NYI_assert (29, 24, 0x2E);
5807 NYI_assert (21, 10, 0x82E);
5808
5809 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5810 {
5811 case 0:
5812 for (i = 0; i < (full ? 16 : 8); i++)
5813 aarch64_set_vec_s8 (cpu, vd, i, - aarch64_get_vec_s8 (cpu, vs, i));
5814 return;
5815
5816 case 1:
5817 for (i = 0; i < (full ? 8 : 4); i++)
5818 aarch64_set_vec_s16 (cpu, vd, i, - aarch64_get_vec_s16 (cpu, vs, i));
5819 return;
5820
5821 case 2:
5822 for (i = 0; i < (full ? 4 : 2); i++)
5823 aarch64_set_vec_s32 (cpu, vd, i, - aarch64_get_vec_s32 (cpu, vs, i));
5824 return;
5825
5826 case 3:
5827 if (! full)
5828 HALT_NYI;
5829 for (i = 0; i < 2; i++)
5830 aarch64_set_vec_s64 (cpu, vd, i, - aarch64_get_vec_s64 (cpu, vs, i));
5831 return;
5832
5833 default:
5834 HALT_UNREACHABLE;
5835 }
5836}
5837
5838static void
5839do_vec_sqrt (sim_cpu *cpu)
5840{
5841 /* instr[31] = 0
5842 instr[30] = full(1)/half(0)
5843 instr[29,23] = 101 1101
5844 instr[22] = single(0)/double(1)
5845 instr[21,10] = 1000 0111 1110
5846 instr[9,5] = Vs
5847 instr[4,0] = Vd. */
5848
5849 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5850 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5851 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5852 unsigned i;
5853
5854 NYI_assert (29, 23, 0x5B);
5855 NYI_assert (21, 10, 0x87E);
5856
5857 if (uimm (aarch64_get_instr (cpu), 22, 22) == 0)
5858 for (i = 0; i < (full ? 4 : 2); i++)
5859 aarch64_set_vec_float (cpu, vd, i,
5860 sqrtf (aarch64_get_vec_float (cpu, vs, i)));
5861 else
5862 for (i = 0; i < 2; i++)
5863 aarch64_set_vec_double (cpu, vd, i,
5864 sqrt (aarch64_get_vec_double (cpu, vs, i)));
5865}
5866
5867static void
5868do_vec_mls_indexed (sim_cpu *cpu)
5869{
5870 /* instr[31] = 0
5871 instr[30] = half(0)/full(1)
5872 instr[29,24] = 10 1111
5873 instr[23,22] = 16-bit(01)/32-bit(10)
5874 instr[21,20+11] = index (if 16-bit)
5875 instr[21+11] = index (if 32-bit)
5876 instr[20,16] = Vm
5877 instr[15,12] = 0100
5878 instr[11] = part of index
5879 instr[10] = 0
5880 instr[9,5] = Vs
5881 instr[4,0] = Vd. */
5882
5883 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5884 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5885 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5886 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5887 unsigned i;
5888
5889 NYI_assert (15, 12, 4);
5890 NYI_assert (10, 10, 0);
5891
5892 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5893 {
5894 case 1:
5895 {
5896 unsigned elem;
5897 uint32_t val;
5898
5899 if (vm > 15)
5900 HALT_NYI;
5901
5902 elem = (uimm (aarch64_get_instr (cpu), 21, 20) << 1)
5903 | uimm (aarch64_get_instr (cpu), 11, 11);
5904 val = aarch64_get_vec_u16 (cpu, vm, elem);
5905
5906 for (i = 0; i < (full ? 8 : 4); i++)
5907 aarch64_set_vec_u32 (cpu, vd, i,
5908 aarch64_get_vec_u32 (cpu, vd, i) -
5909 (aarch64_get_vec_u32 (cpu, vs, i) * val));
5910 return;
5911 }
5912
5913 case 2:
5914 {
5915 unsigned elem = (uimm (aarch64_get_instr (cpu), 21, 21) << 1)
5916 | uimm (aarch64_get_instr (cpu), 11, 11);
5917 uint64_t val = aarch64_get_vec_u32 (cpu, vm, elem);
5918
5919 for (i = 0; i < (full ? 4 : 2); i++)
5920 aarch64_set_vec_u64 (cpu, vd, i,
5921 aarch64_get_vec_u64 (cpu, vd, i) -
5922 (aarch64_get_vec_u64 (cpu, vs, i) * val));
5923 return;
5924 }
5925
5926 case 0:
5927 case 3:
5928 default:
5929 HALT_NYI;
5930 }
5931}
5932
5933static void
5934do_vec_SUB (sim_cpu *cpu)
5935{
5936 /* instr [31] = 0
5937 instr [30] = half(0)/full(1)
5938 instr [29,24] = 10 1110
5939 instr [23,22] = size: byte(00, half(01), word (10), long (11)
5940 instr [21] = 1
5941 instr [20,16] = Vm
5942 instr [15,10] = 10 0001
5943 instr [9, 5] = Vn
5944 instr [4, 0] = Vd. */
5945
5946 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5947 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5948 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5949 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5950 unsigned i;
5951
5952 NYI_assert (29, 24, 0x2E);
5953 NYI_assert (21, 21, 1);
5954 NYI_assert (15, 10, 0x21);
5955
5956 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5957 {
5958 case 0:
5959 for (i = 0; i < (full ? 16 : 8); i++)
5960 aarch64_set_vec_s8 (cpu, vd, i,
5961 aarch64_get_vec_s8 (cpu, vn, i)
5962 - aarch64_get_vec_s8 (cpu, vm, i));
5963 return;
5964
5965 case 1:
5966 for (i = 0; i < (full ? 8 : 4); i++)
5967 aarch64_set_vec_s16 (cpu, vd, i,
5968 aarch64_get_vec_s16 (cpu, vn, i)
5969 - aarch64_get_vec_s16 (cpu, vm, i));
5970 return;
5971
5972 case 2:
5973 for (i = 0; i < (full ? 4 : 2); i++)
5974 aarch64_set_vec_s32 (cpu, vd, i,
5975 aarch64_get_vec_s32 (cpu, vn, i)
5976 - aarch64_get_vec_s32 (cpu, vm, i));
5977 return;
5978
5979 case 3:
5980 if (full == 0)
5981 HALT_UNALLOC;
5982
5983 for (i = 0; i < 2; i++)
5984 aarch64_set_vec_s64 (cpu, vd, i,
5985 aarch64_get_vec_s64 (cpu, vn, i)
5986 - aarch64_get_vec_s64 (cpu, vm, i));
5987 return;
5988
5989 default:
5990 HALT_UNREACHABLE;
5991 }
5992}
5993
5994static void
5995do_vec_MLS (sim_cpu *cpu)
5996{
5997 /* instr [31] = 0
5998 instr [30] = half(0)/full(1)
5999 instr [29,24] = 10 1110
6000 instr [23,22] = size: byte(00, half(01), word (10)
6001 instr [21] = 1
6002 instr [20,16] = Vm
6003 instr [15,10] = 10 0101
6004 instr [9, 5] = Vn
6005 instr [4, 0] = Vd. */
6006
6007 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6008 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6009 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6010 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6011 unsigned i;
6012
6013 NYI_assert (29, 24, 0x2E);
6014 NYI_assert (21, 21, 1);
6015 NYI_assert (15, 10, 0x25);
6016
6017 switch (uimm (aarch64_get_instr (cpu), 23, 22))
6018 {
6019 case 0:
6020 for (i = 0; i < (full ? 16 : 8); i++)
6021 aarch64_set_vec_u8 (cpu, vd, i,
6022 (aarch64_get_vec_u8 (cpu, vn, i)
6023 * aarch64_get_vec_u8 (cpu, vm, i))
6024 - aarch64_get_vec_u8 (cpu, vd, i));
6025 return;
6026
6027 case 1:
6028 for (i = 0; i < (full ? 8 : 4); i++)
6029 aarch64_set_vec_u16 (cpu, vd, i,
6030 (aarch64_get_vec_u16 (cpu, vn, i)
6031 * aarch64_get_vec_u16 (cpu, vm, i))
6032 - aarch64_get_vec_u16 (cpu, vd, i));
6033 return;
6034
6035 case 2:
6036 for (i = 0; i < (full ? 4 : 2); i++)
6037 aarch64_set_vec_u32 (cpu, vd, i,
6038 (aarch64_get_vec_u32 (cpu, vn, i)
6039 * aarch64_get_vec_u32 (cpu, vm, i))
6040 - aarch64_get_vec_u32 (cpu, vd, i));
6041 return;
6042
6043 default:
6044 HALT_UNALLOC;
6045 }
6046}
6047
6048static void
6049do_vec_FDIV (sim_cpu *cpu)
6050{
6051 /* instr [31] = 0
6052 instr [30] = half(0)/full(1)
6053 instr [29,23] = 10 1110 0
6054 instr [22] = float()/double(1)
6055 instr [21] = 1
6056 instr [20,16] = Vm
6057 instr [15,10] = 1111 11
6058 instr [9, 5] = Vn
6059 instr [4, 0] = Vd. */
6060
6061 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6062 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6063 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6064 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6065 unsigned i;
6066
6067 NYI_assert (29, 23, 0x5C);
6068 NYI_assert (21, 21, 1);
6069 NYI_assert (15, 10, 0x3F);
6070
6071 if (uimm (aarch64_get_instr (cpu), 22, 22))
6072 {
6073 if (! full)
6074 HALT_UNALLOC;
6075
6076 for (i = 0; i < 2; i++)
6077 aarch64_set_vec_double (cpu, vd, i,
6078 aarch64_get_vec_double (cpu, vn, i)
6079 / aarch64_get_vec_double (cpu, vm, i));
6080 }
6081 else
6082 for (i = 0; i < (full ? 4 : 2); i++)
6083 aarch64_set_vec_float (cpu, vd, i,
6084 aarch64_get_vec_float (cpu, vn, i)
6085 / aarch64_get_vec_float (cpu, vm, i));
6086}
6087
6088static void
6089do_vec_FMUL (sim_cpu *cpu)
6090{
6091 /* instr [31] = 0
6092 instr [30] = half(0)/full(1)
6093 instr [29,23] = 10 1110 0
6094 instr [22] = float(0)/double(1)
6095 instr [21] = 1
6096 instr [20,16] = Vm
6097 instr [15,10] = 1101 11
6098 instr [9, 5] = Vn
6099 instr [4, 0] = Vd. */
6100
6101 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6102 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6103 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6104 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6105 unsigned i;
6106
6107 NYI_assert (29, 23, 0x5C);
6108 NYI_assert (21, 21, 1);
6109 NYI_assert (15, 10, 0x37);
6110
6111 if (uimm (aarch64_get_instr (cpu), 22, 22))
6112 {
6113 if (! full)
6114 HALT_UNALLOC;
6115
6116 for (i = 0; i < 2; i++)
6117 aarch64_set_vec_double (cpu, vd, i,
6118 aarch64_get_vec_double (cpu, vn, i)
6119 * aarch64_get_vec_double (cpu, vm, i));
6120 }
6121 else
6122 for (i = 0; i < (full ? 4 : 2); i++)
6123 aarch64_set_vec_float (cpu, vd, i,
6124 aarch64_get_vec_float (cpu, vn, i)
6125 * aarch64_get_vec_float (cpu, vm, i));
6126}
6127
6128static void
6129do_vec_FADDP (sim_cpu *cpu)
6130{
6131 /* instr [31] = 0
6132 instr [30] = half(0)/full(1)
6133 instr [29,23] = 10 1110 0
6134 instr [22] = float(0)/double(1)
6135 instr [21] = 1
6136 instr [20,16] = Vm
6137 instr [15,10] = 1101 01
6138 instr [9, 5] = Vn
6139 instr [4, 0] = Vd. */
6140
6141 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6142 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6143 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6144 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6145
6146 NYI_assert (29, 23, 0x5C);
6147 NYI_assert (21, 21, 1);
6148 NYI_assert (15, 10, 0x35);
6149
6150 if (uimm (aarch64_get_instr (cpu), 22, 22))
6151 {
57aa1742
NC
6152 /* Extract values before adding them incase vd == vn/vm. */
6153 double tmp1 = aarch64_get_vec_double (cpu, vn, 0);
6154 double tmp2 = aarch64_get_vec_double (cpu, vn, 1);
6155 double tmp3 = aarch64_get_vec_double (cpu, vm, 0);
6156 double tmp4 = aarch64_get_vec_double (cpu, vm, 1);
6157
2e8cf49e
NC
6158 if (! full)
6159 HALT_UNALLOC;
6160
57aa1742
NC
6161 aarch64_set_vec_double (cpu, vd, 0, tmp1 + tmp2);
6162 aarch64_set_vec_double (cpu, vd, 1, tmp3 + tmp4);
2e8cf49e
NC
6163 }
6164 else
6165 {
57aa1742
NC
6166 /* Extract values before adding them incase vd == vn/vm. */
6167 float tmp1 = aarch64_get_vec_float (cpu, vn, 0);
6168 float tmp2 = aarch64_get_vec_float (cpu, vn, 1);
6169 float tmp5 = aarch64_get_vec_float (cpu, vm, 0);
6170 float tmp6 = aarch64_get_vec_float (cpu, vm, 1);
6171
2e8cf49e 6172 if (full)
57aa1742
NC
6173 {
6174 float tmp3 = aarch64_get_vec_float (cpu, vn, 2);
6175 float tmp4 = aarch64_get_vec_float (cpu, vn, 3);
6176 float tmp7 = aarch64_get_vec_float (cpu, vm, 2);
6177 float tmp8 = aarch64_get_vec_float (cpu, vm, 3);
6178
6179 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6180 aarch64_set_vec_float (cpu, vd, 1, tmp3 + tmp4);
6181 aarch64_set_vec_float (cpu, vd, 2, tmp5 + tmp6);
6182 aarch64_set_vec_float (cpu, vd, 3, tmp7 + tmp8);
6183 }
6184 else
6185 {
6186 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6187 aarch64_set_vec_float (cpu, vd, 1, tmp5 + tmp6);
6188 }
2e8cf49e
NC
6189 }
6190}
6191
6192static void
6193do_vec_FSQRT (sim_cpu *cpu)
6194{
6195 /* instr[31] = 0
6196 instr[30] = half(0)/full(1)
6197 instr[29,23] = 10 1110 1
6198 instr[22] = single(0)/double(1)
6199 instr[21,10] = 10 0001 1111 10
6200 instr[9,5] = Vsrc
6201 instr[4,0] = Vdest. */
6202
6203 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6204 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6205 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6206 int i;
6207
6208 NYI_assert (29, 23, 0x5D);
6209 NYI_assert (21, 10, 0x87E);
6210
6211 if (uimm (aarch64_get_instr (cpu), 22, 22))
6212 {
6213 if (! full)
6214 HALT_UNALLOC;
6215
6216 for (i = 0; i < 2; i++)
6217 aarch64_set_vec_double (cpu, vd, i,
6218 sqrt (aarch64_get_vec_double (cpu, vn, i)));
6219 }
6220 else
6221 {
6222 for (i = 0; i < (full ? 4 : 2); i++)
6223 aarch64_set_vec_float (cpu, vd, i,
6224 sqrtf (aarch64_get_vec_float (cpu, vn, i)));
6225 }
6226}
6227
6228static void
6229do_vec_FNEG (sim_cpu *cpu)
6230{
6231 /* instr[31] = 0
6232 instr[30] = half (0)/full (1)
6233 instr[29,23] = 10 1110 1
6234 instr[22] = single (0)/double (1)
6235 instr[21,10] = 10 0000 1111 10
6236 instr[9,5] = Vsrc
6237 instr[4,0] = Vdest. */
6238
6239 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6240 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6241 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6242 int i;
6243
6244 NYI_assert (29, 23, 0x5D);
6245 NYI_assert (21, 10, 0x83E);
6246
6247 if (uimm (aarch64_get_instr (cpu), 22, 22))
6248 {
6249 if (! full)
6250 HALT_UNALLOC;
6251
6252 for (i = 0; i < 2; i++)
6253 aarch64_set_vec_double (cpu, vd, i,
6254 - aarch64_get_vec_double (cpu, vn, i));
6255 }
6256 else
6257 {
6258 for (i = 0; i < (full ? 4 : 2); i++)
6259 aarch64_set_vec_float (cpu, vd, i,
6260 - aarch64_get_vec_float (cpu, vn, i));
6261 }
6262}
6263
6264static void
6265do_vec_NOT (sim_cpu *cpu)
6266{
6267 /* instr[31] = 0
6268 instr[30] = half (0)/full (1)
6269 instr[29,21] = 10 1110 001
6270 instr[20,16] = 0 0000
6271 instr[15,10] = 0101 10
6272 instr[9,5] = Vn
6273 instr[4.0] = Vd. */
6274
6275 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6276 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6277 unsigned i;
6278 int full = uimm (aarch64_get_instr (cpu), 30, 30);
6279
6280 NYI_assert (29, 10, 0xB8816);
6281
6282 for (i = 0; i < (full ? 16 : 8); i++)
6283 aarch64_set_vec_u8 (cpu, vd, i, ~ aarch64_get_vec_u8 (cpu, vn, i));
6284}
6285
6286static void
6287do_vec_MOV_element (sim_cpu *cpu)
6288{
6289 /* instr[31,21] = 0110 1110 000
6290 instr[20,16] = size & dest index
6291 instr[15] = 0
6292 instr[14,11] = source index
6293 instr[10] = 1
6294 instr[9,5] = Vs
6295 instr[4.0] = Vd. */
6296
6297 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
6298 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6299 unsigned src_index;
6300 unsigned dst_index;
6301
6302 NYI_assert (31, 21, 0x370);
6303 NYI_assert (15, 15, 0);
6304 NYI_assert (10, 10, 1);
6305
6306 if (uimm (aarch64_get_instr (cpu), 16, 16))
6307 {
6308 /* Move a byte. */
6309 src_index = uimm (aarch64_get_instr (cpu), 14, 11);
6310 dst_index = uimm (aarch64_get_instr (cpu), 20, 17);
6311 aarch64_set_vec_u8 (cpu, vd, dst_index,
6312 aarch64_get_vec_u8 (cpu, vs, src_index));
6313 }
6314 else if (uimm (aarch64_get_instr (cpu), 17, 17))
6315 {
6316 /* Move 16-bits. */
6317 NYI_assert (11, 11, 0);
6318 src_index = uimm (aarch64_get_instr (cpu), 14, 12);
6319 dst_index = uimm (aarch64_get_instr (cpu), 20, 18);
6320 aarch64_set_vec_u16 (cpu, vd, dst_index,
6321 aarch64_get_vec_u16 (cpu, vs, src_index));
6322 }
6323 else if (uimm (aarch64_get_instr (cpu), 18, 18))
6324 {
6325 /* Move 32-bits. */
6326 NYI_assert (12, 11, 0);
6327 src_index = uimm (aarch64_get_instr (cpu), 14, 13);
6328 dst_index = uimm (aarch64_get_instr (cpu), 20, 19);
6329 aarch64_set_vec_u32 (cpu, vd, dst_index,
6330 aarch64_get_vec_u32 (cpu, vs, src_index));
6331 }
6332 else
6333 {
6334 NYI_assert (19, 19, 1);
6335 NYI_assert (13, 11, 0);
6336 src_index = uimm (aarch64_get_instr (cpu), 14, 14);
6337 dst_index = uimm (aarch64_get_instr (cpu), 20, 20);
6338 aarch64_set_vec_u64 (cpu, vd, dst_index,
6339 aarch64_get_vec_u64 (cpu, vs, src_index));
6340 }
6341}
6342
6343static void
6344dexAdvSIMD0 (sim_cpu *cpu)
6345{
6346 /* instr [28,25] = 0 111. */
6347 if ( uimm (aarch64_get_instr (cpu), 15, 10) == 0x07
6348 && (uimm (aarch64_get_instr (cpu), 9, 5) ==
6349 uimm (aarch64_get_instr (cpu), 20, 16)))
6350 {
6351 if (uimm (aarch64_get_instr (cpu), 31, 21) == 0x075
6352 || uimm (aarch64_get_instr (cpu), 31, 21) == 0x275)
6353 {
6354 do_vec_MOV_whole_vector (cpu);
6355 return;
6356 }
6357 }
6358
6359 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x1E0)
6360 {
6361 do_vec_MOV_immediate (cpu);
6362 return;
6363 }
6364
6365 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x5E0)
6366 {
6367 do_vec_MVNI (cpu);
6368 return;
6369 }
6370
6371 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x1C0
6372 || uimm (aarch64_get_instr (cpu), 29, 19) == 0x1C1)
6373 {
6374 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x03)
6375 {
6376 do_vec_DUP_scalar_into_vector (cpu);
6377 return;
6378 }
6379 }
6380
6381 switch (uimm (aarch64_get_instr (cpu), 29, 24))
6382 {
6383 case 0x0E: do_vec_op1 (cpu); return;
6384 case 0x0F: do_vec_op2 (cpu); return;
6385
6386 case 0x2f:
6387 switch (uimm (aarch64_get_instr (cpu), 15, 10))
6388 {
6389 case 0x01: do_vec_SSHR_USHR (cpu); return;
6390 case 0x10:
6391 case 0x12: do_vec_mls_indexed (cpu); return;
6392 case 0x29: do_vec_xtl (cpu); return;
6393 default:
6394 HALT_NYI;
6395 }
6396
6397 case 0x2E:
6398 if (uimm (aarch64_get_instr (cpu), 21, 21) == 1)
6399 {
6400 switch (uimm (aarch64_get_instr (cpu), 15, 10))
6401 {
6402 case 0x07:
6403 switch (uimm (aarch64_get_instr (cpu), 23, 22))
6404 {
6405 case 0: do_vec_EOR (cpu); return;
6406 case 1: do_vec_BSL (cpu); return;
6407 case 2:
6408 case 3: do_vec_bit (cpu); return;
6409 }
6410 break;
6411
6412 case 0x08: do_vec_sub_long (cpu); return;
6413 case 0x11: do_vec_USHL (cpu); return;
6414 case 0x16: do_vec_NOT (cpu); return;
6415 case 0x19: do_vec_max (cpu); return;
6416 case 0x1B: do_vec_min (cpu); return;
6417 case 0x21: do_vec_SUB (cpu); return;
6418 case 0x25: do_vec_MLS (cpu); return;
6419 case 0x31: do_vec_FminmaxNMP (cpu); return;
6420 case 0x35: do_vec_FADDP (cpu); return;
6421 case 0x37: do_vec_FMUL (cpu); return;
6422 case 0x3F: do_vec_FDIV (cpu); return;
6423
6424 case 0x3E:
6425 switch (uimm (aarch64_get_instr (cpu), 20, 16))
6426 {
6427 case 0x00: do_vec_FNEG (cpu); return;
6428 case 0x01: do_vec_FSQRT (cpu); return;
6429 default: HALT_NYI;
6430 }
6431
6432 case 0x0D:
6433 case 0x0F:
6434 case 0x22:
6435 case 0x23:
6436 case 0x26:
6437 case 0x2A:
6438 case 0x32:
6439 case 0x36:
6440 case 0x39:
6441 case 0x3A:
6442 do_vec_compare (cpu); return;
6443
6444 default: break;
6445 }
6446 }
6447
6448 if (uimm (aarch64_get_instr (cpu), 31, 21) == 0x370)
6449 {
6450 do_vec_MOV_element (cpu);
6451 return;
6452 }
6453
6454 switch (uimm (aarch64_get_instr (cpu), 21, 10))
6455 {
6456 case 0x82E: do_vec_neg (cpu); return;
6457 case 0x87E: do_vec_sqrt (cpu); return;
6458 default:
6459 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x30)
6460 {
6461 do_vec_mull (cpu);
6462 return;
6463 }
6464 break;
6465 }
6466 break;
6467
6468 default:
6469 break;
6470 }
6471
6472 HALT_NYI;
6473}
6474
6475/* 3 sources. */
6476
6477/* Float multiply add. */
6478static void
6479fmadds (sim_cpu *cpu)
6480{
6481 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6482 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6483 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6484 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6485
6486 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6487 + aarch64_get_FP_float (cpu, sn)
6488 * aarch64_get_FP_float (cpu, sm));
6489}
6490
6491/* Double multiply add. */
6492static void
6493fmaddd (sim_cpu *cpu)
6494{
6495 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6496 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6497 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6498 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6499
6500 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6501 + aarch64_get_FP_double (cpu, sn)
6502 * aarch64_get_FP_double (cpu, sm));
6503}
6504
6505/* Float multiply subtract. */
6506static void
6507fmsubs (sim_cpu *cpu)
6508{
6509 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6510 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6511 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6512 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6513
6514 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6515 - aarch64_get_FP_float (cpu, sn)
6516 * aarch64_get_FP_float (cpu, sm));
6517}
6518
6519/* Double multiply subtract. */
6520static void
6521fmsubd (sim_cpu *cpu)
6522{
6523 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6524 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6525 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6526 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6527
6528 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6529 - aarch64_get_FP_double (cpu, sn)
6530 * aarch64_get_FP_double (cpu, sm));
6531}
6532
6533/* Float negative multiply add. */
6534static void
6535fnmadds (sim_cpu *cpu)
6536{
6537 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6538 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6539 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6540 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6541
6542 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6543 + (- aarch64_get_FP_float (cpu, sn))
6544 * aarch64_get_FP_float (cpu, sm));
6545}
6546
6547/* Double negative multiply add. */
6548static void
6549fnmaddd (sim_cpu *cpu)
6550{
6551 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6552 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6553 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6554 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6555
6556 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6557 + (- aarch64_get_FP_double (cpu, sn))
6558 * aarch64_get_FP_double (cpu, sm));
6559}
6560
6561/* Float negative multiply subtract. */
6562static void
6563fnmsubs (sim_cpu *cpu)
6564{
6565 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6566 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6567 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6568 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6569
6570 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6571 + aarch64_get_FP_float (cpu, sn)
6572 * aarch64_get_FP_float (cpu, sm));
6573}
6574
6575/* Double negative multiply subtract. */
6576static void
6577fnmsubd (sim_cpu *cpu)
6578{
6579 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6580 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6581 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6582 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6583
6584 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6585 + aarch64_get_FP_double (cpu, sn)
6586 * aarch64_get_FP_double (cpu, sm));
6587}
6588
6589static void
6590dexSimpleFPDataProc3Source (sim_cpu *cpu)
6591{
6592 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
6593 instr[30] = 0
6594 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
6595 instr[28,25] = 1111
6596 instr[24] = 1
6597 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
6598 instr[21] ==> o1 : 0 ==> unnegated, 1 ==> negated
6599 instr[15] ==> o2 : 0 ==> ADD, 1 ==> SUB */
6600
6601 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
6602 | uimm (aarch64_get_instr (cpu), 29, 29);
6603 /* dispatch on combined type:o1:o2. */
6604 uint32_t dispatch = (uimm (aarch64_get_instr (cpu), 23, 21) << 1)
6605 | uimm (aarch64_get_instr (cpu), 15, 15);
6606
6607 if (M_S != 0)
6608 HALT_UNALLOC;
6609
6610 switch (dispatch)
6611 {
6612 case 0: fmadds (cpu); return;
6613 case 1: fmsubs (cpu); return;
6614 case 2: fnmadds (cpu); return;
6615 case 3: fnmsubs (cpu); return;
6616 case 4: fmaddd (cpu); return;
6617 case 5: fmsubd (cpu); return;
6618 case 6: fnmaddd (cpu); return;
6619 case 7: fnmsubd (cpu); return;
6620 default:
6621 /* type > 1 is currently unallocated. */
6622 HALT_UNALLOC;
6623 }
6624}
6625
6626static void
6627dexSimpleFPFixedConvert (sim_cpu *cpu)
6628{
6629 HALT_NYI;
6630}
6631
6632static void
6633dexSimpleFPCondCompare (sim_cpu *cpu)
6634{
6635 HALT_NYI;
6636}
6637
6638/* 2 sources. */
6639
6640/* Float add. */
6641static void
6642fadds (sim_cpu *cpu)
6643{
6644 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6645 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6646 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6647
6648 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6649 + aarch64_get_FP_float (cpu, sm));
6650}
6651
6652/* Double add. */
6653static void
6654faddd (sim_cpu *cpu)
6655{
6656 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6657 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6658 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6659
6660 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6661 + aarch64_get_FP_double (cpu, sm));
6662}
6663
6664/* Float divide. */
6665static void
6666fdivs (sim_cpu *cpu)
6667{
6668 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6669 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6670 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6671
6672 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6673 / aarch64_get_FP_float (cpu, sm));
6674}
6675
6676/* Double divide. */
6677static void
6678fdivd (sim_cpu *cpu)
6679{
6680 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6681 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6682 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6683
6684 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6685 / aarch64_get_FP_double (cpu, sm));
6686}
6687
6688/* Float multiply. */
6689static void
6690fmuls (sim_cpu *cpu)
6691{
6692 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6693 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6694 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6695
6696 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6697 * aarch64_get_FP_float (cpu, sm));
6698}
6699
6700/* Double multiply. */
6701static void
6702fmuld (sim_cpu *cpu)
6703{
6704 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6705 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6706 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6707
6708 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6709 * aarch64_get_FP_double (cpu, sm));
6710}
6711
6712/* Float negate and multiply. */
6713static void
6714fnmuls (sim_cpu *cpu)
6715{
6716 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6717 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6718 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6719
6720 aarch64_set_FP_float (cpu, sd, - (aarch64_get_FP_float (cpu, sn)
6721 * aarch64_get_FP_float (cpu, sm)));
6722}
6723
6724/* Double negate and multiply. */
6725static void
6726fnmuld (sim_cpu *cpu)
6727{
6728 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6729 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6730 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6731
6732 aarch64_set_FP_double (cpu, sd, - (aarch64_get_FP_double (cpu, sn)
6733 * aarch64_get_FP_double (cpu, sm)));
6734}
6735
6736/* Float subtract. */
6737static void
6738fsubs (sim_cpu *cpu)
6739{
6740 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6741 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6742 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6743
6744 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6745 - aarch64_get_FP_float (cpu, sm));
6746}
6747
6748/* Double subtract. */
6749static void
6750fsubd (sim_cpu *cpu)
6751{
6752 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6753 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6754 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6755
6756 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6757 - aarch64_get_FP_double (cpu, sm));
6758}
6759
6760static void
6761do_FMINNM (sim_cpu *cpu)
6762{
6763 /* instr[31,23] = 0 0011 1100
6764 instr[22] = float(0)/double(1)
6765 instr[21] = 1
6766 instr[20,16] = Sm
6767 instr[15,10] = 01 1110
6768 instr[9,5] = Sn
6769 instr[4,0] = Cpu */
6770
6771 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6772 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6773 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6774
6775 NYI_assert (31, 23, 0x03C);
6776 NYI_assert (15, 10, 0x1E);
6777
6778 if (uimm (aarch64_get_instr (cpu), 22, 22))
6779 aarch64_set_FP_double (cpu, sd,
6780 dminnm (aarch64_get_FP_double (cpu, sn),
6781 aarch64_get_FP_double (cpu, sm)));
6782 else
6783 aarch64_set_FP_float (cpu, sd,
6784 fminnm (aarch64_get_FP_float (cpu, sn),
6785 aarch64_get_FP_float (cpu, sm)));
6786}
6787
6788static void
6789do_FMAXNM (sim_cpu *cpu)
6790{
6791 /* instr[31,23] = 0 0011 1100
6792 instr[22] = float(0)/double(1)
6793 instr[21] = 1
6794 instr[20,16] = Sm
6795 instr[15,10] = 01 1010
6796 instr[9,5] = Sn
6797 instr[4,0] = Cpu */
6798
6799 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6800 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6801 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6802
6803 NYI_assert (31, 23, 0x03C);
6804 NYI_assert (15, 10, 0x1A);
6805
6806 if (uimm (aarch64_get_instr (cpu), 22, 22))
6807 aarch64_set_FP_double (cpu, sd,
6808 dmaxnm (aarch64_get_FP_double (cpu, sn),
6809 aarch64_get_FP_double (cpu, sm)));
6810 else
6811 aarch64_set_FP_float (cpu, sd,
6812 fmaxnm (aarch64_get_FP_float (cpu, sn),
6813 aarch64_get_FP_float (cpu, sm)));
6814}
6815
6816static void
6817dexSimpleFPDataProc2Source (sim_cpu *cpu)
6818{
6819 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
6820 instr[30] = 0
6821 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
6822 instr[28,25] = 1111
6823 instr[24] = 0
6824 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
6825 instr[21] = 1
6826 instr[20,16] = Vm
6827 instr[15,12] ==> opcode : 0000 ==> FMUL, 0001 ==> FDIV
6828 0010 ==> FADD, 0011 ==> FSUB,
6829 0100 ==> FMAX, 0101 ==> FMIN
6830 0110 ==> FMAXNM, 0111 ==> FMINNM
6831 1000 ==> FNMUL, ow ==> UNALLOC
6832 instr[11,10] = 10
6833 instr[9,5] = Vn
6834 instr[4,0] = Vd */
6835
6836 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
6837 | uimm (aarch64_get_instr (cpu), 29, 29);
6838 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
6839 /* Dispatch on opcode. */
6840 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 15, 12);
6841
6842 if (type > 1)
6843 HALT_UNALLOC;
6844
6845 if (M_S != 0)
6846 HALT_UNALLOC;
6847
6848 if (type)
6849 switch (dispatch)
6850 {
6851 case 0: fmuld (cpu); return;
6852 case 1: fdivd (cpu); return;
6853 case 2: faddd (cpu); return;
6854 case 3: fsubd (cpu); return;
6855 case 6: do_FMAXNM (cpu); return;
6856 case 7: do_FMINNM (cpu); return;
6857 case 8: fnmuld (cpu); return;
6858
6859 /* Have not yet implemented fmax and fmin. */
6860 case 4:
6861 case 5:
6862 HALT_NYI;
6863
6864 default:
6865 HALT_UNALLOC;
6866 }
6867 else /* type == 0 => floats. */
6868 switch (dispatch)
6869 {
6870 case 0: fmuls (cpu); return;
6871 case 1: fdivs (cpu); return;
6872 case 2: fadds (cpu); return;
6873 case 3: fsubs (cpu); return;
6874 case 6: do_FMAXNM (cpu); return;
6875 case 7: do_FMINNM (cpu); return;
6876 case 8: fnmuls (cpu); return;
6877
6878 case 4:
6879 case 5:
6880 HALT_NYI;
6881
6882 default:
6883 HALT_UNALLOC;
6884 }
6885}
6886
6887static void
6888dexSimpleFPCondSelect (sim_cpu *cpu)
6889{
6890 /* FCSEL
6891 instr[31,23] = 0 0011 1100
6892 instr[22] = 0=>single 1=>double
6893 instr[21] = 1
6894 instr[20,16] = Sm
6895 instr[15,12] = cond
6896 instr[11,10] = 11
6897 instr[9,5] = Sn
6898 instr[4,0] = Cpu */
6899 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6900 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6901 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6902 uint32_t set = testConditionCode (cpu, uimm (aarch64_get_instr (cpu), 15, 12));
6903
6904 NYI_assert (31, 23, 0x03C);
6905 NYI_assert (11, 10, 0x3);
6906
6907 if (uimm (aarch64_get_instr (cpu), 22, 22))
6908 aarch64_set_FP_double (cpu, sd, set ? sn : sm);
6909 else
6910 aarch64_set_FP_float (cpu, sd, set ? sn : sm);
6911}
6912
6913/* Store 32 bit unscaled signed 9 bit. */
6914static void
6915fsturs (sim_cpu *cpu, int32_t offset)
6916{
6917 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6918 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6919
e101a78b
NC
6920 aarch64_set_mem_u32 (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
6921 aarch64_get_vec_u32 (cpu, rn, 0));
2e8cf49e
NC
6922}
6923
6924/* Store 64 bit unscaled signed 9 bit. */
6925static void
6926fsturd (sim_cpu *cpu, int32_t offset)
6927{
6928 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6929 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6930
e101a78b
NC
6931 aarch64_set_mem_u64 (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
6932 aarch64_get_vec_u64 (cpu, rn, 0));
2e8cf49e
NC
6933}
6934
6935/* Store 128 bit unscaled signed 9 bit. */
6936static void
6937fsturq (sim_cpu *cpu, int32_t offset)
6938{
6939 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6940 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6941 FRegister a;
6942
6943 aarch64_get_FP_long_double (cpu, rn, & a);
6944 aarch64_set_mem_long_double (cpu,
6945 aarch64_get_reg_u64 (cpu, st, 1)
6946 + offset, a);
6947}
6948
6949/* TODO FP move register. */
6950
6951/* 32 bit fp to fp move register. */
6952static void
6953ffmovs (sim_cpu *cpu)
6954{
6955 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6956 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6957
6958 aarch64_set_FP_float (cpu, st, aarch64_get_FP_float (cpu, rn));
6959}
6960
6961/* 64 bit fp to fp move register. */
6962static void
6963ffmovd (sim_cpu *cpu)
6964{
6965 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6966 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6967
6968 aarch64_set_FP_double (cpu, st, aarch64_get_FP_double (cpu, rn));
6969}
6970
6971/* 32 bit GReg to Vec move register. */
6972static void
6973fgmovs (sim_cpu *cpu)
6974{
6975 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6976 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6977
6978 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_reg_u32 (cpu, rn, NO_SP));
6979}
6980
6981/* 64 bit g to fp move register. */
6982static void
6983fgmovd (sim_cpu *cpu)
6984{
6985 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6986 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6987
6988 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_reg_u64 (cpu, rn, NO_SP));
6989}
6990
6991/* 32 bit fp to g move register. */
6992static void
6993gfmovs (sim_cpu *cpu)
6994{
6995 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6996 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6997
6998 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u32 (cpu, rn, 0));
6999}
7000
7001/* 64 bit fp to g move register. */
7002static void
7003gfmovd (sim_cpu *cpu)
7004{
7005 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
7006 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
7007
7008 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u64 (cpu, rn, 0));
7009}
7010
7011/* FP move immediate
7012
7013 These install an immediate 8 bit value in the target register
7014 where the 8 bits comprise 1 sign bit, 4 bits of fraction and a 3
7015 bit exponent. */
7016
7017static void
7018fmovs (sim_cpu *cpu)
7019{
7020 unsigned int sd = uimm (aarch64_get_instr (cpu), 4, 0);
7021 uint32_t imm = uimm (aarch64_get_instr (cpu), 20, 13);
7022 float f = fp_immediate_for_encoding_32 (imm);
7023
7024 aarch64_set_FP_float (cpu, sd, f);
7025}
7026
7027static void
7028fmovd (sim_cpu *cpu)
7029{
7030 unsigned int sd = uimm (aarch64_get_instr (cpu), 4, 0);
7031 uint32_t imm = uimm (aarch64_get_instr (cpu), 20, 13);
7032 double d = fp_immediate_for_encoding_64 (imm);
7033
7034 aarch64_set_FP_double (cpu, sd, d);
7035}
7036
7037static void
7038dexSimpleFPImmediate (sim_cpu *cpu)
7039{
7040 /* instr[31,23] == 00111100
7041 instr[22] == type : single(0)/double(1)
7042 instr[21] == 1
7043 instr[20,13] == imm8
7044 instr[12,10] == 100
7045 instr[9,5] == imm5 : 00000 ==> PK, ow ==> UNALLOC
7046 instr[4,0] == Rd */
7047 uint32_t imm5 = uimm (aarch64_get_instr (cpu), 9, 5);
7048
7049 NYI_assert (31, 23, 0x3C);
7050
7051 if (imm5 != 0)
7052 HALT_UNALLOC;
7053
7054 if (uimm (aarch64_get_instr (cpu), 22, 22))
7055 fmovd (cpu);
7056 else
7057 fmovs (cpu);
7058}
7059
7060/* TODO specific decode and execute for group Load Store. */
7061
7062/* TODO FP load/store single register (unscaled offset). */
7063
7064/* TODO load 8 bit unscaled signed 9 bit. */
7065/* TODO load 16 bit unscaled signed 9 bit. */
7066
7067/* Load 32 bit unscaled signed 9 bit. */
7068static void
7069fldurs (sim_cpu *cpu, int32_t offset)
7070{
7071 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
7072 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
7073
e101a78b
NC
7074 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_mem_u32
7075 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7076}
7077
7078/* Load 64 bit unscaled signed 9 bit. */
7079static void
7080fldurd (sim_cpu *cpu, int32_t offset)
7081{
7082 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
7083 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
7084
e101a78b
NC
7085 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_mem_u64
7086 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
2e8cf49e
NC
7087}
7088
7089/* Load 128 bit unscaled signed 9 bit. */
7090static void
7091fldurq (sim_cpu *cpu, int32_t offset)
7092{
7093 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
7094 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
7095 FRegister a;
7096 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
7097
7098 aarch64_get_mem_long_double (cpu, addr, & a);
7099 aarch64_set_FP_long_double (cpu, st, a);
7100}
7101
7102/* TODO store 8 bit unscaled signed 9 bit. */
7103/* TODO store 16 bit unscaled signed 9 bit. */
7104
7105
7106/* 1 source. */
7107
7108/* Float absolute value. */
7109static void
7110fabss (sim_cpu *cpu)
7111{
7112 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7113 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7114 float value = aarch64_get_FP_float (cpu, sn);
7115
7116 aarch64_set_FP_float (cpu, sd, fabsf (value));
7117}
7118
7119/* Double absolute value. */
7120static void
7121fabcpu (sim_cpu *cpu)
7122{
7123 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7124 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7125 double value = aarch64_get_FP_double (cpu, sn);
7126
7127 aarch64_set_FP_double (cpu, sd, fabs (value));
7128}
7129
7130/* Float negative value. */
7131static void
7132fnegs (sim_cpu *cpu)
7133{
7134 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7135 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7136
7137 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sn));
7138}
7139
7140/* Double negative value. */
7141static void
7142fnegd (sim_cpu *cpu)
7143{
7144 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7145 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7146
7147 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sn));
7148}
7149
7150/* Float square root. */
7151static void
7152fsqrts (sim_cpu *cpu)
7153{
7154 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7155 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7156
7157 aarch64_set_FP_float (cpu, sd, sqrt (aarch64_get_FP_float (cpu, sn)));
7158}
7159
7160/* Double square root. */
7161static void
7162fsqrtd (sim_cpu *cpu)
7163{
7164 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7165 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7166
7167 aarch64_set_FP_double (cpu, sd,
7168 sqrt (aarch64_get_FP_double (cpu, sn)));
7169}
7170
7171/* Convert double to float. */
7172static void
7173fcvtds (sim_cpu *cpu)
7174{
7175 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7176 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7177
7178 aarch64_set_FP_float (cpu, sd, (float) aarch64_get_FP_double (cpu, sn));
7179}
7180
7181/* Convert float to double. */
7182static void
7183fcvtcpu (sim_cpu *cpu)
7184{
7185 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7186 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7187
7188 aarch64_set_FP_double (cpu, sd, (double) aarch64_get_FP_float (cpu, sn));
7189}
7190
7191static void
7192do_FRINT (sim_cpu *cpu)
7193{
7194 /* instr[31,23] = 0001 1110 0
7195 instr[22] = single(0)/double(1)
7196 instr[21,18] = 1001
7197 instr[17,15] = rounding mode
7198 instr[14,10] = 10000
7199 instr[9,5] = source
7200 instr[4,0] = dest */
7201
7202 float val;
7203 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7204 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7205 unsigned int rmode = uimm (aarch64_get_instr (cpu), 17, 15);
7206
7207 NYI_assert (31, 23, 0x03C);
7208 NYI_assert (21, 18, 0x9);
7209 NYI_assert (14, 10, 0x10);
7210
7211 if (rmode == 6 || rmode == 7)
7212 /* FIXME: Add support for rmode == 6 exactness check. */
7213 rmode = uimm (aarch64_get_FPSR (cpu), 23, 22);
7214
7215 if (uimm (aarch64_get_instr (cpu), 22, 22))
7216 {
7217 double val = aarch64_get_FP_double (cpu, rs);
7218
7219 switch (rmode)
7220 {
7221 case 0: /* mode N: nearest or even. */
7222 {
7223 double rval = round (val);
7224
7225 if (val - rval == 0.5)
7226 {
7227 if (((rval / 2.0) * 2.0) != rval)
7228 rval += 1.0;
7229 }
7230
7231 aarch64_set_FP_double (cpu, rd, round (val));
7232 return;
7233 }
7234
7235 case 1: /* mode P: towards +inf. */
7236 if (val < 0.0)
7237 aarch64_set_FP_double (cpu, rd, trunc (val));
7238 else
7239 aarch64_set_FP_double (cpu, rd, round (val));
7240 return;
7241
7242 case 2: /* mode M: towards -inf. */
7243 if (val < 0.0)
7244 aarch64_set_FP_double (cpu, rd, round (val));
7245 else
7246 aarch64_set_FP_double (cpu, rd, trunc (val));
7247 return;
7248
7249 case 3: /* mode Z: towards 0. */
7250 aarch64_set_FP_double (cpu, rd, trunc (val));
7251 return;
7252
7253 case 4: /* mode A: away from 0. */
7254 aarch64_set_FP_double (cpu, rd, round (val));
7255 return;
7256
7257 case 6: /* mode X: use FPCR with exactness check. */
7258 case 7: /* mode I: use FPCR mode. */
7259 HALT_NYI;
7260
7261 default:
7262 HALT_UNALLOC;
7263 }
7264 }
7265
7266 val = aarch64_get_FP_float (cpu, rs);
7267
7268 switch (rmode)
7269 {
7270 case 0: /* mode N: nearest or even. */
7271 {
7272 float rval = roundf (val);
7273
7274 if (val - rval == 0.5)
7275 {
7276 if (((rval / 2.0) * 2.0) != rval)
7277 rval += 1.0;
7278 }
7279
7280 aarch64_set_FP_float (cpu, rd, rval);
7281 return;
7282 }
7283
7284 case 1: /* mode P: towards +inf. */
7285 if (val < 0.0)
7286 aarch64_set_FP_float (cpu, rd, truncf (val));
7287 else
7288 aarch64_set_FP_float (cpu, rd, roundf (val));
7289 return;
7290
7291 case 2: /* mode M: towards -inf. */
7292 if (val < 0.0)
7293 aarch64_set_FP_float (cpu, rd, truncf (val));
7294 else
7295 aarch64_set_FP_float (cpu, rd, roundf (val));
7296 return;
7297
7298 case 3: /* mode Z: towards 0. */
7299 aarch64_set_FP_float (cpu, rd, truncf (val));
7300 return;
7301
7302 case 4: /* mode A: away from 0. */
7303 aarch64_set_FP_float (cpu, rd, roundf (val));
7304 return;
7305
7306 case 6: /* mode X: use FPCR with exactness check. */
7307 case 7: /* mode I: use FPCR mode. */
7308 HALT_NYI;
7309
7310 default:
7311 HALT_UNALLOC;
7312 }
7313}
7314
7315static void
7316dexSimpleFPDataProc1Source (sim_cpu *cpu)
7317{
7318 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7319 instr[30] = 0
7320 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7321 instr[28,25] = 1111
7322 instr[24] = 0
7323 instr[23,22] ==> type : 00 ==> source is single,
7324 01 ==> source is double
7325 10 ==> UNALLOC
7326 11 ==> UNALLOC or source is half
7327 instr[21] = 1
7328 instr[20,15] ==> opcode : with type 00 or 01
7329 000000 ==> FMOV, 000001 ==> FABS,
7330 000010 ==> FNEG, 000011 ==> FSQRT,
7331 000100 ==> UNALLOC, 000101 ==> FCVT,(to single/double)
7332 000110 ==> UNALLOC, 000111 ==> FCVT (to half)
7333 001000 ==> FRINTN, 001001 ==> FRINTP,
7334 001010 ==> FRINTM, 001011 ==> FRINTZ,
7335 001100 ==> FRINTA, 001101 ==> UNALLOC
7336 001110 ==> FRINTX, 001111 ==> FRINTI
7337 with type 11
7338 000100 ==> FCVT (half-to-single)
7339 000101 ==> FCVT (half-to-double)
7340 instr[14,10] = 10000. */
7341
7342 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
7343 | uimm (aarch64_get_instr (cpu), 29, 29);
7344 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
7345 uint32_t opcode = uimm (aarch64_get_instr (cpu), 20, 15);
7346
7347 if (M_S != 0)
7348 HALT_UNALLOC;
7349
7350 if (type == 3)
7351 {
7352 if (opcode == 4 || opcode == 5)
7353 HALT_NYI;
7354 else
7355 HALT_UNALLOC;
7356 }
7357
7358 if (type == 2)
7359 HALT_UNALLOC;
7360
7361 switch (opcode)
7362 {
7363 case 0:
7364 if (type)
7365 ffmovd (cpu);
7366 else
7367 ffmovs (cpu);
7368 return;
7369
7370 case 1:
7371 if (type)
7372 fabcpu (cpu);
7373 else
7374 fabss (cpu);
7375 return;
7376
7377 case 2:
7378 if (type)
7379 fnegd (cpu);
7380 else
7381 fnegs (cpu);
7382 return;
7383
7384 case 3:
7385 if (type)
7386 fsqrtd (cpu);
7387 else
7388 fsqrts (cpu);
7389 return;
7390
7391 case 4:
7392 if (type)
7393 fcvtds (cpu);
7394 else
7395 HALT_UNALLOC;
7396 return;
7397
7398 case 5:
7399 if (type)
7400 HALT_UNALLOC;
7401 fcvtcpu (cpu);
7402 return;
7403
7404 case 8: /* FRINTN etc. */
7405 case 9:
7406 case 10:
7407 case 11:
7408 case 12:
7409 case 14:
7410 case 15:
7411 do_FRINT (cpu);
7412 return;
7413
7414 case 7: /* FCVT double/single to half precision. */
7415 case 13:
7416 HALT_NYI;
7417
7418 default:
7419 HALT_UNALLOC;
7420 }
7421}
7422
7423/* 32 bit signed int to float. */
7424static void
7425scvtf32 (sim_cpu *cpu)
7426{
7427 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7428 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7429
7430 aarch64_set_FP_float
7431 (cpu, sd, (float) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7432}
7433
7434/* signed int to float. */
7435static void
7436scvtf (sim_cpu *cpu)
7437{
7438 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7439 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7440
7441 aarch64_set_FP_float
7442 (cpu, sd, (float) aarch64_get_reg_s64 (cpu, rn, NO_SP));
7443}
7444
7445/* 32 bit signed int to double. */
7446static void
7447scvtd32 (sim_cpu *cpu)
7448{
7449 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7450 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7451
7452 aarch64_set_FP_double
7453 (cpu, sd, (double) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7454}
7455
7456/* signed int to double. */
7457static void
7458scvtd (sim_cpu *cpu)
7459{
7460 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7461 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7462
7463 aarch64_set_FP_double
7464 (cpu, sd, (double) aarch64_get_reg_s64 (cpu, rn, NO_SP));
7465}
7466
7467static const float FLOAT_INT_MAX = (float) INT_MAX;
7468static const float FLOAT_INT_MIN = (float) INT_MIN;
7469static const double DOUBLE_INT_MAX = (double) INT_MAX;
7470static const double DOUBLE_INT_MIN = (double) INT_MIN;
7471static const float FLOAT_LONG_MAX = (float) LONG_MAX;
7472static const float FLOAT_LONG_MIN = (float) LONG_MIN;
7473static const double DOUBLE_LONG_MAX = (double) LONG_MAX;
7474static const double DOUBLE_LONG_MIN = (double) LONG_MIN;
7475
7476/* Check for FP exception conditions:
7477 NaN raises IO
7478 Infinity raises IO
7479 Out of Range raises IO and IX and saturates value
7480 Denormal raises ID and IX and sets to zero. */
7481#define RAISE_EXCEPTIONS(F, VALUE, FTYPE, ITYPE) \
7482 do \
7483 { \
7484 switch (fpclassify (F)) \
7485 { \
7486 case FP_INFINITE: \
7487 case FP_NAN: \
7488 aarch64_set_FPSR (cpu, IO); \
7489 if (signbit (F)) \
7490 VALUE = ITYPE##_MAX; \
7491 else \
7492 VALUE = ITYPE##_MIN; \
7493 break; \
7494 \
7495 case FP_NORMAL: \
7496 if (F >= FTYPE##_##ITYPE##_MAX) \
7497 { \
7498 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7499 VALUE = ITYPE##_MAX; \
7500 } \
7501 else if (F <= FTYPE##_##ITYPE##_MIN) \
7502 { \
7503 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7504 VALUE = ITYPE##_MIN; \
7505 } \
7506 break; \
7507 \
7508 case FP_SUBNORMAL: \
7509 aarch64_set_FPSR_bits (cpu, IO | IX | ID, IX | ID); \
7510 VALUE = 0; \
7511 break; \
7512 \
7513 default: \
7514 case FP_ZERO: \
7515 VALUE = 0; \
7516 break; \
7517 } \
7518 } \
7519 while (0)
7520
7521/* 32 bit convert float to signed int truncate towards zero. */
7522static void
7523fcvtszs32 (sim_cpu *cpu)
7524{
7525 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7526 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7527 /* TODO : check that this rounds toward zero. */
7528 float f = aarch64_get_FP_float (cpu, sn);
7529 int32_t value = (int32_t) f;
7530
7531 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
7532
7533 /* Avoid sign extension to 64 bit. */
7534 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7535}
7536
7537/* 64 bit convert float to signed int truncate towards zero. */
7538static void
7539fcvtszs (sim_cpu *cpu)
7540{
7541 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7542 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7543 float f = aarch64_get_FP_float (cpu, sn);
7544 int64_t value = (int64_t) f;
7545
7546 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
7547
7548 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7549}
7550
7551/* 32 bit convert double to signed int truncate towards zero. */
7552static void
7553fcvtszd32 (sim_cpu *cpu)
7554{
7555 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7556 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7557 /* TODO : check that this rounds toward zero. */
7558 double d = aarch64_get_FP_double (cpu, sn);
7559 int32_t value = (int32_t) d;
7560
7561 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
7562
7563 /* Avoid sign extension to 64 bit. */
7564 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7565}
7566
7567/* 64 bit convert double to signed int truncate towards zero. */
7568static void
7569fcvtszd (sim_cpu *cpu)
7570{
7571 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7572 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7573 /* TODO : check that this rounds toward zero. */
7574 double d = aarch64_get_FP_double (cpu, sn);
7575 int64_t value;
7576
7577 value = (int64_t) d;
7578
7579 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7580
7581 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7582}
7583
7584static void
7585do_fcvtzu (sim_cpu *cpu)
7586{
7587 /* instr[31] = size: 32-bit (0), 64-bit (1)
7588 instr[30,23] = 00111100
7589 instr[22] = type: single (0)/ double (1)
7590 instr[21] = enable (0)/disable(1) precision
7591 instr[20,16] = 11001
7592 instr[15,10] = precision
7593 instr[9,5] = Rs
7594 instr[4,0] = Rd. */
7595
7596 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7597 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7598
7599 NYI_assert (30, 23, 0x3C);
7600 NYI_assert (20, 16, 0x19);
7601
7602 if (uimm (aarch64_get_instr (cpu), 21, 21) != 1)
7603 /* Convert to fixed point. */
7604 HALT_NYI;
7605
7606 if (uimm (aarch64_get_instr (cpu), 31, 31))
7607 {
7608 /* Convert to unsigned 64-bit integer. */
7609 if (uimm (aarch64_get_instr (cpu), 22, 22))
7610 {
7611 double d = aarch64_get_FP_double (cpu, rs);
7612 uint64_t value = (uint64_t) d;
7613
7614 /* Do not raise an exception if we have reached ULONG_MAX. */
7615 if (value != (1UL << 63))
7616 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7617
7618 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7619 }
7620 else
7621 {
7622 float f = aarch64_get_FP_float (cpu, rs);
7623 uint64_t value = (uint64_t) f;
7624
7625 /* Do not raise an exception if we have reached ULONG_MAX. */
7626 if (value != (1UL << 63))
7627 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
7628
7629 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7630 }
7631 }
7632 else
7633 {
7634 uint32_t value;
7635
7636 /* Convert to unsigned 32-bit integer. */
7637 if (uimm (aarch64_get_instr (cpu), 22, 22))
7638 {
7639 double d = aarch64_get_FP_double (cpu, rs);
7640
7641 value = (uint32_t) d;
7642 /* Do not raise an exception if we have reached UINT_MAX. */
7643 if (value != (1UL << 31))
7644 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
7645 }
7646 else
7647 {
7648 float f = aarch64_get_FP_float (cpu, rs);
7649
7650 value = (uint32_t) f;
7651 /* Do not raise an exception if we have reached UINT_MAX. */
7652 if (value != (1UL << 31))
7653 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
7654 }
7655
7656 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7657 }
7658}
7659
7660static void
7661do_UCVTF (sim_cpu *cpu)
7662{
7663 /* instr[31] = size: 32-bit (0), 64-bit (1)
7664 instr[30,23] = 001 1110 0
7665 instr[22] = type: single (0)/ double (1)
7666 instr[21] = enable (0)/disable(1) precision
7667 instr[20,16] = 0 0011
7668 instr[15,10] = precision
7669 instr[9,5] = Rs
7670 instr[4,0] = Rd. */
7671
7672 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7673 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7674
7675 NYI_assert (30, 23, 0x3C);
7676 NYI_assert (20, 16, 0x03);
7677
7678 if (uimm (aarch64_get_instr (cpu), 21, 21) != 1)
7679 HALT_NYI;
7680
7681 /* FIXME: Add exception raising. */
7682 if (uimm (aarch64_get_instr (cpu), 31, 31))
7683 {
7684 uint64_t value = aarch64_get_reg_u64 (cpu, rs, NO_SP);
7685
7686 if (uimm (aarch64_get_instr (cpu), 22, 22))
7687 aarch64_set_FP_double (cpu, rd, (double) value);
7688 else
7689 aarch64_set_FP_float (cpu, rd, (float) value);
7690 }
7691 else
7692 {
7693 uint32_t value = aarch64_get_reg_u32 (cpu, rs, NO_SP);
7694
7695 if (uimm (aarch64_get_instr (cpu), 22, 22))
7696 aarch64_set_FP_double (cpu, rd, (double) value);
7697 else
7698 aarch64_set_FP_float (cpu, rd, (float) value);
7699 }
7700}
7701
7702static void
7703float_vector_move (sim_cpu *cpu)
7704{
7705 /* instr[31,17] == 100 1111 0101 0111
7706 instr[16] ==> direction 0=> to GR, 1=> from GR
7707 instr[15,10] => ???
7708 instr[9,5] ==> source
7709 instr[4,0] ==> dest. */
7710
7711 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7712 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7713
7714 NYI_assert (31, 17, 0x4F57);
7715
7716 if (uimm (aarch64_get_instr (cpu), 15, 10) != 0)
7717 HALT_UNALLOC;
7718
7719 if (uimm (aarch64_get_instr (cpu), 16, 16))
7720 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_reg_u64 (cpu, rn, NO_SP));
7721 else
7722 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, rn, 1));
7723}
7724
7725static void
7726dexSimpleFPIntegerConvert (sim_cpu *cpu)
7727{
7728 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
7729 instr[30 = 0
7730 instr[29] = S : 0 ==> OK, 1 ==> UNALLOC
7731 instr[28,25] = 1111
7732 instr[24] = 0
7733 instr[23,22] = type : 00 ==> single, 01 ==> double, 1x ==> UNALLOC
7734 instr[21] = 1
7735 instr[20,19] = rmode
7736 instr[18,16] = opcode
7737 instr[15,10] = 10 0000 */
7738
7739 uint32_t rmode_opcode;
7740 uint32_t size_type;
7741 uint32_t type;
7742 uint32_t size;
7743 uint32_t S;
7744
7745 if (uimm (aarch64_get_instr (cpu), 31, 17) == 0x4F57)
7746 {
7747 float_vector_move (cpu);
7748 return;
7749 }
7750
7751 size = uimm (aarch64_get_instr (cpu), 31, 31);
7752 S = uimm (aarch64_get_instr (cpu), 29, 29);
7753 if (S != 0)
7754 HALT_UNALLOC;
7755
7756 type = uimm (aarch64_get_instr (cpu), 23, 22);
7757 if (type > 1)
7758 HALT_UNALLOC;
7759
7760 rmode_opcode = uimm (aarch64_get_instr (cpu), 20, 16);
7761 size_type = (size << 1) | type; /* 0==32f, 1==32d, 2==64f, 3==64d. */
7762
7763 switch (rmode_opcode)
7764 {
7765 case 2: /* SCVTF. */
7766 switch (size_type)
7767 {
7768 case 0: scvtf32 (cpu); return;
7769 case 1: scvtd32 (cpu); return;
7770 case 2: scvtf (cpu); return;
7771 case 3: scvtd (cpu); return;
7772 default:
7773 HALT_UNREACHABLE;
7774 }
7775
7776 case 6: /* FMOV GR, Vec. */
7777 switch (size_type)
7778 {
7779 case 0: gfmovs (cpu); return;
7780 case 3: gfmovd (cpu); return;
7781 default: HALT_UNALLOC;
7782 }
7783
7784 case 7: /* FMOV vec, GR. */
7785 switch (size_type)
7786 {
7787 case 0: fgmovs (cpu); return;
7788 case 3: fgmovd (cpu); return;
7789 default: HALT_UNALLOC;
7790 }
7791
7792 case 24: /* FCVTZS. */
7793 switch (size_type)
7794 {
7795 case 0: fcvtszs32 (cpu); return;
7796 case 1: fcvtszd32 (cpu); return;
7797 case 2: fcvtszs (cpu); return;
7798 case 3: fcvtszd (cpu); return;
7799 default: HALT_UNREACHABLE;
7800 }
7801
7802 case 25: do_fcvtzu (cpu); return;
7803 case 3: do_UCVTF (cpu); return;
7804
7805 case 0: /* FCVTNS. */
7806 case 1: /* FCVTNU. */
7807 case 4: /* FCVTAS. */
7808 case 5: /* FCVTAU. */
7809 case 8: /* FCVPTS. */
7810 case 9: /* FCVTPU. */
7811 case 16: /* FCVTMS. */
7812 case 17: /* FCVTMU. */
7813 default:
7814 HALT_NYI;
7815 }
7816}
7817
7818static void
7819set_flags_for_float_compare (sim_cpu *cpu, float fvalue1, float fvalue2)
7820{
7821 uint32_t flags;
7822
7823 if (isnan (fvalue1) || isnan (fvalue2))
7824 flags = C|V;
7825 else
7826 {
7827 float result = fvalue1 - fvalue2;
7828
7829 if (result == 0.0)
7830 flags = Z|C;
7831 else if (result < 0)
7832 flags = N;
7833 else /* (result > 0). */
7834 flags = C;
7835 }
7836
7837 aarch64_set_CPSR (cpu, flags);
7838}
7839
7840static void
7841fcmps (sim_cpu *cpu)
7842{
7843 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7844 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7845
7846 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7847 float fvalue2 = aarch64_get_FP_float (cpu, sm);
7848
7849 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
7850}
7851
7852/* Float compare to zero -- Invalid Operation exception
7853 only on signaling NaNs. */
7854static void
7855fcmpzs (sim_cpu *cpu)
7856{
7857 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7858 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7859
7860 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
7861}
7862
7863/* Float compare -- Invalid Operation exception on all NaNs. */
7864static void
7865fcmpes (sim_cpu *cpu)
7866{
7867 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7868 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7869
7870 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7871 float fvalue2 = aarch64_get_FP_float (cpu, sm);
7872
7873 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
7874}
7875
7876/* Float compare to zero -- Invalid Operation exception on all NaNs. */
7877static void
7878fcmpzes (sim_cpu *cpu)
7879{
7880 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7881 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7882
7883 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
7884}
7885
7886static void
7887set_flags_for_double_compare (sim_cpu *cpu, double dval1, double dval2)
7888{
7889 uint32_t flags;
7890
7891 if (isnan (dval1) || isnan (dval2))
7892 flags = C|V;
7893 else
7894 {
7895 double result = dval1 - dval2;
7896
7897 if (result == 0.0)
7898 flags = Z|C;
7899 else if (result < 0)
7900 flags = N;
7901 else /* (result > 0). */
7902 flags = C;
7903 }
7904
7905 aarch64_set_CPSR (cpu, flags);
7906}
7907
7908/* Double compare -- Invalid Operation exception only on signaling NaNs. */
7909static void
7910fcmpd (sim_cpu *cpu)
7911{
7912 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7913 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7914
7915 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7916 double dvalue2 = aarch64_get_FP_double (cpu, sm);
7917
7918 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
7919}
7920
7921/* Double compare to zero -- Invalid Operation exception
7922 only on signaling NaNs. */
7923static void
7924fcmpzd (sim_cpu *cpu)
7925{
7926 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7927 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7928
7929 set_flags_for_double_compare (cpu, dvalue1, 0.0);
7930}
7931
7932/* Double compare -- Invalid Operation exception on all NaNs. */
7933static void
7934fcmped (sim_cpu *cpu)
7935{
7936 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7937 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7938
7939 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7940 double dvalue2 = aarch64_get_FP_double (cpu, sm);
7941
7942 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
7943}
7944
7945/* Double compare to zero -- Invalid Operation exception on all NaNs. */
7946static void
7947fcmpzed (sim_cpu *cpu)
7948{
7949 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7950 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7951
7952 set_flags_for_double_compare (cpu, dvalue1, 0.0);
7953}
7954
7955static void
7956dexSimpleFPCompare (sim_cpu *cpu)
7957{
7958 /* assert instr[28,25] == 1111
7959 instr[30:24:21:13,10] = 0011000
7960 instr[31] = M : 0 ==> OK, 1 ==> UNALLOC
7961 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7962 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7963 instr[15,14] ==> op : 00 ==> OK, ow ==> UNALLOC
7964 instr[4,0] ==> opcode2 : 00000 ==> FCMP, 10000 ==> FCMPE,
7965 01000 ==> FCMPZ, 11000 ==> FCMPEZ,
7966 ow ==> UNALLOC */
7967 uint32_t dispatch;
7968 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
7969 | uimm (aarch64_get_instr (cpu), 29, 29);
7970 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
7971 uint32_t op = uimm (aarch64_get_instr (cpu), 15, 14);
7972 uint32_t op2_2_0 = uimm (aarch64_get_instr (cpu), 2, 0);
7973
7974 if (op2_2_0 != 0)
7975 HALT_UNALLOC;
7976
7977 if (M_S != 0)
7978 HALT_UNALLOC;
7979
7980 if (type > 1)
7981 HALT_UNALLOC;
7982
7983 if (op != 0)
7984 HALT_UNALLOC;
7985
7986 /* dispatch on type and top 2 bits of opcode. */
7987 dispatch = (type << 2) | uimm (aarch64_get_instr (cpu), 4, 3);
7988
7989 switch (dispatch)
7990 {
7991 case 0: fcmps (cpu); return;
7992 case 1: fcmpzs (cpu); return;
7993 case 2: fcmpes (cpu); return;
7994 case 3: fcmpzes (cpu); return;
7995 case 4: fcmpd (cpu); return;
7996 case 5: fcmpzd (cpu); return;
7997 case 6: fcmped (cpu); return;
7998 case 7: fcmpzed (cpu); return;
7999 default: HALT_UNREACHABLE;
8000 }
8001}
8002
8003static void
8004do_scalar_FADDP (sim_cpu *cpu)
8005{
8006 /* instr [31,23] = 011111100
8007 instr [22] = single(0)/double(1)
8008 instr [21,10] = 1100 0011 0110
8009 instr [9,5] = Fn
8010 instr [4,0] = Fd. */
8011
8012 unsigned Fn = uimm (aarch64_get_instr (cpu), 9, 5);
8013 unsigned Fd = uimm (aarch64_get_instr (cpu), 4, 0);
8014
8015 NYI_assert (31, 23, 0x0FC);
8016 NYI_assert (21, 10, 0xC36);
8017
8018 if (uimm (aarch64_get_instr (cpu), 22, 22))
8019 {
8020 double val1 = aarch64_get_vec_double (cpu, Fn, 0);
8021 double val2 = aarch64_get_vec_double (cpu, Fn, 1);
8022
8023 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8024 }
8025 else
8026 {
8027 float val1 = aarch64_get_vec_float (cpu, Fn, 0);
8028 float val2 = aarch64_get_vec_float (cpu, Fn, 1);
8029
8030 aarch64_set_FP_float (cpu, Fd, val1 + val2);
8031 }
8032}
8033
8034/* Floating point absolute difference. */
8035
8036static void
8037do_scalar_FABD (sim_cpu *cpu)
8038{
8039 /* instr [31,23] = 0111 1110 1
8040 instr [22] = float(0)/double(1)
8041 instr [21] = 1
8042 instr [20,16] = Rm
8043 instr [15,10] = 1101 01
8044 instr [9, 5] = Rn
8045 instr [4, 0] = Rd. */
8046
8047 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8048 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8049 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8050
8051 NYI_assert (31, 23, 0x0FD);
8052 NYI_assert (21, 21, 1);
8053 NYI_assert (15, 10, 0x35);
8054
8055 if (uimm (aarch64_get_instr (cpu), 22, 22))
8056 aarch64_set_FP_double (cpu, rd,
8057 fabs (aarch64_get_FP_double (cpu, rn)
8058 - aarch64_get_FP_double (cpu, rm)));
8059 else
8060 aarch64_set_FP_float (cpu, rd,
8061 fabsf (aarch64_get_FP_float (cpu, rn)
8062 - aarch64_get_FP_float (cpu, rm)));
8063}
8064
8065static void
8066do_scalar_CMGT (sim_cpu *cpu)
8067{
8068 /* instr [31,21] = 0101 1110 111
8069 instr [20,16] = Rm
8070 instr [15,10] = 00 1101
8071 instr [9, 5] = Rn
8072 instr [4, 0] = Rd. */
8073
8074 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8075 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8076 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8077
8078 NYI_assert (31, 21, 0x2F7);
8079 NYI_assert (15, 10, 0x0D);
8080
8081 aarch64_set_vec_u64 (cpu, rd, 0,
8082 aarch64_get_vec_u64 (cpu, rn, 0) >
8083 aarch64_get_vec_u64 (cpu, rm, 0) ? -1L : 0L);
8084}
8085
8086static void
8087do_scalar_USHR (sim_cpu *cpu)
8088{
8089 /* instr [31,23] = 0111 1111 0
8090 instr [22,16] = shift amount
8091 instr [15,10] = 0000 01
8092 instr [9, 5] = Rn
8093 instr [4, 0] = Rd. */
8094
8095 unsigned amount = 128 - uimm (aarch64_get_instr (cpu), 22, 16);
8096 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8097 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8098
8099 NYI_assert (31, 23, 0x0FE);
8100 NYI_assert (15, 10, 0x01);
8101
8102 aarch64_set_vec_u64 (cpu, rd, 0,
8103 aarch64_get_vec_u64 (cpu, rn, 0) >> amount);
8104}
8105
8106static void
8107do_scalar_SHL (sim_cpu *cpu)
8108{
8109 /* instr [31,23] = 0111 1101 0
8110 instr [22,16] = shift amount
8111 instr [15,10] = 0101 01
8112 instr [9, 5] = Rn
8113 instr [4, 0] = Rd. */
8114
8115 unsigned amount = uimm (aarch64_get_instr (cpu), 22, 16) - 64;
8116 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8117 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8118
8119 NYI_assert (31, 23, 0x0BE);
8120 NYI_assert (15, 10, 0x15);
8121
8122 if (uimm (aarch64_get_instr (cpu), 22, 22) == 0)
8123 HALT_UNALLOC;
8124
8125 aarch64_set_vec_u64 (cpu, rd, 0,
8126 aarch64_get_vec_u64 (cpu, rn, 0) << amount);
8127}
8128
8129/* FCMEQ FCMGT FCMGE. */
8130static void
8131do_scalar_FCM (sim_cpu *cpu)
8132{
8133 /* instr [31,30] = 01
8134 instr [29] = U
8135 instr [28,24] = 1 1110
8136 instr [23] = E
8137 instr [22] = size
8138 instr [21] = 1
8139 instr [20,16] = Rm
8140 instr [15,12] = 1110
8141 instr [11] = AC
8142 instr [10] = 1
8143 instr [9, 5] = Rn
8144 instr [4, 0] = Rd. */
8145
8146 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8147 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8148 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8149 unsigned EUac = (uimm (aarch64_get_instr (cpu), 23, 23) << 2)
8150 | (uimm (aarch64_get_instr (cpu), 29, 29) << 1)
8151 | uimm (aarch64_get_instr (cpu), 11, 11);
8152 unsigned result;
8153 float val1;
8154 float val2;
8155
8156 NYI_assert (31, 30, 1);
8157 NYI_assert (28, 24, 0x1E);
8158 NYI_assert (21, 21, 1);
8159 NYI_assert (15, 12, 0xE);
8160 NYI_assert (10, 10, 1);
8161
8162 if (uimm (aarch64_get_instr (cpu), 22, 22))
8163 {
8164 double val1 = aarch64_get_FP_double (cpu, rn);
8165 double val2 = aarch64_get_FP_double (cpu, rm);
8166
8167 switch (EUac)
8168 {
8169 case 0: /* 000 */
8170 result = val1 == val2;
8171 break;
8172
8173 case 3: /* 011 */
8174 val1 = fabs (val1);
8175 val2 = fabs (val2);
8176 /* Fall through. */
8177 case 2: /* 010 */
8178 result = val1 >= val2;
8179 break;
8180
8181 case 7: /* 111 */
8182 val1 = fabs (val1);
8183 val2 = fabs (val2);
8184 /* Fall through. */
8185 case 6: /* 110 */
8186 result = val1 > val2;
8187 break;
8188
8189 default:
8190 HALT_UNALLOC;
8191 }
8192
8193 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8194 return;
8195 }
8196
8197 val1 = aarch64_get_FP_float (cpu, rn);
8198 val2 = aarch64_get_FP_float (cpu, rm);
8199
8200 switch (EUac)
8201 {
8202 case 0: /* 000 */
8203 result = val1 == val2;
8204 break;
8205
8206 case 3: /* 011 */
8207 val1 = fabsf (val1);
8208 val2 = fabsf (val2);
8209 /* Fall through. */
8210 case 2: /* 010 */
8211 result = val1 >= val2;
8212 break;
8213
8214 case 7: /* 111 */
8215 val1 = fabsf (val1);
8216 val2 = fabsf (val2);
8217 /* Fall through. */
8218 case 6: /* 110 */
8219 result = val1 > val2;
8220 break;
8221
8222 default:
8223 HALT_UNALLOC;
8224 }
8225
8226 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8227}
8228
8229/* An alias of DUP. */
8230static void
8231do_scalar_MOV (sim_cpu *cpu)
8232{
8233 /* instr [31,21] = 0101 1110 000
8234 instr [20,16] = imm5
8235 instr [15,10] = 0000 01
8236 instr [9, 5] = Rn
8237 instr [4, 0] = Rd. */
8238
8239 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8240 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8241 unsigned index;
8242
8243 NYI_assert (31, 21, 0x2F0);
8244 NYI_assert (15, 10, 0x01);
8245
8246 if (uimm (aarch64_get_instr (cpu), 16, 16))
8247 {
8248 /* 8-bit. */
8249 index = uimm (aarch64_get_instr (cpu), 20, 17);
8250 aarch64_set_vec_u8
8251 (cpu, rd, 0, aarch64_get_vec_u8 (cpu, rn, index));
8252 }
8253 else if (uimm (aarch64_get_instr (cpu), 17, 17))
8254 {
8255 /* 16-bit. */
8256 index = uimm (aarch64_get_instr (cpu), 20, 18);
8257 aarch64_set_vec_u16
8258 (cpu, rd, 0, aarch64_get_vec_u16 (cpu, rn, index));
8259 }
8260 else if (uimm (aarch64_get_instr (cpu), 18, 18))
8261 {
8262 /* 32-bit. */
8263 index = uimm (aarch64_get_instr (cpu), 20, 19);
8264 aarch64_set_vec_u32
8265 (cpu, rd, 0, aarch64_get_vec_u32 (cpu, rn, index));
8266 }
8267 else if (uimm (aarch64_get_instr (cpu), 19, 19))
8268 {
8269 /* 64-bit. */
8270 index = uimm (aarch64_get_instr (cpu), 20, 20);
8271 aarch64_set_vec_u64
8272 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, index));
8273 }
8274 else
8275 HALT_UNALLOC;
8276}
8277
e101a78b
NC
8278static void
8279do_scalar_NEG (sim_cpu *cpu)
8280{
8281 /* instr [31,24] = 0111 1110
8282 instr [23,22] = 11
8283 instr [21,10] = 1000 0010 1110
8284 instr [9, 5] = Rn
8285 instr [4, 0] = Rd. */
8286
8287 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8288 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8289
8290 NYI_assert (31, 24, 0x7E);
8291 NYI_assert (21, 10, 0x82E);
8292 NYI_assert (23, 22, 3);
8293
8294 aarch64_set_vec_u64 (cpu, rd, 0, - aarch64_get_vec_u64 (cpu, rn, 0));
8295}
8296
2e8cf49e
NC
8297static void
8298do_double_add (sim_cpu *cpu)
8299{
8300 /* instr [28,25] = 1111. */
8301 unsigned Fd;
8302 unsigned Fm;
8303 unsigned Fn;
8304 double val1;
8305 double val2;
8306
8307 switch (uimm (aarch64_get_instr (cpu), 31, 23))
8308 {
8309 case 0xBC:
8310 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8311 {
8312 case 0x01: do_scalar_MOV (cpu); return;
8313 case 0x39: do_scalar_FCM (cpu); return;
8314 case 0x3B: do_scalar_FCM (cpu); return;
8315 }
8316 break;
8317
8318 case 0xBE: do_scalar_SHL (cpu); return;
8319
8320 case 0xFC:
8321 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8322 {
8323 case 0x36: do_scalar_FADDP (cpu); return;
8324 case 0x39: do_scalar_FCM (cpu); return;
8325 case 0x3B: do_scalar_FCM (cpu); return;
8326 }
8327 break;
8328
8329 case 0xFD:
8330 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8331 {
8332 case 0x0D: do_scalar_CMGT (cpu); return;
8333 case 0x35: do_scalar_FABD (cpu); return;
8334 case 0x39: do_scalar_FCM (cpu); return;
8335 case 0x3B: do_scalar_FCM (cpu); return;
e101a78b 8336 case 0x2E: do_scalar_NEG (cpu); return;
2e8cf49e
NC
8337 default:
8338 HALT_NYI;
8339 }
8340
8341 case 0xFE: do_scalar_USHR (cpu); return;
8342 default:
8343 break;
8344 }
8345
8346 /* instr [31,21] = 0101 1110 111
8347 instr [20,16] = Fn
8348 instr [15,10] = 1000 01
8349 instr [9,5] = Fm
8350 instr [4,0] = Fd. */
8351 if (uimm (aarch64_get_instr (cpu), 31, 21) != 0x2F7
8352 || uimm (aarch64_get_instr (cpu), 15, 10) != 0x21)
8353 HALT_NYI;
8354
8355 Fd = uimm (aarch64_get_instr (cpu), 4, 0);
8356 Fm = uimm (aarch64_get_instr (cpu), 9, 5);
8357 Fn = uimm (aarch64_get_instr (cpu), 20, 16);
8358
8359 val1 = aarch64_get_FP_double (cpu, Fm);
8360 val2 = aarch64_get_FP_double (cpu, Fn);
8361
8362 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8363}
8364
8365static void
8366dexAdvSIMD1 (sim_cpu *cpu)
8367{
8368 /* instr [28,25] = 1 111. */
8369
8370 /* we are currently only interested in the basic
8371 scalar fp routines which all have bit 30 = 0. */
8372 if (uimm (aarch64_get_instr (cpu), 30, 30))
8373 do_double_add (cpu);
8374
8375 /* instr[24] is set for FP data processing 3-source and clear for
8376 all other basic scalar fp instruction groups. */
8377 else if (uimm (aarch64_get_instr (cpu), 24, 24))
8378 dexSimpleFPDataProc3Source (cpu);
8379
8380 /* instr[21] is clear for floating <-> fixed conversions and set for
8381 all other basic scalar fp instruction groups. */
8382 else if (!uimm (aarch64_get_instr (cpu), 21, 21))
8383 dexSimpleFPFixedConvert (cpu);
8384
8385 /* instr[11,10] : 01 ==> cond compare, 10 ==> Data Proc 2 Source
8386 11 ==> cond select, 00 ==> other. */
8387 else
8388 switch (uimm (aarch64_get_instr (cpu), 11, 10))
8389 {
8390 case 1: dexSimpleFPCondCompare (cpu); return;
8391 case 2: dexSimpleFPDataProc2Source (cpu); return;
8392 case 3: dexSimpleFPCondSelect (cpu); return;
8393
8394 default:
8395 /* Now an ordered cascade of tests.
8396 FP immediate has aarch64_get_instr (cpu)[12] == 1.
8397 FP compare has aarch64_get_instr (cpu)[13] == 1.
8398 FP Data Proc 1 Source has aarch64_get_instr (cpu)[14] == 1.
8399 FP floating <--> integer conversions has aarch64_get_instr (cpu)[15] == 0. */
8400 if (uimm (aarch64_get_instr (cpu), 12, 12))
8401 dexSimpleFPImmediate (cpu);
8402
8403 else if (uimm (aarch64_get_instr (cpu), 13, 13))
8404 dexSimpleFPCompare (cpu);
8405
8406 else if (uimm (aarch64_get_instr (cpu), 14, 14))
8407 dexSimpleFPDataProc1Source (cpu);
8408
8409 else if (!uimm (aarch64_get_instr (cpu), 15, 15))
8410 dexSimpleFPIntegerConvert (cpu);
8411
8412 else
8413 /* If we get here then instr[15] == 1 which means UNALLOC. */
8414 HALT_UNALLOC;
8415 }
8416}
8417
8418/* PC relative addressing. */
8419
8420static void
8421pcadr (sim_cpu *cpu)
8422{
8423 /* instr[31] = op : 0 ==> ADR, 1 ==> ADRP
8424 instr[30,29] = immlo
8425 instr[23,5] = immhi. */
8426 uint64_t address;
8427 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8428 uint32_t isPage = uimm (aarch64_get_instr (cpu), 31, 31);
8429 union { int64_t u64; uint64_t s64; } imm;
8430 uint64_t offset;
8431
8432 imm.s64 = simm64 (aarch64_get_instr (cpu), 23, 5);
8433 offset = imm.u64;
8434 offset = (offset << 2) | uimm (aarch64_get_instr (cpu), 30, 29);
8435
8436 address = aarch64_get_PC (cpu);
8437
8438 if (isPage)
8439 {
8440 offset <<= 12;
8441 address &= ~0xfff;
8442 }
8443
8444 aarch64_set_reg_u64 (cpu, rd, NO_SP, address + offset);
8445}
8446
8447/* Specific decode and execute for group Data Processing Immediate. */
8448
8449static void
8450dexPCRelAddressing (sim_cpu *cpu)
8451{
8452 /* assert instr[28,24] = 10000. */
8453 pcadr (cpu);
8454}
8455
8456/* Immediate logical.
8457 The bimm32/64 argument is constructed by replicating a 2, 4, 8,
8458 16, 32 or 64 bit sequence pulled out at decode and possibly
8459 inverting it..
8460
8461 N.B. the output register (dest) can normally be Xn or SP
8462 the exception occurs for flag setting instructions which may
8463 only use Xn for the output (dest). The input register can
8464 never be SP. */
8465
8466/* 32 bit and immediate. */
8467static void
8468and32 (sim_cpu *cpu, uint32_t bimm)
8469{
8470 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8471 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8472
8473 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8474 aarch64_get_reg_u32 (cpu, rn, NO_SP) & bimm);
8475}
8476
8477/* 64 bit and immediate. */
8478static void
8479and64 (sim_cpu *cpu, uint64_t bimm)
8480{
8481 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8482 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8483
8484 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8485 aarch64_get_reg_u64 (cpu, rn, NO_SP) & bimm);
8486}
8487
8488/* 32 bit and immediate set flags. */
8489static void
8490ands32 (sim_cpu *cpu, uint32_t bimm)
8491{
8492 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8493 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8494
8495 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8496 uint32_t value2 = bimm;
8497
8498 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8499 set_flags_for_binop32 (cpu, value1 & value2);
8500}
8501
8502/* 64 bit and immediate set flags. */
8503static void
8504ands64 (sim_cpu *cpu, uint64_t bimm)
8505{
8506 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8507 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8508
8509 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8510 uint64_t value2 = bimm;
8511
8512 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8513 set_flags_for_binop64 (cpu, value1 & value2);
8514}
8515
8516/* 32 bit exclusive or immediate. */
8517static void
8518eor32 (sim_cpu *cpu, uint32_t bimm)
8519{
8520 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8521 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8522
8523 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8524 aarch64_get_reg_u32 (cpu, rn, NO_SP) ^ bimm);
8525}
8526
8527/* 64 bit exclusive or immediate. */
8528static void
8529eor64 (sim_cpu *cpu, uint64_t bimm)
8530{
8531 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8532 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8533
8534 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8535 aarch64_get_reg_u64 (cpu, rn, NO_SP) ^ bimm);
8536}
8537
8538/* 32 bit or immediate. */
8539static void
8540orr32 (sim_cpu *cpu, uint32_t bimm)
8541{
8542 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8543 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8544
8545 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8546 aarch64_get_reg_u32 (cpu, rn, NO_SP) | bimm);
8547}
8548
8549/* 64 bit or immediate. */
8550static void
8551orr64 (sim_cpu *cpu, uint64_t bimm)
8552{
8553 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8554 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8555
8556 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8557 aarch64_get_reg_u64 (cpu, rn, NO_SP) | bimm);
8558}
8559
8560/* Logical shifted register.
8561 These allow an optional LSL, ASR, LSR or ROR to the second source
8562 register with a count up to the register bit count.
8563 N.B register args may not be SP. */
8564
8565/* 32 bit AND shifted register. */
8566static void
8567and32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8568{
8569 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8570 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8571 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8572
8573 aarch64_set_reg_u64
8574 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8575 & shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8576}
8577
8578/* 64 bit AND shifted register. */
8579static void
8580and64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8581{
8582 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8583 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8584 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8585
8586 aarch64_set_reg_u64
8587 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8588 & shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8589}
8590
8591/* 32 bit AND shifted register setting flags. */
8592static void
8593ands32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8594{
8595 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8596 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8597 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8598
8599 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8600 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
8601 shift, count);
8602
8603 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8604 set_flags_for_binop32 (cpu, value1 & value2);
8605}
8606
8607/* 64 bit AND shifted register setting flags. */
8608static void
8609ands64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8610{
8611 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8612 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8613 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8614
8615 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8616 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
8617 shift, count);
8618
8619 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8620 set_flags_for_binop64 (cpu, value1 & value2);
8621}
8622
8623/* 32 bit BIC shifted register. */
8624static void
8625bic32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8626{
8627 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8628 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8629 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8630
8631 aarch64_set_reg_u64
8632 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8633 & ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8634}
8635
8636/* 64 bit BIC shifted register. */
8637static void
8638bic64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8639{
8640 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8641 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8642 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8643
8644 aarch64_set_reg_u64
8645 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8646 & ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8647}
8648
8649/* 32 bit BIC shifted register setting flags. */
8650static void
8651bics32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8652{
8653 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8654 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8655 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8656
8657 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8658 uint32_t value2 = ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
8659 shift, count);
8660
8661 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8662 set_flags_for_binop32 (cpu, value1 & value2);
8663}
8664
8665/* 64 bit BIC shifted register setting flags. */
8666static void
8667bics64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8668{
8669 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8670 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8671 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8672
8673 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8674 uint64_t value2 = ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
8675 shift, count);
8676
8677 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8678 set_flags_for_binop64 (cpu, value1 & value2);
8679}
8680
8681/* 32 bit EON shifted register. */
8682static void
8683eon32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8684{
8685 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8686 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8687 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8688
8689 aarch64_set_reg_u64
8690 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8691 ^ ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8692}
8693
8694/* 64 bit EON shifted register. */
8695static void
8696eon64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8697{
8698 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8699 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8700 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8701
8702 aarch64_set_reg_u64
8703 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8704 ^ ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8705}
8706
8707/* 32 bit EOR shifted register. */
8708static void
8709eor32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8710{
8711 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8712 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8713 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8714
8715 aarch64_set_reg_u64
8716 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8717 ^ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8718}
8719
8720/* 64 bit EOR shifted register. */
8721static void
8722eor64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8723{
8724 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8725 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8726 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8727
8728 aarch64_set_reg_u64
8729 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8730 ^ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8731}
8732
8733/* 32 bit ORR shifted register. */
8734static void
8735orr32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8736{
8737 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8738 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8739 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8740
8741 aarch64_set_reg_u64
8742 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8743 | shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8744}
8745
8746/* 64 bit ORR shifted register. */
8747static void
8748orr64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8749{
8750 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8751 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8752 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8753
8754 aarch64_set_reg_u64
8755 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8756 | shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8757}
8758
8759/* 32 bit ORN shifted register. */
8760static void
8761orn32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8762{
8763 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8764 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8765 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8766
8767 aarch64_set_reg_u64
8768 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8769 | ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8770}
8771
8772/* 64 bit ORN shifted register. */
8773static void
8774orn64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8775{
8776 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8777 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8778 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8779
8780 aarch64_set_reg_u64
8781 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8782 | ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8783}
8784
8785static void
8786dexLogicalImmediate (sim_cpu *cpu)
8787{
8788 /* assert instr[28,23] = 1001000
8789 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8790 instr[30,29] = op : 0 ==> AND, 1 ==> ORR, 2 ==> EOR, 3 ==> ANDS
8791 instr[22] = N : used to construct immediate mask
8792 instr[21,16] = immr
8793 instr[15,10] = imms
8794 instr[9,5] = Rn
8795 instr[4,0] = Rd */
8796
8797 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
8798 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
8799 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
8800 /* uint32_t immr = uimm (aarch64_get_instr (cpu), 21, 16);. */
8801 /* uint32_t imms = uimm (aarch64_get_instr (cpu), 15, 10);. */
8802 uint32_t index = uimm (aarch64_get_instr (cpu), 22, 10);
8803 uint64_t bimm64 = LITable [index];
8804 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 30, 29);
8805
8806 if (~size & N)
8807 HALT_UNALLOC;
8808
8809 if (!bimm64)
8810 HALT_UNALLOC;
8811
8812 if (size == 0)
8813 {
8814 uint32_t bimm = (uint32_t) bimm64;
8815
8816 switch (dispatch)
8817 {
8818 case 0: and32 (cpu, bimm); return;
8819 case 1: orr32 (cpu, bimm); return;
8820 case 2: eor32 (cpu, bimm); return;
8821 case 3: ands32 (cpu, bimm); return;
8822 }
8823 }
8824 else
8825 {
8826 switch (dispatch)
8827 {
8828 case 0: and64 (cpu, bimm64); return;
8829 case 1: orr64 (cpu, bimm64); return;
8830 case 2: eor64 (cpu, bimm64); return;
8831 case 3: ands64 (cpu, bimm64); return;
8832 }
8833 }
8834 HALT_UNALLOC;
8835}
8836
8837/* Immediate move.
8838 The uimm argument is a 16 bit value to be inserted into the
8839 target register the pos argument locates the 16 bit word in the
8840 dest register i.e. it is in {0, 1} for 32 bit and {0, 1, 2,
8841 3} for 64 bit.
8842 N.B register arg may not be SP so it should be.
8843 accessed using the setGZRegisterXXX accessors. */
8844
8845/* 32 bit move 16 bit immediate zero remaining shorts. */
8846static void
8847movz32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8848{
8849 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8850
8851 aarch64_set_reg_u64 (cpu, rd, NO_SP, val << (pos * 16));
8852}
8853
8854/* 64 bit move 16 bit immediate zero remaining shorts. */
8855static void
8856movz64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8857{
8858 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8859
8860 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((uint64_t) val) << (pos * 16));
8861}
8862
8863/* 32 bit move 16 bit immediate negated. */
8864static void
8865movn32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8866{
8867 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8868
8869 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((val << (pos * 16)) ^ 0xffffffffU));
8870}
8871
8872/* 64 bit move 16 bit immediate negated. */
8873static void
8874movn64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8875{
8876 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8877
8878 aarch64_set_reg_u64
8879 (cpu, rd, NO_SP, ((((uint64_t) val) << (pos * 16))
8880 ^ 0xffffffffffffffffULL));
8881}
8882
8883/* 32 bit move 16 bit immediate keep remaining shorts. */
8884static void
8885movk32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8886{
8887 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8888 uint32_t current = aarch64_get_reg_u32 (cpu, rd, NO_SP);
8889 uint32_t value = val << (pos * 16);
8890 uint32_t mask = ~(0xffffU << (pos * 16));
8891
8892 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
8893}
8894
8895/* 64 bit move 16 it immediate keep remaining shorts. */
8896static void
8897movk64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8898{
8899 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8900 uint64_t current = aarch64_get_reg_u64 (cpu, rd, NO_SP);
8901 uint64_t value = (uint64_t) val << (pos * 16);
8902 uint64_t mask = ~(0xffffULL << (pos * 16));
8903
8904 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
8905}
8906
8907static void
8908dexMoveWideImmediate (sim_cpu *cpu)
8909{
8910 /* assert instr[28:23] = 100101
8911 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8912 instr[30,29] = op : 0 ==> MOVN, 1 ==> UNALLOC, 2 ==> MOVZ, 3 ==> MOVK
8913 instr[22,21] = shift : 00 == LSL#0, 01 = LSL#16, 10 = LSL#32, 11 = LSL#48
8914 instr[20,5] = uimm16
8915 instr[4,0] = Rd */
8916
8917 /* N.B. the (multiple of 16) shift is applied by the called routine,
8918 we just pass the multiplier. */
8919
8920 uint32_t imm;
8921 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
8922 uint32_t op = uimm (aarch64_get_instr (cpu), 30, 29);
8923 uint32_t shift = uimm (aarch64_get_instr (cpu), 22, 21);
8924
8925 /* 32 bit can only shift 0 or 1 lot of 16.
8926 anything else is an unallocated instruction. */
8927 if (size == 0 && (shift > 1))
8928 HALT_UNALLOC;
8929
8930 if (op == 1)
8931 HALT_UNALLOC;
8932
8933 imm = uimm (aarch64_get_instr (cpu), 20, 5);
8934
8935 if (size == 0)
8936 {
8937 if (op == 0)
8938 movn32 (cpu, imm, shift);
8939 else if (op == 2)
8940 movz32 (cpu, imm, shift);
8941 else
8942 movk32 (cpu, imm, shift);
8943 }
8944 else
8945 {
8946 if (op == 0)
8947 movn64 (cpu, imm, shift);
8948 else if (op == 2)
8949 movz64 (cpu, imm, shift);
8950 else
8951 movk64 (cpu, imm, shift);
8952 }
8953}
8954
8955/* Bitfield operations.
8956 These take a pair of bit positions r and s which are in {0..31}
8957 or {0..63} depending on the instruction word size.
8958 N.B register args may not be SP. */
8959
8960/* OK, we start with ubfm which just needs to pick
8961 some bits out of source zero the rest and write
8962 the result to dest. Just need two logical shifts. */
8963
8964/* 32 bit bitfield move, left and right of affected zeroed
8965 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8966static void
8967ubfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8968{
8969 unsigned rd;
8970 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8971 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8972
8973 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
8974 if (r <= s)
8975 {
8976 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
8977 We want only bits s:xxx:r at the bottom of the word
8978 so we LSL bit s up to bit 31 i.e. by 31 - s
8979 and then we LSR to bring bit 31 down to bit s - r
8980 i.e. by 31 + r - s. */
8981 value <<= 31 - s;
8982 value >>= 31 + r - s;
8983 }
8984 else
8985 {
8986 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0
8987 We want only bits s:xxx:0 starting at it 31-(r-1)
8988 so we LSL bit s up to bit 31 i.e. by 31 - s
8989 and then we LSL to bring bit 31 down to 31-(r-1)+s
8990 i.e. by r - (s + 1). */
8991 value <<= 31 - s;
8992 value >>= r - (s + 1);
8993 }
8994
8995 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8996 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8997}
8998
8999/* 64 bit bitfield move, left and right of affected zeroed
9000 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9001static void
9002ubfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9003{
9004 unsigned rd;
9005 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9006 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9007
9008 if (r <= s)
9009 {
9010 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9011 We want only bits s:xxx:r at the bottom of the word.
9012 So we LSL bit s up to bit 63 i.e. by 63 - s
9013 and then we LSR to bring bit 63 down to bit s - r
9014 i.e. by 63 + r - s. */
9015 value <<= 63 - s;
9016 value >>= 63 + r - s;
9017 }
9018 else
9019 {
9020 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0.
9021 We want only bits s:xxx:0 starting at it 63-(r-1).
9022 So we LSL bit s up to bit 63 i.e. by 63 - s
9023 and then we LSL to bring bit 63 down to 63-(r-1)+s
9024 i.e. by r - (s + 1). */
9025 value <<= 63 - s;
9026 value >>= r - (s + 1);
9027 }
9028
9029 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9030 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
9031}
9032
9033/* The signed versions need to insert sign bits
9034 on the left of the inserted bit field. so we do
9035 much the same as the unsigned version except we
9036 use an arithmetic shift right -- this just means
9037 we need to operate on signed values. */
9038
9039/* 32 bit bitfield move, left of affected sign-extended, right zeroed. */
9040/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9041static void
9042sbfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9043{
9044 unsigned rd;
9045 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9046 /* as per ubfm32 but use an ASR instead of an LSR. */
9047 int32_t value = aarch64_get_reg_s32 (cpu, rn, NO_SP);
9048
9049 if (r <= s)
9050 {
9051 value <<= 31 - s;
9052 value >>= 31 + r - s;
9053 }
9054 else
9055 {
9056 value <<= 31 - s;
9057 value >>= r - (s + 1);
9058 }
9059
9060 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9061 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
9062}
9063
9064/* 64 bit bitfield move, left of affected sign-extended, right zeroed. */
9065/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9066static void
9067sbfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9068{
9069 unsigned rd;
9070 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9071 /* acpu per ubfm but use an ASR instead of an LSR. */
9072 int64_t value = aarch64_get_reg_s64 (cpu, rn, NO_SP);
9073
9074 if (r <= s)
9075 {
9076 value <<= 63 - s;
9077 value >>= 63 + r - s;
9078 }
9079 else
9080 {
9081 value <<= 63 - s;
9082 value >>= r - (s + 1);
9083 }
9084
9085 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9086 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
9087}
9088
9089/* Finally, these versions leave non-affected bits
9090 as is. so we need to generate the bits as per
9091 ubfm and also generate a mask to pick the
9092 bits from the original and computed values. */
9093
9094/* 32 bit bitfield move, non-affected bits left as is.
9095 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
9096static void
9097bfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
9098{
9099 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9100 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9101 uint32_t mask = -1;
9102 unsigned rd;
9103 uint32_t value2;
9104
9105 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
9106 if (r <= s)
9107 {
9108 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
9109 We want only bits s:xxx:r at the bottom of the word
9110 so we LSL bit s up to bit 31 i.e. by 31 - s
9111 and then we LSR to bring bit 31 down to bit s - r
9112 i.e. by 31 + r - s. */
9113 value <<= 31 - s;
9114 value >>= 31 + r - s;
9115 /* the mask must include the same bits. */
9116 mask <<= 31 - s;
9117 mask >>= 31 + r - s;
9118 }
9119 else
9120 {
9121 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0.
9122 We want only bits s:xxx:0 starting at it 31-(r-1)
9123 so we LSL bit s up to bit 31 i.e. by 31 - s
9124 and then we LSL to bring bit 31 down to 31-(r-1)+s
9125 i.e. by r - (s + 1). */
9126 value <<= 31 - s;
9127 value >>= r - (s + 1);
9128 /* The mask must include the same bits. */
9129 mask <<= 31 - s;
9130 mask >>= r - (s + 1);
9131 }
9132
9133 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9134 value2 = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9135
9136 value2 &= ~mask;
9137 value2 |= value;
9138
9139 aarch64_set_reg_u64
9140 (cpu, rd, NO_SP, (aarch64_get_reg_u32 (cpu, rd, NO_SP) & ~mask) | value);
9141}
9142
9143/* 64 bit bitfield move, non-affected bits left as is.
9144 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9145static void
9146bfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9147{
9148 unsigned rd;
9149 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9150 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9151 uint64_t mask = 0xffffffffffffffffULL;
9152
9153 if (r <= s)
9154 {
9155 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9156 We want only bits s:xxx:r at the bottom of the word
9157 so we LSL bit s up to bit 63 i.e. by 63 - s
9158 and then we LSR to bring bit 63 down to bit s - r
9159 i.e. by 63 + r - s. */
9160 value <<= 63 - s;
9161 value >>= 63 + r - s;
9162 /* The mask must include the same bits. */
9163 mask <<= 63 - s;
9164 mask >>= 63 + r - s;
9165 }
9166 else
9167 {
9168 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0
9169 We want only bits s:xxx:0 starting at it 63-(r-1)
9170 so we LSL bit s up to bit 63 i.e. by 63 - s
9171 and then we LSL to bring bit 63 down to 63-(r-1)+s
9172 i.e. by r - (s + 1). */
9173 value <<= 63 - s;
9174 value >>= r - (s + 1);
9175 /* The mask must include the same bits. */
9176 mask <<= 63 - s;
9177 mask >>= r - (s + 1);
9178 }
9179
9180 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9181 aarch64_set_reg_u64
9182 (cpu, rd, NO_SP, (aarch64_get_reg_u64 (cpu, rd, NO_SP) & ~mask) | value);
9183}
9184
9185static void
9186dexBitfieldImmediate (sim_cpu *cpu)
9187{
9188 /* assert instr[28:23] = 100110
9189 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9190 instr[30,29] = op : 0 ==> SBFM, 1 ==> BFM, 2 ==> UBFM, 3 ==> UNALLOC
9191 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit ow UNALLOC
9192 instr[21,16] = immr : 0xxxxx for 32 bit, xxxxxx for 64 bit
9193 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9194 instr[9,5] = Rn
9195 instr[4,0] = Rd */
9196
9197 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9198 uint32_t dispatch;
9199 uint32_t imms;
9200 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
9201 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
9202 /* 32 bit operations must have immr[5] = 0 and imms[5] = 0. */
9203 /* or else we have an UNALLOC. */
9204 uint32_t immr = uimm (aarch64_get_instr (cpu), 21, 16);
9205
9206 if (~size & N)
9207 HALT_UNALLOC;
9208
9209 if (!size && uimm (immr, 5, 5))
9210 HALT_UNALLOC;
9211
9212 imms = uimm (aarch64_get_instr (cpu), 15, 10);
9213 if (!size && uimm (imms, 5, 5))
9214 HALT_UNALLOC;
9215
9216 /* Switch on combined size and op. */
9217 dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
9218 switch (dispatch)
9219 {
9220 case 0: sbfm32 (cpu, immr, imms); return;
9221 case 1: bfm32 (cpu, immr, imms); return;
9222 case 2: ubfm32 (cpu, immr, imms); return;
9223 case 4: sbfm (cpu, immr, imms); return;
9224 case 5: bfm (cpu, immr, imms); return;
9225 case 6: ubfm (cpu, immr, imms); return;
9226 default: HALT_UNALLOC;
9227 }
9228}
9229
9230static void
9231do_EXTR_32 (sim_cpu *cpu)
9232{
9233 /* instr[31:21] = 00010011100
9234 instr[20,16] = Rm
9235 instr[15,10] = imms : 0xxxxx for 32 bit
9236 instr[9,5] = Rn
9237 instr[4,0] = Rd */
9238 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9239 unsigned imms = uimm (aarch64_get_instr (cpu), 15, 10) & 31;
9240 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9241 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
9242 uint64_t val1;
9243 uint64_t val2;
9244
9245 val1 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
9246 val1 >>= imms;
9247 val2 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9248 val2 <<= (32 - imms);
9249
9250 aarch64_set_reg_u64 (cpu, rd, NO_SP, val1 | val2);
9251}
9252
9253static void
9254do_EXTR_64 (sim_cpu *cpu)
9255{
9256 /* instr[31:21] = 10010011100
9257 instr[20,16] = Rm
9258 instr[15,10] = imms
9259 instr[9,5] = Rn
9260 instr[4,0] = Rd */
9261 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9262 unsigned imms = uimm (aarch64_get_instr (cpu), 15, 10) & 63;
9263 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9264 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
9265 uint64_t val;
9266
9267 val = aarch64_get_reg_u64 (cpu, rm, NO_SP);
9268 val >>= imms;
9269 val |= (aarch64_get_reg_u64 (cpu, rn, NO_SP) << (64 - imms));
9270
9271 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
9272}
9273
9274static void
9275dexExtractImmediate (sim_cpu *cpu)
9276{
9277 /* assert instr[28:23] = 100111
9278 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9279 instr[30,29] = op21 : 0 ==> EXTR, 1,2,3 ==> UNALLOC
9280 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit or UNALLOC
9281 instr[21] = op0 : must be 0 or UNALLOC
9282 instr[20,16] = Rm
9283 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9284 instr[9,5] = Rn
9285 instr[4,0] = Rd */
9286
9287 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9288 /* 64 bit operations must have N = 1 or else we have an UNALLOC. */
9289 uint32_t dispatch;
9290 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
9291 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
9292 /* 32 bit operations must have imms[5] = 0
9293 or else we have an UNALLOC. */
9294 uint32_t imms = uimm (aarch64_get_instr (cpu), 15, 10);
9295
9296 if (size ^ N)
9297 HALT_UNALLOC;
9298
9299 if (!size && uimm (imms, 5, 5))
9300 HALT_UNALLOC;
9301
9302 /* Switch on combined size and op. */
9303 dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
9304
9305 if (dispatch == 0)
9306 do_EXTR_32 (cpu);
9307
9308 else if (dispatch == 4)
9309 do_EXTR_64 (cpu);
9310
9311 else if (dispatch == 1)
9312 HALT_NYI;
9313 else
9314 HALT_UNALLOC;
9315}
9316
9317static void
9318dexDPImm (sim_cpu *cpu)
9319{
9320 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
9321 assert group == GROUP_DPIMM_1000 || grpoup == GROUP_DPIMM_1001
9322 bits [25,23] of a DPImm are the secondary dispatch vector. */
9323 uint32_t group2 = dispatchDPImm (aarch64_get_instr (cpu));
9324
9325 switch (group2)
9326 {
9327 case DPIMM_PCADR_000:
9328 case DPIMM_PCADR_001:
9329 dexPCRelAddressing (cpu);
9330 return;
9331
9332 case DPIMM_ADDSUB_010:
9333 case DPIMM_ADDSUB_011:
9334 dexAddSubtractImmediate (cpu);
9335 return;
9336
9337 case DPIMM_LOG_100:
9338 dexLogicalImmediate (cpu);
9339 return;
9340
9341 case DPIMM_MOV_101:
9342 dexMoveWideImmediate (cpu);
9343 return;
9344
9345 case DPIMM_BITF_110:
9346 dexBitfieldImmediate (cpu);
9347 return;
9348
9349 case DPIMM_EXTR_111:
9350 dexExtractImmediate (cpu);
9351 return;
9352
9353 default:
9354 /* Should never reach here. */
9355 HALT_NYI;
9356 }
9357}
9358
9359static void
9360dexLoadUnscaledImmediate (sim_cpu *cpu)
9361{
9362 /* instr[29,24] == 111_00
9363 instr[21] == 0
9364 instr[11,10] == 00
9365 instr[31,30] = size
9366 instr[26] = V
9367 instr[23,22] = opc
9368 instr[20,12] = simm9
9369 instr[9,5] = rn may be SP. */
9370 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9371 uint32_t V = uimm (aarch64_get_instr (cpu), 26, 26);
9372 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9373 | uimm (aarch64_get_instr (cpu), 23, 22));
9374 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
9375
9376 if (!V)
9377 {
9378 /* GReg operations. */
9379 switch (dispatch)
9380 {
9381 case 0: sturb (cpu, imm); return;
9382 case 1: ldurb32 (cpu, imm); return;
9383 case 2: ldursb64 (cpu, imm); return;
9384 case 3: ldursb32 (cpu, imm); return;
9385 case 4: sturh (cpu, imm); return;
9386 case 5: ldurh32 (cpu, imm); return;
9387 case 6: ldursh64 (cpu, imm); return;
9388 case 7: ldursh32 (cpu, imm); return;
9389 case 8: stur32 (cpu, imm); return;
9390 case 9: ldur32 (cpu, imm); return;
9391 case 10: ldursw (cpu, imm); return;
9392 case 12: stur64 (cpu, imm); return;
9393 case 13: ldur64 (cpu, imm); return;
9394
9395 case 14:
9396 /* PRFUM NYI. */
9397 HALT_NYI;
9398
9399 default:
9400 case 11:
9401 case 15:
9402 HALT_UNALLOC;
9403 }
9404 }
9405
9406 /* FReg operations. */
9407 switch (dispatch)
9408 {
9409 case 2: fsturq (cpu, imm); return;
9410 case 3: fldurq (cpu, imm); return;
9411 case 8: fsturs (cpu, imm); return;
9412 case 9: fldurs (cpu, imm); return;
9413 case 12: fsturd (cpu, imm); return;
9414 case 13: fldurd (cpu, imm); return;
9415
9416 case 0: /* STUR 8 bit FP. */
9417 case 1: /* LDUR 8 bit FP. */
9418 case 4: /* STUR 16 bit FP. */
9419 case 5: /* LDUR 8 bit FP. */
9420 HALT_NYI;
9421
9422 default:
9423 case 6:
9424 case 7:
9425 case 10:
9426 case 11:
9427 case 14:
9428 case 15:
9429 HALT_UNALLOC;
9430 }
9431}
9432
9433/* N.B. A preliminary note regarding all the ldrs<x>32
9434 instructions
9435
9436 The signed value loaded by these instructions is cast to unsigned
9437 before being assigned to aarch64_get_reg_u64 (cpu, N) i.e. to the
9438 64 bit element of the GReg union. this performs a 32 bit sign extension
9439 (as required) but avoids 64 bit sign extension, thus ensuring that the
9440 top half of the register word is zero. this is what the spec demands
9441 when a 32 bit load occurs. */
9442
9443/* 32 bit load sign-extended byte scaled unsigned 12 bit. */
9444static void
9445ldrsb32_abs (sim_cpu *cpu, uint32_t offset)
9446{
9447 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9448 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9449
9450 /* The target register may not be SP but the source may be
9451 there is no scaling required for a byte load. */
9452 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
9453 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9454 (int64_t) aarch64_get_mem_s8 (cpu, address));
9455}
9456
9457/* 32 bit load sign-extended byte scaled or unscaled zero-
9458 or sign-extended 32-bit register offset. */
9459static void
9460ldrsb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9461{
9462 unsigned int rm = uimm (aarch64_get_instr (cpu), 20, 16);
9463 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9464 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9465
9466 /* rn may reference SP, rm and rt must reference ZR. */
9467
9468 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9469 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9470 extension);
9471
9472 /* There is no scaling required for a byte load. */
9473 aarch64_set_reg_u64
9474 (cpu, rt, NO_SP, (int64_t) aarch64_get_mem_s8 (cpu, address
9475 + displacement));
9476}
9477
9478/* 32 bit load sign-extended byte unscaled signed 9 bit with
9479 pre- or post-writeback. */
9480static void
9481ldrsb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9482{
9483 uint64_t address;
9484 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9485 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9486
9487 if (rn == rt && wb != NoWriteBack)
9488 HALT_UNALLOC;
9489
9490 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9491
9492 if (wb == Pre)
9493 address += offset;
9494
9495 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9496 (int64_t) aarch64_get_mem_s8 (cpu, address));
9497
9498 if (wb == Post)
9499 address += offset;
9500
9501 if (wb != NoWriteBack)
9502 aarch64_set_reg_u64 (cpu, rn, NO_SP, address);
9503}
9504
9505/* 8 bit store scaled. */
9506static void
9507fstrb_abs (sim_cpu *cpu, uint32_t offset)
9508{
9509 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9510 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9511
9512 aarch64_set_mem_u8 (cpu,
9513 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
9514 aarch64_get_vec_u8 (cpu, st, 0));
9515}
9516
9517/* 8 bit store scaled or unscaled zero- or
9518 sign-extended 8-bit register offset. */
9519static void
9520fstrb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9521{
9522 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9523 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9524 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9525
9526 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9527 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9528 extension);
9529 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9530
9531 aarch64_set_mem_u8
9532 (cpu, address + displacement, aarch64_get_vec_u8 (cpu, st, 0));
9533}
9534
9535/* 16 bit store scaled. */
9536static void
9537fstrh_abs (sim_cpu *cpu, uint32_t offset)
9538{
9539 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9540 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9541
9542 aarch64_set_mem_u16
9543 (cpu,
9544 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16),
9545 aarch64_get_vec_u16 (cpu, st, 0));
9546}
9547
9548/* 16 bit store scaled or unscaled zero-
9549 or sign-extended 16-bit register offset. */
9550static void
9551fstrh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9552{
9553 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9554 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9555 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9556
9557 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9558 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9559 extension);
9560 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9561
9562 aarch64_set_mem_u16
9563 (cpu, address + displacement, aarch64_get_vec_u16 (cpu, st, 0));
9564}
9565
9566/* 32 bit store scaled unsigned 12 bit. */
9567static void
9568fstrs_abs (sim_cpu *cpu, uint32_t offset)
9569{
9570 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9571 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9572
e101a78b 9573 aarch64_set_mem_u32
2e8cf49e
NC
9574 (cpu,
9575 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
e101a78b 9576 aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
9577}
9578
9579/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
9580static void
9581fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9582{
9583 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9584 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9585
9586 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9587
9588 if (wb != Post)
9589 address += offset;
9590
e101a78b 9591 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
9592
9593 if (wb == Post)
9594 address += offset;
9595
9596 if (wb != NoWriteBack)
9597 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9598}
9599
9600/* 32 bit store scaled or unscaled zero-
9601 or sign-extended 32-bit register offset. */
9602static void
9603fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9604{
9605 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9606 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9607 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9608
9609 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9610 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9611 extension);
9612 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9613
e101a78b
NC
9614 aarch64_set_mem_u32
9615 (cpu, address + displacement, aarch64_get_vec_u32 (cpu, st, 0));
2e8cf49e
NC
9616}
9617
9618/* 64 bit store scaled unsigned 12 bit. */
9619static void
9620fstrd_abs (sim_cpu *cpu, uint32_t offset)
9621{
9622 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9623 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9624
e101a78b 9625 aarch64_set_mem_u64
2e8cf49e
NC
9626 (cpu,
9627 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
e101a78b 9628 aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
9629}
9630
9631/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
9632static void
9633fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9634{
9635 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9636 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9637
9638 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9639
9640 if (wb != Post)
9641 address += offset;
9642
e101a78b 9643 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
9644
9645 if (wb == Post)
9646 address += offset;
9647
9648 if (wb != NoWriteBack)
9649 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9650}
9651
9652/* 64 bit store scaled or unscaled zero-
9653 or sign-extended 32-bit register offset. */
9654static void
9655fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9656{
9657 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9658 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9659 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9660
9661 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9662 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9663 extension);
9664 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
9665
e101a78b
NC
9666 aarch64_set_mem_u64
9667 (cpu, address + displacement, aarch64_get_vec_u64 (cpu, st, 0));
2e8cf49e
NC
9668}
9669
9670/* 128 bit store scaled unsigned 12 bit. */
9671static void
9672fstrq_abs (sim_cpu *cpu, uint32_t offset)
9673{
9674 FRegister a;
9675 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9676 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9677 uint64_t addr;
9678
9679 aarch64_get_FP_long_double (cpu, st, & a);
9680
9681 addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
9682 aarch64_set_mem_long_double (cpu, addr, a);
9683}
9684
9685/* 128 bit store unscaled signed 9 bit with pre- or post-writeback. */
9686static void
9687fstrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9688{
9689 FRegister a;
9690 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9691 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9692 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9693
9694 if (wb != Post)
9695 address += offset;
9696
9697 aarch64_get_FP_long_double (cpu, st, & a);
9698 aarch64_set_mem_long_double (cpu, address, a);
9699
9700 if (wb == Post)
9701 address += offset;
9702
9703 if (wb != NoWriteBack)
9704 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9705}
9706
9707/* 128 bit store scaled or unscaled zero-
9708 or sign-extended 32-bit register offset. */
9709static void
9710fstrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9711{
9712 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9713 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9714 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9715
9716 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9717 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9718 extension);
9719 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
9720
9721 FRegister a;
9722
9723 aarch64_get_FP_long_double (cpu, st, & a);
9724 aarch64_set_mem_long_double (cpu, address + displacement, a);
9725}
9726
9727static void
9728dexLoadImmediatePrePost (sim_cpu *cpu)
9729{
9730 /* instr[29,24] == 111_00
9731 instr[21] == 0
9732 instr[11,10] == 00
9733 instr[31,30] = size
9734 instr[26] = V
9735 instr[23,22] = opc
9736 instr[20,12] = simm9
9737 instr[11] = wb : 0 ==> Post, 1 ==> Pre
9738 instr[9,5] = rn may be SP. */
9739 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9740 uint32_t V = uimm (aarch64_get_instr (cpu), 26, 26);
9741 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9742 | uimm (aarch64_get_instr (cpu), 23, 22));
9743 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
9744 WriteBack wb = writeback (aarch64_get_instr (cpu), 11);
9745
9746 if (!V)
9747 {
9748 /* GReg operations. */
9749 switch (dispatch)
9750 {
9751 case 0: strb_wb (cpu, imm, wb); return;
9752 case 1: ldrb32_wb (cpu, imm, wb); return;
9753 case 2: ldrsb_wb (cpu, imm, wb); return;
9754 case 3: ldrsb32_wb (cpu, imm, wb); return;
9755 case 4: strh_wb (cpu, imm, wb); return;
9756 case 5: ldrh32_wb (cpu, imm, wb); return;
9757 case 6: ldrsh64_wb (cpu, imm, wb); return;
9758 case 7: ldrsh32_wb (cpu, imm, wb); return;
9759 case 8: str32_wb (cpu, imm, wb); return;
9760 case 9: ldr32_wb (cpu, imm, wb); return;
9761 case 10: ldrsw_wb (cpu, imm, wb); return;
9762 case 12: str_wb (cpu, imm, wb); return;
9763 case 13: ldr_wb (cpu, imm, wb); return;
9764
9765 default:
9766 case 11:
9767 case 14:
9768 case 15:
9769 HALT_UNALLOC;
9770 }
9771 }
9772
9773 /* FReg operations. */
9774 switch (dispatch)
9775 {
9776 case 2: fstrq_wb (cpu, imm, wb); return;
9777 case 3: fldrq_wb (cpu, imm, wb); return;
9778 case 8: fstrs_wb (cpu, imm, wb); return;
9779 case 9: fldrs_wb (cpu, imm, wb); return;
9780 case 12: fstrd_wb (cpu, imm, wb); return;
9781 case 13: fldrd_wb (cpu, imm, wb); return;
9782
9783 case 0: /* STUR 8 bit FP. */
9784 case 1: /* LDUR 8 bit FP. */
9785 case 4: /* STUR 16 bit FP. */
9786 case 5: /* LDUR 8 bit FP. */
9787 HALT_NYI;
9788
9789 default:
9790 case 6:
9791 case 7:
9792 case 10:
9793 case 11:
9794 case 14:
9795 case 15:
9796 HALT_UNALLOC;
9797 }
9798}
9799
9800static void
9801dexLoadRegisterOffset (sim_cpu *cpu)
9802{
9803 /* instr[31,30] = size
9804 instr[29,27] = 111
9805 instr[26] = V
9806 instr[25,24] = 00
9807 instr[23,22] = opc
9808 instr[21] = 1
9809 instr[20,16] = rm
9810 instr[15,13] = option : 010 ==> UXTW, 011 ==> UXTX/LSL,
9811 110 ==> SXTW, 111 ==> SXTX,
9812 ow ==> RESERVED
9813 instr[12] = scaled
9814 instr[11,10] = 10
9815 instr[9,5] = rn
9816 instr[4,0] = rt. */
9817
9818 uint32_t V = uimm (aarch64_get_instr (cpu), 26,26);
9819 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9820 | uimm (aarch64_get_instr (cpu), 23, 22));
9821 Scaling scale = scaling (aarch64_get_instr (cpu), 12);
9822 Extension extensionType = extension (aarch64_get_instr (cpu), 13);
9823
9824 /* Check for illegal extension types. */
9825 if (uimm (extensionType, 1, 1) == 0)
9826 HALT_UNALLOC;
9827
9828 if (extensionType == UXTX || extensionType == SXTX)
9829 extensionType = NoExtension;
9830
9831 if (!V)
9832 {
9833 /* GReg operations. */
9834 switch (dispatch)
9835 {
9836 case 0: strb_scale_ext (cpu, scale, extensionType); return;
9837 case 1: ldrb32_scale_ext (cpu, scale, extensionType); return;
9838 case 2: ldrsb_scale_ext (cpu, scale, extensionType); return;
9839 case 3: ldrsb32_scale_ext (cpu, scale, extensionType); return;
9840 case 4: strh_scale_ext (cpu, scale, extensionType); return;
9841 case 5: ldrh32_scale_ext (cpu, scale, extensionType); return;
9842 case 6: ldrsh_scale_ext (cpu, scale, extensionType); return;
9843 case 7: ldrsh32_scale_ext (cpu, scale, extensionType); return;
9844 case 8: str32_scale_ext (cpu, scale, extensionType); return;
9845 case 9: ldr32_scale_ext (cpu, scale, extensionType); return;
9846 case 10: ldrsw_scale_ext (cpu, scale, extensionType); return;
9847 case 12: str_scale_ext (cpu, scale, extensionType); return;
9848 case 13: ldr_scale_ext (cpu, scale, extensionType); return;
9849 case 14: prfm_scale_ext (cpu, scale, extensionType); return;
9850
9851 default:
9852 case 11:
9853 case 15:
9854 HALT_UNALLOC;
9855 }
9856 }
9857
9858 /* FReg operations. */
9859 switch (dispatch)
9860 {
9861 case 1: /* LDUR 8 bit FP. */
9862 HALT_NYI;
9863 case 3: fldrq_scale_ext (cpu, scale, extensionType); return;
9864 case 5: /* LDUR 8 bit FP. */
9865 HALT_NYI;
9866 case 9: fldrs_scale_ext (cpu, scale, extensionType); return;
9867 case 13: fldrd_scale_ext (cpu, scale, extensionType); return;
9868
9869 case 0: fstrb_scale_ext (cpu, scale, extensionType); return;
9870 case 2: fstrq_scale_ext (cpu, scale, extensionType); return;
9871 case 4: fstrh_scale_ext (cpu, scale, extensionType); return;
9872 case 8: fstrs_scale_ext (cpu, scale, extensionType); return;
9873 case 12: fstrd_scale_ext (cpu, scale, extensionType); return;
9874
9875 default:
9876 case 6:
9877 case 7:
9878 case 10:
9879 case 11:
9880 case 14:
9881 case 15:
9882 HALT_UNALLOC;
9883 }
9884}
9885
9886static void
9887dexLoadUnsignedImmediate (sim_cpu *cpu)
9888{
9889 /* assert instr[29,24] == 111_01
9890 instr[31,30] = size
9891 instr[26] = V
9892 instr[23,22] = opc
9893 instr[21,10] = uimm12 : unsigned immediate offset
9894 instr[9,5] = rn may be SP. */
9895 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9896 uint32_t V = uimm (aarch64_get_instr (cpu), 26,26);
9897 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9898 | uimm (aarch64_get_instr (cpu), 23, 22));
9899 uint32_t imm = uimm (aarch64_get_instr (cpu), 21, 10);
9900
9901 if (!V)
9902 {
9903 /* GReg operations. */
9904 switch (dispatch)
9905 {
9906 case 0: strb_abs (cpu, imm); return;
9907 case 1: ldrb32_abs (cpu, imm); return;
9908 case 2: ldrsb_abs (cpu, imm); return;
9909 case 3: ldrsb32_abs (cpu, imm); return;
9910 case 4: strh_abs (cpu, imm); return;
9911 case 5: ldrh32_abs (cpu, imm); return;
9912 case 6: ldrsh_abs (cpu, imm); return;
9913 case 7: ldrsh32_abs (cpu, imm); return;
9914 case 8: str32_abs (cpu, imm); return;
9915 case 9: ldr32_abs (cpu, imm); return;
9916 case 10: ldrsw_abs (cpu, imm); return;
9917 case 12: str_abs (cpu, imm); return;
9918 case 13: ldr_abs (cpu, imm); return;
9919 case 14: prfm_abs (cpu, imm); return;
9920
9921 default:
9922 case 11:
9923 case 15:
9924 HALT_UNALLOC;
9925 }
9926 }
9927
9928 /* FReg operations. */
9929 switch (dispatch)
9930 {
9931 case 3: fldrq_abs (cpu, imm); return;
9932 case 9: fldrs_abs (cpu, imm); return;
9933 case 13: fldrd_abs (cpu, imm); return;
9934
9935 case 0: fstrb_abs (cpu, imm); return;
9936 case 2: fstrq_abs (cpu, imm); return;
9937 case 4: fstrh_abs (cpu, imm); return;
9938 case 8: fstrs_abs (cpu, imm); return;
9939 case 12: fstrd_abs (cpu, imm); return;
9940
9941 case 1: /* LDR 8 bit FP. */
9942 case 5: /* LDR 8 bit FP. */
9943 HALT_NYI;
9944
9945 default:
9946 case 6:
9947 case 7:
9948 case 10:
9949 case 11:
9950 case 14:
9951 case 15:
9952 HALT_UNALLOC;
9953 }
9954}
9955
9956static void
9957dexLoadExclusive (sim_cpu *cpu)
9958{
9959 /* assert instr[29:24] = 001000;
9960 instr[31,30] = size
9961 instr[23] = 0 if exclusive
9962 instr[22] = L : 1 if load, 0 if store
9963 instr[21] = 1 if pair
9964 instr[20,16] = Rs
9965 instr[15] = o0 : 1 if ordered
9966 instr[14,10] = Rt2
9967 instr[9,5] = Rn
9968 instr[4.0] = Rt. */
9969
9970 switch (uimm (aarch64_get_instr (cpu), 22, 21))
9971 {
9972 case 2: ldxr (cpu); return;
9973 case 0: stxr (cpu); return;
9974 default: HALT_NYI;
9975 }
9976}
9977
9978static void
9979dexLoadOther (sim_cpu *cpu)
9980{
9981 uint32_t dispatch;
9982
9983 /* instr[29,25] = 111_0
9984 instr[24] == 0 ==> dispatch, 1 ==> ldst reg unsigned immediate
9985 instr[21:11,10] is the secondary dispatch. */
9986 if (uimm (aarch64_get_instr (cpu), 24, 24))
9987 {
9988 dexLoadUnsignedImmediate (cpu);
9989 return;
9990 }
9991
9992 dispatch = ( (uimm (aarch64_get_instr (cpu), 21, 21) << 2)
9993 | uimm (aarch64_get_instr (cpu), 11, 10));
9994 switch (dispatch)
9995 {
9996 case 0: dexLoadUnscaledImmediate (cpu); return;
9997 case 1: dexLoadImmediatePrePost (cpu); return;
9998 case 3: dexLoadImmediatePrePost (cpu); return;
9999 case 6: dexLoadRegisterOffset (cpu); return;
10000
10001 default:
10002 case 2:
10003 case 4:
10004 case 5:
10005 case 7:
10006 HALT_NYI;
10007 }
10008}
10009
10010static void
10011store_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10012{
10013 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10014 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10015 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10016 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10017
10018 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10019 HALT_UNALLOC; /* ??? */
10020
10021 offset <<= 2;
10022
10023 if (wb != Post)
10024 address += offset;
10025
10026 aarch64_set_mem_u32 (cpu, address,
10027 aarch64_get_reg_u32 (cpu, rm, NO_SP));
10028 aarch64_set_mem_u32 (cpu, address + 4,
10029 aarch64_get_reg_u32 (cpu, rn, NO_SP));
10030
10031 if (wb == Post)
10032 address += offset;
10033
10034 if (wb != NoWriteBack)
10035 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10036}
10037
10038static void
10039store_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10040{
10041 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10042 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10043 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10044 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10045
10046 if ((rn == rd || rm == rd) && wb != NoWriteBack)
10047 HALT_UNALLOC; /* ??? */
10048
10049 offset <<= 3;
10050
10051 if (wb != Post)
10052 address += offset;
10053
10054 aarch64_set_mem_u64 (cpu, address,
10055 aarch64_get_reg_u64 (cpu, rm, SP_OK));
10056 aarch64_set_mem_u64 (cpu, address + 8,
10057 aarch64_get_reg_u64 (cpu, rn, SP_OK));
10058
10059 if (wb == Post)
10060 address += offset;
10061
10062 if (wb != NoWriteBack)
10063 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10064}
10065
10066static void
10067load_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10068{
10069 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10070 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10071 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10072 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10073
10074 /* treat this as unalloc to make sure we don't do it. */
10075 if (rn == rm)
10076 HALT_UNALLOC;
10077
10078 offset <<= 2;
10079
10080 if (wb != Post)
10081 address += offset;
10082
10083 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u32 (cpu, address));
10084 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u32 (cpu, address + 4));
10085
10086 if (wb == Post)
10087 address += offset;
10088
10089 if (wb != NoWriteBack)
10090 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10091}
10092
10093static void
10094load_pair_s32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10095{
10096 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10097 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10098 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10099 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10100
10101 /* Treat this as unalloc to make sure we don't do it. */
10102 if (rn == rm)
10103 HALT_UNALLOC;
10104
10105 offset <<= 2;
10106
10107 if (wb != Post)
10108 address += offset;
10109
10110 aarch64_set_reg_s64 (cpu, rm, SP_OK, aarch64_get_mem_s32 (cpu, address));
10111 aarch64_set_reg_s64 (cpu, rn, SP_OK, aarch64_get_mem_s32 (cpu, address + 4));
10112
10113 if (wb == Post)
10114 address += offset;
10115
10116 if (wb != NoWriteBack)
10117 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10118}
10119
10120static void
10121load_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10122{
10123 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10124 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10125 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10126 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10127
10128 /* Treat this as unalloc to make sure we don't do it. */
10129 if (rn == rm)
10130 HALT_UNALLOC;
10131
10132 offset <<= 3;
10133
10134 if (wb != Post)
10135 address += offset;
10136
10137 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u64 (cpu, address));
10138 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u64 (cpu, address + 8));
10139
10140 if (wb == Post)
10141 address += offset;
10142
10143 if (wb != NoWriteBack)
10144 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10145}
10146
10147static void
10148dex_load_store_pair_gr (sim_cpu *cpu)
10149{
10150 /* instr[31,30] = size (10=> 64-bit, 01=> signed 32-bit, 00=> 32-bit)
10151 instr[29,25] = instruction encoding: 101_0
10152 instr[26] = V : 1 if fp 0 if gp
10153 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10154 instr[22] = load/store (1=> load)
10155 instr[21,15] = signed, scaled, offset
10156 instr[14,10] = Rn
10157 instr[ 9, 5] = Rd
10158 instr[ 4, 0] = Rm. */
10159
10160 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 3)
10161 | uimm (aarch64_get_instr (cpu), 24, 22));
10162 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10163
10164 switch (dispatch)
10165 {
10166 case 2: store_pair_u32 (cpu, offset, Post); return;
10167 case 3: load_pair_u32 (cpu, offset, Post); return;
10168 case 4: store_pair_u32 (cpu, offset, NoWriteBack); return;
10169 case 5: load_pair_u32 (cpu, offset, NoWriteBack); return;
10170 case 6: store_pair_u32 (cpu, offset, Pre); return;
10171 case 7: load_pair_u32 (cpu, offset, Pre); return;
10172
10173 case 11: load_pair_s32 (cpu, offset, Post); return;
10174 case 13: load_pair_s32 (cpu, offset, NoWriteBack); return;
10175 case 15: load_pair_s32 (cpu, offset, Pre); return;
10176
10177 case 18: store_pair_u64 (cpu, offset, Post); return;
10178 case 19: load_pair_u64 (cpu, offset, Post); return;
10179 case 20: store_pair_u64 (cpu, offset, NoWriteBack); return;
10180 case 21: load_pair_u64 (cpu, offset, NoWriteBack); return;
10181 case 22: store_pair_u64 (cpu, offset, Pre); return;
10182 case 23: load_pair_u64 (cpu, offset, Pre); return;
10183
10184 default:
10185 HALT_UNALLOC;
10186 }
10187}
10188
10189static void
10190store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10191{
10192 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10193 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10194 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10195 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10196
10197 offset <<= 2;
10198
10199 if (wb != Post)
10200 address += offset;
10201
e101a78b
NC
10202 aarch64_set_mem_u32 (cpu, address, aarch64_get_vec_u32 (cpu, rm, 0));
10203 aarch64_set_mem_u32 (cpu, address + 4, aarch64_get_vec_u32 (cpu, rn, 0));
2e8cf49e
NC
10204
10205 if (wb == Post)
10206 address += offset;
10207
10208 if (wb != NoWriteBack)
10209 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10210}
10211
10212static void
10213store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10214{
10215 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10216 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10217 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10218 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10219
10220 offset <<= 3;
10221
10222 if (wb != Post)
10223 address += offset;
10224
e101a78b
NC
10225 aarch64_set_mem_u64 (cpu, address, aarch64_get_vec_u64 (cpu, rm, 0));
10226 aarch64_set_mem_u64 (cpu, address + 8, aarch64_get_vec_u64 (cpu, rn, 0));
2e8cf49e
NC
10227
10228 if (wb == Post)
10229 address += offset;
10230
10231 if (wb != NoWriteBack)
10232 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10233}
10234
10235static void
10236store_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10237{
10238 FRegister a;
10239 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10240 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10241 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10242 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10243
10244 offset <<= 4;
10245
10246 if (wb != Post)
10247 address += offset;
10248
10249 aarch64_get_FP_long_double (cpu, rm, & a);
10250 aarch64_set_mem_long_double (cpu, address, a);
10251 aarch64_get_FP_long_double (cpu, rn, & a);
10252 aarch64_set_mem_long_double (cpu, address + 16, a);
10253
10254 if (wb == Post)
10255 address += offset;
10256
10257 if (wb != NoWriteBack)
10258 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10259}
10260
10261static void
10262load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10263{
10264 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10265 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10266 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10267 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10268
10269 if (rm == rn)
10270 HALT_UNALLOC;
10271
10272 offset <<= 2;
10273
10274 if (wb != Post)
10275 address += offset;
10276
e101a78b
NC
10277 aarch64_set_vec_u32 (cpu, rm, 0, aarch64_get_mem_u32 (cpu, address));
10278 aarch64_set_vec_u32 (cpu, rn, 0, aarch64_get_mem_u32 (cpu, address + 4));
2e8cf49e
NC
10279
10280 if (wb == Post)
10281 address += offset;
10282
10283 if (wb != NoWriteBack)
10284 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10285}
10286
10287static void
10288load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10289{
10290 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10291 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10292 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10293 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10294
10295 if (rm == rn)
10296 HALT_UNALLOC;
10297
10298 offset <<= 3;
10299
10300 if (wb != Post)
10301 address += offset;
10302
e101a78b
NC
10303 aarch64_set_vec_u64 (cpu, rm, 0, aarch64_get_mem_u64 (cpu, address));
10304 aarch64_set_vec_u64 (cpu, rn, 0, aarch64_get_mem_u64 (cpu, address + 8));
2e8cf49e
NC
10305
10306 if (wb == Post)
10307 address += offset;
10308
10309 if (wb != NoWriteBack)
10310 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10311}
10312
10313static void
10314load_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10315{
10316 FRegister a;
10317 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10318 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10319 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10320 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10321
10322 if (rm == rn)
10323 HALT_UNALLOC;
10324
10325 offset <<= 4;
10326
10327 if (wb != Post)
10328 address += offset;
10329
10330 aarch64_get_mem_long_double (cpu, address, & a);
10331 aarch64_set_FP_long_double (cpu, rm, a);
10332 aarch64_get_mem_long_double (cpu, address + 16, & a);
10333 aarch64_set_FP_long_double (cpu, rn, a);
10334
10335 if (wb == Post)
10336 address += offset;
10337
10338 if (wb != NoWriteBack)
10339 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10340}
10341
10342static void
10343dex_load_store_pair_fp (sim_cpu *cpu)
10344{
10345 /* instr[31,30] = size (10=> 128-bit, 01=> 64-bit, 00=> 32-bit)
10346 instr[29,25] = instruction encoding
10347 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10348 instr[22] = load/store (1=> load)
10349 instr[21,15] = signed, scaled, offset
10350 instr[14,10] = Rn
10351 instr[ 9, 5] = Rd
10352 instr[ 4, 0] = Rm */
10353
10354 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 3)
10355 | uimm (aarch64_get_instr (cpu), 24, 22));
10356 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10357
10358 switch (dispatch)
10359 {
10360 case 2: store_pair_float (cpu, offset, Post); return;
10361 case 3: load_pair_float (cpu, offset, Post); return;
10362 case 4: store_pair_float (cpu, offset, NoWriteBack); return;
10363 case 5: load_pair_float (cpu, offset, NoWriteBack); return;
10364 case 6: store_pair_float (cpu, offset, Pre); return;
10365 case 7: load_pair_float (cpu, offset, Pre); return;
10366
10367 case 10: store_pair_double (cpu, offset, Post); return;
10368 case 11: load_pair_double (cpu, offset, Post); return;
10369 case 12: store_pair_double (cpu, offset, NoWriteBack); return;
10370 case 13: load_pair_double (cpu, offset, NoWriteBack); return;
10371 case 14: store_pair_double (cpu, offset, Pre); return;
10372 case 15: load_pair_double (cpu, offset, Pre); return;
10373
10374 case 18: store_pair_long_double (cpu, offset, Post); return;
10375 case 19: load_pair_long_double (cpu, offset, Post); return;
10376 case 20: store_pair_long_double (cpu, offset, NoWriteBack); return;
10377 case 21: load_pair_long_double (cpu, offset, NoWriteBack); return;
10378 case 22: store_pair_long_double (cpu, offset, Pre); return;
10379 case 23: load_pair_long_double (cpu, offset, Pre); return;
10380
10381 default:
10382 HALT_UNALLOC;
10383 }
10384}
10385
10386static inline unsigned
10387vec_reg (unsigned v, unsigned o)
10388{
10389 return (v + o) & 0x3F;
10390}
10391
10392/* Load multiple N-element structures to N consecutive registers. */
10393static void
10394vec_load (sim_cpu *cpu, uint64_t address, unsigned N)
10395{
10396 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10397 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10398 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10399 unsigned i;
10400
10401 switch (size)
10402 {
10403 case 0: /* 8-bit operations. */
10404 if (all)
10405 for (i = 0; i < (16 * N); i++)
10406 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15,
10407 aarch64_get_mem_u8 (cpu, address + i));
10408 else
10409 for (i = 0; i < (8 * N); i++)
10410 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7,
10411 aarch64_get_mem_u8 (cpu, address + i));
10412 return;
10413
10414 case 1: /* 16-bit operations. */
10415 if (all)
10416 for (i = 0; i < (8 * N); i++)
10417 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7,
10418 aarch64_get_mem_u16 (cpu, address + i * 2));
10419 else
10420 for (i = 0; i < (4 * N); i++)
10421 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3,
10422 aarch64_get_mem_u16 (cpu, address + i * 2));
10423 return;
10424
10425 case 2: /* 32-bit operations. */
10426 if (all)
10427 for (i = 0; i < (4 * N); i++)
10428 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3,
10429 aarch64_get_mem_u32 (cpu, address + i * 4));
10430 else
10431 for (i = 0; i < (2 * N); i++)
10432 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1,
10433 aarch64_get_mem_u32 (cpu, address + i * 4));
10434 return;
10435
10436 case 3: /* 64-bit operations. */
10437 if (all)
10438 for (i = 0; i < (2 * N); i++)
10439 aarch64_set_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1,
10440 aarch64_get_mem_u64 (cpu, address + i * 8));
10441 else
10442 for (i = 0; i < N; i++)
10443 aarch64_set_vec_u64 (cpu, vec_reg (vd, i), 0,
10444 aarch64_get_mem_u64 (cpu, address + i * 8));
10445 return;
10446
10447 default:
10448 HALT_UNREACHABLE;
10449 }
10450}
10451
10452/* LD4: load multiple 4-element to four consecutive registers. */
10453static void
10454LD4 (sim_cpu *cpu, uint64_t address)
10455{
10456 vec_load (cpu, address, 4);
10457}
10458
10459/* LD3: load multiple 3-element structures to three consecutive registers. */
10460static void
10461LD3 (sim_cpu *cpu, uint64_t address)
10462{
10463 vec_load (cpu, address, 3);
10464}
10465
10466/* LD2: load multiple 2-element structures to two consecutive registers. */
10467static void
10468LD2 (sim_cpu *cpu, uint64_t address)
10469{
10470 vec_load (cpu, address, 2);
10471}
10472
10473/* Load multiple 1-element structures into one register. */
10474static void
10475LD1_1 (sim_cpu *cpu, uint64_t address)
10476{
10477 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10478 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10479 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10480 unsigned i;
10481
10482 switch (size)
10483 {
10484 case 0:
10485 /* LD1 {Vd.16b}, addr, #16 */
10486 /* LD1 {Vd.8b}, addr, #8 */
10487 for (i = 0; i < (all ? 16 : 8); i++)
10488 aarch64_set_vec_u8 (cpu, vd, i,
10489 aarch64_get_mem_u8 (cpu, address + i));
10490 return;
10491
10492 case 1:
10493 /* LD1 {Vd.8h}, addr, #16 */
10494 /* LD1 {Vd.4h}, addr, #8 */
10495 for (i = 0; i < (all ? 8 : 4); i++)
10496 aarch64_set_vec_u16 (cpu, vd, i,
10497 aarch64_get_mem_u16 (cpu, address + i * 2));
10498 return;
10499
10500 case 2:
10501 /* LD1 {Vd.4s}, addr, #16 */
10502 /* LD1 {Vd.2s}, addr, #8 */
10503 for (i = 0; i < (all ? 4 : 2); i++)
10504 aarch64_set_vec_u32 (cpu, vd, i,
10505 aarch64_get_mem_u32 (cpu, address + i * 4));
10506 return;
10507
10508 case 3:
10509 /* LD1 {Vd.2d}, addr, #16 */
10510 /* LD1 {Vd.1d}, addr, #8 */
10511 for (i = 0; i < (all ? 2 : 1); i++)
10512 aarch64_set_vec_u64 (cpu, vd, i,
10513 aarch64_get_mem_u64 (cpu, address + i * 8));
10514 return;
10515
10516 default:
10517 HALT_UNREACHABLE;
10518 }
10519}
10520
10521/* Load multiple 1-element structures into two registers. */
10522static void
10523LD1_2 (sim_cpu *cpu, uint64_t address)
10524{
10525 /* FIXME: This algorithm is *exactly* the same as the LD2 version.
10526 So why have two different instructions ? There must be something
10527 wrong somewhere. */
10528 vec_load (cpu, address, 2);
10529}
10530
10531/* Load multiple 1-element structures into three registers. */
10532static void
10533LD1_3 (sim_cpu *cpu, uint64_t address)
10534{
10535 /* FIXME: This algorithm is *exactly* the same as the LD3 version.
10536 So why have two different instructions ? There must be something
10537 wrong somewhere. */
10538 vec_load (cpu, address, 3);
10539}
10540
10541/* Load multiple 1-element structures into four registers. */
10542static void
10543LD1_4 (sim_cpu *cpu, uint64_t address)
10544{
10545 /* FIXME: This algorithm is *exactly* the same as the LD4 version.
10546 So why have two different instructions ? There must be something
10547 wrong somewhere. */
10548 vec_load (cpu, address, 4);
10549}
10550
10551/* Store multiple N-element structures to N consecutive registers. */
10552static void
10553vec_store (sim_cpu *cpu, uint64_t address, unsigned N)
10554{
10555 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10556 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10557 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10558 unsigned i;
10559
10560 switch (size)
10561 {
10562 case 0: /* 8-bit operations. */
10563 if (all)
10564 for (i = 0; i < (16 * N); i++)
10565 aarch64_set_mem_u8
10566 (cpu, address + i,
10567 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15));
10568 else
10569 for (i = 0; i < (8 * N); i++)
10570 aarch64_set_mem_u8
10571 (cpu, address + i,
10572 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7));
10573 return;
10574
10575 case 1: /* 16-bit operations. */
10576 if (all)
10577 for (i = 0; i < (8 * N); i++)
10578 aarch64_set_mem_u16
10579 (cpu, address + i * 2,
10580 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7));
10581 else
10582 for (i = 0; i < (4 * N); i++)
10583 aarch64_set_mem_u16
10584 (cpu, address + i * 2,
10585 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3));
10586 return;
10587
10588 case 2: /* 32-bit operations. */
10589 if (all)
10590 for (i = 0; i < (4 * N); i++)
10591 aarch64_set_mem_u32
10592 (cpu, address + i * 4,
10593 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3));
10594 else
10595 for (i = 0; i < (2 * N); i++)
10596 aarch64_set_mem_u32
10597 (cpu, address + i * 4,
10598 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1));
10599 return;
10600
10601 case 3: /* 64-bit operations. */
10602 if (all)
10603 for (i = 0; i < (2 * N); i++)
10604 aarch64_set_mem_u64
10605 (cpu, address + i * 8,
10606 aarch64_get_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1));
10607 else
10608 for (i = 0; i < N; i++)
10609 aarch64_set_mem_u64
10610 (cpu, address + i * 8,
10611 aarch64_get_vec_u64 (cpu, vec_reg (vd, i), 0));
10612 return;
10613
10614 default:
10615 HALT_UNREACHABLE;
10616 }
10617}
10618
10619/* Store multiple 4-element structure to four consecutive registers. */
10620static void
10621ST4 (sim_cpu *cpu, uint64_t address)
10622{
10623 vec_store (cpu, address, 4);
10624}
10625
10626/* Store multiple 3-element structures to three consecutive registers. */
10627static void
10628ST3 (sim_cpu *cpu, uint64_t address)
10629{
10630 vec_store (cpu, address, 3);
10631}
10632
10633/* Store multiple 2-element structures to two consecutive registers. */
10634static void
10635ST2 (sim_cpu *cpu, uint64_t address)
10636{
10637 vec_store (cpu, address, 2);
10638}
10639
10640/* Store multiple 1-element structures into one register. */
10641static void
10642ST1_1 (sim_cpu *cpu, uint64_t address)
10643{
10644 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10645 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10646 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10647 unsigned i;
10648
10649 switch (size)
10650 {
10651 case 0:
10652 for (i = 0; i < (all ? 16 : 8); i++)
10653 aarch64_set_mem_u8 (cpu, address + i,
10654 aarch64_get_vec_u8 (cpu, vd, i));
10655 return;
10656
10657 case 1:
10658 for (i = 0; i < (all ? 8 : 4); i++)
10659 aarch64_set_mem_u16 (cpu, address + i * 2,
10660 aarch64_get_vec_u16 (cpu, vd, i));
10661 return;
10662
10663 case 2:
10664 for (i = 0; i < (all ? 4 : 2); i++)
10665 aarch64_set_mem_u32 (cpu, address + i * 4,
10666 aarch64_get_vec_u32 (cpu, vd, i));
10667 return;
10668
10669 case 3:
10670 for (i = 0; i < (all ? 2 : 1); i++)
10671 aarch64_set_mem_u64 (cpu, address + i * 8,
10672 aarch64_get_vec_u64 (cpu, vd, i));
10673 return;
10674
10675 default:
10676 HALT_UNREACHABLE;
10677 }
10678}
10679
10680/* Store multiple 1-element structures into two registers. */
10681static void
10682ST1_2 (sim_cpu *cpu, uint64_t address)
10683{
10684 /* FIXME: This algorithm is *exactly* the same as the ST2 version.
10685 So why have two different instructions ? There must be
10686 something wrong somewhere. */
10687 vec_store (cpu, address, 2);
10688}
10689
10690/* Store multiple 1-element structures into three registers. */
10691static void
10692ST1_3 (sim_cpu *cpu, uint64_t address)
10693{
10694 /* FIXME: This algorithm is *exactly* the same as the ST3 version.
10695 So why have two different instructions ? There must be
10696 something wrong somewhere. */
10697 vec_store (cpu, address, 3);
10698}
10699
10700/* Store multiple 1-element structures into four registers. */
10701static void
10702ST1_4 (sim_cpu *cpu, uint64_t address)
10703{
10704 /* FIXME: This algorithm is *exactly* the same as the ST4 version.
10705 So why have two different instructions ? There must be
10706 something wrong somewhere. */
10707 vec_store (cpu, address, 4);
10708}
10709
10710static void
10711do_vec_LDnR (sim_cpu *cpu, uint64_t address)
10712{
10713 /* instr[31] = 0
10714 instr[30] = element selector 0=>half, 1=>all elements
10715 instr[29,24] = 00 1101
10716 instr[23] = 0=>simple, 1=>post
10717 instr[22] = 1
10718 instr[21] = width: LD1R-or-LD3R (0) / LD2R-or-LD4R (1)
10719 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
10720 11111 (immediate post inc)
10721 instr[15,14] = 11
10722 instr[13] = width: LD1R-or-LD2R (0) / LD3R-or-LD4R (1)
10723 instr[12] = 0
10724 instr[11,10] = element size 00=> byte(b), 01=> half(h),
10725 10=> word(s), 11=> double(d)
10726 instr[9,5] = address
10727 instr[4,0] = Vd */
10728
10729 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
10730 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10731 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10732 int i;
10733
10734 NYI_assert (29, 24, 0x0D);
10735 NYI_assert (22, 22, 1);
10736 NYI_assert (15, 14, 3);
10737 NYI_assert (12, 12, 0);
10738
10739 switch ((uimm (aarch64_get_instr (cpu), 13, 13) << 1)
10740 | uimm (aarch64_get_instr (cpu), 21, 21))
10741 {
10742 case 0: /* LD1R. */
10743 switch (size)
10744 {
10745 case 0:
10746 {
10747 uint8_t val = aarch64_get_mem_u8 (cpu, address);
10748 for (i = 0; i < (full ? 16 : 8); i++)
10749 aarch64_set_vec_u8 (cpu, vd, i, val);
10750 break;
10751 }
10752
10753 case 1:
10754 {
10755 uint16_t val = aarch64_get_mem_u16 (cpu, address);
10756 for (i = 0; i < (full ? 8 : 4); i++)
10757 aarch64_set_vec_u16 (cpu, vd, i, val);
10758 break;
10759 }
10760
10761 case 2:
10762 {
10763 uint32_t val = aarch64_get_mem_u32 (cpu, address);
10764 for (i = 0; i < (full ? 4 : 2); i++)
10765 aarch64_set_vec_u32 (cpu, vd, i, val);
10766 break;
10767 }
10768
10769 case 3:
10770 {
10771 uint64_t val = aarch64_get_mem_u64 (cpu, address);
10772 for (i = 0; i < (full ? 2 : 1); i++)
10773 aarch64_set_vec_u64 (cpu, vd, i, val);
10774 break;
10775 }
10776
10777 default:
10778 HALT_UNALLOC;
10779 }
10780 break;
10781
10782 case 1: /* LD2R. */
10783 switch (size)
10784 {
10785 case 0:
10786 {
10787 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10788 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10789
10790 for (i = 0; i < (full ? 16 : 8); i++)
10791 {
10792 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10793 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10794 }
10795 break;
10796 }
10797
10798 case 1:
10799 {
10800 uint16_t val1 = aarch64_get_mem_u16 (cpu, address);
10801 uint16_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10802
10803 for (i = 0; i < (full ? 8 : 4); i++)
10804 {
10805 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10806 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10807 }
10808 break;
10809 }
10810
10811 case 2:
10812 {
10813 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10814 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10815
10816 for (i = 0; i < (full ? 4 : 2); i++)
10817 {
10818 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10819 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10820 }
10821 break;
10822 }
10823
10824 case 3:
10825 {
10826 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10827 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10828
10829 for (i = 0; i < (full ? 2 : 1); i++)
10830 {
10831 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10832 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10833 }
10834 break;
10835 }
10836
10837 default:
10838 HALT_UNALLOC;
10839 }
10840 break;
10841
10842 case 2: /* LD3R. */
10843 switch (size)
10844 {
10845 case 0:
10846 {
10847 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10848 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10849 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
10850
10851 for (i = 0; i < (full ? 16 : 8); i++)
10852 {
10853 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10854 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10855 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
10856 }
10857 }
10858 break;
10859
10860 case 1:
10861 {
10862 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
10863 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10864 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
10865
10866 for (i = 0; i < (full ? 8 : 4); i++)
10867 {
10868 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10869 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10870 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
10871 }
10872 }
10873 break;
10874
10875 case 2:
10876 {
10877 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10878 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10879 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
10880
10881 for (i = 0; i < (full ? 4 : 2); i++)
10882 {
10883 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10884 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10885 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
10886 }
10887 }
10888 break;
10889
10890 case 3:
10891 {
10892 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10893 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10894 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
10895
10896 for (i = 0; i < (full ? 2 : 1); i++)
10897 {
10898 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10899 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10900 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
10901 }
10902 }
10903 break;
10904
10905 default:
10906 HALT_UNALLOC;
10907 }
10908 break;
10909
10910 case 3: /* LD4R. */
10911 switch (size)
10912 {
10913 case 0:
10914 {
10915 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10916 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10917 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
10918 uint8_t val4 = aarch64_get_mem_u8 (cpu, address + 3);
10919
10920 for (i = 0; i < (full ? 16 : 8); i++)
10921 {
10922 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10923 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10924 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
10925 aarch64_set_vec_u8 (cpu, vd + 3, 0, val4);
10926 }
10927 }
10928 break;
10929
10930 case 1:
10931 {
10932 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
10933 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10934 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
10935 uint32_t val4 = aarch64_get_mem_u16 (cpu, address + 6);
10936
10937 for (i = 0; i < (full ? 8 : 4); i++)
10938 {
10939 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10940 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10941 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
10942 aarch64_set_vec_u16 (cpu, vd + 3, 0, val4);
10943 }
10944 }
10945 break;
10946
10947 case 2:
10948 {
10949 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10950 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10951 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
10952 uint32_t val4 = aarch64_get_mem_u32 (cpu, address + 12);
10953
10954 for (i = 0; i < (full ? 4 : 2); i++)
10955 {
10956 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10957 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10958 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
10959 aarch64_set_vec_u32 (cpu, vd + 3, 0, val4);
10960 }
10961 }
10962 break;
10963
10964 case 3:
10965 {
10966 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10967 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10968 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
10969 uint64_t val4 = aarch64_get_mem_u64 (cpu, address + 24);
10970
10971 for (i = 0; i < (full ? 2 : 1); i++)
10972 {
10973 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10974 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10975 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
10976 aarch64_set_vec_u64 (cpu, vd + 3, 0, val4);
10977 }
10978 }
10979 break;
10980
10981 default:
10982 HALT_UNALLOC;
10983 }
10984 break;
10985
10986 default:
10987 HALT_UNALLOC;
10988 }
10989}
10990
10991static void
10992do_vec_load_store (sim_cpu *cpu)
10993{
10994 /* {LD|ST}<N> {Vd..Vd+N}, vaddr
10995
10996 instr[31] = 0
10997 instr[30] = element selector 0=>half, 1=>all elements
10998 instr[29,25] = 00110
10999 instr[24] = ?
11000 instr[23] = 0=>simple, 1=>post
11001 instr[22] = 0=>store, 1=>load
11002 instr[21] = 0 (LDn) / small(0)-large(1) selector (LDnR)
11003 instr[20,16] = 00000 (simple), Vinc (reg-post-inc, no SP),
11004 11111 (immediate post inc)
11005 instr[15,12] = elements and destinations. eg for load:
11006 0000=>LD4 => load multiple 4-element to
11007 four consecutive registers
11008 0100=>LD3 => load multiple 3-element to
11009 three consecutive registers
11010 1000=>LD2 => load multiple 2-element to
11011 two consecutive registers
11012 0010=>LD1 => load multiple 1-element to
11013 four consecutive registers
11014 0110=>LD1 => load multiple 1-element to
11015 three consecutive registers
11016 1010=>LD1 => load multiple 1-element to
11017 two consecutive registers
11018 0111=>LD1 => load multiple 1-element to
11019 one register
11020 1100=>LDR1,LDR2
11021 1110=>LDR3,LDR4
11022 instr[11,10] = element size 00=> byte(b), 01=> half(h),
11023 10=> word(s), 11=> double(d)
11024 instr[9,5] = Vn, can be SP
11025 instr[4,0] = Vd */
11026
11027 int post;
11028 int load;
11029 unsigned vn;
11030 uint64_t address;
11031 int type;
11032
11033 if (uimm (aarch64_get_instr (cpu), 31, 31) != 0
11034 || uimm (aarch64_get_instr (cpu), 29, 25) != 0x06)
11035 HALT_NYI;
11036
11037 type = uimm (aarch64_get_instr (cpu), 15, 12);
11038 if (type != 0xE && type != 0xE && uimm (aarch64_get_instr (cpu), 21, 21) != 0)
11039 HALT_NYI;
11040
11041 post = uimm (aarch64_get_instr (cpu), 23, 23);
11042 load = uimm (aarch64_get_instr (cpu), 22, 22);
11043 vn = uimm (aarch64_get_instr (cpu), 9, 5);
11044 address = aarch64_get_reg_u64 (cpu, vn, SP_OK);
11045
11046 if (post)
11047 {
11048 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
11049
11050 if (vm == R31)
11051 {
11052 unsigned sizeof_operation;
11053
11054 switch (type)
11055 {
11056 case 0: sizeof_operation = 32; break;
11057 case 4: sizeof_operation = 24; break;
11058 case 8: sizeof_operation = 16; break;
11059
11060 case 0xC:
11061 sizeof_operation = uimm (aarch64_get_instr (cpu), 21, 21) ? 2 : 1;
11062 sizeof_operation <<= uimm (aarch64_get_instr (cpu), 11, 10);
11063 break;
11064
11065 case 0xE:
11066 sizeof_operation = uimm (aarch64_get_instr (cpu), 21, 21) ? 8 : 4;
11067 sizeof_operation <<= uimm (aarch64_get_instr (cpu), 11, 10);
11068 break;
11069
2e8cf49e 11070 case 7:
57aa1742
NC
11071 /* One register, immediate offset variant. */
11072 sizeof_operation = 8;
11073 break;
11074
11075 case 10:
11076 /* Two registers, immediate offset variant. */
11077 sizeof_operation = 16;
11078 break;
11079
11080 case 6:
11081 /* Three registers, immediate offset variant. */
11082 sizeof_operation = 24;
11083 break;
11084
11085 case 2:
11086 /* Four registers, immediate offset variant. */
11087 sizeof_operation = 32;
2e8cf49e
NC
11088 break;
11089
11090 default:
11091 HALT_UNALLOC;
11092 }
11093
11094 if (uimm (aarch64_get_instr (cpu), 30, 30))
11095 sizeof_operation *= 2;
11096
11097 aarch64_set_reg_u64 (cpu, vn, SP_OK, address + sizeof_operation);
11098 }
11099 else
11100 aarch64_set_reg_u64 (cpu, vn, SP_OK,
11101 address + aarch64_get_reg_u64 (cpu, vm, NO_SP));
11102 }
11103 else
11104 {
11105 NYI_assert (20, 16, 0);
11106 }
11107
11108 if (load)
11109 {
11110 switch (type)
11111 {
11112 case 0: LD4 (cpu, address); return;
11113 case 4: LD3 (cpu, address); return;
11114 case 8: LD2 (cpu, address); return;
11115 case 2: LD1_4 (cpu, address); return;
11116 case 6: LD1_3 (cpu, address); return;
11117 case 10: LD1_2 (cpu, address); return;
11118 case 7: LD1_1 (cpu, address); return;
11119
11120 case 0xE:
11121 case 0xC: do_vec_LDnR (cpu, address); return;
11122
11123 default:
11124 HALT_NYI;
11125 }
11126 }
11127
11128 /* Stores. */
11129 switch (type)
11130 {
11131 case 0: ST4 (cpu, address); return;
11132 case 4: ST3 (cpu, address); return;
11133 case 8: ST2 (cpu, address); return;
11134 case 2: ST1_4 (cpu, address); return;
11135 case 6: ST1_3 (cpu, address); return;
11136 case 10: ST1_2 (cpu, address); return;
11137 case 7: ST1_1 (cpu, address); return;
11138 default:
11139 HALT_NYI;
11140 }
11141}
11142
11143static void
11144dexLdSt (sim_cpu *cpu)
11145{
11146 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
11147 assert group == GROUP_LDST_0100 || group == GROUP_LDST_0110 ||
11148 group == GROUP_LDST_1100 || group == GROUP_LDST_1110
11149 bits [29,28:26] of a LS are the secondary dispatch vector. */
11150 uint32_t group2 = dispatchLS (aarch64_get_instr (cpu));
11151
11152 switch (group2)
11153 {
11154 case LS_EXCL_000:
11155 dexLoadExclusive (cpu); return;
11156
11157 case LS_LIT_010:
11158 case LS_LIT_011:
11159 dexLoadLiteral (cpu); return;
11160
11161 case LS_OTHER_110:
11162 case LS_OTHER_111:
11163 dexLoadOther (cpu); return;
11164
11165 case LS_ADVSIMD_001:
11166 do_vec_load_store (cpu); return;
11167
11168 case LS_PAIR_100:
11169 dex_load_store_pair_gr (cpu); return;
11170
11171 case LS_PAIR_101:
11172 dex_load_store_pair_fp (cpu); return;
11173
11174 default:
11175 /* Should never reach here. */
11176 HALT_NYI;
11177 }
11178}
11179
11180/* Specific decode and execute for group Data Processing Register. */
11181
11182static void
11183dexLogicalShiftedRegister (sim_cpu *cpu)
11184{
11185 /* assert instr[28:24] = 01010
11186 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11187 instr[30,29:21] = op,N : 000 ==> AND, 001 ==> BIC,
11188 010 ==> ORR, 011 ==> ORN
11189 100 ==> EOR, 101 ==> EON,
11190 110 ==> ANDS, 111 ==> BICS
11191 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> ROR
11192 instr[15,10] = count : must be 0xxxxx for 32 bit
11193 instr[9,5] = Rn
11194 instr[4,0] = Rd */
11195
11196 /* unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16); */
11197 uint32_t dispatch;
11198 Shift shiftType;
11199 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
11200
11201 /* 32 bit operations must have count[5] = 0. */
11202 /* or else we have an UNALLOC. */
11203 uint32_t count = uimm (aarch64_get_instr (cpu), 15, 10);
11204
11205 if (!size && uimm (count, 5, 5))
11206 HALT_UNALLOC;
11207
11208 shiftType = shift (aarch64_get_instr (cpu), 22);
11209
11210 /* dispatch on size:op:N i.e aarch64_get_instr (cpu)[31,29:21]. */
11211 dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 29) << 1)
11212 | uimm (aarch64_get_instr (cpu), 21, 21));
11213
11214 switch (dispatch)
11215 {
11216 case 0: and32_shift (cpu, shiftType, count); return;
11217 case 1: bic32_shift (cpu, shiftType, count); return;
11218 case 2: orr32_shift (cpu, shiftType, count); return;
11219 case 3: orn32_shift (cpu, shiftType, count); return;
11220 case 4: eor32_shift (cpu, shiftType, count); return;
11221 case 5: eon32_shift (cpu, shiftType, count); return;
11222 case 6: ands32_shift (cpu, shiftType, count); return;
11223 case 7: bics32_shift (cpu, shiftType, count); return;
11224 case 8: and64_shift (cpu, shiftType, count); return;
11225 case 9: bic64_shift (cpu, shiftType, count); return;
11226 case 10:orr64_shift (cpu, shiftType, count); return;
11227 case 11:orn64_shift (cpu, shiftType, count); return;
11228 case 12:eor64_shift (cpu, shiftType, count); return;
11229 case 13:eon64_shift (cpu, shiftType, count); return;
11230 case 14:ands64_shift (cpu, shiftType, count); return;
11231 case 15:bics64_shift (cpu, shiftType, count); return;
11232 default: HALT_UNALLOC;
11233 }
11234}
11235
11236/* 32 bit conditional select. */
11237static void
11238csel32 (sim_cpu *cpu, CondCode cc)
11239{
11240 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11241 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11242 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11243
11244 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11245 testConditionCode (cpu, cc)
11246 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11247 : aarch64_get_reg_u32 (cpu, rm, NO_SP));
11248}
11249
11250/* 64 bit conditional select. */
11251static void
11252csel64 (sim_cpu *cpu, CondCode cc)
11253{
11254 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11255 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11256 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11257
11258 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11259 testConditionCode (cpu, cc)
11260 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11261 : aarch64_get_reg_u64 (cpu, rm, NO_SP));
11262}
11263
11264/* 32 bit conditional increment. */
11265static void
11266csinc32 (sim_cpu *cpu, CondCode cc)
11267{
11268 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11269 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11270 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11271
11272 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11273 testConditionCode (cpu, cc)
11274 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11275 : aarch64_get_reg_u32 (cpu, rm, NO_SP) + 1);
11276}
11277
11278/* 64 bit conditional increment. */
11279static void
11280csinc64 (sim_cpu *cpu, CondCode cc)
11281{
11282 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11283 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11284 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11285
11286 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11287 testConditionCode (cpu, cc)
11288 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11289 : aarch64_get_reg_u64 (cpu, rm, NO_SP) + 1);
11290}
11291
11292/* 32 bit conditional invert. */
11293static void
11294csinv32 (sim_cpu *cpu, CondCode cc)
11295{
11296 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11297 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11298 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11299
11300 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11301 testConditionCode (cpu, cc)
11302 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11303 : ~ aarch64_get_reg_u32 (cpu, rm, NO_SP));
11304}
11305
11306/* 64 bit conditional invert. */
11307static void
11308csinv64 (sim_cpu *cpu, CondCode cc)
11309{
11310 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11311 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11312 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11313
11314 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11315 testConditionCode (cpu, cc)
11316 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11317 : ~ aarch64_get_reg_u64 (cpu, rm, NO_SP));
11318}
11319
11320/* 32 bit conditional negate. */
11321static void
11322csneg32 (sim_cpu *cpu, CondCode cc)
11323{
11324 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11325 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11326 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11327
11328 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11329 testConditionCode (cpu, cc)
11330 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11331 : - aarch64_get_reg_u32 (cpu, rm, NO_SP));
11332}
11333
11334/* 64 bit conditional negate. */
11335static void
11336csneg64 (sim_cpu *cpu, CondCode cc)
11337{
11338 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11339 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11340 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11341
11342 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11343 testConditionCode (cpu, cc)
11344 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11345 : - aarch64_get_reg_u64 (cpu, rm, NO_SP));
11346}
11347
11348static void
11349dexCondSelect (sim_cpu *cpu)
11350{
11351 /* assert instr[28,21] = 11011011
11352 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11353 instr[30:11,10] = op : 000 ==> CSEL, 001 ==> CSINC,
11354 100 ==> CSINV, 101 ==> CSNEG,
11355 _1_ ==> UNALLOC
11356 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11357 instr[15,12] = cond
11358 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC */
11359
11360 CondCode cc;
11361 uint32_t dispatch;
11362 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11363 uint32_t op2 = uimm (aarch64_get_instr (cpu), 11, 10);
11364
11365 if (S == 1)
11366 HALT_UNALLOC;
11367
11368 if (op2 & 0x2)
11369 HALT_UNALLOC;
11370
11371 cc = condcode (aarch64_get_instr (cpu), 12);
11372 dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 1) | op2);
11373
11374 switch (dispatch)
11375 {
11376 case 0: csel32 (cpu, cc); return;
11377 case 1: csinc32 (cpu, cc); return;
11378 case 2: csinv32 (cpu, cc); return;
11379 case 3: csneg32 (cpu, cc); return;
11380 case 4: csel64 (cpu, cc); return;
11381 case 5: csinc64 (cpu, cc); return;
11382 case 6: csinv64 (cpu, cc); return;
11383 case 7: csneg64 (cpu, cc); return;
11384 default: HALT_UNALLOC;
11385 }
11386}
11387
11388/* Some helpers for counting leading 1 or 0 bits. */
11389
11390/* Counts the number of leading bits which are the same
11391 in a 32 bit value in the range 1 to 32. */
11392static uint32_t
11393leading32 (uint32_t value)
11394{
11395 int32_t mask= 0xffff0000;
11396 uint32_t count= 16; /* Counts number of bits set in mask. */
11397 uint32_t lo = 1; /* Lower bound for number of sign bits. */
11398 uint32_t hi = 32; /* Upper bound for number of sign bits. */
11399
11400 while (lo + 1 < hi)
11401 {
11402 int32_t test = (value & mask);
11403
11404 if (test == 0 || test == mask)
11405 {
11406 lo = count;
11407 count = (lo + hi) / 2;
11408 mask >>= (count - lo);
11409 }
11410 else
11411 {
11412 hi = count;
11413 count = (lo + hi) / 2;
11414 mask <<= hi - count;
11415 }
11416 }
11417
11418 if (lo != hi)
11419 {
11420 int32_t test;
11421
11422 mask >>= 1;
11423 test = (value & mask);
11424
11425 if (test == 0 || test == mask)
11426 count = hi;
11427 else
11428 count = lo;
11429 }
11430
11431 return count;
11432}
11433
11434/* Counts the number of leading bits which are the same
11435 in a 64 bit value in the range 1 to 64. */
11436static uint64_t
11437leading64 (uint64_t value)
11438{
11439 int64_t mask= 0xffffffff00000000LL;
11440 uint64_t count = 32; /* Counts number of bits set in mask. */
11441 uint64_t lo = 1; /* Lower bound for number of sign bits. */
11442 uint64_t hi = 64; /* Upper bound for number of sign bits. */
11443
11444 while (lo + 1 < hi)
11445 {
11446 int64_t test = (value & mask);
11447
11448 if (test == 0 || test == mask)
11449 {
11450 lo = count;
11451 count = (lo + hi) / 2;
11452 mask >>= (count - lo);
11453 }
11454 else
11455 {
11456 hi = count;
11457 count = (lo + hi) / 2;
11458 mask <<= hi - count;
11459 }
11460 }
11461
11462 if (lo != hi)
11463 {
11464 int64_t test;
11465
11466 mask >>= 1;
11467 test = (value & mask);
11468
11469 if (test == 0 || test == mask)
11470 count = hi;
11471 else
11472 count = lo;
11473 }
11474
11475 return count;
11476}
11477
11478/* Bit operations. */
11479/* N.B register args may not be SP. */
11480
11481/* 32 bit count leading sign bits. */
11482static void
11483cls32 (sim_cpu *cpu)
11484{
11485 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11486 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11487
11488 /* N.B. the result needs to exclude the leading bit. */
11489 aarch64_set_reg_u64
11490 (cpu, rd, NO_SP, leading32 (aarch64_get_reg_u32 (cpu, rn, NO_SP)) - 1);
11491}
11492
11493/* 64 bit count leading sign bits. */
11494static void
11495cls64 (sim_cpu *cpu)
11496{
11497 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11498 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11499
11500 /* N.B. the result needs to exclude the leading bit. */
11501 aarch64_set_reg_u64
11502 (cpu, rd, NO_SP, leading64 (aarch64_get_reg_u64 (cpu, rn, NO_SP)) - 1);
11503}
11504
11505/* 32 bit count leading zero bits. */
11506static void
11507clz32 (sim_cpu *cpu)
11508{
11509 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11510 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11511 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11512
11513 /* if the sign (top) bit is set then the count is 0. */
11514 if (pick32 (value, 31, 31))
11515 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11516 else
11517 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading32 (value));
11518}
11519
11520/* 64 bit count leading zero bits. */
11521static void
11522clz64 (sim_cpu *cpu)
11523{
11524 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11525 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11526 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11527
11528 /* if the sign (top) bit is set then the count is 0. */
11529 if (pick64 (value, 63, 63))
11530 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11531 else
11532 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading64 (value));
11533}
11534
11535/* 32 bit reverse bits. */
11536static void
11537rbit32 (sim_cpu *cpu)
11538{
11539 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11540 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11541 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11542 uint32_t result = 0;
11543 int i;
11544
11545 for (i = 0; i < 32; i++)
11546 {
11547 result <<= 1;
11548 result |= (value & 1);
11549 value >>= 1;
11550 }
11551 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11552}
11553
11554/* 64 bit reverse bits. */
11555static void
11556rbit64 (sim_cpu *cpu)
11557{
11558 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11559 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11560 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11561 uint64_t result = 0;
11562 int i;
11563
11564 for (i = 0; i < 64; i++)
11565 {
11566 result <<= 1;
57aa1742 11567 result |= (value & 1UL);
2e8cf49e
NC
11568 value >>= 1;
11569 }
11570 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11571}
11572
11573/* 32 bit reverse bytes. */
11574static void
11575rev32 (sim_cpu *cpu)
11576{
11577 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11578 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11579 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11580 uint32_t result = 0;
11581 int i;
11582
11583 for (i = 0; i < 4; i++)
11584 {
11585 result <<= 8;
11586 result |= (value & 0xff);
11587 value >>= 8;
11588 }
11589 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11590}
11591
11592/* 64 bit reverse bytes. */
11593static void
11594rev64 (sim_cpu *cpu)
11595{
11596 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11597 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11598 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11599 uint64_t result = 0;
11600 int i;
11601
11602 for (i = 0; i < 8; i++)
11603 {
11604 result <<= 8;
11605 result |= (value & 0xffULL);
11606 value >>= 8;
11607 }
11608 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11609}
11610
11611/* 32 bit reverse shorts. */
11612/* N.B.this reverses the order of the bytes in each half word. */
11613static void
11614revh32 (sim_cpu *cpu)
11615{
11616 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11617 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11618 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11619 uint32_t result = 0;
11620 int i;
11621
11622 for (i = 0; i < 2; i++)
11623 {
11624 result <<= 8;
11625 result |= (value & 0x00ff00ff);
11626 value >>= 8;
11627 }
11628 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11629}
11630
11631/* 64 bit reverse shorts. */
11632/* N.B.this reverses the order of the bytes in each half word. */
11633static void
11634revh64 (sim_cpu *cpu)
11635{
11636 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11637 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11638 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11639 uint64_t result = 0;
11640 int i;
11641
11642 for (i = 0; i < 2; i++)
11643 {
11644 result <<= 8;
11645 result |= (value & 0x00ff00ff00ff00ffULL);
11646 value >>= 8;
11647 }
11648 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11649}
11650
11651static void
11652dexDataProc1Source (sim_cpu *cpu)
11653{
11654 /* assert instr[30] == 1
11655 aarch64_get_instr (cpu)[28,21] == 111010110
11656 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11657 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11658 instr[20,16] = opcode2 : 00000 ==> ok, ow ==> UNALLOC
11659 instr[15,10] = opcode : 000000 ==> RBIT, 000001 ==> REV16,
11660 000010 ==> REV, 000011 ==> UNALLOC
11661 000100 ==> CLZ, 000101 ==> CLS
11662 ow ==> UNALLOC
11663 instr[9,5] = rn : may not be SP
11664 instr[4,0] = rd : may not be SP. */
11665
11666 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11667 uint32_t opcode2 = uimm (aarch64_get_instr (cpu), 20, 16);
11668 uint32_t opcode = uimm (aarch64_get_instr (cpu), 15, 10);
11669 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 31) << 3) | opcode);
11670
11671 if (S == 1)
11672 HALT_UNALLOC;
11673
11674 if (opcode2 != 0)
11675 HALT_UNALLOC;
11676
11677 if (opcode & 0x38)
11678 HALT_UNALLOC;
11679
11680 switch (dispatch)
11681 {
11682 case 0: rbit32 (cpu); return;
11683 case 1: revh32 (cpu); return;
11684 case 2: rev32 (cpu); return;
11685 case 4: clz32 (cpu); return;
11686 case 5: cls32 (cpu); return;
11687 case 8: rbit64 (cpu); return;
11688 case 9: revh64 (cpu); return;
11689 case 10:rev32 (cpu); return;
11690 case 11:rev64 (cpu); return;
11691 case 12:clz64 (cpu); return;
11692 case 13:cls64 (cpu); return;
11693 default: HALT_UNALLOC;
11694 }
11695}
11696
11697/* Variable shift.
11698 Shifts by count supplied in register.
11699 N.B register args may not be SP.
11700 These all use the shifted auxiliary function for
11701 simplicity and clarity. Writing the actual shift
11702 inline would avoid a branch and so be faster but
11703 would also necessitate getting signs right. */
11704
11705/* 32 bit arithmetic shift right. */
11706static void
11707asrv32 (sim_cpu *cpu)
11708{
11709 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11710 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11711 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11712
11713 aarch64_set_reg_u64
11714 (cpu, rd, NO_SP,
11715 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ASR,
11716 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11717}
11718
11719/* 64 bit arithmetic shift right. */
11720static void
11721asrv64 (sim_cpu *cpu)
11722{
11723 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11724 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11725 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11726
11727 aarch64_set_reg_u64
11728 (cpu, rd, NO_SP,
11729 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ASR,
11730 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11731}
11732
11733/* 32 bit logical shift left. */
11734static void
11735lslv32 (sim_cpu *cpu)
11736{
11737 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11738 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11739 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11740
11741 aarch64_set_reg_u64
11742 (cpu, rd, NO_SP,
11743 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSL,
11744 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11745}
11746
11747/* 64 bit arithmetic shift left. */
11748static void
11749lslv64 (sim_cpu *cpu)
11750{
11751 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11752 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11753 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11754
11755 aarch64_set_reg_u64
11756 (cpu, rd, NO_SP,
11757 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSL,
11758 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11759}
11760
11761/* 32 bit logical shift right. */
11762static void
11763lsrv32 (sim_cpu *cpu)
11764{
11765 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11766 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11767 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11768
11769 aarch64_set_reg_u64
11770 (cpu, rd, NO_SP,
11771 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSR,
11772 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11773}
11774
11775/* 64 bit logical shift right. */
11776static void
11777lsrv64 (sim_cpu *cpu)
11778{
11779 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11780 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11781 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11782
11783 aarch64_set_reg_u64
11784 (cpu, rd, NO_SP,
11785 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSR,
11786 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11787}
11788
11789/* 32 bit rotate right. */
11790static void
11791rorv32 (sim_cpu *cpu)
11792{
11793 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11794 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11795 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11796
11797 aarch64_set_reg_u64
11798 (cpu, rd, NO_SP,
11799 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ROR,
11800 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11801}
11802
11803/* 64 bit rotate right. */
11804static void
11805rorv64 (sim_cpu *cpu)
11806{
11807 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11808 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11809 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11810
11811 aarch64_set_reg_u64
11812 (cpu, rd, NO_SP,
11813 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ROR,
11814 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11815}
11816
11817
11818/* divide. */
11819
11820/* 32 bit signed divide. */
11821static void
11822cpuiv32 (sim_cpu *cpu)
11823{
11824 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11825 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11826 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11827 /* N.B. the pseudo-code does the divide using 64 bit data. */
11828 /* TODO : check that this rounds towards zero as required. */
11829 int64_t dividend = aarch64_get_reg_s32 (cpu, rn, NO_SP);
11830 int64_t divisor = aarch64_get_reg_s32 (cpu, rm, NO_SP);
11831
11832 aarch64_set_reg_s64 (cpu, rd, NO_SP,
11833 divisor ? ((int32_t) (dividend / divisor)) : 0);
11834}
11835
11836/* 64 bit signed divide. */
11837static void
11838cpuiv64 (sim_cpu *cpu)
11839{
11840 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11841 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11842 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11843
11844 /* TODO : check that this rounds towards zero as required. */
11845 int64_t divisor = aarch64_get_reg_s64 (cpu, rm, NO_SP);
11846
11847 aarch64_set_reg_s64
11848 (cpu, rd, NO_SP,
11849 divisor ? (aarch64_get_reg_s64 (cpu, rn, NO_SP) / divisor) : 0);
11850}
11851
11852/* 32 bit unsigned divide. */
11853static void
11854udiv32 (sim_cpu *cpu)
11855{
11856 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11857 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11858 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11859
11860 /* N.B. the pseudo-code does the divide using 64 bit data. */
11861 uint64_t dividend = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11862 uint64_t divisor = aarch64_get_reg_u32 (cpu, rm, NO_SP);
11863
11864 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11865 divisor ? (uint32_t) (dividend / divisor) : 0);
11866}
11867
11868/* 64 bit unsigned divide. */
11869static void
11870udiv64 (sim_cpu *cpu)
11871{
11872 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11873 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11874 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11875
11876 /* TODO : check that this rounds towards zero as required. */
11877 uint64_t divisor = aarch64_get_reg_u64 (cpu, rm, NO_SP);
11878
11879 aarch64_set_reg_u64
11880 (cpu, rd, NO_SP,
11881 divisor ? (aarch64_get_reg_u64 (cpu, rn, NO_SP) / divisor) : 0);
11882}
11883
11884static void
11885dexDataProc2Source (sim_cpu *cpu)
11886{
11887 /* assert instr[30] == 0
11888 instr[28,21] == 11010110
11889 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11890 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11891 instr[15,10] = opcode : 000010 ==> UDIV, 000011 ==> CPUIV,
11892 001000 ==> LSLV, 001001 ==> LSRV
11893 001010 ==> ASRV, 001011 ==> RORV
11894 ow ==> UNALLOC. */
11895
11896 uint32_t dispatch;
11897 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11898 uint32_t opcode = uimm (aarch64_get_instr (cpu), 15, 10);
11899
11900 if (S == 1)
11901 HALT_UNALLOC;
11902
11903 if (opcode & 0x34)
11904 HALT_UNALLOC;
11905
11906 dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 31) << 3)
11907 | (uimm (opcode, 3, 3) << 2)
11908 | uimm (opcode, 1, 0));
11909 switch (dispatch)
11910 {
11911 case 2: udiv32 (cpu); return;
11912 case 3: cpuiv32 (cpu); return;
11913 case 4: lslv32 (cpu); return;
11914 case 5: lsrv32 (cpu); return;
11915 case 6: asrv32 (cpu); return;
11916 case 7: rorv32 (cpu); return;
11917 case 10: udiv64 (cpu); return;
11918 case 11: cpuiv64 (cpu); return;
11919 case 12: lslv64 (cpu); return;
11920 case 13: lsrv64 (cpu); return;
11921 case 14: asrv64 (cpu); return;
11922 case 15: rorv64 (cpu); return;
11923 default: HALT_UNALLOC;
11924 }
11925}
11926
11927
11928/* Multiply. */
11929
11930/* 32 bit multiply and add. */
11931static void
11932madd32 (sim_cpu *cpu)
11933{
11934 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11935 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11936 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11937 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11938
11939 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11940 aarch64_get_reg_u32 (cpu, ra, NO_SP)
11941 + aarch64_get_reg_u32 (cpu, rn, NO_SP)
11942 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
11943}
11944
11945/* 64 bit multiply and add. */
11946static void
11947madd64 (sim_cpu *cpu)
11948{
11949 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11950 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11951 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11952 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11953
11954 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11955 aarch64_get_reg_u64 (cpu, ra, NO_SP)
11956 + aarch64_get_reg_u64 (cpu, rn, NO_SP)
11957 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
11958}
11959
11960/* 32 bit multiply and sub. */
11961static void
11962msub32 (sim_cpu *cpu)
11963{
11964 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11965 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11966 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11967 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11968
11969 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11970 aarch64_get_reg_u32 (cpu, ra, NO_SP)
11971 - aarch64_get_reg_u32 (cpu, rn, NO_SP)
11972 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
11973}
11974
11975/* 64 bit multiply and sub. */
11976static void
11977msub64 (sim_cpu *cpu)
11978{
11979 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11980 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11981 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11982 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11983
11984 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11985 aarch64_get_reg_u64 (cpu, ra, NO_SP)
11986 - aarch64_get_reg_u64 (cpu, rn, NO_SP)
11987 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
11988}
11989
11990/* Signed multiply add long -- source, source2 : 32 bit, source3 : 64 bit. */
11991static void
11992smaddl (sim_cpu *cpu)
11993{
11994 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11995 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11996 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11997 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11998
11999 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12000 obtain a 64 bit product. */
12001 aarch64_set_reg_s64
12002 (cpu, rd, NO_SP,
12003 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12004 + ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12005 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12006}
12007
12008/* Signed multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12009static void
12010smsubl (sim_cpu *cpu)
12011{
12012 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12013 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
12014 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12015 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12016
12017 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12018 obtain a 64 bit product. */
12019 aarch64_set_reg_s64
12020 (cpu, rd, NO_SP,
12021 aarch64_get_reg_s64 (cpu, ra, NO_SP)
12022 - ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
12023 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
12024}
12025
12026/* Integer Multiply/Divide. */
12027
12028/* First some macros and a helper function. */
12029/* Macros to test or access elements of 64 bit words. */
12030
12031/* Mask used to access lo 32 bits of 64 bit unsigned int. */
12032#define LOW_WORD_MASK ((1ULL << 32) - 1)
12033/* Return the lo 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12034#define lowWordToU64(_value_u64) ((_value_u64) & LOW_WORD_MASK)
12035/* Return the hi 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
12036#define highWordToU64(_value_u64) ((_value_u64) >> 32)
12037
12038/* Offset of sign bit in 64 bit signed integger. */
12039#define SIGN_SHIFT_U64 63
12040/* The sign bit itself -- also identifies the minimum negative int value. */
12041#define SIGN_BIT_U64 (1UL << SIGN_SHIFT_U64)
12042/* Return true if a 64 bit signed int presented as an unsigned int is the
12043 most negative value. */
12044#define isMinimumU64(_value_u64) ((_value_u64) == SIGN_BIT_U64)
12045/* Return true (non-zero) if a 64 bit signed int presented as an unsigned
12046 int has its sign bit set to false. */
12047#define isSignSetU64(_value_u64) ((_value_u64) & SIGN_BIT_U64)
12048/* Return 1L or -1L according to whether a 64 bit signed int presented as
12049 an unsigned int has its sign bit set or not. */
12050#define signOfU64(_value_u64) (1L + (((value_u64) >> SIGN_SHIFT_U64) * -2L)
12051/* Clear the sign bit of a 64 bit signed int presented as an unsigned int. */
12052#define clearSignU64(_value_u64) ((_value_u64) &= ~SIGN_BIT_U64)
12053
12054/* Multiply two 64 bit ints and return.
12055 the hi 64 bits of the 128 bit product. */
12056
12057static uint64_t
12058mul64hi (uint64_t value1, uint64_t value2)
12059{
12060 uint64_t resultmid1;
12061 uint64_t result;
12062 uint64_t value1_lo = lowWordToU64 (value1);
12063 uint64_t value1_hi = highWordToU64 (value1) ;
12064 uint64_t value2_lo = lowWordToU64 (value2);
12065 uint64_t value2_hi = highWordToU64 (value2);
12066
12067 /* Cross-multiply and collect results. */
12068
12069 uint64_t xproductlo = value1_lo * value2_lo;
12070 uint64_t xproductmid1 = value1_lo * value2_hi;
12071 uint64_t xproductmid2 = value1_hi * value2_lo;
12072 uint64_t xproducthi = value1_hi * value2_hi;
12073 uint64_t carry = 0;
12074 /* Start accumulating 64 bit results. */
12075 /* Drop bottom half of lowest cross-product. */
12076 uint64_t resultmid = xproductlo >> 32;
12077 /* Add in middle products. */
12078 resultmid = resultmid + xproductmid1;
12079
12080 /* Check for overflow. */
12081 if (resultmid < xproductmid1)
12082 /* Carry over 1 into top cross-product. */
12083 carry++;
12084
12085 resultmid1 = resultmid + xproductmid2;
12086
12087 /* Check for overflow. */
12088 if (resultmid1 < xproductmid2)
12089 /* Carry over 1 into top cross-product. */
12090 carry++;
12091
12092 /* Drop lowest 32 bits of middle cross-product. */
12093 result = resultmid1 >> 32;
12094
12095 /* Add top cross-product plus and any carry. */
12096 result += xproducthi + carry;
12097
12098 return result;
12099}
12100
12101/* Signed multiply high, source, source2 :
12102 64 bit, dest <-- high 64-bit of result. */
12103static void
12104smulh (sim_cpu *cpu)
12105{
12106 uint64_t uresult;
12107 int64_t result;
12108 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12109 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12110 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12111 GReg ra = greg (aarch64_get_instr (cpu), 10);
12112 int64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12113 int64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
12114 uint64_t uvalue1;
12115 uint64_t uvalue2;
12116 int64_t signum = 1;
12117
12118 if (ra != R31)
12119 HALT_UNALLOC;
12120
12121 /* Convert to unsigned and use the unsigned mul64hi routine
12122 the fix the sign up afterwards. */
12123 if (value1 < 0)
12124 {
12125 signum *= -1L;
12126 uvalue1 = -value1;
12127 }
12128 else
12129 {
12130 uvalue1 = value1;
12131 }
12132
12133 if (value2 < 0)
12134 {
12135 signum *= -1L;
12136 uvalue2 = -value2;
12137 }
12138 else
12139 {
12140 uvalue2 = value2;
12141 }
12142
12143 uresult = mul64hi (uvalue1, uvalue2);
12144 result = uresult;
12145 result *= signum;
12146
12147 aarch64_set_reg_s64 (cpu, rd, NO_SP, result);
12148}
12149
12150/* Unsigned multiply add long -- source, source2 :
12151 32 bit, source3 : 64 bit. */
12152static void
12153umaddl (sim_cpu *cpu)
12154{
12155 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12156 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
12157 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12158 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12159
12160 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12161 obtain a 64 bit product. */
12162 aarch64_set_reg_u64
12163 (cpu, rd, NO_SP,
12164 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12165 + ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12166 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12167}
12168
12169/* Unsigned multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12170static void
12171umsubl (sim_cpu *cpu)
12172{
12173 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12174 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
12175 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12176 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12177
12178 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12179 obtain a 64 bit product. */
12180 aarch64_set_reg_u64
12181 (cpu, rd, NO_SP,
12182 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12183 - ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12184 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12185}
12186
12187/* Unsigned multiply high, source, source2 :
12188 64 bit, dest <-- high 64-bit of result. */
12189static void
12190umulh (sim_cpu *cpu)
12191{
12192 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12193 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12194 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12195 GReg ra = greg (aarch64_get_instr (cpu), 10);
12196
12197 if (ra != R31)
12198 HALT_UNALLOC;
12199
12200 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12201 mul64hi (aarch64_get_reg_u64 (cpu, rn, NO_SP),
12202 aarch64_get_reg_u64 (cpu, rm, NO_SP)));
12203}
12204
12205static void
12206dexDataProc3Source (sim_cpu *cpu)
12207{
12208 /* assert instr[28,24] == 11011. */
12209 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit (for rd at least)
12210 instr[30,29] = op54 : 00 ==> ok, ow ==> UNALLOC
12211 instr[23,21] = op31 : 111 ==> UNALLOC, o2 ==> ok
12212 instr[15] = o0 : 0/1 ==> ok
12213 instr[23,21:15] ==> op : 0000 ==> MADD, 0001 ==> MSUB, (32/64 bit)
12214 0010 ==> SMADDL, 0011 ==> SMSUBL, (64 bit only)
12215 0100 ==> SMULH, (64 bit only)
12216 1010 ==> UMADDL, 1011 ==> UNSUBL, (64 bit only)
12217 1100 ==> UMULH (64 bit only)
12218 ow ==> UNALLOC. */
12219
12220 uint32_t dispatch;
12221 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
12222 uint32_t op54 = uimm (aarch64_get_instr (cpu), 30, 29);
12223 uint32_t op31 = uimm (aarch64_get_instr (cpu), 23, 21);
12224 uint32_t o0 = uimm (aarch64_get_instr (cpu), 15, 15);
12225
12226 if (op54 != 0)
12227 HALT_UNALLOC;
12228
12229 if (size == 0)
12230 {
12231 if (op31 != 0)
12232 HALT_UNALLOC;
12233
12234 if (o0 == 0)
12235 madd32 (cpu);
12236 else
12237 msub32 (cpu);
12238 return;
12239 }
12240
12241 dispatch = (op31 << 1) | o0;
12242
12243 switch (dispatch)
12244 {
12245 case 0: madd64 (cpu); return;
12246 case 1: msub64 (cpu); return;
12247 case 2: smaddl (cpu); return;
12248 case 3: smsubl (cpu); return;
12249 case 4: smulh (cpu); return;
12250 case 10: umaddl (cpu); return;
12251 case 11: umsubl (cpu); return;
12252 case 12: umulh (cpu); return;
12253 default: HALT_UNALLOC;
12254 }
12255}
12256
12257static void
12258dexDPReg (sim_cpu *cpu)
12259{
12260 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12261 assert group == GROUP_DPREG_0101 || group == GROUP_DPREG_1101
12262 bits [28:24:21] of a DPReg are the secondary dispatch vector. */
12263 uint32_t group2 = dispatchDPReg (aarch64_get_instr (cpu));
12264
12265 switch (group2)
12266 {
12267 case DPREG_LOG_000:
12268 case DPREG_LOG_001:
12269 dexLogicalShiftedRegister (cpu); return;
12270
12271 case DPREG_ADDSHF_010:
12272 dexAddSubtractShiftedRegister (cpu); return;
12273
12274 case DPREG_ADDEXT_011:
12275 dexAddSubtractExtendedRegister (cpu); return;
12276
12277 case DPREG_ADDCOND_100:
12278 {
12279 /* This set bundles a variety of different operations. */
12280 /* Check for. */
12281 /* 1) add/sub w carry. */
12282 uint32_t mask1 = 0x1FE00000U;
12283 uint32_t val1 = 0x1A000000U;
12284 /* 2) cond compare register/immediate. */
12285 uint32_t mask2 = 0x1FE00000U;
12286 uint32_t val2 = 0x1A400000U;
12287 /* 3) cond select. */
12288 uint32_t mask3 = 0x1FE00000U;
12289 uint32_t val3 = 0x1A800000U;
12290 /* 4) data proc 1/2 source. */
12291 uint32_t mask4 = 0x1FE00000U;
12292 uint32_t val4 = 0x1AC00000U;
12293
12294 if ((aarch64_get_instr (cpu) & mask1) == val1)
12295 dexAddSubtractWithCarry (cpu);
12296
12297 else if ((aarch64_get_instr (cpu) & mask2) == val2)
12298 CondCompare (cpu);
12299
12300 else if ((aarch64_get_instr (cpu) & mask3) == val3)
12301 dexCondSelect (cpu);
12302
12303 else if ((aarch64_get_instr (cpu) & mask4) == val4)
12304 {
12305 /* Bit 30 is clear for data proc 2 source
12306 and set for data proc 1 source. */
12307 if (aarch64_get_instr (cpu) & (1U << 30))
12308 dexDataProc1Source (cpu);
12309 else
12310 dexDataProc2Source (cpu);
12311 }
12312
12313 else
12314 /* Should not reach here. */
12315 HALT_NYI;
12316
12317 return;
12318 }
12319
12320 case DPREG_3SRC_110:
12321 dexDataProc3Source (cpu); return;
12322
12323 case DPREG_UNALLOC_101:
12324 HALT_UNALLOC;
12325
12326 case DPREG_3SRC_111:
12327 dexDataProc3Source (cpu); return;
12328
12329 default:
12330 /* Should never reach here. */
12331 HALT_NYI;
12332 }
12333}
12334
12335/* Unconditional Branch immediate.
12336 Offset is a PC-relative byte offset in the range +/- 128MiB.
12337 The offset is assumed to be raw from the decode i.e. the
12338 simulator is expected to scale them from word offsets to byte. */
12339
12340/* Unconditional branch. */
12341static void
12342buc (sim_cpu *cpu, int32_t offset)
12343{
12344 aarch64_set_next_PC_by_offset (cpu, offset);
12345}
12346
12347static unsigned stack_depth = 0;
12348
12349/* Unconditional branch and link -- writes return PC to LR. */
12350static void
12351bl (sim_cpu *cpu, int32_t offset)
12352{
12353 aarch64_save_LR (cpu);
12354 aarch64_set_next_PC_by_offset (cpu, offset);
12355
12356 if (TRACE_BRANCH_P (cpu))
12357 {
12358 ++ stack_depth;
12359 TRACE_BRANCH (cpu,
12360 " %*scall %" PRIx64 " [%s]"
12361 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12362 stack_depth, " ", aarch64_get_next_PC (cpu),
12363 aarch64_get_func (aarch64_get_next_PC (cpu)),
12364 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12365 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12366 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12367 );
12368 }
12369}
12370
12371/* Unconditional Branch register.
12372 Branch/return address is in source register. */
12373
12374/* Unconditional branch. */
12375static void
12376br (sim_cpu *cpu)
12377{
12378 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12379 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12380}
12381
12382/* Unconditional branch and link -- writes return PC to LR. */
12383static void
12384blr (sim_cpu *cpu)
12385{
12386 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12387
12388 /* The pseudo code in the spec says we update LR before fetching.
12389 the value from the rn. */
12390 aarch64_save_LR (cpu);
12391 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12392
12393 if (TRACE_BRANCH_P (cpu))
12394 {
12395 ++ stack_depth;
12396 TRACE_BRANCH (cpu,
12397 " %*scall %" PRIx64 " [%s]"
12398 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12399 stack_depth, " ", aarch64_get_next_PC (cpu),
12400 aarch64_get_func (aarch64_get_next_PC (cpu)),
12401 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12402 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12403 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12404 );
12405 }
12406}
12407
12408/* Return -- assembler will default source to LR this is functionally
12409 equivalent to br but, presumably, unlike br it side effects the
12410 branch predictor. */
12411static void
12412ret (sim_cpu *cpu)
12413{
12414 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12415 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12416
12417 if (TRACE_BRANCH_P (cpu))
12418 {
12419 TRACE_BRANCH (cpu,
12420 " %*sreturn [result: %" PRIx64 "]",
12421 stack_depth, " ", aarch64_get_reg_u64 (cpu, 0, NO_SP));
12422 -- stack_depth;
12423 }
12424}
12425
12426/* NOP -- we implement this and call it from the decode in case we
12427 want to intercept it later. */
12428
12429static void
12430nop (sim_cpu *cpu)
12431{
12432}
12433
12434/* Data synchronization barrier. */
12435
12436static void
12437dsb (sim_cpu *cpu)
12438{
12439}
12440
12441/* Data memory barrier. */
12442
12443static void
12444dmb (sim_cpu *cpu)
12445{
12446}
12447
12448/* Instruction synchronization barrier. */
12449
12450static void
12451isb (sim_cpu *cpu)
12452{
12453}
12454
12455static void
12456dexBranchImmediate (sim_cpu *cpu)
12457{
12458 /* assert instr[30,26] == 00101
12459 instr[31] ==> 0 == B, 1 == BL
12460 instr[25,0] == imm26 branch offset counted in words. */
12461
12462 uint32_t top = uimm (aarch64_get_instr (cpu), 31, 31);
12463 /* We have a 26 byte signed word offset which we need to pass to the
12464 execute routine as a signed byte offset. */
12465 int32_t offset = simm32 (aarch64_get_instr (cpu), 25, 0) << 2;
12466
12467 if (top)
12468 bl (cpu, offset);
12469 else
12470 buc (cpu, offset);
12471}
12472
12473/* Control Flow. */
12474
12475/* Conditional branch
12476
12477 Offset is a PC-relative byte offset in the range +/- 1MiB pos is
12478 a bit position in the range 0 .. 63
12479
12480 cc is a CondCode enum value as pulled out of the decode
12481
12482 N.B. any offset register (source) can only be Xn or Wn. */
12483
12484static void
12485bcc (sim_cpu *cpu, int32_t offset, CondCode cc)
12486{
12487 /* the test returns TRUE if CC is met. */
12488 if (testConditionCode (cpu, cc))
12489 aarch64_set_next_PC_by_offset (cpu, offset);
12490}
12491
12492/* 32 bit branch on register non-zero. */
12493static void
12494cbnz32 (sim_cpu *cpu, int32_t offset)
12495{
12496 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12497
12498 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) != 0)
12499 aarch64_set_next_PC_by_offset (cpu, offset);
12500}
12501
12502/* 64 bit branch on register zero. */
12503static void
12504cbnz (sim_cpu *cpu, int32_t offset)
12505{
12506 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12507
12508 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) != 0)
12509 aarch64_set_next_PC_by_offset (cpu, offset);
12510}
12511
12512/* 32 bit branch on register non-zero. */
12513static void
12514cbz32 (sim_cpu *cpu, int32_t offset)
12515{
12516 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12517
12518 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) == 0)
12519 aarch64_set_next_PC_by_offset (cpu, offset);
12520}
12521
12522/* 64 bit branch on register zero. */
12523static void
12524cbz (sim_cpu *cpu, int32_t offset)
12525{
12526 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12527
12528 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) == 0)
12529 aarch64_set_next_PC_by_offset (cpu, offset);
12530}
12531
12532/* Branch on register bit test non-zero -- one size fits all. */
12533static void
12534tbnz (sim_cpu *cpu, uint32_t pos, int32_t offset)
12535{
12536 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12537
12538 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) & (1 << pos))
12539 aarch64_set_next_PC_by_offset (cpu, offset);
12540}
12541
12542/* branch on register bit test zero -- one size fits all. */
12543static void
12544tbz (sim_cpu *cpu, uint32_t pos, int32_t offset)
12545{
12546 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12547
12548 if (!(aarch64_get_reg_u64 (cpu, rt, NO_SP) & (1 << pos)))
12549 aarch64_set_next_PC_by_offset (cpu, offset);
12550}
12551
12552static void
12553dexCompareBranchImmediate (sim_cpu *cpu)
12554{
12555 /* instr[30,25] = 01 1010
12556 instr[31] = size : 0 ==> 32, 1 ==> 64
12557 instr[24] = op : 0 ==> CBZ, 1 ==> CBNZ
12558 instr[23,5] = simm19 branch offset counted in words
12559 instr[4,0] = rt */
12560
12561 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
12562 uint32_t op = uimm (aarch64_get_instr (cpu), 24, 24);
12563 int32_t offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
12564
12565 if (size == 0)
12566 {
12567 if (op == 0)
12568 cbz32 (cpu, offset);
12569 else
12570 cbnz32 (cpu, offset);
12571 }
12572 else
12573 {
12574 if (op == 0)
12575 cbz (cpu, offset);
12576 else
12577 cbnz (cpu, offset);
12578 }
12579}
12580
12581static void
12582dexTestBranchImmediate (sim_cpu *cpu)
12583{
12584 /* instr[31] = b5 : bit 5 of test bit idx
12585 instr[30,25] = 01 1011
12586 instr[24] = op : 0 ==> TBZ, 1 == TBNZ
12587 instr[23,19] = b40 : bits 4 to 0 of test bit idx
12588 instr[18,5] = simm14 : signed offset counted in words
12589 instr[4,0] = uimm5 */
12590
12591 uint32_t pos = ((uimm (aarch64_get_instr (cpu), 31, 31) << 4)
12592 | uimm (aarch64_get_instr (cpu), 23,19));
12593 int32_t offset = simm32 (aarch64_get_instr (cpu), 18, 5) << 2;
12594
12595 NYI_assert (30, 25, 0x1b);
12596
12597 if (uimm (aarch64_get_instr (cpu), 24, 24) == 0)
12598 tbz (cpu, pos, offset);
12599 else
12600 tbnz (cpu, pos, offset);
12601}
12602
12603static void
12604dexCondBranchImmediate (sim_cpu *cpu)
12605{
12606 /* instr[31,25] = 010 1010
12607 instr[24] = op1; op => 00 ==> B.cond
12608 instr[23,5] = simm19 : signed offset counted in words
12609 instr[4] = op0
12610 instr[3,0] = cond */
12611
12612 int32_t offset;
12613 CondCode cc;
12614 uint32_t op = ((uimm (aarch64_get_instr (cpu), 24, 24) << 1)
12615 | uimm (aarch64_get_instr (cpu), 4, 4));
12616
12617 NYI_assert (31, 25, 0x2a);
12618
12619 if (op != 0)
12620 HALT_UNALLOC;
12621
12622 offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
12623 cc = condcode (aarch64_get_instr (cpu), 0);
12624
12625 bcc (cpu, offset, cc);
12626}
12627
12628static void
12629dexBranchRegister (sim_cpu *cpu)
12630{
12631 /* instr[31,25] = 110 1011
12632 instr[24,21] = op : 0 ==> BR, 1 => BLR, 2 => RET, 3 => ERET, 4 => DRPS
12633 instr[20,16] = op2 : must be 11111
12634 instr[15,10] = op3 : must be 000000
12635 instr[4,0] = op2 : must be 11111. */
12636
12637 uint32_t op = uimm (aarch64_get_instr (cpu), 24, 21);
12638 uint32_t op2 = uimm (aarch64_get_instr (cpu), 20, 16);
12639 uint32_t op3 = uimm (aarch64_get_instr (cpu), 15, 10);
12640 uint32_t op4 = uimm (aarch64_get_instr (cpu), 4, 0);
12641
12642 NYI_assert (31, 25, 0x6b);
12643
12644 if (op2 != 0x1F || op3 != 0 || op4 != 0)
12645 HALT_UNALLOC;
12646
12647 if (op == 0)
12648 br (cpu);
12649
12650 else if (op == 1)
12651 blr (cpu);
12652
12653 else if (op == 2)
12654 ret (cpu);
12655
12656 else
12657 {
12658 /* ERET and DRPS accept 0b11111 for rn = aarch64_get_instr (cpu)[4,0]. */
12659 /* anything else is unallocated. */
12660 uint32_t rn = greg (aarch64_get_instr (cpu), 0);
12661
12662 if (rn != 0x1f)
12663 HALT_UNALLOC;
12664
12665 if (op == 4 || op == 5)
12666 HALT_NYI;
12667
12668 HALT_UNALLOC;
12669 }
12670}
12671
12672/* FIXME: We should get the Angel SWI values from ../../libgloss/aarch64/svc.h
12673 but this may not be available. So instead we define the values we need
12674 here. */
12675#define AngelSVC_Reason_Open 0x01
12676#define AngelSVC_Reason_Close 0x02
12677#define AngelSVC_Reason_Write 0x05
12678#define AngelSVC_Reason_Read 0x06
12679#define AngelSVC_Reason_IsTTY 0x09
12680#define AngelSVC_Reason_Seek 0x0A
12681#define AngelSVC_Reason_FLen 0x0C
12682#define AngelSVC_Reason_Remove 0x0E
12683#define AngelSVC_Reason_Rename 0x0F
12684#define AngelSVC_Reason_Clock 0x10
12685#define AngelSVC_Reason_Time 0x11
12686#define AngelSVC_Reason_System 0x12
12687#define AngelSVC_Reason_Errno 0x13
12688#define AngelSVC_Reason_GetCmdLine 0x15
12689#define AngelSVC_Reason_HeapInfo 0x16
12690#define AngelSVC_Reason_ReportException 0x18
12691#define AngelSVC_Reason_Elapsed 0x30
12692
12693
12694static void
12695handle_halt (sim_cpu *cpu, uint32_t val)
12696{
12697 uint64_t result = 0;
12698
12699 if (val != 0xf000)
12700 {
12701 TRACE_SYSCALL (cpu, " HLT [0x%x]", val);
12702 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12703 sim_stopped, SIM_SIGTRAP);
12704 }
12705
12706 /* We have encountered an Angel SVC call. See if we can process it. */
12707 switch (aarch64_get_reg_u32 (cpu, 0, NO_SP))
12708 {
12709 case AngelSVC_Reason_HeapInfo:
12710 {
12711 /* Get the values. */
12712 uint64_t stack_top = aarch64_get_stack_start (cpu);
12713 uint64_t heap_base = aarch64_get_heap_start (cpu);
12714
12715 /* Get the pointer */
12716 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12717 ptr = aarch64_get_mem_u64 (cpu, ptr);
12718
12719 /* Fill in the memory block. */
12720 /* Start addr of heap. */
12721 aarch64_set_mem_u64 (cpu, ptr + 0, heap_base);
12722 /* End addr of heap. */
12723 aarch64_set_mem_u64 (cpu, ptr + 8, stack_top);
12724 /* Lowest stack addr. */
12725 aarch64_set_mem_u64 (cpu, ptr + 16, heap_base);
12726 /* Initial stack addr. */
12727 aarch64_set_mem_u64 (cpu, ptr + 24, stack_top);
12728
12729 TRACE_SYSCALL (cpu, " AngelSVC: Get Heap Info");
12730 }
12731 break;
12732
12733 case AngelSVC_Reason_Open:
12734 {
12735 /* Get the pointer */
12736 /* uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);. */
12737 /* FIXME: For now we just assume that we will only be asked
12738 to open the standard file descriptors. */
12739 static int fd = 0;
12740 result = fd ++;
12741
12742 TRACE_SYSCALL (cpu, " AngelSVC: Open file %d", fd - 1);
12743 }
12744 break;
12745
12746 case AngelSVC_Reason_Close:
12747 {
12748 uint64_t fh = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12749 TRACE_SYSCALL (cpu, " AngelSVC: Close file %d", (int) fh);
12750 result = 0;
12751 }
12752 break;
12753
12754 case AngelSVC_Reason_Errno:
12755 result = 0;
12756 TRACE_SYSCALL (cpu, " AngelSVC: Get Errno");
12757 break;
12758
12759 case AngelSVC_Reason_Clock:
12760 result =
12761#ifdef CLOCKS_PER_SEC
12762 (CLOCKS_PER_SEC >= 100)
12763 ? (clock () / (CLOCKS_PER_SEC / 100))
12764 : ((clock () * 100) / CLOCKS_PER_SEC)
12765#else
12766 /* Presume unix... clock() returns microseconds. */
12767 (clock () / 10000)
12768#endif
12769 ;
12770 TRACE_SYSCALL (cpu, " AngelSVC: Get Clock");
12771 break;
12772
12773 case AngelSVC_Reason_GetCmdLine:
12774 {
12775 /* Get the pointer */
12776 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12777 ptr = aarch64_get_mem_u64 (cpu, ptr);
12778
12779 /* FIXME: No command line for now. */
12780 aarch64_set_mem_u64 (cpu, ptr, 0);
12781 TRACE_SYSCALL (cpu, " AngelSVC: Get Command Line");
12782 }
12783 break;
12784
12785 case AngelSVC_Reason_IsTTY:
12786 result = 1;
12787 TRACE_SYSCALL (cpu, " AngelSVC: IsTTY ?");
12788 break;
12789
12790 case AngelSVC_Reason_Write:
12791 {
12792 /* Get the pointer */
12793 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12794 /* Get the write control block. */
12795 uint64_t fd = aarch64_get_mem_u64 (cpu, ptr);
12796 uint64_t buf = aarch64_get_mem_u64 (cpu, ptr + 8);
12797 uint64_t len = aarch64_get_mem_u64 (cpu, ptr + 16);
12798
12799 TRACE_SYSCALL (cpu, "write of %" PRIx64 " bytes from %"
12800 PRIx64 " on descriptor %" PRIx64,
12801 len, buf, fd);
12802
12803 if (len > 1280)
12804 {
12805 TRACE_SYSCALL (cpu,
12806 " AngelSVC: Write: Suspiciously long write: %ld",
12807 (long) len);
12808 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12809 sim_stopped, SIM_SIGBUS);
12810 }
12811 else if (fd == 1)
12812 {
12813 printf ("%.*s", (int) len, aarch64_get_mem_ptr (cpu, buf));
2e8cf49e
NC
12814 }
12815 else if (fd == 2)
12816 {
12817 TRACE (cpu, 0, "\n");
12818 sim_io_eprintf (CPU_STATE (cpu), "%.*s",
12819 (int) len, aarch64_get_mem_ptr (cpu, buf));
12820 TRACE (cpu, 0, "\n");
12821 }
12822 else
12823 {
12824 TRACE_SYSCALL (cpu,
12825 " AngelSVC: Write: Unexpected file handle: %d",
12826 (int) fd);
12827 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12828 sim_stopped, SIM_SIGABRT);
12829 }
12830 }
12831 break;
12832
12833 case AngelSVC_Reason_ReportException:
12834 {
12835 /* Get the pointer */
12836 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12837 /*ptr = aarch64_get_mem_u64 (cpu, ptr);. */
12838 uint64_t type = aarch64_get_mem_u64 (cpu, ptr);
12839 uint64_t state = aarch64_get_mem_u64 (cpu, ptr + 8);
12840
12841 TRACE_SYSCALL (cpu,
12842 "Angel Exception: type 0x%" PRIx64 " state %" PRIx64,
12843 type, state);
12844
12845 if (type == 0x20026)
12846 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12847 sim_exited, state);
12848 else
12849 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12850 sim_stopped, SIM_SIGINT);
12851 }
12852 break;
12853
12854 case AngelSVC_Reason_Read:
12855 case AngelSVC_Reason_FLen:
12856 case AngelSVC_Reason_Seek:
12857 case AngelSVC_Reason_Remove:
12858 case AngelSVC_Reason_Time:
12859 case AngelSVC_Reason_System:
12860 case AngelSVC_Reason_Rename:
12861 case AngelSVC_Reason_Elapsed:
12862 default:
12863 TRACE_SYSCALL (cpu, " HLT [Unknown angel %x]",
12864 aarch64_get_reg_u32 (cpu, 0, NO_SP));
12865 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12866 sim_stopped, SIM_SIGTRAP);
12867 }
12868
12869 aarch64_set_reg_u64 (cpu, 0, NO_SP, result);
12870}
12871
12872static void
12873dexExcpnGen (sim_cpu *cpu)
12874{
12875 /* instr[31:24] = 11010100
12876 instr[23,21] = opc : 000 ==> GEN EXCPN, 001 ==> BRK
12877 010 ==> HLT, 101 ==> DBG GEN EXCPN
12878 instr[20,5] = imm16
12879 instr[4,2] = opc2 000 ==> OK, ow ==> UNALLOC
12880 instr[1,0] = LL : discriminates opc */
12881
12882 uint32_t opc = uimm (aarch64_get_instr (cpu), 23, 21);
12883 uint32_t imm16 = uimm (aarch64_get_instr (cpu), 20, 5);
12884 uint32_t opc2 = uimm (aarch64_get_instr (cpu), 4, 2);
12885 uint32_t LL;
12886
12887 NYI_assert (31, 24, 0xd4);
12888
12889 if (opc2 != 0)
12890 HALT_UNALLOC;
12891
12892 LL = uimm (aarch64_get_instr (cpu), 1, 0);
12893
12894 /* We only implement HLT and BRK for now. */
12895 if (opc == 1 && LL == 0)
12896 {
12897 TRACE_EVENTS (cpu, " BRK [0x%x]", imm16);
12898 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12899 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
12900 }
12901
12902 if (opc == 2 && LL == 0)
12903 handle_halt (cpu, imm16);
12904
12905 else if (opc == 0 || opc == 5)
12906 HALT_NYI;
12907
12908 else
12909 HALT_UNALLOC;
12910}
12911
caa8d700
NC
12912/* Stub for accessing system registers.
12913 We implement support for the DCZID register since this is used
12914 by the C library's memset function. */
12915
12916static uint64_t
12917system_get (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
12918 unsigned crm, unsigned op2)
12919{
12920 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 7)
12921 /* DCZID_EL0 - the Data Cache Zero ID register.
12922 We do not support DC ZVA at the moment, so
12923 we return a value with the disable bit set. */
12924 return ((uint64_t) 1) << 4;
12925
12926 HALT_NYI;
12927}
12928
12929static void
12930do_mrs (sim_cpu *cpu)
12931{
12932 /* instr[31:20] = 1101 01010 0011
12933 instr[19] = op0
12934 instr[18,16] = op1
12935 instr[15,12] = CRn
12936 instr[11,8] = CRm
12937 instr[7,5] = op2
12938 instr[4,0] = Rt */
12939 unsigned sys_op0 = uimm (aarch64_get_instr (cpu), 19, 19) + 2;
12940 unsigned sys_op1 = uimm (aarch64_get_instr (cpu), 18, 16);
12941 unsigned sys_crn = uimm (aarch64_get_instr (cpu), 15, 12);
12942 unsigned sys_crm = uimm (aarch64_get_instr (cpu), 11, 8);
12943 unsigned sys_op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12944 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12945
12946 aarch64_set_reg_u64 (cpu, rt, NO_SP,
12947 system_get (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2));
12948}
12949
2e8cf49e
NC
12950static void
12951dexSystem (sim_cpu *cpu)
12952{
12953 /* instr[31:22] = 1101 01010 0
12954 instr[21] = L
12955 instr[20,19] = op0
12956 instr[18,16] = op1
12957 instr[15,12] = CRn
12958 instr[11,8] = CRm
12959 instr[7,5] = op2
12960 instr[4,0] = uimm5 */
12961
12962 /* We are interested in HINT, DSB, DMB and ISB
12963
12964 Hint #0 encodes NOOP (this is the only hint we care about)
12965 L == 0, op0 == 0, op1 = 011, CRn = 0010, Rt = 11111,
12966 CRm op2 != 0000 000 OR CRm op2 == 0000 000 || CRm op > 0000 101
12967
12968 DSB, DMB, ISB are data store barrier, data memory barrier and
12969 instruction store barrier, respectively, where
12970
12971 L == 0, op0 == 0, op1 = 011, CRn = 0011, Rt = 11111,
12972 op2 : DSB ==> 100, DMB ==> 101, ISB ==> 110
12973 CRm<3:2> ==> domain, CRm<1:0> ==> types,
12974 domain : 00 ==> OuterShareable, 01 ==> Nonshareable,
12975 10 ==> InerShareable, 11 ==> FullSystem
12976 types : 01 ==> Reads, 10 ==> Writes,
12977 11 ==> All, 00 ==> All (domain == FullSystem). */
12978
12979 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12980 uint32_t l_op0_op1_crn = uimm (aarch64_get_instr (cpu), 21, 12);
12981
12982 NYI_assert (31, 22, 0x354);
12983
12984 switch (l_op0_op1_crn)
12985 {
12986 case 0x032:
12987 if (rt == 0x1F)
12988 {
12989 /* NOP has CRm != 0000 OR. */
12990 /* (CRm == 0000 AND (op2 == 000 OR op2 > 101)). */
12991 uint32_t crm = uimm (aarch64_get_instr (cpu), 11, 8);
12992 uint32_t op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12993
12994 if (crm != 0 || (op2 == 0 || op2 > 5))
12995 {
12996 /* Actually call nop method so we can reimplement it later. */
12997 nop (cpu);
12998 return;
12999 }
13000 }
13001 HALT_NYI;
13002
13003 case 0x033:
13004 {
13005 uint32_t op2 = uimm (aarch64_get_instr (cpu), 7, 5);
13006
13007 switch (op2)
13008 {
caa8d700 13009 case 2: HALT_NYI;
2e8cf49e
NC
13010 case 4: dsb (cpu); return;
13011 case 5: dmb (cpu); return;
13012 case 6: isb (cpu); return;
13013 case 7:
13014 default: HALT_UNALLOC;
13015 }
13016 }
13017
13018 case 0x3B0:
13019 /* MRS Wt, sys-reg. */
caa8d700 13020 do_mrs (cpu);
2e8cf49e
NC
13021 return;
13022
13023 case 0x3B4:
13024 case 0x3BD:
13025 /* MRS Xt, sys-reg. */
caa8d700 13026 do_mrs (cpu);
2e8cf49e
NC
13027 return;
13028
13029 case 0x0B7:
13030 /* DC <type>, x<n>. */
caa8d700 13031 HALT_NYI;
2e8cf49e
NC
13032 return;
13033
13034 default:
caa8d700
NC
13035 /* if (uimm (aarch64_get_instr (cpu), 21, 20) == 0x1)
13036 MRS Xt, sys-reg. */
2e8cf49e 13037 HALT_NYI;
caa8d700 13038 return;
2e8cf49e
NC
13039 }
13040}
13041
13042static void
13043dexBr (sim_cpu *cpu)
13044{
13045 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
13046 assert group == GROUP_BREXSYS_1010 || group == GROUP_BREXSYS_1011
13047 bits [31,29] of a BrExSys are the secondary dispatch vector. */
13048 uint32_t group2 = dispatchBrExSys (aarch64_get_instr (cpu));
13049
13050 switch (group2)
13051 {
13052 case BR_IMM_000:
13053 return dexBranchImmediate (cpu);
13054
13055 case BR_IMMCMP_001:
13056 /* Compare has bit 25 clear while test has it set. */
13057 if (!uimm (aarch64_get_instr (cpu), 25, 25))
13058 dexCompareBranchImmediate (cpu);
13059 else
13060 dexTestBranchImmediate (cpu);
13061 return;
13062
13063 case BR_IMMCOND_010:
13064 /* This is a conditional branch if bit 25 is clear otherwise
13065 unallocated. */
13066 if (!uimm (aarch64_get_instr (cpu), 25, 25))
13067 dexCondBranchImmediate (cpu);
13068 else
13069 HALT_UNALLOC;
13070 return;
13071
13072 case BR_UNALLOC_011:
13073 HALT_UNALLOC;
13074
13075 case BR_IMM_100:
13076 dexBranchImmediate (cpu);
13077 return;
13078
13079 case BR_IMMCMP_101:
13080 /* Compare has bit 25 clear while test has it set. */
13081 if (!uimm (aarch64_get_instr (cpu), 25, 25))
13082 dexCompareBranchImmediate (cpu);
13083 else
13084 dexTestBranchImmediate (cpu);
13085 return;
13086
13087 case BR_REG_110:
13088 /* Unconditional branch reg has bit 25 set. */
13089 if (uimm (aarch64_get_instr (cpu), 25, 25))
13090 dexBranchRegister (cpu);
13091
13092 /* This includes both Excpn Gen, System and unalloc operations.
13093 We need to decode the Excpn Gen operation BRK so we can plant
13094 debugger entry points.
13095 Excpn Gen operations have aarch64_get_instr (cpu)[24] = 0.
13096 we need to decode at least one of the System operations NOP
13097 which is an alias for HINT #0.
13098 System operations have aarch64_get_instr (cpu)[24,22] = 100. */
13099 else if (uimm (aarch64_get_instr (cpu), 24, 24) == 0)
13100 dexExcpnGen (cpu);
13101
13102 else if (uimm (aarch64_get_instr (cpu), 24, 22) == 4)
13103 dexSystem (cpu);
13104
13105 else
13106 HALT_UNALLOC;
13107
13108 return;
13109
13110 case BR_UNALLOC_111:
13111 HALT_UNALLOC;
13112
13113 default:
13114 /* Should never reach here. */
13115 HALT_NYI;
13116 }
13117}
13118
13119static void
13120aarch64_decode_and_execute (sim_cpu *cpu, uint64_t pc)
13121{
13122 /* We need to check if gdb wants an in here. */
13123 /* checkBreak (cpu);. */
13124
13125 uint64_t group = dispatchGroup (aarch64_get_instr (cpu));
13126
13127 switch (group)
13128 {
13129 case GROUP_PSEUDO_0000: dexPseudo (cpu); break;
13130 case GROUP_LDST_0100: dexLdSt (cpu); break;
13131 case GROUP_DPREG_0101: dexDPReg (cpu); break;
13132 case GROUP_LDST_0110: dexLdSt (cpu); break;
13133 case GROUP_ADVSIMD_0111: dexAdvSIMD0 (cpu); break;
13134 case GROUP_DPIMM_1000: dexDPImm (cpu); break;
13135 case GROUP_DPIMM_1001: dexDPImm (cpu); break;
13136 case GROUP_BREXSYS_1010: dexBr (cpu); break;
13137 case GROUP_BREXSYS_1011: dexBr (cpu); break;
13138 case GROUP_LDST_1100: dexLdSt (cpu); break;
13139 case GROUP_DPREG_1101: dexDPReg (cpu); break;
13140 case GROUP_LDST_1110: dexLdSt (cpu); break;
13141 case GROUP_ADVSIMD_1111: dexAdvSIMD1 (cpu); break;
13142
13143 case GROUP_UNALLOC_0001:
13144 case GROUP_UNALLOC_0010:
13145 case GROUP_UNALLOC_0011:
13146 HALT_UNALLOC;
13147
13148 default:
13149 /* Should never reach here. */
13150 HALT_NYI;
13151 }
13152}
13153
13154static bfd_boolean
13155aarch64_step (sim_cpu *cpu)
13156{
13157 uint64_t pc = aarch64_get_PC (cpu);
13158
13159 if (pc == TOP_LEVEL_RETURN_PC)
13160 return FALSE;
13161
13162 aarch64_set_next_PC (cpu, pc + 4);
13163 aarch64_get_instr (cpu) = aarch64_get_mem_u32 (cpu, pc);
13164
57aa1742 13165 TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %08x", pc,
1a846c62
MF
13166 aarch64_get_instr (cpu));
13167 TRACE_DISASM (cpu, pc);
2e8cf49e
NC
13168
13169 aarch64_decode_and_execute (cpu, pc);
13170
13171 return TRUE;
13172}
13173
13174void
13175aarch64_run (SIM_DESC sd)
13176{
13177 sim_cpu *cpu = STATE_CPU (sd, 0);
13178
13179 while (aarch64_step (cpu))
13180 aarch64_update_PC (cpu);
13181
13182 sim_engine_halt (sd, NULL, NULL, aarch64_get_PC (cpu),
13183 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13184}
13185
13186void
13187aarch64_init (sim_cpu *cpu, uint64_t pc)
13188{
13189 uint64_t sp = aarch64_get_stack_start (cpu);
13190
13191 /* Install SP, FP and PC and set LR to -20
13192 so we can detect a top-level return. */
13193 aarch64_set_reg_u64 (cpu, SP, SP_OK, sp);
13194 aarch64_set_reg_u64 (cpu, FP, SP_OK, sp);
13195 aarch64_set_reg_u64 (cpu, LR, SP_OK, TOP_LEVEL_RETURN_PC);
13196 aarch64_set_next_PC (cpu, pc);
13197 aarch64_update_PC (cpu);
13198 aarch64_init_LIT_table ();
13199}
This page took 0.531959 seconds and 4 git commands to generate.