]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/aarch64/simulator.c
Fix bugs in the simulation of the AArch64's ADDP, FADDP, LD1, CCMP and CCMP instructions.
[thirdparty/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
NC
38#define TST(_flag) (aarch64_test_CPSR_bit (cpu, _flag))
39#define IS_SET(_X) ( TST (( _X )))
40#define IS_CLEAR(_X) (!TST (( _X )))
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
463 aarch64_set_FP_float (cpu, rd,
464 aarch64_get_mem_float
465 (cpu, aarch64_get_PC (cpu) + offset * 4));
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
474 aarch64_set_FP_double (cpu, st,
475 aarch64_get_mem_double
476 (cpu, aarch64_get_PC (cpu) + offset * 4));
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
548 aarch64_set_FP_float (cpu, st, aarch64_get_mem_float (cpu, address));
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
563 aarch64_set_FP_float (cpu, st,
564 aarch64_get_mem_float
565 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
566 + SCALE (offset, 32)));
567}
568
569/* Load 32 bit scaled or unscaled zero- or sign-extended
570 32-bit register offset. */
571static void
572fldrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
573{
574 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
575 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
576 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
577 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
578 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
579 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
580
581 aarch64_set_FP_float (cpu, st,
582 aarch64_get_mem_float
583 (cpu, address + displacement));
584}
585
586/* Load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
587static void
588fldrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
589{
590 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
591 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
592 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
593
594 if (wb != Post)
595 address += offset;
596
597 aarch64_set_FP_double (cpu, st, aarch64_get_mem_double (cpu, address));
598
599 if (wb == Post)
600 address += offset;
601
602 if (wb != NoWriteBack)
603 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
604}
605
606/* Load 64 bit scaled unsigned 12 bit. */
607static void
608fldrd_abs (sim_cpu *cpu, uint32_t offset)
609{
610 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
611 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
612 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64);
613
614 aarch64_set_FP_double (cpu, st, aarch64_get_mem_double (cpu, address));
615}
616
617/* Load 64 bit scaled or unscaled zero- or sign-extended 32-bit register offset. */
618static void
619fldrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
620{
621 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
622 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
623 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
624
625 fldrd_wb (cpu, displacement, NoWriteBack);
626}
627
628/* Load 128 bit unscaled signed 9 bit with pre- or post-writeback. */
629static void
630fldrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
631{
632 FRegister a;
633 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
634 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
635 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
636
637 if (wb != Post)
638 address += offset;
639
640 aarch64_get_mem_long_double (cpu, address, & a);
641 aarch64_set_FP_long_double (cpu, st, a);
642
643 if (wb == Post)
644 address += offset;
645
646 if (wb != NoWriteBack)
647 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
648}
649
650/* Load 128 bit scaled unsigned 12 bit. */
651static void
652fldrq_abs (sim_cpu *cpu, uint32_t offset)
653{
654 FRegister a;
655 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
656 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
657 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
658
659 aarch64_get_mem_long_double (cpu, address, & a);
660 aarch64_set_FP_long_double (cpu, st, a);
661}
662
663/* Load 128 bit scaled or unscaled zero- or sign-extended 32-bit register offset */
664static void
665fldrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
666{
667 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
668 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
669 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
670
671 fldrq_wb (cpu, displacement, NoWriteBack);
672}
673
674/* Memory Access
675
676 load-store single register
677 There are four addressing modes available here which all employ a
678 64 bit source (base) register.
679
680 N.B. the base register (source) can be the stack pointer.
681 The secondary source register (source2)can only be an Xn register.
682
683 Scaled, 12-bit, unsigned immediate offset, without pre- and
684 post-index options.
685 Unscaled, 9-bit, signed immediate offset with pre- or post-index
686 writeback.
687 scaled or unscaled 64-bit register offset.
688 scaled or unscaled 32-bit extended register offset.
689
690 All offsets are assumed to be raw from the decode i.e. the
691 simulator is expected to adjust scaled offsets based on the
692 accessed data size with register or extended register offset
693 versions the same applies except that in the latter case the
694 operation may also require a sign extend.
695
696 A separate method is provided for each possible addressing mode. */
697
698/* 32 bit load 32 bit scaled unsigned 12 bit */
699static void
700ldr32_abs (sim_cpu *cpu, uint32_t offset)
701{
702 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
703 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
704
705 /* The target register may not be SP but the source may be. */
706 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
707 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
708 + SCALE (offset, 32)));
709}
710
711/* 32 bit load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
712static void
713ldr32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
714{
715 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
716 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
717 uint64_t address;
718
719 if (rn == rt && wb != NoWriteBack)
720 HALT_UNALLOC;
721
722 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
723
724 if (wb != Post)
725 address += offset;
726
727 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
728
729 if (wb == Post)
730 address += offset;
731
732 if (wb != NoWriteBack)
733 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
734}
735
736/* 32 bit load 32 bit scaled or unscaled
737 zero- or sign-extended 32-bit register offset */
738static void
739ldr32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
740{
741 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
742 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
743 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
744 /* rn may reference SP, rm and rt must reference ZR */
745
746 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
747 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
748 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
749
750 aarch64_set_reg_u64 (cpu, rt, NO_SP,
751 aarch64_get_mem_u32 (cpu, address + displacement));
752}
753
754/* 64 bit load 64 bit scaled unsigned 12 bit */
755static void
756ldr_abs (sim_cpu *cpu, uint32_t offset)
757{
758 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
759 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
760
761 /* The target register may not be SP but the source may be. */
762 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
763 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
764 + SCALE (offset, 64)));
765}
766
767/* 64 bit load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
768static void
769ldr_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
770{
771 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
772 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
773 uint64_t address;
774
775 if (rn == rt && wb != NoWriteBack)
776 HALT_UNALLOC;
777
778 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
779
780 if (wb != Post)
781 address += offset;
782
783 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
784
785 if (wb == Post)
786 address += offset;
787
788 if (wb != NoWriteBack)
789 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
790}
791
792/* 64 bit load 64 bit scaled or unscaled zero-
793 or sign-extended 32-bit register offset. */
794static void
795ldr_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
796{
797 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
798 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
799 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
800 /* rn may reference SP, rm and rt must reference ZR */
801
802 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
803 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
804 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
805
806 aarch64_set_reg_u64 (cpu, rt, NO_SP,
807 aarch64_get_mem_u64 (cpu, address + displacement));
808}
809
810/* 32 bit load zero-extended byte scaled unsigned 12 bit. */
811static void
812ldrb32_abs (sim_cpu *cpu, uint32_t offset)
813{
814 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
815 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
816
817 /* The target register may not be SP but the source may be
818 there is no scaling required for a byte load. */
819 aarch64_set_reg_u64 (cpu, rt, NO_SP,
820 aarch64_get_mem_u8
821 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
822}
823
824/* 32 bit load zero-extended byte unscaled signed 9 bit with pre- or post-writeback. */
825static void
826ldrb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
827{
828 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
829 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
830 uint64_t address;
831
832 if (rn == rt && wb != NoWriteBack)
833 HALT_UNALLOC;
834
835 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
836
837 if (wb != Post)
838 address += offset;
839
840 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
841
842 if (wb == Post)
843 address += offset;
844
845 if (wb != NoWriteBack)
846 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
847}
848
849/* 32 bit load zero-extended byte scaled or unscaled zero-
850 or sign-extended 32-bit register offset. */
851static void
852ldrb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
853{
854 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
855 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
856 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
857 /* rn may reference SP, rm and rt must reference ZR */
858
859 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
860 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
861 extension);
862
863 /* There is no scaling required for a byte load. */
864 aarch64_set_reg_u64 (cpu, rt, NO_SP,
865 aarch64_get_mem_u8 (cpu, address + displacement));
866}
867
868/* 64 bit load sign-extended byte unscaled signed 9 bit
869 with pre- or post-writeback. */
870static void
871ldrsb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
872{
873 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
874 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
875 uint64_t address;
876
877 if (rn == rt && wb != NoWriteBack)
878 HALT_UNALLOC;
879
880 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
881
882 if (wb != Post)
883 address += offset;
884
885 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s8 (cpu, address));
886
887 if (wb == Post)
888 address += offset;
889
890 if (wb != NoWriteBack)
891 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
892}
893
894/* 64 bit load sign-extended byte scaled unsigned 12 bit. */
895static void
896ldrsb_abs (sim_cpu *cpu, uint32_t offset)
897{
898 ldrsb_wb (cpu, offset, NoWriteBack);
899}
900
901/* 64 bit load sign-extended byte scaled or unscaled zero-
902 or sign-extended 32-bit register offset. */
903static void
904ldrsb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
905{
906 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
907 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
908 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
909 /* rn may reference SP, rm and rt must reference ZR */
910
911 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
912 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
913 extension);
914 /* There is no scaling required for a byte load. */
915 aarch64_set_reg_u64 (cpu, rt, NO_SP,
916 aarch64_get_mem_s8 (cpu, address + displacement));
917}
918
919/* 32 bit load zero-extended short scaled unsigned 12 bit. */
920static void
921ldrh32_abs (sim_cpu *cpu, uint32_t offset)
922{
923 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
924 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
925
926 /* The target register may not be SP but the source may be. */
927 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16
928 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
929 + SCALE (offset, 16)));
930}
931
932/* 32 bit load zero-extended short unscaled signed 9 bit
933 with pre- or post-writeback. */
934static void
935ldrh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
936{
937 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
938 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
939 uint64_t address;
940
941 if (rn == rt && wb != NoWriteBack)
942 HALT_UNALLOC;
943
944 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
945
946 if (wb != Post)
947 address += offset;
948
949 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
950
951 if (wb == Post)
952 address += offset;
953
954 if (wb != NoWriteBack)
955 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
956}
957
958/* 32 bit load zero-extended short scaled or unscaled zero-
959 or sign-extended 32-bit register offset. */
960static void
961ldrh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
962{
963 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
964 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
965 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
966 /* rn may reference SP, rm and rt must reference ZR */
967
968 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
969 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
970 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
971
972 aarch64_set_reg_u64 (cpu, rt, NO_SP,
973 aarch64_get_mem_u16 (cpu, address + displacement));
974}
975
976/* 32 bit load sign-extended short scaled unsigned 12 bit. */
977static void
978ldrsh32_abs (sim_cpu *cpu, uint32_t offset)
979{
980 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
981 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
982
983 /* The target register may not be SP but the source may be. */
984 aarch64_set_reg_u64 (cpu, rt, NO_SP, (uint32_t) aarch64_get_mem_s16
985 (cpu,
986 aarch64_get_reg_u64 (cpu, rn, SP_OK)
987 + SCALE (offset, 16)));
988}
989
990/* 32 bit load sign-extended short unscaled signed 9 bit
991 with pre- or post-writeback. */
992static void
993ldrsh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
994{
995 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
996 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
997 uint64_t address;
998
999 if (rn == rt && wb != NoWriteBack)
1000 HALT_UNALLOC;
1001
1002 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1003
1004 if (wb != Post)
1005 address += offset;
1006
1007 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1008 (uint32_t) aarch64_get_mem_s16 (cpu, address));
1009
1010 if (wb == Post)
1011 address += offset;
1012
1013 if (wb != NoWriteBack)
1014 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1015}
1016
1017/* 32 bit load sign-extended short scaled or unscaled zero-
1018 or sign-extended 32-bit register offset. */
1019static void
1020ldrsh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1021{
1022 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1023 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1024 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1025 /* rn may reference SP, rm and rt must reference ZR */
1026
1027 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1028 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1029 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1030
1031 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1032 (uint32_t) aarch64_get_mem_s16
1033 (cpu, address + displacement));
1034}
1035
1036/* 64 bit load sign-extended short scaled unsigned 12 bit. */
1037static void
1038ldrsh_abs (sim_cpu *cpu, uint32_t offset)
1039{
1040 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1041 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1042
1043 /* The target register may not be SP but the source may be. */
1044 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s16
1045 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1046 + SCALE (offset, 16)));
1047}
1048
1049/* 64 bit load sign-extended short unscaled signed 9 bit
1050 with pre- or post-writeback. */
1051static void
1052ldrsh64_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1053{
1054 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1055 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1056 uint64_t address;
1057
1058 if (rn == rt && wb != NoWriteBack)
1059 HALT_UNALLOC;
1060
1061 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1062
1063 if (wb != Post)
1064 address += offset;
1065
1066 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s16 (cpu, address));
1067
1068 if (wb == Post)
1069 address += offset;
1070
1071 if (wb != NoWriteBack)
1072 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1073}
1074
1075/* 64 bit load sign-extended short scaled or unscaled zero-
1076 or sign-extended 32-bit register offset. */
1077static void
1078ldrsh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1079{
1080 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1081 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1082 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1083 /* rn may reference SP, rm and rt must reference ZR */
1084
1085 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1086 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1087 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1088
1089 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1090 aarch64_get_mem_s16 (cpu, address + displacement));
1091}
1092
1093/* 64 bit load sign-extended 32 bit scaled unsigned 12 bit. */
1094static void
1095ldrsw_abs (sim_cpu *cpu, uint32_t offset)
1096{
1097 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1098 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1099
1100 /* The target register may not be SP but the source may be. */
1101 return aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32
1102 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1103 + SCALE (offset, 32)));
1104}
1105
1106/* 64 bit load sign-extended 32 bit unscaled signed 9 bit
1107 with pre- or post-writeback. */
1108static void
1109ldrsw_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1110{
1111 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1112 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1113 uint64_t address;
1114
1115 if (rn == rt && wb != NoWriteBack)
1116 HALT_UNALLOC;
1117
1118 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1119
1120 if (wb != Post)
1121 address += offset;
1122
1123 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32 (cpu, address));
1124
1125 if (wb == Post)
1126 address += offset;
1127
1128 if (wb != NoWriteBack)
1129 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1130}
1131
1132/* 64 bit load sign-extended 32 bit scaled or unscaled zero-
1133 or sign-extended 32-bit register offset. */
1134static void
1135ldrsw_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1136{
1137 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1138 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1139 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1140 /* rn may reference SP, rm and rt must reference ZR */
1141
1142 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1143 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1144 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1145
1146 aarch64_set_reg_s64 (cpu, rt, NO_SP,
1147 aarch64_get_mem_s32 (cpu, address + displacement));
1148}
1149
1150/* N.B. with stores the value in source is written to the
1151 address identified by source2 modified by source3/offset. */
1152
1153/* 32 bit store scaled unsigned 12 bit. */
1154static void
1155str32_abs (sim_cpu *cpu, uint32_t offset)
1156{
1157 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1158 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1159
1160 /* The target register may not be SP but the source may be. */
1161 aarch64_set_mem_u32 (cpu, (aarch64_get_reg_u64 (cpu, rn, SP_OK)
1162 + SCALE (offset, 32)),
1163 aarch64_get_reg_u32 (cpu, rt, NO_SP));
1164}
1165
1166/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
1167static void
1168str32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1169{
1170 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1171 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1172 uint64_t address;
1173
1174 if (rn == rt && wb != NoWriteBack)
1175 HALT_UNALLOC;
1176
1177 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1178 if (wb != Post)
1179 address += offset;
1180
1181 aarch64_set_mem_u32 (cpu, address, aarch64_get_reg_u32 (cpu, rt, NO_SP));
1182
1183 if (wb == Post)
1184 address += offset;
1185
1186 if (wb != NoWriteBack)
1187 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1188}
1189
1190/* 32 bit store scaled or unscaled zero- or
1191 sign-extended 32-bit register offset. */
1192static void
1193str32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1194{
1195 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1196 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1197 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1198
1199 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1200 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1201 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1202
1203 aarch64_set_mem_u32 (cpu, address + displacement,
1204 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1205}
1206
1207/* 64 bit store scaled unsigned 12 bit. */
1208static void
1209str_abs (sim_cpu *cpu, uint32_t offset)
1210{
1211 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1212 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1213
1214 aarch64_set_mem_u64 (cpu,
1215 aarch64_get_reg_u64 (cpu, rn, SP_OK)
1216 + SCALE (offset, 64),
1217 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1218}
1219
1220/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
1221static void
1222str_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1223{
1224 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1225 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1226 uint64_t address;
1227
1228 if (rn == rt && wb != NoWriteBack)
1229 HALT_UNALLOC;
1230
1231 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1232
1233 if (wb != Post)
1234 address += offset;
1235
1236 aarch64_set_mem_u64 (cpu, address, aarch64_get_reg_u64 (cpu, rt, NO_SP));
1237
1238 if (wb == Post)
1239 address += offset;
1240
1241 if (wb != NoWriteBack)
1242 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1243}
1244
1245/* 64 bit store scaled or unscaled zero-
1246 or sign-extended 32-bit register offset. */
1247static void
1248str_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1249{
1250 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1251 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1252 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1253 /* rn may reference SP, rm and rt must reference ZR */
1254
1255 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1256 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1257 extension);
1258 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1259
1260 aarch64_set_mem_u64 (cpu, address + displacement,
1261 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1262}
1263
1264/* 32 bit store byte scaled unsigned 12 bit. */
1265static void
1266strb_abs (sim_cpu *cpu, uint32_t offset)
1267{
1268 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1269 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1270
1271 /* The target register may not be SP but the source may be.
1272 There is no scaling required for a byte load. */
1273 aarch64_set_mem_u8 (cpu,
1274 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
1275 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1276}
1277
1278/* 32 bit store byte unscaled signed 9 bit with pre- or post-writeback. */
1279static void
1280strb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1281{
1282 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1283 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1284 uint64_t address;
1285
1286 if (rn == rt && wb != NoWriteBack)
1287 HALT_UNALLOC;
1288
1289 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1290
1291 if (wb != Post)
1292 address += offset;
1293
1294 aarch64_set_mem_u8 (cpu, address, aarch64_get_reg_u8 (cpu, rt, NO_SP));
1295
1296 if (wb == Post)
1297 address += offset;
1298
1299 if (wb != NoWriteBack)
1300 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1301}
1302
1303/* 32 bit store byte scaled or unscaled zero-
1304 or sign-extended 32-bit register offset. */
1305static void
1306strb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1307{
1308 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1309 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1310 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1311 /* rn may reference SP, rm and rt must reference ZR */
1312
1313 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1314 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1315 extension);
1316
1317 /* There is no scaling required for a byte load. */
1318 aarch64_set_mem_u8 (cpu, address + displacement,
1319 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1320}
1321
1322/* 32 bit store short scaled unsigned 12 bit. */
1323static void
1324strh_abs (sim_cpu *cpu, uint32_t offset)
1325{
1326 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1327 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1328
1329 /* The target register may not be SP but the source may be. */
1330 aarch64_set_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1331 + SCALE (offset, 16),
1332 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1333}
1334
1335/* 32 bit store short unscaled signed 9 bit with pre- or post-writeback. */
1336static void
1337strh_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1338{
1339 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1340 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1341 uint64_t address;
1342
1343 if (rn == rt && wb != NoWriteBack)
1344 HALT_UNALLOC;
1345
1346 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1347
1348 if (wb != Post)
1349 address += offset;
1350
1351 aarch64_set_mem_u16 (cpu, address, aarch64_get_reg_u16 (cpu, rt, NO_SP));
1352
1353 if (wb == Post)
1354 address += offset;
1355
1356 if (wb != NoWriteBack)
1357 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1358}
1359
1360/* 32 bit store short scaled or unscaled zero-
1361 or sign-extended 32-bit register offset. */
1362static void
1363strh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1364{
1365 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1366 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1367 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1368 /* rn may reference SP, rm and rt must reference ZR */
1369
1370 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1371 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1372 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1373
1374 aarch64_set_mem_u16 (cpu, address + displacement,
1375 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1376}
1377
1378/* Prefetch unsigned 12 bit. */
1379static void
1380prfm_abs (sim_cpu *cpu, uint32_t offset)
1381{
1382 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1383 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1384 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1385 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1386 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1387 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1388 ow ==> UNALLOC
1389 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1390 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK)
1391 + SCALE (offset, 64). */
1392
1393 /* TODO : implement prefetch of address. */
1394}
1395
1396/* Prefetch scaled or unscaled zero- or sign-extended 32-bit register offset. */
1397static void
1398prfm_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1399{
1400 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1401 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1402 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1403 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1404 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1405 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1406 ow ==> UNALLOC
1407 rn may reference SP, rm may only reference ZR
1408 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1409 uint64_t base = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1410 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1411 extension);
1412 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1413 uint64_t address = base + displacement. */
1414
1415 /* TODO : implement prefetch of address */
1416}
1417
1418/* 64 bit pc-relative prefetch. */
1419static void
1420prfm_pcrel (sim_cpu *cpu, int32_t offset)
1421{
1422 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1423 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1424 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1425 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1426 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1427 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1428 ow ==> UNALLOC
1429 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1430 uint64_t address = aarch64_get_PC (cpu) + offset. */
1431
1432 /* TODO : implement this */
1433}
1434
1435/* Load-store exclusive. */
1436
1437static void
1438ldxr (sim_cpu *cpu)
1439{
1440 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1441 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1442 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1443 int size = uimm (aarch64_get_instr (cpu), 31, 30);
1444 /* int ordered = uimm (aarch64_get_instr (cpu), 15, 15); */
1445 /* int exclusive = ! uimm (aarch64_get_instr (cpu), 23, 23); */
1446
1447 switch (size)
1448 {
1449 case 0:
1450 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
1451 break;
1452 case 1:
1453 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
1454 break;
1455 case 2:
1456 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
1457 break;
1458 case 3:
1459 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
1460 break;
1461 default:
1462 HALT_UNALLOC;
1463 }
1464}
1465
1466static void
1467stxr (sim_cpu *cpu)
1468{
1469 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1470 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1471 unsigned rs = uimm (aarch64_get_instr (cpu), 20, 16);
1472 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1473 int size = uimm (aarch64_get_instr (cpu), 31, 30);
1474 uint64_t data = aarch64_get_reg_u64 (cpu, rt, NO_SP);
1475
1476 switch (size)
1477 {
1478 case 0: aarch64_set_mem_u8 (cpu, address, data); break;
1479 case 1: aarch64_set_mem_u16 (cpu, address, data); break;
1480 case 2: aarch64_set_mem_u32 (cpu, address, data); break;
1481 case 3: aarch64_set_mem_u64 (cpu, address, data); break;
1482 default: HALT_UNALLOC;
1483 }
1484
1485 aarch64_set_reg_u64 (cpu, rs, NO_SP, 0); /* Always exclusive... */
1486}
1487
1488static void
1489dexLoadLiteral (sim_cpu *cpu)
1490{
1491 /* instr[29,27] == 011
1492 instr[25,24] == 00
1493 instr[31,30:26] = opc: 000 ==> LDRW, 001 ==> FLDRS
1494 010 ==> LDRX, 011 ==> FLDRD
1495 100 ==> LDRSW, 101 ==> FLDRQ
1496 110 ==> PRFM, 111 ==> UNALLOC
1497 instr[26] ==> V : 0 ==> GReg, 1 ==> FReg
1498 instr[23, 5] == simm19 */
1499
1500 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
1501 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 1)
1502 | uimm (aarch64_get_instr (cpu), 26, 26));
1503 int32_t imm = simm32 (aarch64_get_instr (cpu), 23, 5);
1504
1505 switch (dispatch)
1506 {
1507 case 0: ldr32_pcrel (cpu, imm); break;
1508 case 1: fldrs_pcrel (cpu, imm); break;
1509 case 2: ldr_pcrel (cpu, imm); break;
1510 case 3: fldrd_pcrel (cpu, imm); break;
1511 case 4: ldrsw_pcrel (cpu, imm); break;
1512 case 5: fldrq_pcrel (cpu, imm); break;
1513 case 6: prfm_pcrel (cpu, imm); break;
1514 case 7:
1515 default:
1516 HALT_UNALLOC;
1517 }
1518}
1519
1520/* Immediate arithmetic
1521 The aimm argument is a 12 bit unsigned value or a 12 bit unsigned
1522 value left shifted by 12 bits (done at decode).
1523
1524 N.B. the register args (dest, source) can normally be Xn or SP.
1525 the exception occurs for flag setting instructions which may
1526 only use Xn for the output (dest). */
1527
1528/* 32 bit add immediate. */
1529static void
1530add32 (sim_cpu *cpu, uint32_t aimm)
1531{
1532 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1533 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1534
1535 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1536 aarch64_get_reg_u32 (cpu, rn, SP_OK) + aimm);
1537}
1538
1539/* 64 bit add immediate. */
1540static void
1541add64 (sim_cpu *cpu, uint32_t aimm)
1542{
1543 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1544 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1545
1546 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1547 aarch64_get_reg_u64 (cpu, rn, SP_OK) + aimm);
1548}
1549
1550static void
1551set_flags_for_add32 (sim_cpu *cpu, int32_t value1, int32_t value2)
1552{
1553 int32_t result = value1 + value2;
1554 int64_t sresult = (int64_t) value1 + (int64_t) value2;
1555 uint64_t uresult = (uint64_t)(uint32_t) value1
1556 + (uint64_t)(uint32_t) value2;
1557 uint32_t flags = 0;
1558
1559 if (result == 0)
1560 flags |= Z;
1561
1562 if (result & (1 << 31))
1563 flags |= N;
1564
1565 if (uresult != result)
1566 flags |= C;
1567
1568 if (sresult != result)
1569 flags |= V;
1570
1571 aarch64_set_CPSR (cpu, flags);
1572}
1573
1574static void
1575set_flags_for_add64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1576{
1577 int64_t sval1 = value1;
1578 int64_t sval2 = value2;
1579 uint64_t result = value1 + value2;
1580 int64_t sresult = sval1 + sval2;
1581 uint32_t flags = 0;
1582
1583 if (result == 0)
1584 flags |= Z;
1585
1586 if (result & (1ULL << 63))
1587 flags |= N;
1588
1589 if (sval1 < 0)
1590 {
1591 if (sval2 < 0)
1592 {
1593 /* Negative plus a negative. Overflow happens if
1594 the result is greater than either of the operands. */
1595 if (sresult > sval1 || sresult > sval2)
1596 flags |= V;
1597 }
1598 /* else Negative plus a positive. Overflow cannot happen. */
1599 }
1600 else /* value1 is +ve. */
1601 {
1602 if (sval2 < 0)
1603 {
1604 /* Overflow can only occur if we computed "0 - MININT". */
1605 if (sval1 == 0 && sval2 == (1LL << 63))
1606 flags |= V;
1607 }
1608 else
1609 {
1610 /* Postive plus positive - overflow has happened if the
1611 result is smaller than either of the operands. */
1612 if (result < value1 || result < value2)
1613 flags |= V | C;
1614 }
1615 }
1616
1617 aarch64_set_CPSR (cpu, flags);
1618}
1619
1620#define NEG(a) (((a) & signbit) == signbit)
1621#define POS(a) (((a) & signbit) == 0)
1622
1623static void
1624set_flags_for_sub32 (sim_cpu *cpu, uint32_t value1, uint32_t value2)
1625{
1626 uint32_t result = value1 - value2;
1627 uint32_t flags = 0;
57aa1742 1628 uint32_t signbit = 1U << 31;
2e8cf49e
NC
1629
1630 if (result == 0)
1631 flags |= Z;
1632
1633 if (NEG (result))
1634 flags |= N;
1635
1636 if ( (NEG (value1) && POS (value2))
1637 || (NEG (value1) && POS (result))
1638 || (POS (value2) && POS (result)))
1639 flags |= C;
1640
1641 if ( (NEG (value1) && POS (value2) && POS (result))
1642 || (POS (value1) && NEG (value2) && NEG (result)))
1643 flags |= V;
1644
1645 aarch64_set_CPSR (cpu, flags);
1646}
1647
1648static void
1649set_flags_for_sub64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1650{
1651 uint64_t result = value1 - value2;
1652 uint32_t flags = 0;
1653 uint64_t signbit = 1ULL << 63;
1654
1655 if (result == 0)
1656 flags |= Z;
1657
1658 if (NEG (result))
1659 flags |= N;
1660
1661 if ( (NEG (value1) && POS (value2))
1662 || (NEG (value1) && POS (result))
1663 || (POS (value2) && POS (result)))
1664 flags |= C;
1665
1666 if ( (NEG (value1) && POS (value2) && POS (result))
1667 || (POS (value1) && NEG (value2) && NEG (result)))
1668 flags |= V;
1669
1670 aarch64_set_CPSR (cpu, flags);
1671}
1672
1673static void
1674set_flags_for_binop32 (sim_cpu *cpu, uint32_t result)
1675{
1676 uint32_t flags = 0;
1677
1678 if (result == 0)
1679 flags |= Z;
1680 else
1681 flags &= ~ Z;
1682
1683 if (result & (1 << 31))
1684 flags |= N;
1685 else
1686 flags &= ~ N;
1687
1688 aarch64_set_CPSR (cpu, flags);
1689}
1690
1691static void
1692set_flags_for_binop64 (sim_cpu *cpu, uint64_t result)
1693{
1694 uint32_t flags = 0;
1695
1696 if (result == 0)
1697 flags |= Z;
1698 else
1699 flags &= ~ Z;
1700
1701 if (result & (1ULL << 63))
1702 flags |= N;
1703 else
1704 flags &= ~ N;
1705
1706 aarch64_set_CPSR (cpu, flags);
1707}
1708
1709/* 32 bit add immediate set flags. */
1710static void
1711adds32 (sim_cpu *cpu, uint32_t aimm)
1712{
1713 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1714 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1715 /* TODO : do we need to worry about signs here? */
1716 int32_t value1 = aarch64_get_reg_s32 (cpu, rn, SP_OK);
1717
1718 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + aimm);
1719 set_flags_for_add32 (cpu, value1, aimm);
1720}
1721
1722/* 64 bit add immediate set flags. */
1723static void
1724adds64 (sim_cpu *cpu, uint32_t aimm)
1725{
1726 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1727 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1728 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1729 uint64_t value2 = aimm;
1730
1731 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1732 set_flags_for_add64 (cpu, value1, value2);
1733}
1734
1735/* 32 bit sub immediate. */
1736static void
1737sub32 (sim_cpu *cpu, uint32_t aimm)
1738{
1739 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1740 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1741
1742 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1743 aarch64_get_reg_u32 (cpu, rn, SP_OK) - aimm);
1744}
1745
1746/* 64 bit sub immediate. */
1747static void
1748sub64 (sim_cpu *cpu, uint32_t aimm)
1749{
1750 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1751 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1752
1753 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1754 aarch64_get_reg_u64 (cpu, rn, SP_OK) - aimm);
1755}
1756
1757/* 32 bit sub immediate set flags. */
1758static void
1759subs32 (sim_cpu *cpu, uint32_t aimm)
1760{
1761 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1762 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1763 uint32_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1764 uint32_t value2 = aimm;
1765
1766 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1767 set_flags_for_sub32 (cpu, value1, value2);
1768}
1769
1770/* 64 bit sub immediate set flags. */
1771static void
1772subs64 (sim_cpu *cpu, uint32_t aimm)
1773{
1774 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1775 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1776 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1777 uint32_t value2 = aimm;
1778
1779 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1780 set_flags_for_sub64 (cpu, value1, value2);
1781}
1782
1783/* Data Processing Register. */
1784
1785/* First two helpers to perform the shift operations. */
1786
1787static inline uint32_t
1788shifted32 (uint32_t value, Shift shift, uint32_t count)
1789{
1790 switch (shift)
1791 {
1792 default:
1793 case LSL:
1794 return (value << count);
1795 case LSR:
1796 return (value >> count);
1797 case ASR:
1798 {
1799 int32_t svalue = value;
1800 return (svalue >> count);
1801 }
1802 case ROR:
1803 {
1804 uint32_t top = value >> count;
1805 uint32_t bottom = value << (32 - count);
1806 return (bottom | top);
1807 }
1808 }
1809}
1810
1811static inline uint64_t
1812shifted64 (uint64_t value, Shift shift, uint32_t count)
1813{
1814 switch (shift)
1815 {
1816 default:
1817 case LSL:
1818 return (value << count);
1819 case LSR:
1820 return (value >> count);
1821 case ASR:
1822 {
1823 int64_t svalue = value;
1824 return (svalue >> count);
1825 }
1826 case ROR:
1827 {
1828 uint64_t top = value >> count;
1829 uint64_t bottom = value << (64 - count);
1830 return (bottom | top);
1831 }
1832 }
1833}
1834
1835/* Arithmetic shifted register.
1836 These allow an optional LSL, ASR or LSR to the second source
1837 register with a count up to the register bit count.
1838
1839 N.B register args may not be SP. */
1840
1841/* 32 bit ADD shifted register. */
1842static void
1843add32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1844{
1845 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1846 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1847 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1848
1849 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1850 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1851 + shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1852 shift, count));
1853}
1854
1855/* 64 bit ADD shifted register. */
1856static void
1857add64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1858{
1859 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1860 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1861 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1862
1863 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1864 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1865 + shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1866 shift, count));
1867}
1868
1869/* 32 bit ADD shifted register setting flags. */
1870static void
1871adds32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1872{
1873 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1874 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1875 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1876
1877 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1878 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1879 shift, count);
1880
1881 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1882 set_flags_for_add32 (cpu, value1, value2);
1883}
1884
1885/* 64 bit ADD shifted register setting flags. */
1886static void
1887adds64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1888{
1889 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1890 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1891 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1892
1893 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1894 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1895 shift, count);
1896
1897 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1898 set_flags_for_add64 (cpu, value1, value2);
1899}
1900
1901/* 32 bit SUB shifted register. */
1902static void
1903sub32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1904{
1905 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1906 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1907 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1908
1909 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1910 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1911 - shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1912 shift, count));
1913}
1914
1915/* 64 bit SUB shifted register. */
1916static void
1917sub64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1918{
1919 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1920 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1921 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1922
1923 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1924 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1925 - shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1926 shift, count));
1927}
1928
1929/* 32 bit SUB shifted register setting flags. */
1930static void
1931subs32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1932{
1933 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1934 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1935 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1936
1937 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1938 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1939 shift, count);
1940
1941 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1942 set_flags_for_sub32 (cpu, value1, value2);
1943}
1944
1945/* 64 bit SUB shifted register setting flags. */
1946static void
1947subs64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1948{
1949 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1950 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1951 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1952
1953 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1954 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1955 shift, count);
1956
1957 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1958 set_flags_for_sub64 (cpu, value1, value2);
1959}
1960
1961/* First a couple more helpers to fetch the
1962 relevant source register element either
1963 sign or zero extended as required by the
1964 extension value. */
1965
1966static uint32_t
1967extreg32 (sim_cpu *cpu, unsigned int lo, Extension extension)
1968{
1969 switch (extension)
1970 {
1971 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
1972 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
1973 case UXTW: /* Fall through. */
1974 case UXTX: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
1975 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
1976 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
1977 case SXTW: /* Fall through. */
1978 case SXTX: /* Fall through. */
1979 default: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
1980 }
1981}
1982
1983static uint64_t
1984extreg64 (sim_cpu *cpu, unsigned int lo, Extension extension)
1985{
1986 switch (extension)
1987 {
1988 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
1989 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
1990 case UXTW: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
1991 case UXTX: return aarch64_get_reg_u64 (cpu, lo, NO_SP);
1992 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
1993 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
1994 case SXTW: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
1995 case SXTX:
1996 default: return aarch64_get_reg_s64 (cpu, lo, NO_SP);
1997 }
1998}
1999
2000/* Arithmetic extending register
2001 These allow an optional sign extension of some portion of the
2002 second source register followed by an optional left shift of
2003 between 1 and 4 bits (i.e. a shift of 0-4 bits???)
2004
2005 N.B output (dest) and first input arg (source) may normally be Xn
2006 or SP. However, for flag setting operations dest can only be
2007 Xn. Second input registers are always Xn. */
2008
2009/* 32 bit ADD extending register. */
2010static void
2011add32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2012{
2013 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2014 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2015 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2016
2017 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2018 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2019 + (extreg32 (cpu, rm, extension) << shift));
2020}
2021
2022/* 64 bit ADD extending register.
2023 N.B. This subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2024static void
2025add64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2026{
2027 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2028 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2029 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2030
2031 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2032 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2033 + (extreg64 (cpu, rm, extension) << shift));
2034}
2035
2036/* 32 bit ADD extending register setting flags. */
2037static void
2038adds32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2039{
2040 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2041 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2042 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2043
2044 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2045 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2046
2047 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2048 set_flags_for_add32 (cpu, value1, value2);
2049}
2050
2051/* 64 bit ADD extending register setting flags */
2052/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2053static void
2054adds64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2055{
2056 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2057 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2058 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2059
2060 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2061 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2062
2063 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2064 set_flags_for_add64 (cpu, value1, value2);
2065}
2066
2067/* 32 bit SUB extending register. */
2068static void
2069sub32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2070{
2071 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2072 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2073 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2074
2075 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2076 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2077 - (extreg32 (cpu, rm, extension) << shift));
2078}
2079
2080/* 64 bit SUB extending register. */
2081/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2082static void
2083sub64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2084{
2085 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2086 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2087 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2088
2089 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2090 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2091 - (extreg64 (cpu, rm, extension) << shift));
2092}
2093
2094/* 32 bit SUB extending register setting flags. */
2095static void
2096subs32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2097{
2098 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2099 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2100 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2101
2102 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2103 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2104
2105 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2106 set_flags_for_sub32 (cpu, value1, value2);
2107}
2108
2109/* 64 bit SUB extending register setting flags */
2110/* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2111static void
2112subs64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2113{
2114 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2115 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2116 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2117
2118 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2119 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2120
2121 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2122 set_flags_for_sub64 (cpu, value1, value2);
2123}
2124
2125static void
2126dexAddSubtractImmediate (sim_cpu *cpu)
2127{
2128 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2129 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2130 instr[29] = set : 0 ==> no flags, 1 ==> set flags
2131 instr[28,24] = 10001
2132 instr[23,22] = shift : 00 == LSL#0, 01 = LSL#12 1x = UNALLOC
2133 instr[21,10] = uimm12
2134 instr[9,5] = Rn
2135 instr[4,0] = Rd */
2136
2137 /* N.B. the shift is applied at decode before calling the add/sub routine. */
2138 uint32_t shift = uimm (aarch64_get_instr (cpu), 23, 22);
2139 uint32_t imm = uimm (aarch64_get_instr (cpu), 21, 10);
2140 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2141
2142 NYI_assert (28, 24, 0x11);
2143
2144 if (shift > 1)
2145 HALT_UNALLOC;
2146
2147 if (shift)
2148 imm <<= 12;
2149
2150 switch (dispatch)
2151 {
2152 case 0: add32 (cpu, imm); break;
2153 case 1: adds32 (cpu, imm); break;
2154 case 2: sub32 (cpu, imm); break;
2155 case 3: subs32 (cpu, imm); break;
2156 case 4: add64 (cpu, imm); break;
2157 case 5: adds64 (cpu, imm); break;
2158 case 6: sub64 (cpu, imm); break;
2159 case 7: subs64 (cpu, imm); break;
2160 default:
2161 HALT_UNALLOC;
2162 }
2163}
2164
2165static void
2166dexAddSubtractShiftedRegister (sim_cpu *cpu)
2167{
2168 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2169 instr[30,29] = op : 00 ==> ADD, 01 ==> ADDS, 10 ==> SUB, 11 ==> SUBS
2170 instr[28,24] = 01011
2171 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> UNALLOC
2172 instr[21] = 0
2173 instr[20,16] = Rm
2174 instr[15,10] = count : must be 0xxxxx for 32 bit
2175 instr[9,5] = Rn
2176 instr[4,0] = Rd */
2177
2178 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
2179 /* 32 bit operations must have count[5] = 0
2180 or else we have an UNALLOC. */
2181 uint32_t count = uimm (aarch64_get_instr (cpu), 15, 10);
2182 /* Shift encoded as ROR is unallocated. */
2183 Shift shiftType = shift (aarch64_get_instr (cpu), 22);
2184 /* Dispatch on size:op i.e aarch64_get_instr (cpu)[31,29]. */
2185 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2186
2187 NYI_assert (28, 24, 0x0B);
2188 NYI_assert (21, 21, 0);
2189
2190 if (shiftType == ROR)
2191 HALT_UNALLOC;
2192
2193 if (!size && uimm (count, 5, 5))
2194 HALT_UNALLOC;
2195
2196 switch (dispatch)
2197 {
2198 case 0: add32_shift (cpu, shiftType, count); break;
2199 case 1: adds32_shift (cpu, shiftType, count); break;
2200 case 2: sub32_shift (cpu, shiftType, count); break;
2201 case 3: subs32_shift (cpu, shiftType, count); break;
2202 case 4: add64_shift (cpu, shiftType, count); break;
2203 case 5: adds64_shift (cpu, shiftType, count); break;
2204 case 6: sub64_shift (cpu, shiftType, count); break;
2205 case 7: subs64_shift (cpu, shiftType, count); break;
2206 default:
2207 HALT_UNALLOC;
2208 }
2209}
2210
2211static void
2212dexAddSubtractExtendedRegister (sim_cpu *cpu)
2213{
2214 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2215 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2216 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2217 instr[28,24] = 01011
2218 instr[23,22] = opt : 0 ==> ok, 1,2,3 ==> UNALLOC
2219 instr[21] = 1
2220 instr[20,16] = Rm
2221 instr[15,13] = option : 000 ==> UXTB, 001 ==> UXTH,
2222 000 ==> LSL|UXTW, 001 ==> UXTZ,
2223 000 ==> SXTB, 001 ==> SXTH,
2224 000 ==> SXTW, 001 ==> SXTX,
2225 instr[12,10] = shift : 0,1,2,3,4 ==> ok, 5,6,7 ==> UNALLOC
2226 instr[9,5] = Rn
2227 instr[4,0] = Rd */
2228
2229 Extension extensionType = extension (aarch64_get_instr (cpu), 13);
2230 uint32_t shift = uimm (aarch64_get_instr (cpu), 12, 10);
2231 /* dispatch on size:op:set? i.e aarch64_get_instr (cpu)[31,29] */
2232 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2233
2234 NYI_assert (28, 24, 0x0B);
2235 NYI_assert (21, 21, 1);
2236
2237 /* Shift may not exceed 4. */
2238 if (shift > 4)
2239 HALT_UNALLOC;
2240
2241 switch (dispatch)
2242 {
2243 case 0: add32_ext (cpu, extensionType, shift); break;
2244 case 1: adds32_ext (cpu, extensionType, shift); break;
2245 case 2: sub32_ext (cpu, extensionType, shift); break;
2246 case 3: subs32_ext (cpu, extensionType, shift); break;
2247 case 4: add64_ext (cpu, extensionType, shift); break;
2248 case 5: adds64_ext (cpu, extensionType, shift); break;
2249 case 6: sub64_ext (cpu, extensionType, shift); break;
2250 case 7: subs64_ext (cpu, extensionType, shift); break;
2251 default: HALT_UNALLOC;
2252 }
2253}
2254
2255/* Conditional data processing
2256 Condition register is implicit 3rd source. */
2257
2258/* 32 bit add with carry. */
2259/* N.B register args may not be SP. */
2260
2261static void
2262adc32 (sim_cpu *cpu)
2263{
2264 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2265 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2266 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2267
2268 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2269 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2270 + aarch64_get_reg_u32 (cpu, rm, NO_SP)
2271 + IS_SET (C));
2272}
2273
2274/* 64 bit add with carry */
2275static void
2276adc64 (sim_cpu *cpu)
2277{
2278 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2279 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2280 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2281
2282 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2283 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2284 + aarch64_get_reg_u64 (cpu, rm, NO_SP)
2285 + IS_SET (C));
2286}
2287
2288/* 32 bit add with carry setting flags. */
2289static void
2290adcs32 (sim_cpu *cpu)
2291{
2292 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2293 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2294 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2295
2296 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2297 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2298 uint32_t carry = IS_SET (C);
2299
2300 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2301 set_flags_for_add32 (cpu, value1, value2 + carry);
2302}
2303
2304/* 64 bit add with carry setting flags. */
2305static void
2306adcs64 (sim_cpu *cpu)
2307{
2308 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2309 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2310 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2311
2312 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2313 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2314 uint64_t carry = IS_SET (C);
2315
2316 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2317 set_flags_for_add64 (cpu, value1, value2 + carry);
2318}
2319
2320/* 32 bit sub with carry. */
2321static void
2322sbc32 (sim_cpu *cpu)
2323{
2324 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2325 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2326 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2327
2328 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2329 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2330 - aarch64_get_reg_u32 (cpu, rm, NO_SP)
2331 - 1 + IS_SET (C));
2332}
2333
2334/* 64 bit sub with carry */
2335static void
2336sbc64 (sim_cpu *cpu)
2337{
2338 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2339 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2340 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2341
2342 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2343 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2344 - aarch64_get_reg_u64 (cpu, rm, NO_SP)
2345 - 1 + IS_SET (C));
2346}
2347
2348/* 32 bit sub with carry setting flags */
2349static void
2350sbcs32 (sim_cpu *cpu)
2351{
2352 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2353 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2354 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2355
2356 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2357 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2358 uint32_t carry = IS_SET (C);
2359 uint32_t result = value1 - value2 + 1 - carry;
2360
2361 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2362 set_flags_for_sub32 (cpu, value1, value2 + 1 - carry);
2363}
2364
2365/* 64 bit sub with carry setting flags */
2366static void
2367sbcs64 (sim_cpu *cpu)
2368{
2369 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2370 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2371 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2372
2373 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2374 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2375 uint64_t carry = IS_SET (C);
2376 uint64_t result = value1 - value2 + 1 - carry;
2377
2378 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2379 set_flags_for_sub64 (cpu, value1, value2 + 1 - carry);
2380}
2381
2382static void
2383dexAddSubtractWithCarry (sim_cpu *cpu)
2384{
2385 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2386 instr[30] = op : 0 ==> ADC, 1 ==> SBC
2387 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2388 instr[28,21] = 1 1010 000
2389 instr[20,16] = Rm
2390 instr[15,10] = op2 : 00000 ==> ok, ow ==> UNALLOC
2391 instr[9,5] = Rn
2392 instr[4,0] = Rd */
2393
2394 uint32_t op2 = uimm (aarch64_get_instr (cpu), 15, 10);
2395 /* Dispatch on size:op:set? i.e aarch64_get_instr (cpu)[31,29] */
2396 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2397
2398 NYI_assert (28, 21, 0xD0);
2399
2400 if (op2 != 0)
2401 HALT_UNALLOC;
2402
2403 switch (dispatch)
2404 {
2405 case 0: adc32 (cpu); break;
2406 case 1: adcs32 (cpu); break;
2407 case 2: sbc32 (cpu); break;
2408 case 3: sbcs32 (cpu); break;
2409 case 4: adc64 (cpu); break;
2410 case 5: adcs64 (cpu); break;
2411 case 6: sbc64 (cpu); break;
2412 case 7: sbcs64 (cpu); break;
2413 default: HALT_UNALLOC;
2414 }
2415}
2416
2417static uint32_t
2418testConditionCode (sim_cpu *cpu, CondCode cc)
2419{
2420 /* This should be reduceable to branchless logic
2421 by some careful testing of bits in CC followed
2422 by the requisite masking and combining of bits
2423 from the flag register.
2424
2425 For now we do it with a switch. */
2426 int res;
2427
2428 switch (cc)
2429 {
2430 case EQ: res = IS_SET (Z); break;
2431 case NE: res = IS_CLEAR (Z); break;
2432 case CS: res = IS_SET (C); break;
2433 case CC: res = IS_CLEAR (C); break;
2434 case MI: res = IS_SET (N); break;
2435 case PL: res = IS_CLEAR (N); break;
2436 case VS: res = IS_SET (V); break;
2437 case VC: res = IS_CLEAR (V); break;
2438 case HI: res = IS_SET (C) && IS_CLEAR (Z); break;
2439 case LS: res = IS_CLEAR (C) || IS_SET (Z); break;
2440 case GE: res = IS_SET (N) == IS_SET (V); break;
2441 case LT: res = IS_SET (N) != IS_SET (V); break;
2442 case GT: res = IS_CLEAR (Z) && (IS_SET (N) == IS_SET (V)); break;
2443 case LE: res = IS_SET (Z) || (IS_SET (N) != IS_SET (V)); break;
2444 case AL:
2445 case NV:
2446 default:
2447 res = 1;
2448 break;
2449 }
2450 return res;
2451}
2452
2453static void
2454CondCompare (sim_cpu *cpu) /* aka: ccmp and ccmn */
2455{
2456 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
57aa1742 2457 instr[30] = compare with positive (1) or negative value (0)
2e8cf49e
NC
2458 instr[29,21] = 1 1101 0010
2459 instr[20,16] = Rm or const
2460 instr[15,12] = cond
2461 instr[11] = compare reg (0) or const (1)
2462 instr[10] = 0
2463 instr[9,5] = Rn
2464 instr[4] = 0
2465 instr[3,0] = value for CPSR bits if the comparison does not take place. */
2466 signed int negate;
2467 unsigned rm;
2468 unsigned rn;
2469
2470 NYI_assert (29, 21, 0x1d2);
2471 NYI_assert (10, 10, 0);
2472 NYI_assert (4, 4, 0);
2473
2474 if (! testConditionCode (cpu, uimm (aarch64_get_instr (cpu), 15, 12)))
2475 {
2476 aarch64_set_CPSR (cpu, uimm (aarch64_get_instr (cpu), 3, 0));
2477 return;
2478 }
2479
57aa1742 2480 negate = uimm (aarch64_get_instr (cpu), 30, 30) ? 1 : -1;
2e8cf49e
NC
2481 rm = uimm (aarch64_get_instr (cpu), 20, 16);
2482 rn = uimm (aarch64_get_instr (cpu), 9, 5);
2483
2484 if (uimm (aarch64_get_instr (cpu), 31, 31))
2485 {
2486 if (uimm (aarch64_get_instr (cpu), 11, 11))
2487 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2488 negate * (uint64_t) rm);
2489 else
2490 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2491 negate * aarch64_get_reg_u64 (cpu, rm, SP_OK));
2492 }
2493 else
2494 {
2495 if (uimm (aarch64_get_instr (cpu), 11, 11))
2496 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2497 negate * rm);
2498 else
2499 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2500 negate * aarch64_get_reg_u32 (cpu, rm, SP_OK));
2501 }
2502}
2503
2504static void
2505do_vec_MOV_whole_vector (sim_cpu *cpu)
2506{
2507 /* MOV Vd.T, Vs.T (alias for ORR Vd.T, Vn.T, Vm.T where Vn == Vm)
2508
2509 instr[31] = 0
2510 instr[30] = half(0)/full(1)
2511 instr[29,21] = 001110101
2512 instr[20,16] = Vs
2513 instr[15,10] = 000111
2514 instr[9,5] = Vs
2515 instr[4,0] = Vd */
2516
2517 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2518 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2519
2520 NYI_assert (29, 21, 0x075);
2521 NYI_assert (15, 10, 0x07);
2522
2523 if (uimm (aarch64_get_instr (cpu), 20, 16) != vs)
2524 HALT_NYI;
2525
2526 if (uimm (aarch64_get_instr (cpu), 30, 30))
2527 aarch64_set_vec_u64 (cpu, vd, 1, aarch64_get_vec_u64 (cpu, vs, 1));
2528
2529 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vs, 0));
2530}
2531
2532static void
2533do_vec_MOV_into_scalar (sim_cpu *cpu)
2534{
2535 /* instr[31] = 0
2536 instr[30] = word(0)/long(1)
2537 instr[29,21] = 00 1110 000
2538 instr[20,18] = element size and index
2539 instr[17,10] = 00 0011 11
2540 instr[9,5] = V source
2541 instr[4,0] = R dest */
2542
2543 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2544 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2545
2546 NYI_assert (29, 21, 0x070);
2547 NYI_assert (17, 10, 0x0F);
2548
2549 switch (uimm (aarch64_get_instr (cpu), 20, 18))
2550 {
2551 case 0x2:
2552 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 0));
2553 break;
2554
2555 case 0x6:
2556 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 1));
2557 break;
2558
2559 case 0x1:
2560 case 0x3:
2561 case 0x5:
2562 case 0x7:
2563 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u32
2564 (cpu, vs, uimm (aarch64_get_instr (cpu), 20, 19)));
2565 break;
2566
2567 default:
2568 HALT_NYI;
2569 }
2570}
2571
2572static void
2573do_vec_INS (sim_cpu *cpu)
2574{
2575 /* instr[31,21] = 01001110000
2576 instr[20,16] = element size and index
2577 instr[15,10] = 000111
2578 instr[9,5] = W source
2579 instr[4,0] = V dest */
2580
2581 int index;
2582 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
2583 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2584
2585 NYI_assert (31, 21, 0x270);
2586 NYI_assert (15, 10, 0x07);
2587
2588 if (uimm (aarch64_get_instr (cpu), 16, 16))
2589 {
2590 index = uimm (aarch64_get_instr (cpu), 20, 17);
2591 aarch64_set_vec_u8 (cpu, vd, index,
2592 aarch64_get_reg_u8 (cpu, rs, NO_SP));
2593 }
2594 else if (uimm (aarch64_get_instr (cpu), 17, 17))
2595 {
2596 index = uimm (aarch64_get_instr (cpu), 20, 18);
2597 aarch64_set_vec_u16 (cpu, vd, index,
2598 aarch64_get_reg_u16 (cpu, rs, NO_SP));
2599 }
2600 else if (uimm (aarch64_get_instr (cpu), 18, 18))
2601 {
2602 index = uimm (aarch64_get_instr (cpu), 20, 19);
2603 aarch64_set_vec_u32 (cpu, vd, index,
2604 aarch64_get_reg_u32 (cpu, rs, NO_SP));
2605 }
2606 else if (uimm (aarch64_get_instr (cpu), 19, 19))
2607 {
2608 index = uimm (aarch64_get_instr (cpu), 20, 20);
2609 aarch64_set_vec_u64 (cpu, vd, index,
2610 aarch64_get_reg_u64 (cpu, rs, NO_SP));
2611 }
2612 else
2613 HALT_NYI;
2614}
2615
2616static void
2617do_vec_DUP_vector_into_vector (sim_cpu *cpu)
2618{
2619 /* instr[31] = 0
2620 instr[30] = half(0)/full(1)
2621 instr[29,21] = 00 1110 000
2622 instr[20,16] = element size and index
2623 instr[15,10] = 0000 01
2624 instr[9,5] = V source
2625 instr[4,0] = V dest. */
2626
2627 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
2628 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2629 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2630 int i, index;
2631
2632 NYI_assert (29, 21, 0x070);
2633 NYI_assert (15, 10, 0x01);
2634
2635 if (uimm (aarch64_get_instr (cpu), 16, 16))
2636 {
2637 index = uimm (aarch64_get_instr (cpu), 20, 17);
2638
2639 for (i = 0; i < (full ? 16 : 8); i++)
2640 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, index));
2641 }
2642 else if (uimm (aarch64_get_instr (cpu), 17, 17))
2643 {
2644 index = uimm (aarch64_get_instr (cpu), 20, 18);
2645
2646 for (i = 0; i < (full ? 8 : 4); i++)
2647 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, index));
2648 }
2649 else if (uimm (aarch64_get_instr (cpu), 18, 18))
2650 {
2651 index = uimm (aarch64_get_instr (cpu), 20, 19);
2652
2653 for (i = 0; i < (full ? 4 : 2); i++)
2654 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, index));
2655 }
2656 else
2657 {
2658 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
2659 HALT_UNALLOC;
2660
2661 if (! full)
2662 HALT_UNALLOC;
2663
2664 index = uimm (aarch64_get_instr (cpu), 20, 20);
2665
2666 for (i = 0; i < 2; i++)
2667 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, index));
2668 }
2669}
2670
2671static void
2672do_vec_TBL (sim_cpu *cpu)
2673{
2674 /* instr[31] = 0
2675 instr[30] = half(0)/full(1)
2676 instr[29,21] = 00 1110 000
2677 instr[20,16] = Vm
2678 instr[15] = 0
2679 instr[14,13] = vec length
2680 instr[12,10] = 000
2681 instr[9,5] = V start
2682 instr[4,0] = V dest */
2683
2684 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2685 int len = uimm (aarch64_get_instr (cpu), 14, 13) + 1;
2686 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2687 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2688 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2689 unsigned i;
2690
2691 NYI_assert (29, 21, 0x070);
2692 NYI_assert (12, 10, 0);
2693
2694 for (i = 0; i < (full ? 16 : 8); i++)
2695 {
2696 unsigned int selector = aarch64_get_vec_u8 (cpu, vm, i);
2697 uint8_t val;
2698
2699 if (selector < 16)
2700 val = aarch64_get_vec_u8 (cpu, vn, selector);
2701 else if (selector < 32)
2702 val = len < 2 ? 0 : aarch64_get_vec_u8 (cpu, vn + 1, selector - 16);
2703 else if (selector < 48)
2704 val = len < 3 ? 0 : aarch64_get_vec_u8 (cpu, vn + 2, selector - 32);
2705 else if (selector < 64)
2706 val = len < 4 ? 0 : aarch64_get_vec_u8 (cpu, vn + 3, selector - 48);
2707 else
2708 val = 0;
2709
2710 aarch64_set_vec_u8 (cpu, vd, i, val);
2711 }
2712}
2713
2714static void
2715do_vec_TRN (sim_cpu *cpu)
2716{
2717 /* instr[31] = 0
2718 instr[30] = half(0)/full(1)
2719 instr[29,24] = 00 1110
2720 instr[23,22] = size
2721 instr[21] = 0
2722 instr[20,16] = Vm
2723 instr[15] = 0
2724 instr[14] = TRN1 (0) / TRN2 (1)
2725 instr[13,10] = 1010
2726 instr[9,5] = V source
2727 instr[4,0] = V dest. */
2728
2729 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2730 int second = uimm (aarch64_get_instr (cpu), 14, 14);
2731 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2732 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2733 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2734 unsigned i;
2735
2736 NYI_assert (29, 24, 0x0E);
2737 NYI_assert (13, 10, 0xA);
2738
2739 switch (uimm (aarch64_get_instr (cpu), 23, 22))
2740 {
2741 case 0:
2742 for (i = 0; i < (full ? 8 : 4); i++)
2743 {
2744 aarch64_set_vec_u8
2745 (cpu, vd, i * 2,
2746 aarch64_get_vec_u8 (cpu, second ? vm : vn, i * 2));
2747 aarch64_set_vec_u8
2748 (cpu, vd, 1 * 2 + 1,
2749 aarch64_get_vec_u8 (cpu, second ? vn : vm, i * 2 + 1));
2750 }
2751 break;
2752
2753 case 1:
2754 for (i = 0; i < (full ? 4 : 2); i++)
2755 {
2756 aarch64_set_vec_u16
2757 (cpu, vd, i * 2,
2758 aarch64_get_vec_u16 (cpu, second ? vm : vn, i * 2));
2759 aarch64_set_vec_u16
2760 (cpu, vd, 1 * 2 + 1,
2761 aarch64_get_vec_u16 (cpu, second ? vn : vm, i * 2 + 1));
2762 }
2763 break;
2764
2765 case 2:
2766 aarch64_set_vec_u32
2767 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, second ? vm : vn, 0));
2768 aarch64_set_vec_u32
2769 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, second ? vn : vm, 1));
2770 aarch64_set_vec_u32
2771 (cpu, vd, 2, aarch64_get_vec_u32 (cpu, second ? vm : vn, 2));
2772 aarch64_set_vec_u32
2773 (cpu, vd, 3, aarch64_get_vec_u32 (cpu, second ? vn : vm, 3));
2774 break;
2775
2776 case 3:
2777 if (! full)
2778 HALT_UNALLOC;
2779
2780 aarch64_set_vec_u64 (cpu, vd, 0,
2781 aarch64_get_vec_u64 (cpu, second ? vm : vn, 0));
2782 aarch64_set_vec_u64 (cpu, vd, 1,
2783 aarch64_get_vec_u64 (cpu, second ? vn : vm, 1));
2784 break;
2785
2786 default:
2787 HALT_UNALLOC;
2788 }
2789}
2790
2791static void
2792do_vec_DUP_scalar_into_vector (sim_cpu *cpu)
2793{
2794 /* instr[31] = 0
2795 instr[30] = 0=> zero top 64-bits, 1=> duplicate into top 64-bits
2796 [must be 1 for 64-bit xfer]
2797 instr[29,20] = 00 1110 0000
2798 instr[19,16] = element size: 0001=> 8-bits, 0010=> 16-bits,
2799 0100=> 32-bits. 1000=>64-bits
2800 instr[15,10] = 0000 11
2801 instr[9,5] = W source
2802 instr[4,0] = V dest. */
2803
2804 unsigned i;
2805 unsigned Vd = uimm (aarch64_get_instr (cpu), 4, 0);
2806 unsigned Rs = uimm (aarch64_get_instr (cpu), 9, 5);
2807 int both = uimm (aarch64_get_instr (cpu), 30, 30);
2808
2809 NYI_assert (29, 20, 0x0E0);
2810 NYI_assert (15, 10, 0x03);
2811
2812 switch (uimm (aarch64_get_instr (cpu), 19, 16))
2813 {
2814 case 1:
2815 for (i = 0; i < (both ? 16 : 8); i++)
2816 aarch64_set_vec_u8 (cpu, Vd, i, aarch64_get_reg_u8 (cpu, Rs, NO_SP));
2817 break;
2818
2819 case 2:
2820 for (i = 0; i < (both ? 8 : 4); i++)
2821 aarch64_set_vec_u16 (cpu, Vd, i, aarch64_get_reg_u16 (cpu, Rs, NO_SP));
2822 break;
2823
2824 case 4:
2825 for (i = 0; i < (both ? 4 : 2); i++)
2826 aarch64_set_vec_u32 (cpu, Vd, i, aarch64_get_reg_u32 (cpu, Rs, NO_SP));
2827 break;
2828
2829 case 8:
2830 if (!both)
2831 HALT_NYI;
2832 aarch64_set_vec_u64 (cpu, Vd, 0, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2833 aarch64_set_vec_u64 (cpu, Vd, 1, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2834 break;
2835
2836 default:
2837 HALT_NYI;
2838 }
2839}
2840
2841static void
2842do_vec_UZP (sim_cpu *cpu)
2843{
2844 /* instr[31] = 0
2845 instr[30] = half(0)/full(1)
2846 instr[29,24] = 00 1110
2847 instr[23,22] = size: byte(00), half(01), word (10), long (11)
2848 instr[21] = 0
2849 instr[20,16] = Vm
2850 instr[15] = 0
2851 instr[14] = lower (0) / upper (1)
2852 instr[13,10] = 0110
2853 instr[9,5] = Vn
2854 instr[4,0] = Vd. */
2855
2856 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2857 int upper = uimm (aarch64_get_instr (cpu), 14, 14);
2858
2859 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2860 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2861 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2862
2863 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2864 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2865 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2866 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2867
2868 uint64_t val1 = 0;
2869 uint64_t val2 = 0;
2870
2871 uint64_t input1 = upper ? val_n1 : val_m1;
2872 uint64_t input2 = upper ? val_n2 : val_m2;
2873 unsigned i;
2874
2875 NYI_assert (29, 24, 0x0E);
2876 NYI_assert (21, 21, 0);
2877 NYI_assert (15, 15, 0);
2878 NYI_assert (13, 10, 6);
2879
2880 switch (uimm (aarch64_get_instr (cpu), 23, 23))
2881 {
2882 case 0:
2883 for (i = 0; i < 8; i++)
2884 {
2885 val1 |= (input1 >> (i * 8)) & (0xFFULL << (i * 8));
2886 val2 |= (input2 >> (i * 8)) & (0xFFULL << (i * 8));
2887 }
2888 break;
2889
2890 case 1:
2891 for (i = 0; i < 4; i++)
2892 {
2893 val1 |= (input1 >> (i * 16)) & (0xFFFFULL << (i * 16));
2894 val2 |= (input2 >> (i * 16)) & (0xFFFFULL << (i * 16));
2895 }
2896 break;
2897
2898 case 2:
2899 val1 = ((input1 & 0xFFFFFFFF) | ((input1 >> 32) & 0xFFFFFFFF00000000ULL));
2900 val2 = ((input2 & 0xFFFFFFFF) | ((input2 >> 32) & 0xFFFFFFFF00000000ULL));
2901
2902 case 3:
2903 val1 = input1;
2904 val2 = input2;
2905 break;
2906 }
2907
2908 aarch64_set_vec_u64 (cpu, vd, 0, val1);
2909 if (full)
2910 aarch64_set_vec_u64 (cpu, vd, 1, val2);
2911}
2912
2913static void
2914do_vec_ZIP (sim_cpu *cpu)
2915{
2916 /* instr[31] = 0
2917 instr[30] = half(0)/full(1)
2918 instr[29,24] = 00 1110
2919 instr[23,22] = size: byte(00), hald(01), word (10), long (11)
2920 instr[21] = 0
2921 instr[20,16] = Vm
2922 instr[15] = 0
2923 instr[14] = lower (0) / upper (1)
2924 instr[13,10] = 1110
2925 instr[9,5] = Vn
2926 instr[4,0] = Vd. */
2927
2928 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2929 int upper = uimm (aarch64_get_instr (cpu), 14, 14);
2930
2931 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2932 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2933 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2934
2935 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2936 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2937 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2938 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2939
2940 uint64_t val1 = 0;
2941 uint64_t val2 = 0;
2942
2943 uint64_t input1 = upper ? val_n1 : val_m1;
2944 uint64_t input2 = upper ? val_n2 : val_m2;
2945
2946 NYI_assert (29, 24, 0x0E);
2947 NYI_assert (21, 21, 0);
2948 NYI_assert (15, 15, 0);
2949 NYI_assert (13, 10, 0xE);
2950
2951 switch (uimm (aarch64_get_instr (cpu), 23, 23))
2952 {
2953 case 0:
2954 val1 =
2955 ((input1 << 0) & (0xFF << 0))
2956 | ((input2 << 8) & (0xFF << 8))
2957 | ((input1 << 8) & (0xFF << 16))
2958 | ((input2 << 16) & (0xFF << 24))
2959 | ((input1 << 16) & (0xFFULL << 32))
2960 | ((input2 << 24) & (0xFFULL << 40))
2961 | ((input1 << 24) & (0xFFULL << 48))
2962 | ((input2 << 32) & (0xFFULL << 56));
2963
2964 val2 =
2965 ((input1 >> 32) & (0xFF << 0))
2966 | ((input2 >> 24) & (0xFF << 8))
2967 | ((input1 >> 24) & (0xFF << 16))
2968 | ((input2 >> 16) & (0xFF << 24))
2969 | ((input1 >> 16) & (0xFFULL << 32))
2970 | ((input2 >> 8) & (0xFFULL << 40))
2971 | ((input1 >> 8) & (0xFFULL << 48))
2972 | ((input2 >> 0) & (0xFFULL << 56));
2973 break;
2974
2975 case 1:
2976 val1 =
2977 ((input1 << 0) & (0xFFFF << 0))
2978 | ((input2 << 16) & (0xFFFF << 16))
2979 | ((input1 << 16) & (0xFFFFULL << 32))
2980 | ((input2 << 32) & (0xFFFFULL << 48));
2981
2982 val2 =
2983 ((input1 >> 32) & (0xFFFF << 0))
2984 | ((input2 >> 16) & (0xFFFF << 16))
2985 | ((input1 >> 16) & (0xFFFFULL << 32))
2986 | ((input2 >> 0) & (0xFFFFULL << 48));
2987 break;
2988
2989 case 2:
2990 val1 = (input1 & 0xFFFFFFFFULL) | (input2 << 32);
2991 val2 = (input2 & 0xFFFFFFFFULL) | (input1 << 32);
2992 break;
2993
2994 case 3:
2995 val1 = input1;
2996 val2 = input2;
2997 break;
2998 }
2999
3000 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3001 if (full)
3002 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3003}
3004
3005/* Floating point immediates are encoded in 8 bits.
3006 fpimm[7] = sign bit.
3007 fpimm[6:4] = signed exponent.
3008 fpimm[3:0] = fraction (assuming leading 1).
3009 i.e. F = s * 1.f * 2^(e - b). */
3010
3011static float
3012fp_immediate_for_encoding_32 (uint32_t imm8)
3013{
3014 float u;
3015 uint32_t s, e, f, i;
3016
3017 s = (imm8 >> 7) & 0x1;
3018 e = (imm8 >> 4) & 0x7;
3019 f = imm8 & 0xf;
3020
3021 /* The fp value is s * n/16 * 2r where n is 16+e. */
3022 u = (16.0 + f) / 16.0;
3023
3024 /* N.B. exponent is signed. */
3025 if (e < 4)
3026 {
3027 int epos = e;
3028
3029 for (i = 0; i <= epos; i++)
3030 u *= 2.0;
3031 }
3032 else
3033 {
3034 int eneg = 7 - e;
3035
3036 for (i = 0; i < eneg; i++)
3037 u /= 2.0;
3038 }
3039
3040 if (s)
3041 u = - u;
3042
3043 return u;
3044}
3045
3046static double
3047fp_immediate_for_encoding_64 (uint32_t imm8)
3048{
3049 double u;
3050 uint32_t s, e, f, i;
3051
3052 s = (imm8 >> 7) & 0x1;
3053 e = (imm8 >> 4) & 0x7;
3054 f = imm8 & 0xf;
3055
3056 /* The fp value is s * n/16 * 2r where n is 16+e. */
3057 u = (16.0 + f) / 16.0;
3058
3059 /* N.B. exponent is signed. */
3060 if (e < 4)
3061 {
3062 int epos = e;
3063
3064 for (i = 0; i <= epos; i++)
3065 u *= 2.0;
3066 }
3067 else
3068 {
3069 int eneg = 7 - e;
3070
3071 for (i = 0; i < eneg; i++)
3072 u /= 2.0;
3073 }
3074
3075 if (s)
3076 u = - u;
3077
3078 return u;
3079}
3080
3081static void
3082do_vec_MOV_immediate (sim_cpu *cpu)
3083{
3084 /* instr[31] = 0
3085 instr[30] = full/half selector
3086 instr[29,19] = 00111100000
3087 instr[18,16] = high 3 bits of uimm8
3088 instr[15,12] = size & shift:
3089 0000 => 32-bit
3090 0010 => 32-bit + LSL#8
3091 0100 => 32-bit + LSL#16
3092 0110 => 32-bit + LSL#24
3093 1010 => 16-bit + LSL#8
3094 1000 => 16-bit
3095 1101 => 32-bit + MSL#16
3096 1100 => 32-bit + MSL#8
3097 1110 => 8-bit
3098 1111 => double
3099 instr[11,10] = 01
3100 instr[9,5] = low 5-bits of uimm8
3101 instr[4,0] = Vd. */
3102
3103 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3104 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3105 unsigned val = uimm (aarch64_get_instr (cpu), 18, 16) << 5
3106 | uimm (aarch64_get_instr (cpu), 9, 5);
3107 unsigned i;
3108
3109 NYI_assert (29, 19, 0x1E0);
3110 NYI_assert (11, 10, 1);
3111
3112 switch (uimm (aarch64_get_instr (cpu), 15, 12))
3113 {
3114 case 0x0: /* 32-bit, no shift. */
3115 case 0x2: /* 32-bit, shift by 8. */
3116 case 0x4: /* 32-bit, shift by 16. */
3117 case 0x6: /* 32-bit, shift by 24. */
3118 val <<= (8 * uimm (aarch64_get_instr (cpu), 14, 13));
3119 for (i = 0; i < (full ? 4 : 2); i++)
3120 aarch64_set_vec_u32 (cpu, vd, i, val);
3121 break;
3122
3123 case 0xa: /* 16-bit, shift by 8. */
3124 val <<= 8;
3125 /* Fall through. */
3126 case 0x8: /* 16-bit, no shift. */
3127 for (i = 0; i < (full ? 8 : 4); i++)
3128 aarch64_set_vec_u16 (cpu, vd, i, val);
3129 /* Fall through. */
3130 case 0xd: /* 32-bit, mask shift by 16. */
3131 val <<= 8;
3132 val |= 0xFF;
3133 /* Fall through. */
3134 case 0xc: /* 32-bit, mask shift by 8. */
3135 val <<= 8;
3136 val |= 0xFF;
3137 for (i = 0; i < (full ? 4 : 2); i++)
3138 aarch64_set_vec_u32 (cpu, vd, i, val);
3139 break;
3140
3141 case 0xe: /* 8-bit, no shift. */
3142 for (i = 0; i < (full ? 16 : 8); i++)
3143 aarch64_set_vec_u8 (cpu, vd, i, val);
3144 break;
3145
3146 case 0xf: /* FMOV Vs.{2|4}S, #fpimm. */
3147 {
3148 float u = fp_immediate_for_encoding_32 (val);
3149 for (i = 0; i < (full ? 4 : 2); i++)
3150 aarch64_set_vec_float (cpu, vd, i, u);
3151 break;
3152 }
3153
3154 default:
3155 HALT_NYI;
3156 }
3157}
3158
3159static void
3160do_vec_MVNI (sim_cpu *cpu)
3161{
3162 /* instr[31] = 0
3163 instr[30] = full/half selector
3164 instr[29,19] = 10111100000
3165 instr[18,16] = high 3 bits of uimm8
3166 instr[15,12] = selector
3167 instr[11,10] = 01
3168 instr[9,5] = low 5-bits of uimm8
3169 instr[4,0] = Vd. */
3170
3171 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3172 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3173 unsigned val = uimm (aarch64_get_instr (cpu), 18, 16) << 5
3174 | uimm (aarch64_get_instr (cpu), 9, 5);
3175 unsigned i;
3176
3177 NYI_assert (29, 19, 0x5E0);
3178 NYI_assert (11, 10, 1);
3179
3180 switch (uimm (aarch64_get_instr (cpu), 15, 12))
3181 {
3182 case 0x0: /* 32-bit, no shift. */
3183 case 0x2: /* 32-bit, shift by 8. */
3184 case 0x4: /* 32-bit, shift by 16. */
3185 case 0x6: /* 32-bit, shift by 24. */
3186 val <<= (8 * uimm (aarch64_get_instr (cpu), 14, 13));
3187 val = ~ val;
3188 for (i = 0; i < (full ? 4 : 2); i++)
3189 aarch64_set_vec_u32 (cpu, vd, i, val);
3190 return;
3191
3192 case 0xa: /* 16-bit, 8 bit shift. */
3193 val <<= 8;
3194 case 0x8: /* 16-bit, no shift. */
3195 val = ~ val;
3196 for (i = 0; i < (full ? 8 : 4); i++)
3197 aarch64_set_vec_u16 (cpu, vd, i, val);
3198 return;
3199
3200 case 0xd: /* 32-bit, mask shift by 16. */
3201 val <<= 8;
3202 val |= 0xFF;
3203 case 0xc: /* 32-bit, mask shift by 8. */
3204 val <<= 8;
3205 val |= 0xFF;
3206 val = ~ val;
3207 for (i = 0; i < (full ? 4 : 2); i++)
3208 aarch64_set_vec_u32 (cpu, vd, i, val);
3209 return;
3210
3211 case 0xE: /* MOVI Dn, #mask64 */
3212 {
3213 uint64_t mask = 0;
3214
3215 for (i = 0; i < 8; i++)
3216 if (val & (1 << i))
3217 mask |= (0xF << (i * 4));
3218 aarch64_set_vec_u64 (cpu, vd, 0, mask);
3219 aarch64_set_vec_u64 (cpu, vd, 1, 0);
3220 return;
3221 }
3222
3223 case 0xf: /* FMOV Vd.2D, #fpimm. */
3224 {
3225 double u = fp_immediate_for_encoding_64 (val);
3226
3227 if (! full)
3228 HALT_UNALLOC;
3229
3230 aarch64_set_vec_double (cpu, vd, 0, u);
3231 aarch64_set_vec_double (cpu, vd, 1, u);
3232 return;
3233 }
3234
3235 default:
3236 HALT_NYI;
3237 }
3238}
3239
3240#define ABS(A) ((A) < 0 ? - (A) : (A))
3241
3242static void
3243do_vec_ABS (sim_cpu *cpu)
3244{
3245 /* instr[31] = 0
3246 instr[30] = half(0)/full(1)
3247 instr[29,24] = 00 1110
3248 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3249 instr[21,10] = 10 0000 1011 10
3250 instr[9,5] = Vn
3251 instr[4.0] = Vd. */
3252
3253 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3254 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3255 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
3256 unsigned i;
3257
3258 NYI_assert (29, 24, 0x0E);
3259 NYI_assert (21, 10, 0x82E);
3260
3261 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3262 {
3263 case 0:
3264 for (i = 0; i < (full ? 16 : 8); i++)
3265 aarch64_set_vec_s8 (cpu, vd, i,
3266 ABS (aarch64_get_vec_s8 (cpu, vn, i)));
3267 break;
3268
3269 case 1:
3270 for (i = 0; i < (full ? 8 : 4); i++)
3271 aarch64_set_vec_s16 (cpu, vd, i,
3272 ABS (aarch64_get_vec_s16 (cpu, vn, i)));
3273 break;
3274
3275 case 2:
3276 for (i = 0; i < (full ? 4 : 2); i++)
3277 aarch64_set_vec_s32 (cpu, vd, i,
3278 ABS (aarch64_get_vec_s32 (cpu, vn, i)));
3279 break;
3280
3281 case 3:
3282 if (! full)
3283 HALT_NYI;
3284 for (i = 0; i < 2; i++)
3285 aarch64_set_vec_s64 (cpu, vd, i,
3286 ABS (aarch64_get_vec_s64 (cpu, vn, i)));
3287 break;
3288 }
3289}
3290
3291static void
3292do_vec_ADDV (sim_cpu *cpu)
3293{
3294 /* instr[31] = 0
3295 instr[30] = full/half selector
3296 instr[29,24] = 00 1110
3297 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3298 instr[21,10] = 11 0001 1011 10
3299 instr[9,5] = Vm
3300 instr[4.0] = Rd. */
3301
3302 unsigned vm = uimm (aarch64_get_instr (cpu), 9, 5);
3303 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
3304 unsigned i;
3305 uint64_t val = 0;
3306 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3307
3308 NYI_assert (29, 24, 0x0E);
3309 NYI_assert (21, 10, 0xC6E);
3310
3311 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3312 {
3313 case 0:
3314 for (i = 0; i < (full ? 16 : 8); i++)
3315 val += aarch64_get_vec_u8 (cpu, vm, i);
3316 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3317 return;
3318
3319 case 1:
3320 for (i = 0; i < (full ? 8 : 4); i++)
3321 val += aarch64_get_vec_u16 (cpu, vm, i);
3322 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3323 return;
3324
3325 case 2:
3326 for (i = 0; i < (full ? 4 : 2); i++)
3327 val += aarch64_get_vec_u32 (cpu, vm, i);
3328 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3329 return;
3330
3331 case 3:
3332 if (! full)
3333 HALT_UNALLOC;
3334 val = aarch64_get_vec_u64 (cpu, vm, 0);
3335 val += aarch64_get_vec_u64 (cpu, vm, 1);
3336 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3337 return;
3338
3339 default:
3340 HALT_UNREACHABLE;
3341 }
3342}
3343
3344static void
3345do_vec_ins_2 (sim_cpu *cpu)
3346{
3347 /* instr[31,21] = 01001110000
3348 instr[20,18] = size & element selector
3349 instr[17,14] = 0000
3350 instr[13] = direction: to vec(0), from vec (1)
3351 instr[12,10] = 111
3352 instr[9,5] = Vm
3353 instr[4,0] = Vd. */
3354
3355 unsigned elem;
3356 unsigned vm = uimm (aarch64_get_instr (cpu), 9, 5);
3357 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3358
3359 NYI_assert (31, 21, 0x270);
3360 NYI_assert (17, 14, 0);
3361 NYI_assert (12, 10, 7);
3362
3363 if (uimm (aarch64_get_instr (cpu), 13, 13) == 1)
3364 {
3365 if (uimm (aarch64_get_instr (cpu), 18, 18) == 1)
3366 {
3367 /* 32-bit moves. */
3368 elem = uimm (aarch64_get_instr (cpu), 20, 19);
3369 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3370 aarch64_get_vec_u32 (cpu, vm, elem));
3371 }
3372 else
3373 {
3374 /* 64-bit moves. */
3375 if (uimm (aarch64_get_instr (cpu), 19, 19) != 1)
3376 HALT_NYI;
3377
3378 elem = uimm (aarch64_get_instr (cpu), 20, 20);
3379 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3380 aarch64_get_vec_u64 (cpu, vm, elem));
3381 }
3382 }
3383 else
3384 {
3385 if (uimm (aarch64_get_instr (cpu), 18, 18) == 1)
3386 {
3387 /* 32-bit moves. */
3388 elem = uimm (aarch64_get_instr (cpu), 20, 19);
3389 aarch64_set_vec_u32 (cpu, vd, elem,
3390 aarch64_get_reg_u32 (cpu, vm, NO_SP));
3391 }
3392 else
3393 {
3394 /* 64-bit moves. */
3395 if (uimm (aarch64_get_instr (cpu), 19, 19) != 1)
3396 HALT_NYI;
3397
3398 elem = uimm (aarch64_get_instr (cpu), 20, 20);
3399 aarch64_set_vec_u64 (cpu, vd, elem,
3400 aarch64_get_reg_u64 (cpu, vm, NO_SP));
3401 }
3402 }
3403}
3404
3405static void
3406do_vec_mull (sim_cpu *cpu)
3407{
3408 /* instr[31] = 0
3409 instr[30] = lower(0)/upper(1) selector
3410 instr[29] = signed(0)/unsigned(1)
3411 instr[28,24] = 0 1110
3412 instr[23,22] = size: 8-bit (00), 16-bit (01), 32-bit (10)
3413 instr[21] = 1
3414 instr[20,16] = Vm
3415 instr[15,10] = 11 0000
3416 instr[9,5] = Vn
3417 instr[4.0] = Vd. */
3418
3419 int unsign = uimm (aarch64_get_instr (cpu), 29, 29);
3420 int bias = uimm (aarch64_get_instr (cpu), 30, 30);
3421 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3422 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3423 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3424 unsigned i;
3425
3426 NYI_assert (28, 24, 0x0E);
3427 NYI_assert (15, 10, 0x30);
3428
3429 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3430 {
3431 case 0:
3432 if (bias)
3433 bias = 8;
3434 if (unsign)
3435 for (i = 0; i < 8; i++)
3436 aarch64_set_vec_u16 (cpu, vd, i,
3437 aarch64_get_vec_u8 (cpu, vn, i + bias)
3438 * aarch64_get_vec_u8 (cpu, vm, i + bias));
3439 else
3440 for (i = 0; i < 8; i++)
3441 aarch64_set_vec_s16 (cpu, vd, i,
3442 aarch64_get_vec_s8 (cpu, vn, i + bias)
3443 * aarch64_get_vec_s8 (cpu, vm, i + bias));
3444 return;
3445
3446 case 1:
3447 if (bias)
3448 bias = 4;
3449 if (unsign)
3450 for (i = 0; i < 4; i++)
3451 aarch64_set_vec_u32 (cpu, vd, i,
3452 aarch64_get_vec_u16 (cpu, vn, i + bias)
3453 * aarch64_get_vec_u16 (cpu, vm, i + bias));
3454 else
3455 for (i = 0; i < 4; i++)
3456 aarch64_set_vec_s32 (cpu, vd, i,
3457 aarch64_get_vec_s16 (cpu, vn, i + bias)
3458 * aarch64_get_vec_s16 (cpu, vm, i + bias));
3459 return;
3460
3461 case 2:
3462 if (bias)
3463 bias = 2;
3464 if (unsign)
3465 for (i = 0; i < 2; i++)
3466 aarch64_set_vec_u64 (cpu, vd, i,
3467 (uint64_t) aarch64_get_vec_u32 (cpu, vn,
3468 i + bias)
3469 * (uint64_t) aarch64_get_vec_u32 (cpu, vm,
3470 i + bias));
3471 else
3472 for (i = 0; i < 2; i++)
3473 aarch64_set_vec_s64 (cpu, vd, i,
3474 aarch64_get_vec_s32 (cpu, vn, i + bias)
3475 * aarch64_get_vec_s32 (cpu, vm, i + bias));
3476 return;
3477
3478 case 3:
3479 default:
3480 HALT_NYI;
3481 }
3482}
3483
3484static void
3485do_vec_fadd (sim_cpu *cpu)
3486{
3487 /* instr[31] = 0
3488 instr[30] = half(0)/full(1)
3489 instr[29,24] = 001110
3490 instr[23] = FADD(0)/FSUB(1)
3491 instr[22] = float (0)/double(1)
3492 instr[21] = 1
3493 instr[20,16] = Vm
3494 instr[15,10] = 110101
3495 instr[9,5] = Vn
3496 instr[4.0] = Vd. */
3497
3498 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3499 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3500 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3501 unsigned i;
3502 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3503
3504 NYI_assert (29, 24, 0x0E);
3505 NYI_assert (21, 21, 1);
3506 NYI_assert (15, 10, 0x35);
3507
3508 if (uimm (aarch64_get_instr (cpu), 23, 23))
3509 {
3510 if (uimm (aarch64_get_instr (cpu), 22, 22))
3511 {
3512 if (! full)
3513 HALT_NYI;
3514
3515 for (i = 0; i < 2; i++)
3516 aarch64_set_vec_double (cpu, vd, i,
3517 aarch64_get_vec_double (cpu, vn, i)
3518 - aarch64_get_vec_double (cpu, vm, i));
3519 }
3520 else
3521 {
3522 for (i = 0; i < (full ? 4 : 2); i++)
3523 aarch64_set_vec_float (cpu, vd, i,
3524 aarch64_get_vec_float (cpu, vn, i)
3525 - aarch64_get_vec_float (cpu, vm, i));
3526 }
3527 }
3528 else
3529 {
3530 if (uimm (aarch64_get_instr (cpu), 22, 22))
3531 {
3532 if (! full)
3533 HALT_NYI;
3534
3535 for (i = 0; i < 2; i++)
3536 aarch64_set_vec_double (cpu, vd, i,
3537 aarch64_get_vec_double (cpu, vm, i)
3538 + aarch64_get_vec_double (cpu, vn, i));
3539 }
3540 else
3541 {
3542 for (i = 0; i < (full ? 4 : 2); i++)
3543 aarch64_set_vec_float (cpu, vd, i,
3544 aarch64_get_vec_float (cpu, vm, i)
3545 + aarch64_get_vec_float (cpu, vn, i));
3546 }
3547 }
3548}
3549
3550static void
3551do_vec_add (sim_cpu *cpu)
3552{
3553 /* instr[31] = 0
3554 instr[30] = full/half selector
3555 instr[29,24] = 001110
3556 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3557 instr[21] = 1
3558 instr[20,16] = Vn
3559 instr[15,10] = 100001
3560 instr[9,5] = Vm
3561 instr[4.0] = Vd. */
3562
3563 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3564 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3565 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3566 unsigned i;
3567 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3568
3569 NYI_assert (29, 24, 0x0E);
3570 NYI_assert (21, 21, 1);
3571 NYI_assert (15, 10, 0x21);
3572
3573 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3574 {
3575 case 0:
3576 for (i = 0; i < (full ? 16 : 8); i++)
3577 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
3578 + aarch64_get_vec_u8 (cpu, vm, i));
3579 return;
3580
3581 case 1:
3582 for (i = 0; i < (full ? 8 : 4); i++)
3583 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
3584 + aarch64_get_vec_u16 (cpu, vm, i));
3585 return;
3586
3587 case 2:
3588 for (i = 0; i < (full ? 4 : 2); i++)
3589 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
3590 + aarch64_get_vec_u32 (cpu, vm, i));
3591 return;
3592
3593 case 3:
3594 if (! full)
3595 HALT_UNALLOC;
3596 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vn, 0)
3597 + aarch64_get_vec_u64 (cpu, vm, 0));
3598 aarch64_set_vec_u64 (cpu, vd, 1,
3599 aarch64_get_vec_u64 (cpu, vn, 1)
3600 + aarch64_get_vec_u64 (cpu, vm, 1));
3601 return;
3602
3603 default:
3604 HALT_UNREACHABLE;
3605 }
3606}
3607
3608static void
3609do_vec_mul (sim_cpu *cpu)
3610{
3611 /* instr[31] = 0
3612 instr[30] = full/half selector
3613 instr[29,24] = 00 1110
3614 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3615 instr[21] = 1
3616 instr[20,16] = Vn
3617 instr[15,10] = 10 0111
3618 instr[9,5] = Vm
3619 instr[4.0] = Vd. */
3620
3621 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3622 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3623 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3624 unsigned i;
3625 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3626
3627 NYI_assert (29, 24, 0x0E);
3628 NYI_assert (21, 21, 1);
3629 NYI_assert (15, 10, 0x27);
3630
3631 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3632 {
3633 case 0:
3634 for (i = 0; i < (full ? 16 : 8); i++)
3635 {
3636 uint16_t val = aarch64_get_vec_u8 (cpu, vn, i);
3637 val *= aarch64_get_vec_u8 (cpu, vm, i);
3638
3639 aarch64_set_vec_u16 (cpu, vd, i, val);
3640 }
3641 return;
3642
3643 case 1:
3644 for (i = 0; i < (full ? 8 : 4); i++)
3645 {
3646 uint32_t val = aarch64_get_vec_u16 (cpu, vn, i);
3647 val *= aarch64_get_vec_u16 (cpu, vm, i);
3648
3649 aarch64_set_vec_u32 (cpu, vd, i, val);
3650 }
3651 return;
3652
3653 case 2:
3654 for (i = 0; i < (full ? 4 : 2); i++)
3655 {
3656 uint64_t val = aarch64_get_vec_u32 (cpu, vn, i);
3657 val *= aarch64_get_vec_u32 (cpu, vm, i);
3658
3659 aarch64_set_vec_u64 (cpu, vd, i, val);
3660 }
3661 return;
3662
3663 default:
3664 case 3:
3665 HALT_UNALLOC;
3666 }
3667}
3668
3669static void
3670do_vec_MLA (sim_cpu *cpu)
3671{
3672 /* instr[31] = 0
3673 instr[30] = full/half selector
3674 instr[29,24] = 00 1110
3675 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3676 instr[21] = 1
3677 instr[20,16] = Vn
3678 instr[15,10] = 1001 01
3679 instr[9,5] = Vm
3680 instr[4.0] = Vd. */
3681
3682 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3683 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3684 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3685 unsigned i;
3686 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3687
3688 NYI_assert (29, 24, 0x0E);
3689 NYI_assert (21, 21, 1);
3690 NYI_assert (15, 10, 0x25);
3691
3692 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3693 {
3694 case 0:
3695 for (i = 0; i < (full ? 16 : 8); i++)
3696 {
3697 uint16_t val = aarch64_get_vec_u8 (cpu, vn, i);
3698 val *= aarch64_get_vec_u8 (cpu, vm, i);
3699 val += aarch64_get_vec_u8 (cpu, vd, i);
3700
3701 aarch64_set_vec_u16 (cpu, vd, i, val);
3702 }
3703 return;
3704
3705 case 1:
3706 for (i = 0; i < (full ? 8 : 4); i++)
3707 {
3708 uint32_t val = aarch64_get_vec_u16 (cpu, vn, i);
3709 val *= aarch64_get_vec_u16 (cpu, vm, i);
3710 val += aarch64_get_vec_u16 (cpu, vd, i);
3711
3712 aarch64_set_vec_u32 (cpu, vd, i, val);
3713 }
3714 return;
3715
3716 case 2:
3717 for (i = 0; i < (full ? 4 : 2); i++)
3718 {
3719 uint64_t val = aarch64_get_vec_u32 (cpu, vn, i);
3720 val *= aarch64_get_vec_u32 (cpu, vm, i);
3721 val += aarch64_get_vec_u32 (cpu, vd, i);
3722
3723 aarch64_set_vec_u64 (cpu, vd, i, val);
3724 }
3725 return;
3726
3727 default:
3728 case 3:
3729 HALT_UNALLOC;
3730 }
3731}
3732
3733static float
3734fmaxnm (float a, float b)
3735{
3736 if (fpclassify (a) == FP_NORMAL)
3737 {
3738 if (fpclassify (b) == FP_NORMAL)
3739 return a > b ? a : b;
3740 return a;
3741 }
3742 else if (fpclassify (b) == FP_NORMAL)
3743 return b;
3744 return a;
3745}
3746
3747static float
3748fminnm (float a, float b)
3749{
3750 if (fpclassify (a) == FP_NORMAL)
3751 {
3752 if (fpclassify (b) == FP_NORMAL)
3753 return a < b ? a : b;
3754 return a;
3755 }
3756 else if (fpclassify (b) == FP_NORMAL)
3757 return b;
3758 return a;
3759}
3760
3761static double
3762dmaxnm (double a, double b)
3763{
3764 if (fpclassify (a) == FP_NORMAL)
3765 {
3766 if (fpclassify (b) == FP_NORMAL)
3767 return a > b ? a : b;
3768 return a;
3769 }
3770 else if (fpclassify (b) == FP_NORMAL)
3771 return b;
3772 return a;
3773}
3774
3775static double
3776dminnm (double a, double b)
3777{
3778 if (fpclassify (a) == FP_NORMAL)
3779 {
3780 if (fpclassify (b) == FP_NORMAL)
3781 return a < b ? a : b;
3782 return a;
3783 }
3784 else if (fpclassify (b) == FP_NORMAL)
3785 return b;
3786 return a;
3787}
3788
3789static void
3790do_vec_FminmaxNMP (sim_cpu *cpu)
3791{
3792 /* aarch64_get_instr (cpu)[31] = 0
3793 aarch64_get_instr (cpu)[30] = half (0)/full (1)
3794 aarch64_get_instr (cpu)[29,24] = 10 1110
3795 aarch64_get_instr (cpu)[23] = max(0)/min(1)
3796 aarch64_get_instr (cpu)[22] = float (0)/double (1)
3797 aarch64_get_instr (cpu)[21] = 1
3798 aarch64_get_instr (cpu)[20,16] = Vn
3799 aarch64_get_instr (cpu)[15,10] = 1100 01
3800 aarch64_get_instr (cpu)[9,5] = Vm
3801 aarch64_get_instr (cpu)[4.0] = Vd. */
3802
3803 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3804 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3805 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3806 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3807
3808 NYI_assert (29, 24, 0x2E);
3809 NYI_assert (21, 21, 1);
3810 NYI_assert (15, 10, 0x31);
3811
3812 if (uimm (aarch64_get_instr (cpu), 22, 22))
3813 {
3814 double (* fn)(double, double) = uimm (aarch64_get_instr (cpu), 23, 23)
3815 ? dminnm : dmaxnm;
3816
3817 if (! full)
3818 HALT_NYI;
3819 aarch64_set_vec_double (cpu, vd, 0,
3820 fn (aarch64_get_vec_double (cpu, vn, 0),
3821 aarch64_get_vec_double (cpu, vn, 1)));
3822 aarch64_set_vec_double (cpu, vd, 0,
3823 fn (aarch64_get_vec_double (cpu, vm, 0),
3824 aarch64_get_vec_double (cpu, vm, 1)));
3825 }
3826 else
3827 {
3828 float (* fn)(float, float) = uimm (aarch64_get_instr (cpu), 23, 23)
3829 ? fminnm : fmaxnm;
3830
3831 aarch64_set_vec_float (cpu, vd, 0,
3832 fn (aarch64_get_vec_float (cpu, vn, 0),
3833 aarch64_get_vec_float (cpu, vn, 1)));
3834 if (full)
3835 aarch64_set_vec_float (cpu, vd, 1,
3836 fn (aarch64_get_vec_float (cpu, vn, 2),
3837 aarch64_get_vec_float (cpu, vn, 3)));
3838
3839 aarch64_set_vec_float (cpu, vd, (full ? 2 : 1),
3840 fn (aarch64_get_vec_float (cpu, vm, 0),
3841 aarch64_get_vec_float (cpu, vm, 1)));
3842 if (full)
3843 aarch64_set_vec_float (cpu, vd, 3,
3844 fn (aarch64_get_vec_float (cpu, vm, 2),
3845 aarch64_get_vec_float (cpu, vm, 3)));
3846 }
3847}
3848
3849static void
3850do_vec_AND (sim_cpu *cpu)
3851{
3852 /* instr[31] = 0
3853 instr[30] = half (0)/full (1)
3854 instr[29,21] = 001110001
3855 instr[20,16] = Vm
3856 instr[15,10] = 000111
3857 instr[9,5] = Vn
3858 instr[4.0] = Vd. */
3859
3860 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3861 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3862 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3863 unsigned i;
3864 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3865
3866 NYI_assert (29, 21, 0x071);
3867 NYI_assert (15, 10, 0x07);
3868
3869 for (i = 0; i < (full ? 4 : 2); i++)
3870 aarch64_set_vec_u32 (cpu, vd, i,
3871 aarch64_get_vec_u32 (cpu, vn, i)
3872 & aarch64_get_vec_u32 (cpu, vm, i));
3873}
3874
3875static void
3876do_vec_BSL (sim_cpu *cpu)
3877{
3878 /* instr[31] = 0
3879 instr[30] = half (0)/full (1)
3880 instr[29,21] = 101110011
3881 instr[20,16] = Vm
3882 instr[15,10] = 000111
3883 instr[9,5] = Vn
3884 instr[4.0] = Vd. */
3885
3886 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3887 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3888 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3889 unsigned i;
3890 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3891
3892 NYI_assert (29, 21, 0x173);
3893 NYI_assert (15, 10, 0x07);
3894
3895 for (i = 0; i < (full ? 16 : 8); i++)
3896 aarch64_set_vec_u8 (cpu, vd, i,
3897 ( aarch64_get_vec_u8 (cpu, vd, i)
3898 & aarch64_get_vec_u8 (cpu, vn, i))
3899 | ((~ aarch64_get_vec_u8 (cpu, vd, i))
3900 & aarch64_get_vec_u8 (cpu, vm, i)));
3901}
3902
3903static void
3904do_vec_EOR (sim_cpu *cpu)
3905{
3906 /* instr[31] = 0
3907 instr[30] = half (0)/full (1)
3908 instr[29,21] = 10 1110 001
3909 instr[20,16] = Vm
3910 instr[15,10] = 000111
3911 instr[9,5] = Vn
3912 instr[4.0] = Vd. */
3913
3914 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3915 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3916 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3917 unsigned i;
3918 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3919
3920 NYI_assert (29, 21, 0x171);
3921 NYI_assert (15, 10, 0x07);
3922
3923 for (i = 0; i < (full ? 4 : 2); i++)
3924 aarch64_set_vec_u32 (cpu, vd, i,
3925 aarch64_get_vec_u32 (cpu, vn, i)
3926 ^ aarch64_get_vec_u32 (cpu, vm, i));
3927}
3928
3929static void
3930do_vec_bit (sim_cpu *cpu)
3931{
3932 /* instr[31] = 0
3933 instr[30] = half (0)/full (1)
3934 instr[29,23] = 10 1110 1
3935 instr[22] = BIT (0) / BIF (1)
3936 instr[21] = 1
3937 instr[20,16] = Vm
3938 instr[15,10] = 0001 11
3939 instr[9,5] = Vn
3940 instr[4.0] = Vd. */
3941
3942 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3943 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3944 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3945 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
3946 unsigned test_false = uimm (aarch64_get_instr (cpu), 22, 22);
3947 unsigned i;
3948
3949 NYI_assert (29, 23, 0x5D);
3950 NYI_assert (21, 21, 1);
3951 NYI_assert (15, 10, 0x07);
3952
3953 if (test_false)
3954 {
3955 for (i = 0; i < (full ? 16 : 8); i++)
3956 if (aarch64_get_vec_u32 (cpu, vn, i) == 0)
3957 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
3958 }
3959 else
3960 {
3961 for (i = 0; i < (full ? 16 : 8); i++)
3962 if (aarch64_get_vec_u32 (cpu, vn, i) != 0)
3963 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
3964 }
3965}
3966
3967static void
3968do_vec_ORN (sim_cpu *cpu)
3969{
3970 /* instr[31] = 0
3971 instr[30] = half (0)/full (1)
3972 instr[29,21] = 00 1110 111
3973 instr[20,16] = Vm
3974 instr[15,10] = 00 0111
3975 instr[9,5] = Vn
3976 instr[4.0] = Vd. */
3977
3978 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3979 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3980 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3981 unsigned i;
3982 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3983
3984 NYI_assert (29, 21, 0x077);
3985 NYI_assert (15, 10, 0x07);
3986
3987 for (i = 0; i < (full ? 16 : 8); i++)
3988 aarch64_set_vec_u8 (cpu, vd, i,
3989 aarch64_get_vec_u8 (cpu, vn, i)
3990 | ~ aarch64_get_vec_u8 (cpu, vm, i));
3991}
3992
3993static void
3994do_vec_ORR (sim_cpu *cpu)
3995{
3996 /* instr[31] = 0
3997 instr[30] = half (0)/full (1)
3998 instr[29,21] = 00 1110 101
3999 instr[20,16] = Vm
4000 instr[15,10] = 0001 11
4001 instr[9,5] = Vn
4002 instr[4.0] = Vd. */
4003
4004 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4005 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4006 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4007 unsigned i;
4008 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4009
4010 NYI_assert (29, 21, 0x075);
4011 NYI_assert (15, 10, 0x07);
4012
4013 for (i = 0; i < (full ? 16 : 8); i++)
4014 aarch64_set_vec_u8 (cpu, vd, i,
4015 aarch64_get_vec_u8 (cpu, vn, i)
4016 | aarch64_get_vec_u8 (cpu, vm, i));
4017}
4018
4019static void
4020do_vec_BIC (sim_cpu *cpu)
4021{
4022 /* instr[31] = 0
4023 instr[30] = half (0)/full (1)
4024 instr[29,21] = 00 1110 011
4025 instr[20,16] = Vm
4026 instr[15,10] = 00 0111
4027 instr[9,5] = Vn
4028 instr[4.0] = Vd. */
4029
4030 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4031 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4032 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4033 unsigned i;
4034 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4035
4036 NYI_assert (29, 21, 0x073);
4037 NYI_assert (15, 10, 0x07);
4038
4039 for (i = 0; i < (full ? 16 : 8); i++)
4040 aarch64_set_vec_u8 (cpu, vd, i,
4041 aarch64_get_vec_u8 (cpu, vn, i)
4042 & ~ aarch64_get_vec_u8 (cpu, vm, i));
4043}
4044
4045static void
4046do_vec_XTN (sim_cpu *cpu)
4047{
4048 /* instr[31] = 0
4049 instr[30] = first part (0)/ second part (1)
4050 instr[29,24] = 00 1110
4051 instr[23,22] = size: byte(00), half(01), word (10)
4052 instr[21,10] = 1000 0100 1010
4053 instr[9,5] = Vs
4054 instr[4,0] = Vd. */
4055
4056 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4057 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4058 unsigned bias = uimm (aarch64_get_instr (cpu), 30, 30);
4059 unsigned i;
4060
4061 NYI_assert (29, 24, 0x0E);
4062 NYI_assert (21, 10, 0x84A);
4063
4064 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4065 {
4066 case 0:
4067 if (bias)
4068 for (i = 0; i < 8; i++)
4069 aarch64_set_vec_u8 (cpu, vd, i + 8,
4070 aarch64_get_vec_u16 (cpu, vs, i) >> 8);
4071 else
4072 for (i = 0; i < 8; i++)
4073 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i));
4074 return;
4075
4076 case 1:
4077 if (bias)
4078 for (i = 0; i < 4; i++)
4079 aarch64_set_vec_u16 (cpu, vd, i + 4,
4080 aarch64_get_vec_u32 (cpu, vs, i) >> 16);
4081 else
4082 for (i = 0; i < 4; i++)
4083 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, i));
4084 return;
4085
4086 case 2:
4087 if (bias)
4088 for (i = 0; i < 2; i++)
4089 aarch64_set_vec_u32 (cpu, vd, i + 4,
4090 aarch64_get_vec_u64 (cpu, vs, i) >> 32);
4091 else
4092 for (i = 0; i < 2; i++)
4093 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, i));
4094 return;
4095
4096 default:
4097 HALT_UNALLOC;
4098 }
4099}
4100
2e8cf49e
NC
4101static void
4102do_vec_maxv (sim_cpu *cpu)
4103{
4104 /* instr[31] = 0
4105 instr[30] = half(0)/full(1)
4106 instr[29] = signed (0)/unsigned(1)
4107 instr[28,24] = 0 1110
4108 instr[23,22] = size: byte(00), half(01), word (10)
4109 instr[21] = 1
4110 instr[20,17] = 1 000
4111 instr[16] = max(0)/min(1)
4112 instr[15,10] = 1010 10
4113 instr[9,5] = V source
4114 instr[4.0] = R dest. */
4115
4116 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4117 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
4118 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4119 unsigned i;
4120
4121 NYI_assert (28, 24, 0x0E);
4122 NYI_assert (21, 21, 1);
4123 NYI_assert (20, 17, 8);
4124 NYI_assert (15, 10, 0x2A);
4125
4126 switch ((uimm (aarch64_get_instr (cpu), 29, 29) << 1)
4127 | uimm (aarch64_get_instr (cpu), 16, 16))
4128 {
4129 case 0: /* SMAXV. */
4130 {
4131 int64_t smax;
4132 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4133 {
4134 case 0:
4135 smax = aarch64_get_vec_s8 (cpu, vs, 0);
4136 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4137 smax = max (smax, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4138 break;
4139 case 1:
4140 smax = aarch64_get_vec_s16 (cpu, vs, 0);
4141 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4142 smax = max (smax, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4143 break;
4144 case 2:
4145 smax = aarch64_get_vec_s32 (cpu, vs, 0);
4146 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4147 smax = max (smax, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e
NC
4148 break;
4149 default:
4150 case 3:
4151 HALT_UNALLOC;
4152 }
4153 aarch64_set_reg_s64 (cpu, rd, NO_SP, smax);
4154 return;
4155 }
4156
4157 case 1: /* SMINV. */
4158 {
4159 int64_t smin;
4160 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4161 {
4162 case 0:
4163 smin = aarch64_get_vec_s8 (cpu, vs, 0);
4164 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4165 smin = min (smin, aarch64_get_vec_s8 (cpu, vs, i));
2e8cf49e
NC
4166 break;
4167 case 1:
4168 smin = aarch64_get_vec_s16 (cpu, vs, 0);
4169 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4170 smin = min (smin, aarch64_get_vec_s16 (cpu, vs, i));
2e8cf49e
NC
4171 break;
4172 case 2:
4173 smin = aarch64_get_vec_s32 (cpu, vs, 0);
4174 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4175 smin = min (smin, aarch64_get_vec_s32 (cpu, vs, i));
2e8cf49e
NC
4176 break;
4177 default:
4178 case 3:
4179 HALT_UNALLOC;
4180 }
4181 aarch64_set_reg_s64 (cpu, rd, NO_SP, smin);
4182 return;
4183 }
4184
4185 case 2: /* UMAXV. */
4186 {
4187 uint64_t umax;
4188 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4189 {
4190 case 0:
4191 umax = aarch64_get_vec_u8 (cpu, vs, 0);
4192 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4193 umax = max (umax, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4194 break;
4195 case 1:
4196 umax = aarch64_get_vec_u16 (cpu, vs, 0);
4197 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4198 umax = max (umax, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4199 break;
4200 case 2:
4201 umax = aarch64_get_vec_u32 (cpu, vs, 0);
4202 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4203 umax = max (umax, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e
NC
4204 break;
4205 default:
4206 case 3:
4207 HALT_UNALLOC;
4208 }
4209 aarch64_set_reg_u64 (cpu, rd, NO_SP, umax);
4210 return;
4211 }
4212
4213 case 3: /* UMINV. */
4214 {
4215 uint64_t umin;
4216 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4217 {
4218 case 0:
4219 umin = aarch64_get_vec_u8 (cpu, vs, 0);
4220 for (i = 1; i < (full ? 16 : 8); i++)
bc273e17 4221 umin = min (umin, aarch64_get_vec_u8 (cpu, vs, i));
2e8cf49e
NC
4222 break;
4223 case 1:
4224 umin = aarch64_get_vec_u16 (cpu, vs, 0);
4225 for (i = 1; i < (full ? 8 : 4); i++)
bc273e17 4226 umin = min (umin, aarch64_get_vec_u16 (cpu, vs, i));
2e8cf49e
NC
4227 break;
4228 case 2:
4229 umin = aarch64_get_vec_u32 (cpu, vs, 0);
4230 for (i = 1; i < (full ? 4 : 2); i++)
bc273e17 4231 umin = min (umin, aarch64_get_vec_u32 (cpu, vs, i));
2e8cf49e
NC
4232 break;
4233 default:
4234 case 3:
4235 HALT_UNALLOC;
4236 }
4237 aarch64_set_reg_u64 (cpu, rd, NO_SP, umin);
4238 return;
4239 }
4240
4241 default:
4242 HALT_UNALLOC;
4243 }
4244}
4245
4246static void
4247do_vec_fminmaxV (sim_cpu *cpu)
4248{
4249 /* instr[31,24] = 0110 1110
4250 instr[23] = max(0)/min(1)
4251 instr[22,14] = 011 0000 11
4252 instr[13,12] = nm(00)/normal(11)
4253 instr[11,10] = 10
4254 instr[9,5] = V source
4255 instr[4.0] = R dest. */
4256
4257 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4258 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
4259 unsigned i;
4260 float res = aarch64_get_vec_float (cpu, vs, 0);
4261
4262 NYI_assert (31, 24, 0x6E);
4263 NYI_assert (22, 14, 0x0C3);
4264 NYI_assert (11, 10, 2);
4265
4266 if (uimm (aarch64_get_instr (cpu), 23, 23))
4267 {
4268 switch (uimm (aarch64_get_instr (cpu), 13, 12))
4269 {
4270 case 0: /* FMNINNMV. */
4271 for (i = 1; i < 4; i++)
4272 res = fminnm (res, aarch64_get_vec_float (cpu, vs, i));
4273 break;
4274
4275 case 3: /* FMINV. */
4276 for (i = 1; i < 4; i++)
bc273e17 4277 res = min (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4278 break;
4279
4280 default:
4281 HALT_NYI;
4282 }
4283 }
4284 else
4285 {
4286 switch (uimm (aarch64_get_instr (cpu), 13, 12))
4287 {
4288 case 0: /* FMNAXNMV. */
4289 for (i = 1; i < 4; i++)
4290 res = fmaxnm (res, aarch64_get_vec_float (cpu, vs, i));
4291 break;
4292
4293 case 3: /* FMAXV. */
4294 for (i = 1; i < 4; i++)
bc273e17 4295 res = max (res, aarch64_get_vec_float (cpu, vs, i));
2e8cf49e
NC
4296 break;
4297
4298 default:
4299 HALT_NYI;
4300 }
4301 }
4302
4303 aarch64_set_FP_float (cpu, rd, res);
4304}
4305
4306static void
4307do_vec_Fminmax (sim_cpu *cpu)
4308{
4309 /* instr[31] = 0
4310 instr[30] = half(0)/full(1)
4311 instr[29,24] = 00 1110
4312 instr[23] = max(0)/min(1)
4313 instr[22] = float(0)/double(1)
4314 instr[21] = 1
4315 instr[20,16] = Vm
4316 instr[15,14] = 11
4317 instr[13,12] = nm(00)/normal(11)
4318 instr[11,10] = 01
4319 instr[9,5] = Vn
4320 instr[4,0] = Vd. */
4321
4322 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4323 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4324 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4325 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4326 unsigned min = uimm (aarch64_get_instr (cpu), 23, 23);
4327 unsigned i;
4328
4329 NYI_assert (29, 24, 0x0E);
4330 NYI_assert (21, 21, 1);
4331 NYI_assert (15, 14, 3);
4332 NYI_assert (11, 10, 1);
4333
4334 if (uimm (aarch64_get_instr (cpu), 22, 22))
4335 {
4336 double (* func)(double, double);
4337
4338 if (! full)
4339 HALT_NYI;
4340
4341 if (uimm (aarch64_get_instr (cpu), 13, 12) == 0)
4342 func = min ? dminnm : dmaxnm;
4343 else if (uimm (aarch64_get_instr (cpu), 13, 12) == 3)
4344 func = min ? fmin : fmax;
4345 else
4346 HALT_NYI;
4347
4348 for (i = 0; i < 2; i++)
4349 aarch64_set_vec_double (cpu, vd, i,
4350 func (aarch64_get_vec_double (cpu, vn, i),
4351 aarch64_get_vec_double (cpu, vm, i)));
4352 }
4353 else
4354 {
4355 float (* func)(float, float);
4356
4357 if (uimm (aarch64_get_instr (cpu), 13, 12) == 0)
4358 func = min ? fminnm : fmaxnm;
4359 else if (uimm (aarch64_get_instr (cpu), 13, 12) == 3)
4360 func = min ? fminf : fmaxf;
4361 else
4362 HALT_NYI;
4363
4364 for (i = 0; i < (full ? 4 : 2); i++)
4365 aarch64_set_vec_float (cpu, vd, i,
4366 func (aarch64_get_vec_float (cpu, vn, i),
4367 aarch64_get_vec_float (cpu, vm, i)));
4368 }
4369}
4370
4371static void
4372do_vec_SCVTF (sim_cpu *cpu)
4373{
4374 /* instr[31] = 0
4375 instr[30] = Q
4376 instr[29,23] = 00 1110 0
4377 instr[22] = float(0)/double(1)
4378 instr[21,10] = 10 0001 1101 10
4379 instr[9,5] = Vn
4380 instr[4,0] = Vd. */
4381
4382 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4383 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4384 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4385 unsigned size = uimm (aarch64_get_instr (cpu), 22, 22);
4386 unsigned i;
4387
4388 NYI_assert (29, 23, 0x1C);
4389 NYI_assert (21, 10, 0x876);
4390
4391 if (size)
4392 {
4393 if (! full)
4394 HALT_UNALLOC;
4395
4396 for (i = 0; i < 2; i++)
4397 {
4398 double val = (double) aarch64_get_vec_u64 (cpu, vn, i);
4399 aarch64_set_vec_double (cpu, vd, i, val);
4400 }
4401 }
4402 else
4403 {
4404 for (i = 0; i < (full ? 4 : 2); i++)
4405 {
4406 float val = (float) aarch64_get_vec_u32 (cpu, vn, i);
4407 aarch64_set_vec_float (cpu, vd, i, val);
4408 }
4409 }
4410}
4411
4412#define VEC_CMP(SOURCE, CMP) \
4413 do \
4414 { \
4415 switch (size) \
4416 { \
4417 case 0: \
4418 for (i = 0; i < (full ? 16 : 8); i++) \
4419 aarch64_set_vec_u8 (cpu, vd, i, \
4420 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4421 CMP \
4422 aarch64_get_vec_##SOURCE##8 (cpu, vm, i) \
4423 ? -1 : 0); \
4424 return; \
4425 case 1: \
4426 for (i = 0; i < (full ? 8 : 4); i++) \
4427 aarch64_set_vec_u16 (cpu, vd, i, \
4428 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4429 CMP \
4430 aarch64_get_vec_##SOURCE##16 (cpu, vm, i) \
4431 ? -1 : 0); \
4432 return; \
4433 case 2: \
4434 for (i = 0; i < (full ? 4 : 2); i++) \
4435 aarch64_set_vec_u32 (cpu, vd, i, \
4436 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4437 CMP \
4438 aarch64_get_vec_##SOURCE##32 (cpu, vm, i) \
4439 ? -1 : 0); \
4440 return; \
4441 case 3: \
4442 if (! full) \
4443 HALT_UNALLOC; \
4444 for (i = 0; i < 2; i++) \
4445 aarch64_set_vec_u64 (cpu, vd, i, \
4446 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4447 CMP \
4448 aarch64_get_vec_##SOURCE##64 (cpu, vm, i) \
4449 ? -1ULL : 0); \
4450 return; \
4451 default: \
4452 HALT_UNALLOC; \
4453 } \
4454 } \
4455 while (0)
4456
4457#define VEC_CMP0(SOURCE, CMP) \
4458 do \
4459 { \
4460 switch (size) \
4461 { \
4462 case 0: \
4463 for (i = 0; i < (full ? 16 : 8); i++) \
4464 aarch64_set_vec_u8 (cpu, vd, i, \
4465 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4466 CMP 0 ? -1 : 0); \
4467 return; \
4468 case 1: \
4469 for (i = 0; i < (full ? 8 : 4); i++) \
4470 aarch64_set_vec_u16 (cpu, vd, i, \
4471 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4472 CMP 0 ? -1 : 0); \
4473 return; \
4474 case 2: \
4475 for (i = 0; i < (full ? 4 : 2); i++) \
4476 aarch64_set_vec_u32 (cpu, vd, i, \
4477 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4478 CMP 0 ? -1 : 0); \
4479 return; \
4480 case 3: \
4481 if (! full) \
4482 HALT_UNALLOC; \
4483 for (i = 0; i < 2; i++) \
4484 aarch64_set_vec_u64 (cpu, vd, i, \
4485 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4486 CMP 0 ? -1ULL : 0); \
4487 return; \
4488 default: \
4489 HALT_UNALLOC; \
4490 } \
4491 } \
4492 while (0)
4493
4494#define VEC_FCMP0(CMP) \
4495 do \
4496 { \
4497 if (vm != 0) \
4498 HALT_NYI; \
4499 if (uimm (aarch64_get_instr (cpu), 22, 22)) \
4500 { \
4501 if (! full) \
4502 HALT_NYI; \
4503 for (i = 0; i < 2; i++) \
4504 aarch64_set_vec_u64 (cpu, vd, i, \
4505 aarch64_get_vec_double (cpu, vn, i) \
4506 CMP 0.0 ? -1 : 0); \
4507 } \
4508 else \
4509 { \
4510 for (i = 0; i < (full ? 4 : 2); i++) \
4511 aarch64_set_vec_u32 (cpu, vd, i, \
4512 aarch64_get_vec_float (cpu, vn, i) \
4513 CMP 0.0 ? -1 : 0); \
4514 } \
4515 return; \
4516 } \
4517 while (0)
4518
4519#define VEC_FCMP(CMP) \
4520 do \
4521 { \
4522 if (uimm (aarch64_get_instr (cpu), 22, 22)) \
4523 { \
4524 if (! full) \
4525 HALT_NYI; \
4526 for (i = 0; i < 2; i++) \
4527 aarch64_set_vec_u64 (cpu, vd, i, \
4528 aarch64_get_vec_double (cpu, vn, i) \
4529 CMP \
4530 aarch64_get_vec_double (cpu, vm, i) \
4531 ? -1 : 0); \
4532 } \
4533 else \
4534 { \
4535 for (i = 0; i < (full ? 4 : 2); i++) \
4536 aarch64_set_vec_u32 (cpu, vd, i, \
4537 aarch64_get_vec_float (cpu, vn, i) \
4538 CMP \
4539 aarch64_get_vec_float (cpu, vm, i) \
4540 ? -1 : 0); \
4541 } \
4542 return; \
4543 } \
4544 while (0)
4545
4546static void
4547do_vec_compare (sim_cpu *cpu)
4548{
4549 /* instr[31] = 0
4550 instr[30] = half(0)/full(1)
4551 instr[29] = part-of-comparison-type
4552 instr[28,24] = 0 1110
4553 instr[23,22] = size of integer compares: byte(00), half(01), word (10), long (11)
4554 type of float compares: single (-0) / double (-1)
4555 instr[21] = 1
4556 instr[20,16] = Vm or 00000 (compare vs 0)
4557 instr[15,10] = part-of-comparison-type
4558 instr[9,5] = Vn
4559 instr[4.0] = Vd. */
4560
4561 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4562 int size = uimm (aarch64_get_instr (cpu), 23, 22);
4563 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4564 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4565 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4566 unsigned i;
4567
4568 NYI_assert (28, 24, 0x0E);
4569 NYI_assert (21, 21, 1);
4570
4571 if ((uimm (aarch64_get_instr (cpu), 11, 11)
4572 && uimm (aarch64_get_instr (cpu), 14, 14))
4573 || ((uimm (aarch64_get_instr (cpu), 11, 11) == 0
4574 && uimm (aarch64_get_instr (cpu), 10, 10) == 0)))
4575 {
4576 /* A compare vs 0. */
4577 if (vm != 0)
4578 {
4579 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x2A)
4580 do_vec_maxv (cpu);
4581 else if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x32
4582 || uimm (aarch64_get_instr (cpu), 15, 10) == 0x3E)
4583 do_vec_fminmaxV (cpu);
4584 else if (uimm (aarch64_get_instr (cpu), 29, 23) == 0x1C
4585 && uimm (aarch64_get_instr (cpu), 21, 10) == 0x876)
4586 do_vec_SCVTF (cpu);
4587 else
4588 HALT_NYI;
4589 return;
4590 }
4591 }
4592
4593 if (uimm (aarch64_get_instr (cpu), 14, 14))
4594 {
4595 /* A floating point compare. */
4596 unsigned decode = (uimm (aarch64_get_instr (cpu), 29, 29) << 5)
4597 | (uimm (aarch64_get_instr (cpu), 23, 23) << 4)
4598 | uimm (aarch64_get_instr (cpu), 13, 10);
4599
4600 NYI_assert (15, 15, 1);
4601
4602 switch (decode)
4603 {
4604 case /* 0b010010: GT#0 */ 0x12: VEC_FCMP0 (>);
4605 case /* 0b110010: GE#0 */ 0x32: VEC_FCMP0 (>=);
4606 case /* 0b010110: EQ#0 */ 0x16: VEC_FCMP0 (==);
4607 case /* 0b110110: LE#0 */ 0x36: VEC_FCMP0 (<=);
4608 case /* 0b011010: LT#0 */ 0x1A: VEC_FCMP0 (<);
4609 case /* 0b111001: GT */ 0x39: VEC_FCMP (>);
4610 case /* 0b101001: GE */ 0x29: VEC_FCMP (>=);
4611 case /* 0b001001: EQ */ 0x09: VEC_FCMP (==);
4612
4613 default:
4614 HALT_NYI;
4615 }
4616 }
4617 else
4618 {
4619 unsigned decode = (uimm (aarch64_get_instr (cpu), 29, 29) << 6)
4620 | uimm (aarch64_get_instr (cpu), 15, 10);
4621
4622 switch (decode)
4623 {
4624 case 0x0D: /* 0001101 GT */ VEC_CMP (s, > );
4625 case 0x0F: /* 0001111 GE */ VEC_CMP (s, >= );
4626 case 0x22: /* 0100010 GT #0 */ VEC_CMP0 (s, > );
4627 case 0x26: /* 0100110 EQ #0 */ VEC_CMP0 (s, == );
4628 case 0x2A: /* 0101010 LT #0 */ VEC_CMP0 (s, < );
4629 case 0x4D: /* 1001101 HI */ VEC_CMP (u, > );
4630 case 0x4F: /* 1001111 HS */ VEC_CMP (u, >= );
4631 case 0x62: /* 1100010 GE #0 */ VEC_CMP0 (s, >= );
4632 case 0x63: /* 1100011 EQ */ VEC_CMP (u, == );
4633 case 0x66: /* 1100110 LE #0 */ VEC_CMP0 (s, <= );
4634 default:
4635 if (vm == 0)
4636 HALT_NYI;
4637 do_vec_maxv (cpu);
4638 }
4639 }
4640}
4641
4642static void
4643do_vec_SSHL (sim_cpu *cpu)
4644{
4645 /* instr[31] = 0
4646 instr[30] = first part (0)/ second part (1)
4647 instr[29,24] = 00 1110
4648 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4649 instr[21] = 1
4650 instr[20,16] = Vm
4651 instr[15,10] = 0100 01
4652 instr[9,5] = Vn
4653 instr[4,0] = Vd. */
4654
4655 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4656 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4657 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4658 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4659 unsigned i;
4660
4661 NYI_assert (29, 24, 0x0E);
4662 NYI_assert (21, 21, 1);
4663 NYI_assert (15, 10, 0x11);
4664
4665 /* FIXME: What is a signed shift left in this context ?. */
4666
4667 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4668 {
4669 case 0:
4670 for (i = 0; i < (full ? 16 : 8); i++)
4671 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4672 << aarch64_get_vec_s8 (cpu, vm, i));
4673 return;
4674
4675 case 1:
4676 for (i = 0; i < (full ? 8 : 4); i++)
4677 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4678 << aarch64_get_vec_s16 (cpu, vm, i));
4679 return;
4680
4681 case 2:
4682 for (i = 0; i < (full ? 4 : 2); i++)
4683 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4684 << aarch64_get_vec_s32 (cpu, vm, i));
4685 return;
4686
4687 case 3:
4688 if (! full)
4689 HALT_UNALLOC;
4690 for (i = 0; i < 2; i++)
4691 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4692 << aarch64_get_vec_s64 (cpu, vm, i));
4693 return;
4694
4695 default:
4696 HALT_NYI;
4697 }
4698}
4699
4700static void
4701do_vec_USHL (sim_cpu *cpu)
4702{
4703 /* instr[31] = 0
4704 instr[30] = first part (0)/ second part (1)
4705 instr[29,24] = 10 1110
4706 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4707 instr[21] = 1
4708 instr[20,16] = Vm
4709 instr[15,10] = 0100 01
4710 instr[9,5] = Vn
4711 instr[4,0] = Vd */
4712
4713 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4714 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4715 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4716 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4717 unsigned i;
4718
4719 NYI_assert (29, 24, 0x2E);
4720 NYI_assert (15, 10, 0x11);
4721
4722 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4723 {
4724 case 0:
4725 for (i = 0; i < (full ? 16 : 8); i++)
4726 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4727 << aarch64_get_vec_u8 (cpu, vm, i));
4728 return;
4729
4730 case 1:
4731 for (i = 0; i < (full ? 8 : 4); i++)
4732 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4733 << aarch64_get_vec_u16 (cpu, vm, i));
4734 return;
4735
4736 case 2:
4737 for (i = 0; i < (full ? 4 : 2); i++)
4738 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4739 << aarch64_get_vec_u32 (cpu, vm, i));
4740 return;
4741
4742 case 3:
4743 if (! full)
4744 HALT_UNALLOC;
4745 for (i = 0; i < 2; i++)
4746 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4747 << aarch64_get_vec_u64 (cpu, vm, i));
4748 return;
4749
4750 default:
4751 HALT_NYI;
4752 }
4753}
4754
4755static void
4756do_vec_FMLA (sim_cpu *cpu)
4757{
4758 /* instr[31] = 0
4759 instr[30] = full/half selector
4760 instr[29,23] = 0011100
4761 instr[22] = size: 0=>float, 1=>double
4762 instr[21] = 1
4763 instr[20,16] = Vn
4764 instr[15,10] = 1100 11
4765 instr[9,5] = Vm
4766 instr[4.0] = Vd. */
4767
4768 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4769 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4770 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4771 unsigned i;
4772 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4773
4774 NYI_assert (29, 23, 0x1C);
4775 NYI_assert (21, 21, 1);
4776 NYI_assert (15, 10, 0x33);
4777
4778 if (uimm (aarch64_get_instr (cpu), 22, 22))
4779 {
4780 if (! full)
4781 HALT_UNALLOC;
4782 for (i = 0; i < 2; i++)
4783 aarch64_set_vec_double (cpu, vd, i,
4784 aarch64_get_vec_double (cpu, vn, i) *
4785 aarch64_get_vec_double (cpu, vm, i) +
4786 aarch64_get_vec_double (cpu, vd, i));
4787 }
4788 else
4789 {
4790 for (i = 0; i < (full ? 4 : 2); i++)
4791 aarch64_set_vec_float (cpu, vd, i,
4792 aarch64_get_vec_float (cpu, vn, i) *
4793 aarch64_get_vec_float (cpu, vm, i) +
4794 aarch64_get_vec_float (cpu, vd, i));
4795 }
4796}
4797
4798static void
4799do_vec_max (sim_cpu *cpu)
4800{
4801 /* instr[31] = 0
4802 instr[30] = full/half selector
4803 instr[29] = SMAX (0) / UMAX (1)
4804 instr[28,24] = 0 1110
4805 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4806 instr[21] = 1
4807 instr[20,16] = Vn
4808 instr[15,10] = 0110 01
4809 instr[9,5] = Vm
4810 instr[4.0] = Vd. */
4811
4812 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4813 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4814 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4815 unsigned i;
4816 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4817
4818 NYI_assert (28, 24, 0x0E);
4819 NYI_assert (21, 21, 1);
4820 NYI_assert (15, 10, 0x19);
4821
4822 if (uimm (aarch64_get_instr (cpu), 29, 29))
4823 {
4824 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4825 {
4826 case 0:
4827 for (i = 0; i < (full ? 16 : 8); i++)
4828 aarch64_set_vec_u8 (cpu, vd, i,
4829 aarch64_get_vec_u8 (cpu, vn, i)
4830 > aarch64_get_vec_u8 (cpu, vm, i)
4831 ? aarch64_get_vec_u8 (cpu, vn, i)
4832 : aarch64_get_vec_u8 (cpu, vm, i));
4833 return;
4834
4835 case 1:
4836 for (i = 0; i < (full ? 8 : 4); i++)
4837 aarch64_set_vec_u16 (cpu, vd, i,
4838 aarch64_get_vec_u16 (cpu, vn, i)
4839 > aarch64_get_vec_u16 (cpu, vm, i)
4840 ? aarch64_get_vec_u16 (cpu, vn, i)
4841 : aarch64_get_vec_u16 (cpu, vm, i));
4842 return;
4843
4844 case 2:
4845 for (i = 0; i < (full ? 4 : 2); i++)
4846 aarch64_set_vec_u32 (cpu, vd, i,
4847 aarch64_get_vec_u32 (cpu, vn, i)
4848 > aarch64_get_vec_u32 (cpu, vm, i)
4849 ? aarch64_get_vec_u32 (cpu, vn, i)
4850 : aarch64_get_vec_u32 (cpu, vm, i));
4851 return;
4852
4853 default:
4854 case 3:
4855 HALT_UNALLOC;
4856 }
4857 }
4858 else
4859 {
4860 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4861 {
4862 case 0:
4863 for (i = 0; i < (full ? 16 : 8); i++)
4864 aarch64_set_vec_s8 (cpu, vd, i,
4865 aarch64_get_vec_s8 (cpu, vn, i)
4866 > aarch64_get_vec_s8 (cpu, vm, i)
4867 ? aarch64_get_vec_s8 (cpu, vn, i)
4868 : aarch64_get_vec_s8 (cpu, vm, i));
4869 return;
4870
4871 case 1:
4872 for (i = 0; i < (full ? 8 : 4); i++)
4873 aarch64_set_vec_s16 (cpu, vd, i,
4874 aarch64_get_vec_s16 (cpu, vn, i)
4875 > aarch64_get_vec_s16 (cpu, vm, i)
4876 ? aarch64_get_vec_s16 (cpu, vn, i)
4877 : aarch64_get_vec_s16 (cpu, vm, i));
4878 return;
4879
4880 case 2:
4881 for (i = 0; i < (full ? 4 : 2); i++)
4882 aarch64_set_vec_s32 (cpu, vd, i,
4883 aarch64_get_vec_s32 (cpu, vn, i)
4884 > aarch64_get_vec_s32 (cpu, vm, i)
4885 ? aarch64_get_vec_s32 (cpu, vn, i)
4886 : aarch64_get_vec_s32 (cpu, vm, i));
4887 return;
4888
4889 default:
4890 case 3:
4891 HALT_UNALLOC;
4892 }
4893 }
4894}
4895
4896static void
4897do_vec_min (sim_cpu *cpu)
4898{
4899 /* instr[31] = 0
4900 instr[30] = full/half selector
4901 instr[29] = SMIN (0) / UMIN (1)
4902 instr[28,24] = 0 1110
4903 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4904 instr[21] = 1
4905 instr[20,16] = Vn
4906 instr[15,10] = 0110 11
4907 instr[9,5] = Vm
4908 instr[4.0] = Vd. */
4909
4910 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4911 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4912 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4913 unsigned i;
4914 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4915
4916 NYI_assert (28, 24, 0x0E);
4917 NYI_assert (21, 21, 1);
4918 NYI_assert (15, 10, 0x1B);
4919
4920 if (uimm (aarch64_get_instr (cpu), 29, 29))
4921 {
4922 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4923 {
4924 case 0:
4925 for (i = 0; i < (full ? 16 : 8); i++)
4926 aarch64_set_vec_u8 (cpu, vd, i,
4927 aarch64_get_vec_u8 (cpu, vn, i)
4928 < aarch64_get_vec_u8 (cpu, vm, i)
4929 ? aarch64_get_vec_u8 (cpu, vn, i)
4930 : aarch64_get_vec_u8 (cpu, vm, i));
4931 return;
4932
4933 case 1:
4934 for (i = 0; i < (full ? 8 : 4); i++)
4935 aarch64_set_vec_u16 (cpu, vd, i,
4936 aarch64_get_vec_u16 (cpu, vn, i)
4937 < aarch64_get_vec_u16 (cpu, vm, i)
4938 ? aarch64_get_vec_u16 (cpu, vn, i)
4939 : aarch64_get_vec_u16 (cpu, vm, i));
4940 return;
4941
4942 case 2:
4943 for (i = 0; i < (full ? 4 : 2); i++)
4944 aarch64_set_vec_u32 (cpu, vd, i,
4945 aarch64_get_vec_u32 (cpu, vn, i)
4946 < aarch64_get_vec_u32 (cpu, vm, i)
4947 ? aarch64_get_vec_u32 (cpu, vn, i)
4948 : aarch64_get_vec_u32 (cpu, vm, i));
4949 return;
4950
4951 default:
4952 case 3:
4953 HALT_UNALLOC;
4954 }
4955 }
4956 else
4957 {
4958 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4959 {
4960 case 0:
4961 for (i = 0; i < (full ? 16 : 8); i++)
4962 aarch64_set_vec_s8 (cpu, vd, i,
4963 aarch64_get_vec_s8 (cpu, vn, i)
4964 < aarch64_get_vec_s8 (cpu, vm, i)
4965 ? aarch64_get_vec_s8 (cpu, vn, i)
4966 : aarch64_get_vec_s8 (cpu, vm, i));
4967 return;
4968
4969 case 1:
4970 for (i = 0; i < (full ? 8 : 4); i++)
4971 aarch64_set_vec_s16 (cpu, vd, i,
4972 aarch64_get_vec_s16 (cpu, vn, i)
4973 < aarch64_get_vec_s16 (cpu, vm, i)
4974 ? aarch64_get_vec_s16 (cpu, vn, i)
4975 : aarch64_get_vec_s16 (cpu, vm, i));
4976 return;
4977
4978 case 2:
4979 for (i = 0; i < (full ? 4 : 2); i++)
4980 aarch64_set_vec_s32 (cpu, vd, i,
4981 aarch64_get_vec_s32 (cpu, vn, i)
4982 < aarch64_get_vec_s32 (cpu, vm, i)
4983 ? aarch64_get_vec_s32 (cpu, vn, i)
4984 : aarch64_get_vec_s32 (cpu, vm, i));
4985 return;
4986
4987 default:
4988 case 3:
4989 HALT_UNALLOC;
4990 }
4991 }
4992}
4993
4994static void
4995do_vec_sub_long (sim_cpu *cpu)
4996{
4997 /* instr[31] = 0
4998 instr[30] = lower (0) / upper (1)
4999 instr[29] = signed (0) / unsigned (1)
5000 instr[28,24] = 0 1110
5001 instr[23,22] = size: bytes (00), half (01), word (10)
5002 instr[21] = 1
5003 insrt[20,16] = Vm
5004 instr[15,10] = 0010 00
5005 instr[9,5] = Vn
5006 instr[4,0] = V dest. */
5007
5008 unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
5009 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5010 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5011 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5012 unsigned bias = 0;
5013 unsigned i;
5014
5015 NYI_assert (28, 24, 0x0E);
5016 NYI_assert (21, 21, 1);
5017 NYI_assert (15, 10, 0x08);
5018
5019 if (size == 3)
5020 HALT_UNALLOC;
5021
5022 switch (uimm (aarch64_get_instr (cpu), 30, 29))
5023 {
5024 case 2: /* SSUBL2. */
5025 bias = 2;
5026 case 0: /* SSUBL. */
5027 switch (size)
5028 {
5029 case 0:
5030 bias *= 3;
5031 for (i = 0; i < 8; i++)
5032 aarch64_set_vec_s16 (cpu, vd, i,
5033 aarch64_get_vec_s8 (cpu, vn, i + bias)
5034 - aarch64_get_vec_s8 (cpu, vm, i + bias));
5035 break;
5036
5037 case 1:
5038 bias *= 2;
5039 for (i = 0; i < 4; i++)
5040 aarch64_set_vec_s32 (cpu, vd, i,
5041 aarch64_get_vec_s16 (cpu, vn, i + bias)
5042 - aarch64_get_vec_s16 (cpu, vm, i + bias));
5043 break;
5044
5045 case 2:
5046 for (i = 0; i < 2; i++)
5047 aarch64_set_vec_s64 (cpu, vd, i,
5048 aarch64_get_vec_s32 (cpu, vn, i + bias)
5049 - aarch64_get_vec_s32 (cpu, vm, i + bias));
5050 break;
5051
5052 default:
5053 HALT_UNALLOC;
5054 }
5055 break;
5056
5057 case 3: /* USUBL2. */
5058 bias = 2;
5059 case 1: /* USUBL. */
5060 switch (size)
5061 {
5062 case 0:
5063 bias *= 3;
5064 for (i = 0; i < 8; i++)
5065 aarch64_set_vec_u16 (cpu, vd, i,
5066 aarch64_get_vec_u8 (cpu, vn, i + bias)
5067 - aarch64_get_vec_u8 (cpu, vm, i + bias));
5068 break;
5069
5070 case 1:
5071 bias *= 2;
5072 for (i = 0; i < 4; i++)
5073 aarch64_set_vec_u32 (cpu, vd, i,
5074 aarch64_get_vec_u16 (cpu, vn, i + bias)
5075 - aarch64_get_vec_u16 (cpu, vm, i + bias));
5076 break;
5077
5078 case 2:
5079 for (i = 0; i < 2; i++)
5080 aarch64_set_vec_u64 (cpu, vd, i,
5081 aarch64_get_vec_u32 (cpu, vn, i + bias)
5082 - aarch64_get_vec_u32 (cpu, vm, i + bias));
5083 break;
5084
5085 default:
5086 HALT_UNALLOC;
5087 }
5088 break;
5089 }
5090}
5091
2e8cf49e
NC
5092static void
5093do_vec_ADDP (sim_cpu *cpu)
5094{
5095 /* instr[31] = 0
5096 instr[30] = half(0)/full(1)
5097 instr[29,24] = 00 1110
5098 instr[23,22] = size: bytes (00), half (01), word (10), long (11)
5099 instr[21] = 1
5100 insrt[20,16] = Vm
5101 instr[15,10] = 1011 11
5102 instr[9,5] = Vn
5103 instr[4,0] = V dest. */
5104
57aa1742
NC
5105 FRegister copy_vn;
5106 FRegister copy_vm;
2e8cf49e
NC
5107 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5108 unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
5109 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5110 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5111 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5112 unsigned i, range;
5113
5114 NYI_assert (29, 24, 0x0E);
5115 NYI_assert (21, 21, 1);
5116 NYI_assert (15, 10, 0x2F);
5117
57aa1742
NC
5118 /* Make copies of the source registers in case vd == vn/vm. */
5119 copy_vn = cpu->fr[vn];
5120 copy_vm = cpu->fr[vm];
5121
2e8cf49e
NC
5122 switch (size)
5123 {
5124 case 0:
5125 range = full ? 8 : 4;
57aa1742
NC
5126 for (i = 0; i < range; i++)
5127 {
5128 aarch64_set_vec_u8 (cpu, vd, i,
5129 copy_vn.b[i * 2] + copy_vn.b[i * 2 + 1]);
5130 aarch64_set_vec_u8 (cpu, vd, i + range,
5131 copy_vm.b[i * 2] + copy_vm.b[i * 2 + 1]);
5132 }
2e8cf49e
NC
5133 return;
5134
5135 case 1:
5136 range = full ? 4 : 2;
57aa1742
NC
5137 for (i = 0; i < range; i++)
5138 {
5139 aarch64_set_vec_u16 (cpu, vd, i,
5140 copy_vn.h[i * 2] + copy_vn.h[i * 2 + 1]);
5141 aarch64_set_vec_u16 (cpu, vd, i + range,
5142 copy_vm.h[i * 2] + copy_vm.h[i * 2 + 1]);
5143 }
2e8cf49e
NC
5144 return;
5145
5146 case 2:
5147 range = full ? 2 : 1;
57aa1742
NC
5148 for (i = 0; i < range; i++)
5149 {
5150 aarch64_set_vec_u32 (cpu, vd, i,
5151 copy_vn.w[i * 2] + copy_vn.w[i * 2 + 1]);
5152 aarch64_set_vec_u32 (cpu, vd, i + range,
5153 copy_vm.w[i * 2] + copy_vm.w[i * 2 + 1]);
5154 }
2e8cf49e
NC
5155 return;
5156
5157 case 3:
5158 if (! full)
5159 HALT_UNALLOC;
57aa1742
NC
5160 aarch64_set_vec_u64 (cpu, vd, 0, copy_vn.v[0] + copy_vn.v[1]);
5161 aarch64_set_vec_u64 (cpu, vd, 1, copy_vm.v[0] + copy_vm.v[1]);
2e8cf49e
NC
5162 return;
5163
5164 default:
5165 HALT_NYI;
5166 }
5167}
5168
5169static void
5170do_vec_UMOV (sim_cpu *cpu)
5171{
5172 /* instr[31] = 0
5173 instr[30] = 32-bit(0)/64-bit(1)
5174 instr[29,21] = 00 1110 000
5175 insrt[20,16] = size & index
5176 instr[15,10] = 0011 11
5177 instr[9,5] = V source
5178 instr[4,0] = R dest. */
5179
5180 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5181 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
5182 unsigned index;
5183
5184 NYI_assert (29, 21, 0x070);
5185 NYI_assert (15, 10, 0x0F);
5186
5187 if (uimm (aarch64_get_instr (cpu), 16, 16))
5188 {
5189 /* Byte transfer. */
5190 index = uimm (aarch64_get_instr (cpu), 20, 17);
5191 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5192 aarch64_get_vec_u8 (cpu, vs, index));
5193 }
5194 else if (uimm (aarch64_get_instr (cpu), 17, 17))
5195 {
5196 index = uimm (aarch64_get_instr (cpu), 20, 18);
5197 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5198 aarch64_get_vec_u16 (cpu, vs, index));
5199 }
5200 else if (uimm (aarch64_get_instr (cpu), 18, 18))
5201 {
5202 index = uimm (aarch64_get_instr (cpu), 20, 19);
5203 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5204 aarch64_get_vec_u32 (cpu, vs, index));
5205 }
5206 else
5207 {
5208 if (uimm (aarch64_get_instr (cpu), 30, 30) != 1)
5209 HALT_UNALLOC;
5210
5211 index = uimm (aarch64_get_instr (cpu), 20, 20);
5212 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5213 aarch64_get_vec_u64 (cpu, vs, index));
5214 }
5215}
5216
5217static void
5218do_vec_FABS (sim_cpu *cpu)
5219{
5220 /* instr[31] = 0
5221 instr[30] = half(0)/full(1)
5222 instr[29,23] = 00 1110 1
5223 instr[22] = float(0)/double(1)
5224 instr[21,16] = 10 0000
5225 instr[15,10] = 1111 10
5226 instr[9,5] = Vn
5227 instr[4,0] = Vd. */
5228
5229 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5230 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5231 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5232 unsigned i;
5233
5234 NYI_assert (29, 23, 0x1D);
5235 NYI_assert (21, 10, 0x83E);
5236
5237 if (uimm (aarch64_get_instr (cpu), 22, 22))
5238 {
5239 if (! full)
5240 HALT_NYI;
5241
5242 for (i = 0; i < 2; i++)
5243 aarch64_set_vec_double (cpu, vd, i,
5244 fabs (aarch64_get_vec_double (cpu, vn, i)));
5245 }
5246 else
5247 {
5248 for (i = 0; i < (full ? 4 : 2); i++)
5249 aarch64_set_vec_float (cpu, vd, i,
5250 fabsf (aarch64_get_vec_float (cpu, vn, i)));
5251 }
5252}
5253
5254static void
5255do_vec_FCVTZS (sim_cpu *cpu)
5256{
5257 /* instr[31] = 0
5258 instr[30] = half (0) / all (1)
5259 instr[29,23] = 00 1110 1
5260 instr[22] = single (0) / double (1)
5261 instr[21,10] = 10 0001 1011 10
5262 instr[9,5] = Rn
5263 instr[4,0] = Rd. */
5264
5265 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
5266 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
5267 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5268 unsigned i;
5269
5270 NYI_assert (31, 31, 0);
5271 NYI_assert (29, 23, 0x1D);
5272 NYI_assert (21, 10, 0x86E);
5273
5274 if (uimm (aarch64_get_instr (cpu), 22, 22))
5275 {
5276 if (! full)
5277 HALT_UNALLOC;
5278
5279 for (i = 0; i < 2; i++)
5280 aarch64_set_vec_s64 (cpu, rd, i,
5281 (int64_t) aarch64_get_vec_double (cpu, rn, i));
5282 }
5283 else
5284 for (i = 0; i < (full ? 4 : 2); i++)
5285 aarch64_set_vec_s32 (cpu, rd, i,
5286 (int32_t) aarch64_get_vec_float (cpu, rn, i));
5287}
5288
5289static void
5290do_vec_op1 (sim_cpu *cpu)
5291{
5292 /* instr[31] = 0
5293 instr[30] = half/full
5294 instr[29,24] = 00 1110
5295 instr[23,21] = ???
5296 instr[20,16] = Vm
5297 instr[15,10] = sub-opcode
5298 instr[9,5] = Vn
5299 instr[4,0] = Vd */
5300 NYI_assert (29, 24, 0x0E);
5301
5302 if (uimm (aarch64_get_instr (cpu), 21, 21) == 0)
5303 {
5304 if (uimm (aarch64_get_instr (cpu), 23, 22) == 0)
5305 {
5306 if (uimm (aarch64_get_instr (cpu), 30, 30) == 1
5307 && uimm (aarch64_get_instr (cpu), 17, 14) == 0
5308 && uimm (aarch64_get_instr (cpu), 12, 10) == 7)
5309 return do_vec_ins_2 (cpu);
5310
5311 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5312 {
5313 case 0x01: do_vec_DUP_vector_into_vector (cpu); return;
5314 case 0x03: do_vec_DUP_scalar_into_vector (cpu); return;
5315 case 0x07: do_vec_INS (cpu); return;
5316 case 0x0A: do_vec_TRN (cpu); return;
5317
5318 case 0x0F:
5319 if (uimm (aarch64_get_instr (cpu), 17, 16) == 0)
5320 {
5321 do_vec_MOV_into_scalar (cpu);
5322 return;
5323 }
5324 break;
5325
5326 case 0x00:
5327 case 0x08:
5328 case 0x10:
5329 case 0x18:
5330 do_vec_TBL (cpu); return;
5331
5332 case 0x06:
5333 case 0x16:
5334 do_vec_UZP (cpu); return;
5335
5336 case 0x0E:
5337 case 0x1E:
5338 do_vec_ZIP (cpu); return;
5339
5340 default:
5341 HALT_NYI;
5342 }
5343 }
5344
5345 switch (uimm (aarch64_get_instr (cpu), 13, 10))
5346 {
5347 case 0x6: do_vec_UZP (cpu); return;
5348 case 0xE: do_vec_ZIP (cpu); return;
5349 case 0xA: do_vec_TRN (cpu); return;
5350 case 0xF: do_vec_UMOV (cpu); return;
5351 default: HALT_NYI;
5352 }
5353 }
5354
5355 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5356 {
5357 case 0x07:
5358 switch (uimm (aarch64_get_instr (cpu), 23, 21))
5359 {
5360 case 1: do_vec_AND (cpu); return;
5361 case 3: do_vec_BIC (cpu); return;
5362 case 5: do_vec_ORR (cpu); return;
5363 case 7: do_vec_ORN (cpu); return;
5364 default: HALT_NYI;
5365 }
5366
5367 case 0x08: do_vec_sub_long (cpu); return;
5368 case 0x0a: do_vec_XTN (cpu); return;
5369 case 0x11: do_vec_SSHL (cpu); return;
5370 case 0x19: do_vec_max (cpu); return;
5371 case 0x1B: do_vec_min (cpu); return;
5372 case 0x21: do_vec_add (cpu); return;
5373 case 0x25: do_vec_MLA (cpu); return;
5374 case 0x27: do_vec_mul (cpu); return;
5375 case 0x2F: do_vec_ADDP (cpu); return;
5376 case 0x30: do_vec_mull (cpu); return;
5377 case 0x33: do_vec_FMLA (cpu); return;
5378 case 0x35: do_vec_fadd (cpu); return;
5379
5380 case 0x2E:
5381 switch (uimm (aarch64_get_instr (cpu), 20, 16))
5382 {
5383 case 0x00: do_vec_ABS (cpu); return;
5384 case 0x01: do_vec_FCVTZS (cpu); return;
5385 case 0x11: do_vec_ADDV (cpu); return;
5386 default: HALT_NYI;
5387 }
5388
5389 case 0x31:
5390 case 0x3B:
5391 do_vec_Fminmax (cpu); return;
5392
5393 case 0x0D:
5394 case 0x0F:
5395 case 0x22:
5396 case 0x23:
5397 case 0x26:
5398 case 0x2A:
5399 case 0x32:
5400 case 0x36:
5401 case 0x39:
5402 case 0x3A:
5403 do_vec_compare (cpu); return;
5404
5405 case 0x3E:
5406 do_vec_FABS (cpu); return;
5407
5408 default:
5409 HALT_NYI;
5410 }
5411}
5412
5413static void
5414do_vec_xtl (sim_cpu *cpu)
5415{
5416 /* instr[31] = 0
5417 instr[30,29] = SXTL (00), UXTL (01), SXTL2 (10), UXTL2 (11)
5418 instr[28,22] = 0 1111 00
5419 instr[21,16] = size & shift (USHLL, SSHLL, USHLL2, SSHLL2)
5420 instr[15,10] = 1010 01
5421 instr[9,5] = V source
5422 instr[4,0] = V dest. */
5423
5424 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5425 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5426 unsigned i, shift, bias = 0;
5427
5428 NYI_assert (28, 22, 0x3C);
5429 NYI_assert (15, 10, 0x29);
5430
5431 switch (uimm (aarch64_get_instr (cpu), 30, 29))
5432 {
5433 case 2: /* SXTL2, SSHLL2. */
5434 bias = 2;
5435 case 0: /* SXTL, SSHLL. */
5436 if (uimm (aarch64_get_instr (cpu), 21, 21))
5437 {
5438 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5439 aarch64_set_vec_s64
5440 (cpu, vd, 0, aarch64_get_vec_s32 (cpu, vs, bias) << shift);
5441 aarch64_set_vec_s64
5442 (cpu, vd, 1, aarch64_get_vec_s32 (cpu, vs, bias + 1) << shift);
5443 }
5444 else if (uimm (aarch64_get_instr (cpu), 20, 20))
5445 {
5446 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5447 bias *= 2;
5448 for (i = 0; i < 4; i++)
5449 aarch64_set_vec_s32
5450 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vs, i + bias) << shift);
5451 }
5452 else
5453 {
5454 NYI_assert (19, 19, 1);
5455
5456 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5457 bias *= 3;
5458 for (i = 0; i < 8; i++)
5459 aarch64_set_vec_s16
5460 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vs, i + bias) << shift);
5461 }
5462 return;
5463
5464 case 3: /* UXTL2, USHLL2. */
5465 bias = 2;
5466 case 1: /* UXTL, USHLL. */
5467 if (uimm (aarch64_get_instr (cpu), 21, 21))
5468 {
5469 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5470 aarch64_set_vec_u64
5471 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, vs, bias) << shift);
5472 aarch64_set_vec_u64
5473 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, vs, bias + 1) << shift);
5474 }
5475 else if (uimm (aarch64_get_instr (cpu), 20, 20))
5476 {
5477 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5478 bias *= 2;
5479 for (i = 0; i < 4; i++)
5480 aarch64_set_vec_u32
5481 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i + bias) << shift);
5482 }
5483 else
5484 {
5485 NYI_assert (19, 19, 1);
5486
5487 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5488 bias *= 3;
5489 for (i = 0; i < 8; i++)
5490 aarch64_set_vec_u16
5491 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, i + bias) << shift);
5492 }
5493 return;
5494
5495 default:
5496 HALT_NYI;
5497 }
5498}
5499
5500static void
5501do_vec_SHL (sim_cpu *cpu)
5502{
5503 /* instr [31] = 0
5504 instr [30] = half(0)/full(1)
5505 instr [29,23] = 001 1110
5506 instr [22,16] = size and shift amount
5507 instr [15,10] = 01 0101
5508 instr [9, 5] = Vs
5509 instr [4, 0] = Vd. */
5510
5511 int shift;
5512 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5513 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5514 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5515 unsigned i;
5516
5517 NYI_assert (29, 23, 0x1E);
5518 NYI_assert (15, 10, 0x15);
5519
5520 if (uimm (aarch64_get_instr (cpu), 22, 22))
5521 {
5522 shift = uimm (aarch64_get_instr (cpu), 21, 16) - 1;
5523
5524 if (full == 0)
5525 HALT_UNALLOC;
5526
5527 for (i = 0; i < 2; i++)
5528 {
5529 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5530 aarch64_set_vec_u64 (cpu, vd, i, val << shift);
5531 }
5532
5533 return;
5534 }
5535
5536 if (uimm (aarch64_get_instr (cpu), 21, 21))
5537 {
5538 shift = uimm (aarch64_get_instr (cpu), 20, 16) - 1;
5539
5540 for (i = 0; i < (full ? 4 : 2); i++)
5541 {
5542 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5543 aarch64_set_vec_u32 (cpu, vd, i, val << shift);
5544 }
5545
5546 return;
5547 }
5548
5549 if (uimm (aarch64_get_instr (cpu), 20, 20))
5550 {
5551 shift = uimm (aarch64_get_instr (cpu), 19, 16) - 1;
5552
5553 for (i = 0; i < (full ? 8 : 4); i++)
5554 {
5555 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5556 aarch64_set_vec_u16 (cpu, vd, i, val << shift);
5557 }
5558
5559 return;
5560 }
5561
5562 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
5563 HALT_UNALLOC;
5564
5565 shift = uimm (aarch64_get_instr (cpu), 18, 16) - 1;
5566
5567 for (i = 0; i < (full ? 16 : 8); i++)
5568 {
5569 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5570 aarch64_set_vec_u8 (cpu, vd, i, val << shift);
5571 }
5572}
5573
5574static void
5575do_vec_SSHR_USHR (sim_cpu *cpu)
5576{
5577 /* instr [31] = 0
5578 instr [30] = half(0)/full(1)
5579 instr [29] = signed(0)/unsigned(1)
5580 instr [28,23] = 01 1110
5581 instr [22,16] = size and shift amount
5582 instr [15,10] = 0000 01
5583 instr [9, 5] = Vs
5584 instr [4, 0] = Vd. */
5585
5586 int shift;
5587 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5588 int sign = uimm (aarch64_get_instr (cpu), 29, 29);
5589 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5590 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5591 unsigned i;
5592
5593 NYI_assert (28, 23, 0x1E);
5594 NYI_assert (15, 10, 0x01);
5595
5596 if (uimm (aarch64_get_instr (cpu), 22, 22))
5597 {
5598 shift = uimm (aarch64_get_instr (cpu), 21, 16);
5599
5600 if (full == 0)
5601 HALT_UNALLOC;
5602
5603 if (sign)
5604 for (i = 0; i < 2; i++)
5605 {
5606 int64_t val = aarch64_get_vec_s64 (cpu, vs, i);
5607 aarch64_set_vec_s64 (cpu, vd, i, val >> shift);
5608 }
5609 else
5610 for (i = 0; i < 2; i++)
5611 {
5612 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5613 aarch64_set_vec_u64 (cpu, vd, i, val >> shift);
5614 }
5615
5616 return;
5617 }
5618
5619 if (uimm (aarch64_get_instr (cpu), 21, 21))
5620 {
5621 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5622
5623 if (sign)
5624 for (i = 0; i < (full ? 4 : 2); i++)
5625 {
5626 int32_t val = aarch64_get_vec_s32 (cpu, vs, i);
5627 aarch64_set_vec_s32 (cpu, vd, i, val >> shift);
5628 }
5629 else
5630 for (i = 0; i < (full ? 4 : 2); i++)
5631 {
5632 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5633 aarch64_set_vec_u32 (cpu, vd, i, val >> shift);
5634 }
5635
5636 return;
5637 }
5638
5639 if (uimm (aarch64_get_instr (cpu), 20, 20))
5640 {
5641 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5642
5643 if (sign)
5644 for (i = 0; i < (full ? 8 : 4); i++)
5645 {
5646 int16_t val = aarch64_get_vec_s16 (cpu, vs, i);
5647 aarch64_set_vec_s16 (cpu, vd, i, val >> shift);
5648 }
5649 else
5650 for (i = 0; i < (full ? 8 : 4); i++)
5651 {
5652 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5653 aarch64_set_vec_u16 (cpu, vd, i, val >> shift);
5654 }
5655
5656 return;
5657 }
5658
5659 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
5660 HALT_UNALLOC;
5661
5662 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5663
5664 if (sign)
5665 for (i = 0; i < (full ? 16 : 8); i++)
5666 {
5667 int8_t val = aarch64_get_vec_s8 (cpu, vs, i);
5668 aarch64_set_vec_s8 (cpu, vd, i, val >> shift);
5669 }
5670 else
5671 for (i = 0; i < (full ? 16 : 8); i++)
5672 {
5673 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5674 aarch64_set_vec_u8 (cpu, vd, i, val >> shift);
5675 }
5676}
5677
5678static void
5679do_vec_op2 (sim_cpu *cpu)
5680{
5681 /* instr[31] = 0
5682 instr[30] = half/full
5683 instr[29,24] = 00 1111
5684 instr[23] = ?
5685 instr[22,16] = element size & index
5686 instr[15,10] = sub-opcode
5687 instr[9,5] = Vm
5688 instr[4.0] = Vd */
5689
5690 NYI_assert (29, 24, 0x0F);
5691
5692 if (uimm (aarch64_get_instr (cpu), 23, 23) != 0)
5693 HALT_NYI;
5694
5695 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5696 {
5697 case 0x01: do_vec_SSHR_USHR (cpu); return;
5698 case 0x15: do_vec_SHL (cpu); return;
5699 case 0x29: do_vec_xtl (cpu); return;
5700 default: HALT_NYI;
5701 }
5702}
5703
5704static void
5705do_vec_neg (sim_cpu *cpu)
5706{
5707 /* instr[31] = 0
5708 instr[30] = full(1)/half(0)
5709 instr[29,24] = 10 1110
5710 instr[23,22] = size: byte(00), half (01), word (10), long (11)
5711 instr[21,10] = 1000 0010 1110
5712 instr[9,5] = Vs
5713 instr[4,0] = Vd */
5714
5715 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5716 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5717 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5718 unsigned i;
5719
5720 NYI_assert (29, 24, 0x2E);
5721 NYI_assert (21, 10, 0x82E);
5722
5723 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5724 {
5725 case 0:
5726 for (i = 0; i < (full ? 16 : 8); i++)
5727 aarch64_set_vec_s8 (cpu, vd, i, - aarch64_get_vec_s8 (cpu, vs, i));
5728 return;
5729
5730 case 1:
5731 for (i = 0; i < (full ? 8 : 4); i++)
5732 aarch64_set_vec_s16 (cpu, vd, i, - aarch64_get_vec_s16 (cpu, vs, i));
5733 return;
5734
5735 case 2:
5736 for (i = 0; i < (full ? 4 : 2); i++)
5737 aarch64_set_vec_s32 (cpu, vd, i, - aarch64_get_vec_s32 (cpu, vs, i));
5738 return;
5739
5740 case 3:
5741 if (! full)
5742 HALT_NYI;
5743 for (i = 0; i < 2; i++)
5744 aarch64_set_vec_s64 (cpu, vd, i, - aarch64_get_vec_s64 (cpu, vs, i));
5745 return;
5746
5747 default:
5748 HALT_UNREACHABLE;
5749 }
5750}
5751
5752static void
5753do_vec_sqrt (sim_cpu *cpu)
5754{
5755 /* instr[31] = 0
5756 instr[30] = full(1)/half(0)
5757 instr[29,23] = 101 1101
5758 instr[22] = single(0)/double(1)
5759 instr[21,10] = 1000 0111 1110
5760 instr[9,5] = Vs
5761 instr[4,0] = Vd. */
5762
5763 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5764 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5765 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5766 unsigned i;
5767
5768 NYI_assert (29, 23, 0x5B);
5769 NYI_assert (21, 10, 0x87E);
5770
5771 if (uimm (aarch64_get_instr (cpu), 22, 22) == 0)
5772 for (i = 0; i < (full ? 4 : 2); i++)
5773 aarch64_set_vec_float (cpu, vd, i,
5774 sqrtf (aarch64_get_vec_float (cpu, vs, i)));
5775 else
5776 for (i = 0; i < 2; i++)
5777 aarch64_set_vec_double (cpu, vd, i,
5778 sqrt (aarch64_get_vec_double (cpu, vs, i)));
5779}
5780
5781static void
5782do_vec_mls_indexed (sim_cpu *cpu)
5783{
5784 /* instr[31] = 0
5785 instr[30] = half(0)/full(1)
5786 instr[29,24] = 10 1111
5787 instr[23,22] = 16-bit(01)/32-bit(10)
5788 instr[21,20+11] = index (if 16-bit)
5789 instr[21+11] = index (if 32-bit)
5790 instr[20,16] = Vm
5791 instr[15,12] = 0100
5792 instr[11] = part of index
5793 instr[10] = 0
5794 instr[9,5] = Vs
5795 instr[4,0] = Vd. */
5796
5797 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5798 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5799 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5800 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5801 unsigned i;
5802
5803 NYI_assert (15, 12, 4);
5804 NYI_assert (10, 10, 0);
5805
5806 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5807 {
5808 case 1:
5809 {
5810 unsigned elem;
5811 uint32_t val;
5812
5813 if (vm > 15)
5814 HALT_NYI;
5815
5816 elem = (uimm (aarch64_get_instr (cpu), 21, 20) << 1)
5817 | uimm (aarch64_get_instr (cpu), 11, 11);
5818 val = aarch64_get_vec_u16 (cpu, vm, elem);
5819
5820 for (i = 0; i < (full ? 8 : 4); i++)
5821 aarch64_set_vec_u32 (cpu, vd, i,
5822 aarch64_get_vec_u32 (cpu, vd, i) -
5823 (aarch64_get_vec_u32 (cpu, vs, i) * val));
5824 return;
5825 }
5826
5827 case 2:
5828 {
5829 unsigned elem = (uimm (aarch64_get_instr (cpu), 21, 21) << 1)
5830 | uimm (aarch64_get_instr (cpu), 11, 11);
5831 uint64_t val = aarch64_get_vec_u32 (cpu, vm, elem);
5832
5833 for (i = 0; i < (full ? 4 : 2); i++)
5834 aarch64_set_vec_u64 (cpu, vd, i,
5835 aarch64_get_vec_u64 (cpu, vd, i) -
5836 (aarch64_get_vec_u64 (cpu, vs, i) * val));
5837 return;
5838 }
5839
5840 case 0:
5841 case 3:
5842 default:
5843 HALT_NYI;
5844 }
5845}
5846
5847static void
5848do_vec_SUB (sim_cpu *cpu)
5849{
5850 /* instr [31] = 0
5851 instr [30] = half(0)/full(1)
5852 instr [29,24] = 10 1110
5853 instr [23,22] = size: byte(00, half(01), word (10), long (11)
5854 instr [21] = 1
5855 instr [20,16] = Vm
5856 instr [15,10] = 10 0001
5857 instr [9, 5] = Vn
5858 instr [4, 0] = Vd. */
5859
5860 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5861 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5862 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5863 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5864 unsigned i;
5865
5866 NYI_assert (29, 24, 0x2E);
5867 NYI_assert (21, 21, 1);
5868 NYI_assert (15, 10, 0x21);
5869
5870 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5871 {
5872 case 0:
5873 for (i = 0; i < (full ? 16 : 8); i++)
5874 aarch64_set_vec_s8 (cpu, vd, i,
5875 aarch64_get_vec_s8 (cpu, vn, i)
5876 - aarch64_get_vec_s8 (cpu, vm, i));
5877 return;
5878
5879 case 1:
5880 for (i = 0; i < (full ? 8 : 4); i++)
5881 aarch64_set_vec_s16 (cpu, vd, i,
5882 aarch64_get_vec_s16 (cpu, vn, i)
5883 - aarch64_get_vec_s16 (cpu, vm, i));
5884 return;
5885
5886 case 2:
5887 for (i = 0; i < (full ? 4 : 2); i++)
5888 aarch64_set_vec_s32 (cpu, vd, i,
5889 aarch64_get_vec_s32 (cpu, vn, i)
5890 - aarch64_get_vec_s32 (cpu, vm, i));
5891 return;
5892
5893 case 3:
5894 if (full == 0)
5895 HALT_UNALLOC;
5896
5897 for (i = 0; i < 2; i++)
5898 aarch64_set_vec_s64 (cpu, vd, i,
5899 aarch64_get_vec_s64 (cpu, vn, i)
5900 - aarch64_get_vec_s64 (cpu, vm, i));
5901 return;
5902
5903 default:
5904 HALT_UNREACHABLE;
5905 }
5906}
5907
5908static void
5909do_vec_MLS (sim_cpu *cpu)
5910{
5911 /* instr [31] = 0
5912 instr [30] = half(0)/full(1)
5913 instr [29,24] = 10 1110
5914 instr [23,22] = size: byte(00, half(01), word (10)
5915 instr [21] = 1
5916 instr [20,16] = Vm
5917 instr [15,10] = 10 0101
5918 instr [9, 5] = Vn
5919 instr [4, 0] = Vd. */
5920
5921 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5922 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5923 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5924 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5925 unsigned i;
5926
5927 NYI_assert (29, 24, 0x2E);
5928 NYI_assert (21, 21, 1);
5929 NYI_assert (15, 10, 0x25);
5930
5931 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5932 {
5933 case 0:
5934 for (i = 0; i < (full ? 16 : 8); i++)
5935 aarch64_set_vec_u8 (cpu, vd, i,
5936 (aarch64_get_vec_u8 (cpu, vn, i)
5937 * aarch64_get_vec_u8 (cpu, vm, i))
5938 - aarch64_get_vec_u8 (cpu, vd, i));
5939 return;
5940
5941 case 1:
5942 for (i = 0; i < (full ? 8 : 4); i++)
5943 aarch64_set_vec_u16 (cpu, vd, i,
5944 (aarch64_get_vec_u16 (cpu, vn, i)
5945 * aarch64_get_vec_u16 (cpu, vm, i))
5946 - aarch64_get_vec_u16 (cpu, vd, i));
5947 return;
5948
5949 case 2:
5950 for (i = 0; i < (full ? 4 : 2); i++)
5951 aarch64_set_vec_u32 (cpu, vd, i,
5952 (aarch64_get_vec_u32 (cpu, vn, i)
5953 * aarch64_get_vec_u32 (cpu, vm, i))
5954 - aarch64_get_vec_u32 (cpu, vd, i));
5955 return;
5956
5957 default:
5958 HALT_UNALLOC;
5959 }
5960}
5961
5962static void
5963do_vec_FDIV (sim_cpu *cpu)
5964{
5965 /* instr [31] = 0
5966 instr [30] = half(0)/full(1)
5967 instr [29,23] = 10 1110 0
5968 instr [22] = float()/double(1)
5969 instr [21] = 1
5970 instr [20,16] = Vm
5971 instr [15,10] = 1111 11
5972 instr [9, 5] = Vn
5973 instr [4, 0] = Vd. */
5974
5975 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5976 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5977 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5978 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5979 unsigned i;
5980
5981 NYI_assert (29, 23, 0x5C);
5982 NYI_assert (21, 21, 1);
5983 NYI_assert (15, 10, 0x3F);
5984
5985 if (uimm (aarch64_get_instr (cpu), 22, 22))
5986 {
5987 if (! full)
5988 HALT_UNALLOC;
5989
5990 for (i = 0; i < 2; i++)
5991 aarch64_set_vec_double (cpu, vd, i,
5992 aarch64_get_vec_double (cpu, vn, i)
5993 / aarch64_get_vec_double (cpu, vm, i));
5994 }
5995 else
5996 for (i = 0; i < (full ? 4 : 2); i++)
5997 aarch64_set_vec_float (cpu, vd, i,
5998 aarch64_get_vec_float (cpu, vn, i)
5999 / aarch64_get_vec_float (cpu, vm, i));
6000}
6001
6002static void
6003do_vec_FMUL (sim_cpu *cpu)
6004{
6005 /* instr [31] = 0
6006 instr [30] = half(0)/full(1)
6007 instr [29,23] = 10 1110 0
6008 instr [22] = float(0)/double(1)
6009 instr [21] = 1
6010 instr [20,16] = Vm
6011 instr [15,10] = 1101 11
6012 instr [9, 5] = Vn
6013 instr [4, 0] = Vd. */
6014
6015 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6016 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6017 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6018 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6019 unsigned i;
6020
6021 NYI_assert (29, 23, 0x5C);
6022 NYI_assert (21, 21, 1);
6023 NYI_assert (15, 10, 0x37);
6024
6025 if (uimm (aarch64_get_instr (cpu), 22, 22))
6026 {
6027 if (! full)
6028 HALT_UNALLOC;
6029
6030 for (i = 0; i < 2; i++)
6031 aarch64_set_vec_double (cpu, vd, i,
6032 aarch64_get_vec_double (cpu, vn, i)
6033 * aarch64_get_vec_double (cpu, vm, i));
6034 }
6035 else
6036 for (i = 0; i < (full ? 4 : 2); i++)
6037 aarch64_set_vec_float (cpu, vd, i,
6038 aarch64_get_vec_float (cpu, vn, i)
6039 * aarch64_get_vec_float (cpu, vm, i));
6040}
6041
6042static void
6043do_vec_FADDP (sim_cpu *cpu)
6044{
6045 /* instr [31] = 0
6046 instr [30] = half(0)/full(1)
6047 instr [29,23] = 10 1110 0
6048 instr [22] = float(0)/double(1)
6049 instr [21] = 1
6050 instr [20,16] = Vm
6051 instr [15,10] = 1101 01
6052 instr [9, 5] = Vn
6053 instr [4, 0] = Vd. */
6054
6055 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6056 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6057 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6058 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6059
6060 NYI_assert (29, 23, 0x5C);
6061 NYI_assert (21, 21, 1);
6062 NYI_assert (15, 10, 0x35);
6063
6064 if (uimm (aarch64_get_instr (cpu), 22, 22))
6065 {
57aa1742
NC
6066 /* Extract values before adding them incase vd == vn/vm. */
6067 double tmp1 = aarch64_get_vec_double (cpu, vn, 0);
6068 double tmp2 = aarch64_get_vec_double (cpu, vn, 1);
6069 double tmp3 = aarch64_get_vec_double (cpu, vm, 0);
6070 double tmp4 = aarch64_get_vec_double (cpu, vm, 1);
6071
2e8cf49e
NC
6072 if (! full)
6073 HALT_UNALLOC;
6074
57aa1742
NC
6075 aarch64_set_vec_double (cpu, vd, 0, tmp1 + tmp2);
6076 aarch64_set_vec_double (cpu, vd, 1, tmp3 + tmp4);
2e8cf49e
NC
6077 }
6078 else
6079 {
57aa1742
NC
6080 /* Extract values before adding them incase vd == vn/vm. */
6081 float tmp1 = aarch64_get_vec_float (cpu, vn, 0);
6082 float tmp2 = aarch64_get_vec_float (cpu, vn, 1);
6083 float tmp5 = aarch64_get_vec_float (cpu, vm, 0);
6084 float tmp6 = aarch64_get_vec_float (cpu, vm, 1);
6085
2e8cf49e 6086 if (full)
57aa1742
NC
6087 {
6088 float tmp3 = aarch64_get_vec_float (cpu, vn, 2);
6089 float tmp4 = aarch64_get_vec_float (cpu, vn, 3);
6090 float tmp7 = aarch64_get_vec_float (cpu, vm, 2);
6091 float tmp8 = aarch64_get_vec_float (cpu, vm, 3);
6092
6093 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6094 aarch64_set_vec_float (cpu, vd, 1, tmp3 + tmp4);
6095 aarch64_set_vec_float (cpu, vd, 2, tmp5 + tmp6);
6096 aarch64_set_vec_float (cpu, vd, 3, tmp7 + tmp8);
6097 }
6098 else
6099 {
6100 aarch64_set_vec_float (cpu, vd, 0, tmp1 + tmp2);
6101 aarch64_set_vec_float (cpu, vd, 1, tmp5 + tmp6);
6102 }
2e8cf49e
NC
6103 }
6104}
6105
6106static void
6107do_vec_FSQRT (sim_cpu *cpu)
6108{
6109 /* instr[31] = 0
6110 instr[30] = half(0)/full(1)
6111 instr[29,23] = 10 1110 1
6112 instr[22] = single(0)/double(1)
6113 instr[21,10] = 10 0001 1111 10
6114 instr[9,5] = Vsrc
6115 instr[4,0] = Vdest. */
6116
6117 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6118 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6119 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6120 int i;
6121
6122 NYI_assert (29, 23, 0x5D);
6123 NYI_assert (21, 10, 0x87E);
6124
6125 if (uimm (aarch64_get_instr (cpu), 22, 22))
6126 {
6127 if (! full)
6128 HALT_UNALLOC;
6129
6130 for (i = 0; i < 2; i++)
6131 aarch64_set_vec_double (cpu, vd, i,
6132 sqrt (aarch64_get_vec_double (cpu, vn, i)));
6133 }
6134 else
6135 {
6136 for (i = 0; i < (full ? 4 : 2); i++)
6137 aarch64_set_vec_float (cpu, vd, i,
6138 sqrtf (aarch64_get_vec_float (cpu, vn, i)));
6139 }
6140}
6141
6142static void
6143do_vec_FNEG (sim_cpu *cpu)
6144{
6145 /* instr[31] = 0
6146 instr[30] = half (0)/full (1)
6147 instr[29,23] = 10 1110 1
6148 instr[22] = single (0)/double (1)
6149 instr[21,10] = 10 0000 1111 10
6150 instr[9,5] = Vsrc
6151 instr[4,0] = Vdest. */
6152
6153 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6154 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6155 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6156 int i;
6157
6158 NYI_assert (29, 23, 0x5D);
6159 NYI_assert (21, 10, 0x83E);
6160
6161 if (uimm (aarch64_get_instr (cpu), 22, 22))
6162 {
6163 if (! full)
6164 HALT_UNALLOC;
6165
6166 for (i = 0; i < 2; i++)
6167 aarch64_set_vec_double (cpu, vd, i,
6168 - aarch64_get_vec_double (cpu, vn, i));
6169 }
6170 else
6171 {
6172 for (i = 0; i < (full ? 4 : 2); i++)
6173 aarch64_set_vec_float (cpu, vd, i,
6174 - aarch64_get_vec_float (cpu, vn, i));
6175 }
6176}
6177
6178static void
6179do_vec_NOT (sim_cpu *cpu)
6180{
6181 /* instr[31] = 0
6182 instr[30] = half (0)/full (1)
6183 instr[29,21] = 10 1110 001
6184 instr[20,16] = 0 0000
6185 instr[15,10] = 0101 10
6186 instr[9,5] = Vn
6187 instr[4.0] = Vd. */
6188
6189 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6190 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6191 unsigned i;
6192 int full = uimm (aarch64_get_instr (cpu), 30, 30);
6193
6194 NYI_assert (29, 10, 0xB8816);
6195
6196 for (i = 0; i < (full ? 16 : 8); i++)
6197 aarch64_set_vec_u8 (cpu, vd, i, ~ aarch64_get_vec_u8 (cpu, vn, i));
6198}
6199
6200static void
6201do_vec_MOV_element (sim_cpu *cpu)
6202{
6203 /* instr[31,21] = 0110 1110 000
6204 instr[20,16] = size & dest index
6205 instr[15] = 0
6206 instr[14,11] = source index
6207 instr[10] = 1
6208 instr[9,5] = Vs
6209 instr[4.0] = Vd. */
6210
6211 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
6212 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6213 unsigned src_index;
6214 unsigned dst_index;
6215
6216 NYI_assert (31, 21, 0x370);
6217 NYI_assert (15, 15, 0);
6218 NYI_assert (10, 10, 1);
6219
6220 if (uimm (aarch64_get_instr (cpu), 16, 16))
6221 {
6222 /* Move a byte. */
6223 src_index = uimm (aarch64_get_instr (cpu), 14, 11);
6224 dst_index = uimm (aarch64_get_instr (cpu), 20, 17);
6225 aarch64_set_vec_u8 (cpu, vd, dst_index,
6226 aarch64_get_vec_u8 (cpu, vs, src_index));
6227 }
6228 else if (uimm (aarch64_get_instr (cpu), 17, 17))
6229 {
6230 /* Move 16-bits. */
6231 NYI_assert (11, 11, 0);
6232 src_index = uimm (aarch64_get_instr (cpu), 14, 12);
6233 dst_index = uimm (aarch64_get_instr (cpu), 20, 18);
6234 aarch64_set_vec_u16 (cpu, vd, dst_index,
6235 aarch64_get_vec_u16 (cpu, vs, src_index));
6236 }
6237 else if (uimm (aarch64_get_instr (cpu), 18, 18))
6238 {
6239 /* Move 32-bits. */
6240 NYI_assert (12, 11, 0);
6241 src_index = uimm (aarch64_get_instr (cpu), 14, 13);
6242 dst_index = uimm (aarch64_get_instr (cpu), 20, 19);
6243 aarch64_set_vec_u32 (cpu, vd, dst_index,
6244 aarch64_get_vec_u32 (cpu, vs, src_index));
6245 }
6246 else
6247 {
6248 NYI_assert (19, 19, 1);
6249 NYI_assert (13, 11, 0);
6250 src_index = uimm (aarch64_get_instr (cpu), 14, 14);
6251 dst_index = uimm (aarch64_get_instr (cpu), 20, 20);
6252 aarch64_set_vec_u64 (cpu, vd, dst_index,
6253 aarch64_get_vec_u64 (cpu, vs, src_index));
6254 }
6255}
6256
6257static void
6258dexAdvSIMD0 (sim_cpu *cpu)
6259{
6260 /* instr [28,25] = 0 111. */
6261 if ( uimm (aarch64_get_instr (cpu), 15, 10) == 0x07
6262 && (uimm (aarch64_get_instr (cpu), 9, 5) ==
6263 uimm (aarch64_get_instr (cpu), 20, 16)))
6264 {
6265 if (uimm (aarch64_get_instr (cpu), 31, 21) == 0x075
6266 || uimm (aarch64_get_instr (cpu), 31, 21) == 0x275)
6267 {
6268 do_vec_MOV_whole_vector (cpu);
6269 return;
6270 }
6271 }
6272
6273 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x1E0)
6274 {
6275 do_vec_MOV_immediate (cpu);
6276 return;
6277 }
6278
6279 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x5E0)
6280 {
6281 do_vec_MVNI (cpu);
6282 return;
6283 }
6284
6285 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x1C0
6286 || uimm (aarch64_get_instr (cpu), 29, 19) == 0x1C1)
6287 {
6288 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x03)
6289 {
6290 do_vec_DUP_scalar_into_vector (cpu);
6291 return;
6292 }
6293 }
6294
6295 switch (uimm (aarch64_get_instr (cpu), 29, 24))
6296 {
6297 case 0x0E: do_vec_op1 (cpu); return;
6298 case 0x0F: do_vec_op2 (cpu); return;
6299
6300 case 0x2f:
6301 switch (uimm (aarch64_get_instr (cpu), 15, 10))
6302 {
6303 case 0x01: do_vec_SSHR_USHR (cpu); return;
6304 case 0x10:
6305 case 0x12: do_vec_mls_indexed (cpu); return;
6306 case 0x29: do_vec_xtl (cpu); return;
6307 default:
6308 HALT_NYI;
6309 }
6310
6311 case 0x2E:
6312 if (uimm (aarch64_get_instr (cpu), 21, 21) == 1)
6313 {
6314 switch (uimm (aarch64_get_instr (cpu), 15, 10))
6315 {
6316 case 0x07:
6317 switch (uimm (aarch64_get_instr (cpu), 23, 22))
6318 {
6319 case 0: do_vec_EOR (cpu); return;
6320 case 1: do_vec_BSL (cpu); return;
6321 case 2:
6322 case 3: do_vec_bit (cpu); return;
6323 }
6324 break;
6325
6326 case 0x08: do_vec_sub_long (cpu); return;
6327 case 0x11: do_vec_USHL (cpu); return;
6328 case 0x16: do_vec_NOT (cpu); return;
6329 case 0x19: do_vec_max (cpu); return;
6330 case 0x1B: do_vec_min (cpu); return;
6331 case 0x21: do_vec_SUB (cpu); return;
6332 case 0x25: do_vec_MLS (cpu); return;
6333 case 0x31: do_vec_FminmaxNMP (cpu); return;
6334 case 0x35: do_vec_FADDP (cpu); return;
6335 case 0x37: do_vec_FMUL (cpu); return;
6336 case 0x3F: do_vec_FDIV (cpu); return;
6337
6338 case 0x3E:
6339 switch (uimm (aarch64_get_instr (cpu), 20, 16))
6340 {
6341 case 0x00: do_vec_FNEG (cpu); return;
6342 case 0x01: do_vec_FSQRT (cpu); return;
6343 default: HALT_NYI;
6344 }
6345
6346 case 0x0D:
6347 case 0x0F:
6348 case 0x22:
6349 case 0x23:
6350 case 0x26:
6351 case 0x2A:
6352 case 0x32:
6353 case 0x36:
6354 case 0x39:
6355 case 0x3A:
6356 do_vec_compare (cpu); return;
6357
6358 default: break;
6359 }
6360 }
6361
6362 if (uimm (aarch64_get_instr (cpu), 31, 21) == 0x370)
6363 {
6364 do_vec_MOV_element (cpu);
6365 return;
6366 }
6367
6368 switch (uimm (aarch64_get_instr (cpu), 21, 10))
6369 {
6370 case 0x82E: do_vec_neg (cpu); return;
6371 case 0x87E: do_vec_sqrt (cpu); return;
6372 default:
6373 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x30)
6374 {
6375 do_vec_mull (cpu);
6376 return;
6377 }
6378 break;
6379 }
6380 break;
6381
6382 default:
6383 break;
6384 }
6385
6386 HALT_NYI;
6387}
6388
6389/* 3 sources. */
6390
6391/* Float multiply add. */
6392static void
6393fmadds (sim_cpu *cpu)
6394{
6395 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6396 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6397 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6398 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6399
6400 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6401 + aarch64_get_FP_float (cpu, sn)
6402 * aarch64_get_FP_float (cpu, sm));
6403}
6404
6405/* Double multiply add. */
6406static void
6407fmaddd (sim_cpu *cpu)
6408{
6409 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6410 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6411 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6412 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6413
6414 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6415 + aarch64_get_FP_double (cpu, sn)
6416 * aarch64_get_FP_double (cpu, sm));
6417}
6418
6419/* Float multiply subtract. */
6420static void
6421fmsubs (sim_cpu *cpu)
6422{
6423 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6424 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6425 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6426 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6427
6428 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6429 - aarch64_get_FP_float (cpu, sn)
6430 * aarch64_get_FP_float (cpu, sm));
6431}
6432
6433/* Double multiply subtract. */
6434static void
6435fmsubd (sim_cpu *cpu)
6436{
6437 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6438 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6439 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6440 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6441
6442 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6443 - aarch64_get_FP_double (cpu, sn)
6444 * aarch64_get_FP_double (cpu, sm));
6445}
6446
6447/* Float negative multiply add. */
6448static void
6449fnmadds (sim_cpu *cpu)
6450{
6451 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6452 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6453 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6454 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6455
6456 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6457 + (- aarch64_get_FP_float (cpu, sn))
6458 * aarch64_get_FP_float (cpu, sm));
6459}
6460
6461/* Double negative multiply add. */
6462static void
6463fnmaddd (sim_cpu *cpu)
6464{
6465 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6466 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6467 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6468 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6469
6470 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6471 + (- aarch64_get_FP_double (cpu, sn))
6472 * aarch64_get_FP_double (cpu, sm));
6473}
6474
6475/* Float negative multiply subtract. */
6476static void
6477fnmsubs (sim_cpu *cpu)
6478{
6479 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6480 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6481 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6482 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6483
6484 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6485 + aarch64_get_FP_float (cpu, sn)
6486 * aarch64_get_FP_float (cpu, sm));
6487}
6488
6489/* Double negative multiply subtract. */
6490static void
6491fnmsubd (sim_cpu *cpu)
6492{
6493 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6494 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6495 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6496 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6497
6498 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6499 + aarch64_get_FP_double (cpu, sn)
6500 * aarch64_get_FP_double (cpu, sm));
6501}
6502
6503static void
6504dexSimpleFPDataProc3Source (sim_cpu *cpu)
6505{
6506 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
6507 instr[30] = 0
6508 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
6509 instr[28,25] = 1111
6510 instr[24] = 1
6511 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
6512 instr[21] ==> o1 : 0 ==> unnegated, 1 ==> negated
6513 instr[15] ==> o2 : 0 ==> ADD, 1 ==> SUB */
6514
6515 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
6516 | uimm (aarch64_get_instr (cpu), 29, 29);
6517 /* dispatch on combined type:o1:o2. */
6518 uint32_t dispatch = (uimm (aarch64_get_instr (cpu), 23, 21) << 1)
6519 | uimm (aarch64_get_instr (cpu), 15, 15);
6520
6521 if (M_S != 0)
6522 HALT_UNALLOC;
6523
6524 switch (dispatch)
6525 {
6526 case 0: fmadds (cpu); return;
6527 case 1: fmsubs (cpu); return;
6528 case 2: fnmadds (cpu); return;
6529 case 3: fnmsubs (cpu); return;
6530 case 4: fmaddd (cpu); return;
6531 case 5: fmsubd (cpu); return;
6532 case 6: fnmaddd (cpu); return;
6533 case 7: fnmsubd (cpu); return;
6534 default:
6535 /* type > 1 is currently unallocated. */
6536 HALT_UNALLOC;
6537 }
6538}
6539
6540static void
6541dexSimpleFPFixedConvert (sim_cpu *cpu)
6542{
6543 HALT_NYI;
6544}
6545
6546static void
6547dexSimpleFPCondCompare (sim_cpu *cpu)
6548{
6549 HALT_NYI;
6550}
6551
6552/* 2 sources. */
6553
6554/* Float add. */
6555static void
6556fadds (sim_cpu *cpu)
6557{
6558 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6559 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6560 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6561
6562 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6563 + aarch64_get_FP_float (cpu, sm));
6564}
6565
6566/* Double add. */
6567static void
6568faddd (sim_cpu *cpu)
6569{
6570 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6571 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6572 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6573
6574 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6575 + aarch64_get_FP_double (cpu, sm));
6576}
6577
6578/* Float divide. */
6579static void
6580fdivs (sim_cpu *cpu)
6581{
6582 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6583 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6584 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6585
6586 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6587 / aarch64_get_FP_float (cpu, sm));
6588}
6589
6590/* Double divide. */
6591static void
6592fdivd (sim_cpu *cpu)
6593{
6594 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6595 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6596 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6597
6598 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6599 / aarch64_get_FP_double (cpu, sm));
6600}
6601
6602/* Float multiply. */
6603static void
6604fmuls (sim_cpu *cpu)
6605{
6606 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6607 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6608 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6609
6610 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6611 * aarch64_get_FP_float (cpu, sm));
6612}
6613
6614/* Double multiply. */
6615static void
6616fmuld (sim_cpu *cpu)
6617{
6618 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6619 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6620 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6621
6622 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6623 * aarch64_get_FP_double (cpu, sm));
6624}
6625
6626/* Float negate and multiply. */
6627static void
6628fnmuls (sim_cpu *cpu)
6629{
6630 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6631 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6632 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6633
6634 aarch64_set_FP_float (cpu, sd, - (aarch64_get_FP_float (cpu, sn)
6635 * aarch64_get_FP_float (cpu, sm)));
6636}
6637
6638/* Double negate and multiply. */
6639static void
6640fnmuld (sim_cpu *cpu)
6641{
6642 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6643 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6644 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6645
6646 aarch64_set_FP_double (cpu, sd, - (aarch64_get_FP_double (cpu, sn)
6647 * aarch64_get_FP_double (cpu, sm)));
6648}
6649
6650/* Float subtract. */
6651static void
6652fsubs (sim_cpu *cpu)
6653{
6654 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6655 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6656 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6657
6658 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6659 - aarch64_get_FP_float (cpu, sm));
6660}
6661
6662/* Double subtract. */
6663static void
6664fsubd (sim_cpu *cpu)
6665{
6666 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6667 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6668 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6669
6670 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6671 - aarch64_get_FP_double (cpu, sm));
6672}
6673
6674static void
6675do_FMINNM (sim_cpu *cpu)
6676{
6677 /* instr[31,23] = 0 0011 1100
6678 instr[22] = float(0)/double(1)
6679 instr[21] = 1
6680 instr[20,16] = Sm
6681 instr[15,10] = 01 1110
6682 instr[9,5] = Sn
6683 instr[4,0] = Cpu */
6684
6685 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6686 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6687 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6688
6689 NYI_assert (31, 23, 0x03C);
6690 NYI_assert (15, 10, 0x1E);
6691
6692 if (uimm (aarch64_get_instr (cpu), 22, 22))
6693 aarch64_set_FP_double (cpu, sd,
6694 dminnm (aarch64_get_FP_double (cpu, sn),
6695 aarch64_get_FP_double (cpu, sm)));
6696 else
6697 aarch64_set_FP_float (cpu, sd,
6698 fminnm (aarch64_get_FP_float (cpu, sn),
6699 aarch64_get_FP_float (cpu, sm)));
6700}
6701
6702static void
6703do_FMAXNM (sim_cpu *cpu)
6704{
6705 /* instr[31,23] = 0 0011 1100
6706 instr[22] = float(0)/double(1)
6707 instr[21] = 1
6708 instr[20,16] = Sm
6709 instr[15,10] = 01 1010
6710 instr[9,5] = Sn
6711 instr[4,0] = Cpu */
6712
6713 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6714 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6715 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6716
6717 NYI_assert (31, 23, 0x03C);
6718 NYI_assert (15, 10, 0x1A);
6719
6720 if (uimm (aarch64_get_instr (cpu), 22, 22))
6721 aarch64_set_FP_double (cpu, sd,
6722 dmaxnm (aarch64_get_FP_double (cpu, sn),
6723 aarch64_get_FP_double (cpu, sm)));
6724 else
6725 aarch64_set_FP_float (cpu, sd,
6726 fmaxnm (aarch64_get_FP_float (cpu, sn),
6727 aarch64_get_FP_float (cpu, sm)));
6728}
6729
6730static void
6731dexSimpleFPDataProc2Source (sim_cpu *cpu)
6732{
6733 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
6734 instr[30] = 0
6735 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
6736 instr[28,25] = 1111
6737 instr[24] = 0
6738 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
6739 instr[21] = 1
6740 instr[20,16] = Vm
6741 instr[15,12] ==> opcode : 0000 ==> FMUL, 0001 ==> FDIV
6742 0010 ==> FADD, 0011 ==> FSUB,
6743 0100 ==> FMAX, 0101 ==> FMIN
6744 0110 ==> FMAXNM, 0111 ==> FMINNM
6745 1000 ==> FNMUL, ow ==> UNALLOC
6746 instr[11,10] = 10
6747 instr[9,5] = Vn
6748 instr[4,0] = Vd */
6749
6750 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
6751 | uimm (aarch64_get_instr (cpu), 29, 29);
6752 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
6753 /* Dispatch on opcode. */
6754 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 15, 12);
6755
6756 if (type > 1)
6757 HALT_UNALLOC;
6758
6759 if (M_S != 0)
6760 HALT_UNALLOC;
6761
6762 if (type)
6763 switch (dispatch)
6764 {
6765 case 0: fmuld (cpu); return;
6766 case 1: fdivd (cpu); return;
6767 case 2: faddd (cpu); return;
6768 case 3: fsubd (cpu); return;
6769 case 6: do_FMAXNM (cpu); return;
6770 case 7: do_FMINNM (cpu); return;
6771 case 8: fnmuld (cpu); return;
6772
6773 /* Have not yet implemented fmax and fmin. */
6774 case 4:
6775 case 5:
6776 HALT_NYI;
6777
6778 default:
6779 HALT_UNALLOC;
6780 }
6781 else /* type == 0 => floats. */
6782 switch (dispatch)
6783 {
6784 case 0: fmuls (cpu); return;
6785 case 1: fdivs (cpu); return;
6786 case 2: fadds (cpu); return;
6787 case 3: fsubs (cpu); return;
6788 case 6: do_FMAXNM (cpu); return;
6789 case 7: do_FMINNM (cpu); return;
6790 case 8: fnmuls (cpu); return;
6791
6792 case 4:
6793 case 5:
6794 HALT_NYI;
6795
6796 default:
6797 HALT_UNALLOC;
6798 }
6799}
6800
6801static void
6802dexSimpleFPCondSelect (sim_cpu *cpu)
6803{
6804 /* FCSEL
6805 instr[31,23] = 0 0011 1100
6806 instr[22] = 0=>single 1=>double
6807 instr[21] = 1
6808 instr[20,16] = Sm
6809 instr[15,12] = cond
6810 instr[11,10] = 11
6811 instr[9,5] = Sn
6812 instr[4,0] = Cpu */
6813 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6814 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6815 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6816 uint32_t set = testConditionCode (cpu, uimm (aarch64_get_instr (cpu), 15, 12));
6817
6818 NYI_assert (31, 23, 0x03C);
6819 NYI_assert (11, 10, 0x3);
6820
6821 if (uimm (aarch64_get_instr (cpu), 22, 22))
6822 aarch64_set_FP_double (cpu, sd, set ? sn : sm);
6823 else
6824 aarch64_set_FP_float (cpu, sd, set ? sn : sm);
6825}
6826
6827/* Store 32 bit unscaled signed 9 bit. */
6828static void
6829fsturs (sim_cpu *cpu, int32_t offset)
6830{
6831 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6832 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6833
6834 aarch64_set_mem_float (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
6835 aarch64_get_FP_float (cpu, rn));
6836}
6837
6838/* Store 64 bit unscaled signed 9 bit. */
6839static void
6840fsturd (sim_cpu *cpu, int32_t offset)
6841{
6842 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6843 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6844
6845 aarch64_set_mem_double (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
6846 aarch64_get_FP_double (cpu, rn));
6847}
6848
6849/* Store 128 bit unscaled signed 9 bit. */
6850static void
6851fsturq (sim_cpu *cpu, int32_t offset)
6852{
6853 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6854 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6855 FRegister a;
6856
6857 aarch64_get_FP_long_double (cpu, rn, & a);
6858 aarch64_set_mem_long_double (cpu,
6859 aarch64_get_reg_u64 (cpu, st, 1)
6860 + offset, a);
6861}
6862
6863/* TODO FP move register. */
6864
6865/* 32 bit fp to fp move register. */
6866static void
6867ffmovs (sim_cpu *cpu)
6868{
6869 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6870 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6871
6872 aarch64_set_FP_float (cpu, st, aarch64_get_FP_float (cpu, rn));
6873}
6874
6875/* 64 bit fp to fp move register. */
6876static void
6877ffmovd (sim_cpu *cpu)
6878{
6879 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6880 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6881
6882 aarch64_set_FP_double (cpu, st, aarch64_get_FP_double (cpu, rn));
6883}
6884
6885/* 32 bit GReg to Vec move register. */
6886static void
6887fgmovs (sim_cpu *cpu)
6888{
6889 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6890 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6891
6892 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_reg_u32 (cpu, rn, NO_SP));
6893}
6894
6895/* 64 bit g to fp move register. */
6896static void
6897fgmovd (sim_cpu *cpu)
6898{
6899 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6900 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6901
6902 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_reg_u64 (cpu, rn, NO_SP));
6903}
6904
6905/* 32 bit fp to g move register. */
6906static void
6907gfmovs (sim_cpu *cpu)
6908{
6909 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6910 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6911
6912 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u32 (cpu, rn, 0));
6913}
6914
6915/* 64 bit fp to g move register. */
6916static void
6917gfmovd (sim_cpu *cpu)
6918{
6919 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6920 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6921
6922 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u64 (cpu, rn, 0));
6923}
6924
6925/* FP move immediate
6926
6927 These install an immediate 8 bit value in the target register
6928 where the 8 bits comprise 1 sign bit, 4 bits of fraction and a 3
6929 bit exponent. */
6930
6931static void
6932fmovs (sim_cpu *cpu)
6933{
6934 unsigned int sd = uimm (aarch64_get_instr (cpu), 4, 0);
6935 uint32_t imm = uimm (aarch64_get_instr (cpu), 20, 13);
6936 float f = fp_immediate_for_encoding_32 (imm);
6937
6938 aarch64_set_FP_float (cpu, sd, f);
6939}
6940
6941static void
6942fmovd (sim_cpu *cpu)
6943{
6944 unsigned int sd = uimm (aarch64_get_instr (cpu), 4, 0);
6945 uint32_t imm = uimm (aarch64_get_instr (cpu), 20, 13);
6946 double d = fp_immediate_for_encoding_64 (imm);
6947
6948 aarch64_set_FP_double (cpu, sd, d);
6949}
6950
6951static void
6952dexSimpleFPImmediate (sim_cpu *cpu)
6953{
6954 /* instr[31,23] == 00111100
6955 instr[22] == type : single(0)/double(1)
6956 instr[21] == 1
6957 instr[20,13] == imm8
6958 instr[12,10] == 100
6959 instr[9,5] == imm5 : 00000 ==> PK, ow ==> UNALLOC
6960 instr[4,0] == Rd */
6961 uint32_t imm5 = uimm (aarch64_get_instr (cpu), 9, 5);
6962
6963 NYI_assert (31, 23, 0x3C);
6964
6965 if (imm5 != 0)
6966 HALT_UNALLOC;
6967
6968 if (uimm (aarch64_get_instr (cpu), 22, 22))
6969 fmovd (cpu);
6970 else
6971 fmovs (cpu);
6972}
6973
6974/* TODO specific decode and execute for group Load Store. */
6975
6976/* TODO FP load/store single register (unscaled offset). */
6977
6978/* TODO load 8 bit unscaled signed 9 bit. */
6979/* TODO load 16 bit unscaled signed 9 bit. */
6980
6981/* Load 32 bit unscaled signed 9 bit. */
6982static void
6983fldurs (sim_cpu *cpu, int32_t offset)
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_FP_float (cpu, st, aarch64_get_mem_float
6989 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
6990}
6991
6992/* Load 64 bit unscaled signed 9 bit. */
6993static void
6994fldurd (sim_cpu *cpu, int32_t offset)
6995{
6996 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6997 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6998
6999 aarch64_set_FP_double (cpu, st, aarch64_get_mem_double
7000 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
7001}
7002
7003/* Load 128 bit unscaled signed 9 bit. */
7004static void
7005fldurq (sim_cpu *cpu, int32_t offset)
7006{
7007 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
7008 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
7009 FRegister a;
7010 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
7011
7012 aarch64_get_mem_long_double (cpu, addr, & a);
7013 aarch64_set_FP_long_double (cpu, st, a);
7014}
7015
7016/* TODO store 8 bit unscaled signed 9 bit. */
7017/* TODO store 16 bit unscaled signed 9 bit. */
7018
7019
7020/* 1 source. */
7021
7022/* Float absolute value. */
7023static void
7024fabss (sim_cpu *cpu)
7025{
7026 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7027 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7028 float value = aarch64_get_FP_float (cpu, sn);
7029
7030 aarch64_set_FP_float (cpu, sd, fabsf (value));
7031}
7032
7033/* Double absolute value. */
7034static void
7035fabcpu (sim_cpu *cpu)
7036{
7037 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7038 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7039 double value = aarch64_get_FP_double (cpu, sn);
7040
7041 aarch64_set_FP_double (cpu, sd, fabs (value));
7042}
7043
7044/* Float negative value. */
7045static void
7046fnegs (sim_cpu *cpu)
7047{
7048 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7049 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7050
7051 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sn));
7052}
7053
7054/* Double negative value. */
7055static void
7056fnegd (sim_cpu *cpu)
7057{
7058 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7059 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7060
7061 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sn));
7062}
7063
7064/* Float square root. */
7065static void
7066fsqrts (sim_cpu *cpu)
7067{
7068 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7069 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7070
7071 aarch64_set_FP_float (cpu, sd, sqrt (aarch64_get_FP_float (cpu, sn)));
7072}
7073
7074/* Double square root. */
7075static void
7076fsqrtd (sim_cpu *cpu)
7077{
7078 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7079 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7080
7081 aarch64_set_FP_double (cpu, sd,
7082 sqrt (aarch64_get_FP_double (cpu, sn)));
7083}
7084
7085/* Convert double to float. */
7086static void
7087fcvtds (sim_cpu *cpu)
7088{
7089 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7090 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7091
7092 aarch64_set_FP_float (cpu, sd, (float) aarch64_get_FP_double (cpu, sn));
7093}
7094
7095/* Convert float to double. */
7096static void
7097fcvtcpu (sim_cpu *cpu)
7098{
7099 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7100 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7101
7102 aarch64_set_FP_double (cpu, sd, (double) aarch64_get_FP_float (cpu, sn));
7103}
7104
7105static void
7106do_FRINT (sim_cpu *cpu)
7107{
7108 /* instr[31,23] = 0001 1110 0
7109 instr[22] = single(0)/double(1)
7110 instr[21,18] = 1001
7111 instr[17,15] = rounding mode
7112 instr[14,10] = 10000
7113 instr[9,5] = source
7114 instr[4,0] = dest */
7115
7116 float val;
7117 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7118 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7119 unsigned int rmode = uimm (aarch64_get_instr (cpu), 17, 15);
7120
7121 NYI_assert (31, 23, 0x03C);
7122 NYI_assert (21, 18, 0x9);
7123 NYI_assert (14, 10, 0x10);
7124
7125 if (rmode == 6 || rmode == 7)
7126 /* FIXME: Add support for rmode == 6 exactness check. */
7127 rmode = uimm (aarch64_get_FPSR (cpu), 23, 22);
7128
7129 if (uimm (aarch64_get_instr (cpu), 22, 22))
7130 {
7131 double val = aarch64_get_FP_double (cpu, rs);
7132
7133 switch (rmode)
7134 {
7135 case 0: /* mode N: nearest or even. */
7136 {
7137 double rval = round (val);
7138
7139 if (val - rval == 0.5)
7140 {
7141 if (((rval / 2.0) * 2.0) != rval)
7142 rval += 1.0;
7143 }
7144
7145 aarch64_set_FP_double (cpu, rd, round (val));
7146 return;
7147 }
7148
7149 case 1: /* mode P: towards +inf. */
7150 if (val < 0.0)
7151 aarch64_set_FP_double (cpu, rd, trunc (val));
7152 else
7153 aarch64_set_FP_double (cpu, rd, round (val));
7154 return;
7155
7156 case 2: /* mode M: towards -inf. */
7157 if (val < 0.0)
7158 aarch64_set_FP_double (cpu, rd, round (val));
7159 else
7160 aarch64_set_FP_double (cpu, rd, trunc (val));
7161 return;
7162
7163 case 3: /* mode Z: towards 0. */
7164 aarch64_set_FP_double (cpu, rd, trunc (val));
7165 return;
7166
7167 case 4: /* mode A: away from 0. */
7168 aarch64_set_FP_double (cpu, rd, round (val));
7169 return;
7170
7171 case 6: /* mode X: use FPCR with exactness check. */
7172 case 7: /* mode I: use FPCR mode. */
7173 HALT_NYI;
7174
7175 default:
7176 HALT_UNALLOC;
7177 }
7178 }
7179
7180 val = aarch64_get_FP_float (cpu, rs);
7181
7182 switch (rmode)
7183 {
7184 case 0: /* mode N: nearest or even. */
7185 {
7186 float rval = roundf (val);
7187
7188 if (val - rval == 0.5)
7189 {
7190 if (((rval / 2.0) * 2.0) != rval)
7191 rval += 1.0;
7192 }
7193
7194 aarch64_set_FP_float (cpu, rd, rval);
7195 return;
7196 }
7197
7198 case 1: /* mode P: towards +inf. */
7199 if (val < 0.0)
7200 aarch64_set_FP_float (cpu, rd, truncf (val));
7201 else
7202 aarch64_set_FP_float (cpu, rd, roundf (val));
7203 return;
7204
7205 case 2: /* mode M: towards -inf. */
7206 if (val < 0.0)
7207 aarch64_set_FP_float (cpu, rd, truncf (val));
7208 else
7209 aarch64_set_FP_float (cpu, rd, roundf (val));
7210 return;
7211
7212 case 3: /* mode Z: towards 0. */
7213 aarch64_set_FP_float (cpu, rd, truncf (val));
7214 return;
7215
7216 case 4: /* mode A: away from 0. */
7217 aarch64_set_FP_float (cpu, rd, roundf (val));
7218 return;
7219
7220 case 6: /* mode X: use FPCR with exactness check. */
7221 case 7: /* mode I: use FPCR mode. */
7222 HALT_NYI;
7223
7224 default:
7225 HALT_UNALLOC;
7226 }
7227}
7228
7229static void
7230dexSimpleFPDataProc1Source (sim_cpu *cpu)
7231{
7232 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7233 instr[30] = 0
7234 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7235 instr[28,25] = 1111
7236 instr[24] = 0
7237 instr[23,22] ==> type : 00 ==> source is single,
7238 01 ==> source is double
7239 10 ==> UNALLOC
7240 11 ==> UNALLOC or source is half
7241 instr[21] = 1
7242 instr[20,15] ==> opcode : with type 00 or 01
7243 000000 ==> FMOV, 000001 ==> FABS,
7244 000010 ==> FNEG, 000011 ==> FSQRT,
7245 000100 ==> UNALLOC, 000101 ==> FCVT,(to single/double)
7246 000110 ==> UNALLOC, 000111 ==> FCVT (to half)
7247 001000 ==> FRINTN, 001001 ==> FRINTP,
7248 001010 ==> FRINTM, 001011 ==> FRINTZ,
7249 001100 ==> FRINTA, 001101 ==> UNALLOC
7250 001110 ==> FRINTX, 001111 ==> FRINTI
7251 with type 11
7252 000100 ==> FCVT (half-to-single)
7253 000101 ==> FCVT (half-to-double)
7254 instr[14,10] = 10000. */
7255
7256 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
7257 | uimm (aarch64_get_instr (cpu), 29, 29);
7258 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
7259 uint32_t opcode = uimm (aarch64_get_instr (cpu), 20, 15);
7260
7261 if (M_S != 0)
7262 HALT_UNALLOC;
7263
7264 if (type == 3)
7265 {
7266 if (opcode == 4 || opcode == 5)
7267 HALT_NYI;
7268 else
7269 HALT_UNALLOC;
7270 }
7271
7272 if (type == 2)
7273 HALT_UNALLOC;
7274
7275 switch (opcode)
7276 {
7277 case 0:
7278 if (type)
7279 ffmovd (cpu);
7280 else
7281 ffmovs (cpu);
7282 return;
7283
7284 case 1:
7285 if (type)
7286 fabcpu (cpu);
7287 else
7288 fabss (cpu);
7289 return;
7290
7291 case 2:
7292 if (type)
7293 fnegd (cpu);
7294 else
7295 fnegs (cpu);
7296 return;
7297
7298 case 3:
7299 if (type)
7300 fsqrtd (cpu);
7301 else
7302 fsqrts (cpu);
7303 return;
7304
7305 case 4:
7306 if (type)
7307 fcvtds (cpu);
7308 else
7309 HALT_UNALLOC;
7310 return;
7311
7312 case 5:
7313 if (type)
7314 HALT_UNALLOC;
7315 fcvtcpu (cpu);
7316 return;
7317
7318 case 8: /* FRINTN etc. */
7319 case 9:
7320 case 10:
7321 case 11:
7322 case 12:
7323 case 14:
7324 case 15:
7325 do_FRINT (cpu);
7326 return;
7327
7328 case 7: /* FCVT double/single to half precision. */
7329 case 13:
7330 HALT_NYI;
7331
7332 default:
7333 HALT_UNALLOC;
7334 }
7335}
7336
7337/* 32 bit signed int to float. */
7338static void
7339scvtf32 (sim_cpu *cpu)
7340{
7341 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7342 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7343
7344 aarch64_set_FP_float
7345 (cpu, sd, (float) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7346}
7347
7348/* signed int to float. */
7349static void
7350scvtf (sim_cpu *cpu)
7351{
7352 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7353 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7354
7355 aarch64_set_FP_float
7356 (cpu, sd, (float) aarch64_get_reg_s64 (cpu, rn, NO_SP));
7357}
7358
7359/* 32 bit signed int to double. */
7360static void
7361scvtd32 (sim_cpu *cpu)
7362{
7363 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7364 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7365
7366 aarch64_set_FP_double
7367 (cpu, sd, (double) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7368}
7369
7370/* signed int to double. */
7371static void
7372scvtd (sim_cpu *cpu)
7373{
7374 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7375 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7376
7377 aarch64_set_FP_double
7378 (cpu, sd, (double) aarch64_get_reg_s64 (cpu, rn, NO_SP));
7379}
7380
7381static const float FLOAT_INT_MAX = (float) INT_MAX;
7382static const float FLOAT_INT_MIN = (float) INT_MIN;
7383static const double DOUBLE_INT_MAX = (double) INT_MAX;
7384static const double DOUBLE_INT_MIN = (double) INT_MIN;
7385static const float FLOAT_LONG_MAX = (float) LONG_MAX;
7386static const float FLOAT_LONG_MIN = (float) LONG_MIN;
7387static const double DOUBLE_LONG_MAX = (double) LONG_MAX;
7388static const double DOUBLE_LONG_MIN = (double) LONG_MIN;
7389
7390/* Check for FP exception conditions:
7391 NaN raises IO
7392 Infinity raises IO
7393 Out of Range raises IO and IX and saturates value
7394 Denormal raises ID and IX and sets to zero. */
7395#define RAISE_EXCEPTIONS(F, VALUE, FTYPE, ITYPE) \
7396 do \
7397 { \
7398 switch (fpclassify (F)) \
7399 { \
7400 case FP_INFINITE: \
7401 case FP_NAN: \
7402 aarch64_set_FPSR (cpu, IO); \
7403 if (signbit (F)) \
7404 VALUE = ITYPE##_MAX; \
7405 else \
7406 VALUE = ITYPE##_MIN; \
7407 break; \
7408 \
7409 case FP_NORMAL: \
7410 if (F >= FTYPE##_##ITYPE##_MAX) \
7411 { \
7412 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7413 VALUE = ITYPE##_MAX; \
7414 } \
7415 else if (F <= FTYPE##_##ITYPE##_MIN) \
7416 { \
7417 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7418 VALUE = ITYPE##_MIN; \
7419 } \
7420 break; \
7421 \
7422 case FP_SUBNORMAL: \
7423 aarch64_set_FPSR_bits (cpu, IO | IX | ID, IX | ID); \
7424 VALUE = 0; \
7425 break; \
7426 \
7427 default: \
7428 case FP_ZERO: \
7429 VALUE = 0; \
7430 break; \
7431 } \
7432 } \
7433 while (0)
7434
7435/* 32 bit convert float to signed int truncate towards zero. */
7436static void
7437fcvtszs32 (sim_cpu *cpu)
7438{
7439 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7440 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7441 /* TODO : check that this rounds toward zero. */
7442 float f = aarch64_get_FP_float (cpu, sn);
7443 int32_t value = (int32_t) f;
7444
7445 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
7446
7447 /* Avoid sign extension to 64 bit. */
7448 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7449}
7450
7451/* 64 bit convert float to signed int truncate towards zero. */
7452static void
7453fcvtszs (sim_cpu *cpu)
7454{
7455 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7456 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7457 float f = aarch64_get_FP_float (cpu, sn);
7458 int64_t value = (int64_t) f;
7459
7460 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
7461
7462 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7463}
7464
7465/* 32 bit convert double to signed int truncate towards zero. */
7466static void
7467fcvtszd32 (sim_cpu *cpu)
7468{
7469 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7470 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7471 /* TODO : check that this rounds toward zero. */
7472 double d = aarch64_get_FP_double (cpu, sn);
7473 int32_t value = (int32_t) d;
7474
7475 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
7476
7477 /* Avoid sign extension to 64 bit. */
7478 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7479}
7480
7481/* 64 bit convert double to signed int truncate towards zero. */
7482static void
7483fcvtszd (sim_cpu *cpu)
7484{
7485 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7486 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7487 /* TODO : check that this rounds toward zero. */
7488 double d = aarch64_get_FP_double (cpu, sn);
7489 int64_t value;
7490
7491 value = (int64_t) d;
7492
7493 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7494
7495 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7496}
7497
7498static void
7499do_fcvtzu (sim_cpu *cpu)
7500{
7501 /* instr[31] = size: 32-bit (0), 64-bit (1)
7502 instr[30,23] = 00111100
7503 instr[22] = type: single (0)/ double (1)
7504 instr[21] = enable (0)/disable(1) precision
7505 instr[20,16] = 11001
7506 instr[15,10] = precision
7507 instr[9,5] = Rs
7508 instr[4,0] = Rd. */
7509
7510 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7511 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7512
7513 NYI_assert (30, 23, 0x3C);
7514 NYI_assert (20, 16, 0x19);
7515
7516 if (uimm (aarch64_get_instr (cpu), 21, 21) != 1)
7517 /* Convert to fixed point. */
7518 HALT_NYI;
7519
7520 if (uimm (aarch64_get_instr (cpu), 31, 31))
7521 {
7522 /* Convert to unsigned 64-bit integer. */
7523 if (uimm (aarch64_get_instr (cpu), 22, 22))
7524 {
7525 double d = aarch64_get_FP_double (cpu, rs);
7526 uint64_t value = (uint64_t) d;
7527
7528 /* Do not raise an exception if we have reached ULONG_MAX. */
7529 if (value != (1UL << 63))
7530 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7531
7532 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7533 }
7534 else
7535 {
7536 float f = aarch64_get_FP_float (cpu, rs);
7537 uint64_t value = (uint64_t) f;
7538
7539 /* Do not raise an exception if we have reached ULONG_MAX. */
7540 if (value != (1UL << 63))
7541 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
7542
7543 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7544 }
7545 }
7546 else
7547 {
7548 uint32_t value;
7549
7550 /* Convert to unsigned 32-bit integer. */
7551 if (uimm (aarch64_get_instr (cpu), 22, 22))
7552 {
7553 double d = aarch64_get_FP_double (cpu, rs);
7554
7555 value = (uint32_t) d;
7556 /* Do not raise an exception if we have reached UINT_MAX. */
7557 if (value != (1UL << 31))
7558 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
7559 }
7560 else
7561 {
7562 float f = aarch64_get_FP_float (cpu, rs);
7563
7564 value = (uint32_t) f;
7565 /* Do not raise an exception if we have reached UINT_MAX. */
7566 if (value != (1UL << 31))
7567 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
7568 }
7569
7570 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7571 }
7572}
7573
7574static void
7575do_UCVTF (sim_cpu *cpu)
7576{
7577 /* instr[31] = size: 32-bit (0), 64-bit (1)
7578 instr[30,23] = 001 1110 0
7579 instr[22] = type: single (0)/ double (1)
7580 instr[21] = enable (0)/disable(1) precision
7581 instr[20,16] = 0 0011
7582 instr[15,10] = precision
7583 instr[9,5] = Rs
7584 instr[4,0] = Rd. */
7585
7586 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7587 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7588
7589 NYI_assert (30, 23, 0x3C);
7590 NYI_assert (20, 16, 0x03);
7591
7592 if (uimm (aarch64_get_instr (cpu), 21, 21) != 1)
7593 HALT_NYI;
7594
7595 /* FIXME: Add exception raising. */
7596 if (uimm (aarch64_get_instr (cpu), 31, 31))
7597 {
7598 uint64_t value = aarch64_get_reg_u64 (cpu, rs, NO_SP);
7599
7600 if (uimm (aarch64_get_instr (cpu), 22, 22))
7601 aarch64_set_FP_double (cpu, rd, (double) value);
7602 else
7603 aarch64_set_FP_float (cpu, rd, (float) value);
7604 }
7605 else
7606 {
7607 uint32_t value = aarch64_get_reg_u32 (cpu, rs, NO_SP);
7608
7609 if (uimm (aarch64_get_instr (cpu), 22, 22))
7610 aarch64_set_FP_double (cpu, rd, (double) value);
7611 else
7612 aarch64_set_FP_float (cpu, rd, (float) value);
7613 }
7614}
7615
7616static void
7617float_vector_move (sim_cpu *cpu)
7618{
7619 /* instr[31,17] == 100 1111 0101 0111
7620 instr[16] ==> direction 0=> to GR, 1=> from GR
7621 instr[15,10] => ???
7622 instr[9,5] ==> source
7623 instr[4,0] ==> dest. */
7624
7625 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7626 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7627
7628 NYI_assert (31, 17, 0x4F57);
7629
7630 if (uimm (aarch64_get_instr (cpu), 15, 10) != 0)
7631 HALT_UNALLOC;
7632
7633 if (uimm (aarch64_get_instr (cpu), 16, 16))
7634 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_reg_u64 (cpu, rn, NO_SP));
7635 else
7636 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, rn, 1));
7637}
7638
7639static void
7640dexSimpleFPIntegerConvert (sim_cpu *cpu)
7641{
7642 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
7643 instr[30 = 0
7644 instr[29] = S : 0 ==> OK, 1 ==> UNALLOC
7645 instr[28,25] = 1111
7646 instr[24] = 0
7647 instr[23,22] = type : 00 ==> single, 01 ==> double, 1x ==> UNALLOC
7648 instr[21] = 1
7649 instr[20,19] = rmode
7650 instr[18,16] = opcode
7651 instr[15,10] = 10 0000 */
7652
7653 uint32_t rmode_opcode;
7654 uint32_t size_type;
7655 uint32_t type;
7656 uint32_t size;
7657 uint32_t S;
7658
7659 if (uimm (aarch64_get_instr (cpu), 31, 17) == 0x4F57)
7660 {
7661 float_vector_move (cpu);
7662 return;
7663 }
7664
7665 size = uimm (aarch64_get_instr (cpu), 31, 31);
7666 S = uimm (aarch64_get_instr (cpu), 29, 29);
7667 if (S != 0)
7668 HALT_UNALLOC;
7669
7670 type = uimm (aarch64_get_instr (cpu), 23, 22);
7671 if (type > 1)
7672 HALT_UNALLOC;
7673
7674 rmode_opcode = uimm (aarch64_get_instr (cpu), 20, 16);
7675 size_type = (size << 1) | type; /* 0==32f, 1==32d, 2==64f, 3==64d. */
7676
7677 switch (rmode_opcode)
7678 {
7679 case 2: /* SCVTF. */
7680 switch (size_type)
7681 {
7682 case 0: scvtf32 (cpu); return;
7683 case 1: scvtd32 (cpu); return;
7684 case 2: scvtf (cpu); return;
7685 case 3: scvtd (cpu); return;
7686 default:
7687 HALT_UNREACHABLE;
7688 }
7689
7690 case 6: /* FMOV GR, Vec. */
7691 switch (size_type)
7692 {
7693 case 0: gfmovs (cpu); return;
7694 case 3: gfmovd (cpu); return;
7695 default: HALT_UNALLOC;
7696 }
7697
7698 case 7: /* FMOV vec, GR. */
7699 switch (size_type)
7700 {
7701 case 0: fgmovs (cpu); return;
7702 case 3: fgmovd (cpu); return;
7703 default: HALT_UNALLOC;
7704 }
7705
7706 case 24: /* FCVTZS. */
7707 switch (size_type)
7708 {
7709 case 0: fcvtszs32 (cpu); return;
7710 case 1: fcvtszd32 (cpu); return;
7711 case 2: fcvtszs (cpu); return;
7712 case 3: fcvtszd (cpu); return;
7713 default: HALT_UNREACHABLE;
7714 }
7715
7716 case 25: do_fcvtzu (cpu); return;
7717 case 3: do_UCVTF (cpu); return;
7718
7719 case 0: /* FCVTNS. */
7720 case 1: /* FCVTNU. */
7721 case 4: /* FCVTAS. */
7722 case 5: /* FCVTAU. */
7723 case 8: /* FCVPTS. */
7724 case 9: /* FCVTPU. */
7725 case 16: /* FCVTMS. */
7726 case 17: /* FCVTMU. */
7727 default:
7728 HALT_NYI;
7729 }
7730}
7731
7732static void
7733set_flags_for_float_compare (sim_cpu *cpu, float fvalue1, float fvalue2)
7734{
7735 uint32_t flags;
7736
7737 if (isnan (fvalue1) || isnan (fvalue2))
7738 flags = C|V;
7739 else
7740 {
7741 float result = fvalue1 - fvalue2;
7742
7743 if (result == 0.0)
7744 flags = Z|C;
7745 else if (result < 0)
7746 flags = N;
7747 else /* (result > 0). */
7748 flags = C;
7749 }
7750
7751 aarch64_set_CPSR (cpu, flags);
7752}
7753
7754static void
7755fcmps (sim_cpu *cpu)
7756{
7757 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7758 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7759
7760 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7761 float fvalue2 = aarch64_get_FP_float (cpu, sm);
7762
7763 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
7764}
7765
7766/* Float compare to zero -- Invalid Operation exception
7767 only on signaling NaNs. */
7768static void
7769fcmpzs (sim_cpu *cpu)
7770{
7771 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7772 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7773
7774 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
7775}
7776
7777/* Float compare -- Invalid Operation exception on all NaNs. */
7778static void
7779fcmpes (sim_cpu *cpu)
7780{
7781 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7782 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7783
7784 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7785 float fvalue2 = aarch64_get_FP_float (cpu, sm);
7786
7787 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
7788}
7789
7790/* Float compare to zero -- Invalid Operation exception on all NaNs. */
7791static void
7792fcmpzes (sim_cpu *cpu)
7793{
7794 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7795 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7796
7797 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
7798}
7799
7800static void
7801set_flags_for_double_compare (sim_cpu *cpu, double dval1, double dval2)
7802{
7803 uint32_t flags;
7804
7805 if (isnan (dval1) || isnan (dval2))
7806 flags = C|V;
7807 else
7808 {
7809 double result = dval1 - dval2;
7810
7811 if (result == 0.0)
7812 flags = Z|C;
7813 else if (result < 0)
7814 flags = N;
7815 else /* (result > 0). */
7816 flags = C;
7817 }
7818
7819 aarch64_set_CPSR (cpu, flags);
7820}
7821
7822/* Double compare -- Invalid Operation exception only on signaling NaNs. */
7823static void
7824fcmpd (sim_cpu *cpu)
7825{
7826 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7827 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7828
7829 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7830 double dvalue2 = aarch64_get_FP_double (cpu, sm);
7831
7832 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
7833}
7834
7835/* Double compare to zero -- Invalid Operation exception
7836 only on signaling NaNs. */
7837static void
7838fcmpzd (sim_cpu *cpu)
7839{
7840 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7841 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7842
7843 set_flags_for_double_compare (cpu, dvalue1, 0.0);
7844}
7845
7846/* Double compare -- Invalid Operation exception on all NaNs. */
7847static void
7848fcmped (sim_cpu *cpu)
7849{
7850 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7851 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7852
7853 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7854 double dvalue2 = aarch64_get_FP_double (cpu, sm);
7855
7856 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
7857}
7858
7859/* Double compare to zero -- Invalid Operation exception on all NaNs. */
7860static void
7861fcmpzed (sim_cpu *cpu)
7862{
7863 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7864 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7865
7866 set_flags_for_double_compare (cpu, dvalue1, 0.0);
7867}
7868
7869static void
7870dexSimpleFPCompare (sim_cpu *cpu)
7871{
7872 /* assert instr[28,25] == 1111
7873 instr[30:24:21:13,10] = 0011000
7874 instr[31] = M : 0 ==> OK, 1 ==> UNALLOC
7875 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7876 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7877 instr[15,14] ==> op : 00 ==> OK, ow ==> UNALLOC
7878 instr[4,0] ==> opcode2 : 00000 ==> FCMP, 10000 ==> FCMPE,
7879 01000 ==> FCMPZ, 11000 ==> FCMPEZ,
7880 ow ==> UNALLOC */
7881 uint32_t dispatch;
7882 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
7883 | uimm (aarch64_get_instr (cpu), 29, 29);
7884 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
7885 uint32_t op = uimm (aarch64_get_instr (cpu), 15, 14);
7886 uint32_t op2_2_0 = uimm (aarch64_get_instr (cpu), 2, 0);
7887
7888 if (op2_2_0 != 0)
7889 HALT_UNALLOC;
7890
7891 if (M_S != 0)
7892 HALT_UNALLOC;
7893
7894 if (type > 1)
7895 HALT_UNALLOC;
7896
7897 if (op != 0)
7898 HALT_UNALLOC;
7899
7900 /* dispatch on type and top 2 bits of opcode. */
7901 dispatch = (type << 2) | uimm (aarch64_get_instr (cpu), 4, 3);
7902
7903 switch (dispatch)
7904 {
7905 case 0: fcmps (cpu); return;
7906 case 1: fcmpzs (cpu); return;
7907 case 2: fcmpes (cpu); return;
7908 case 3: fcmpzes (cpu); return;
7909 case 4: fcmpd (cpu); return;
7910 case 5: fcmpzd (cpu); return;
7911 case 6: fcmped (cpu); return;
7912 case 7: fcmpzed (cpu); return;
7913 default: HALT_UNREACHABLE;
7914 }
7915}
7916
7917static void
7918do_scalar_FADDP (sim_cpu *cpu)
7919{
7920 /* instr [31,23] = 011111100
7921 instr [22] = single(0)/double(1)
7922 instr [21,10] = 1100 0011 0110
7923 instr [9,5] = Fn
7924 instr [4,0] = Fd. */
7925
7926 unsigned Fn = uimm (aarch64_get_instr (cpu), 9, 5);
7927 unsigned Fd = uimm (aarch64_get_instr (cpu), 4, 0);
7928
7929 NYI_assert (31, 23, 0x0FC);
7930 NYI_assert (21, 10, 0xC36);
7931
7932 if (uimm (aarch64_get_instr (cpu), 22, 22))
7933 {
7934 double val1 = aarch64_get_vec_double (cpu, Fn, 0);
7935 double val2 = aarch64_get_vec_double (cpu, Fn, 1);
7936
7937 aarch64_set_FP_double (cpu, Fd, val1 + val2);
7938 }
7939 else
7940 {
7941 float val1 = aarch64_get_vec_float (cpu, Fn, 0);
7942 float val2 = aarch64_get_vec_float (cpu, Fn, 1);
7943
7944 aarch64_set_FP_float (cpu, Fd, val1 + val2);
7945 }
7946}
7947
7948/* Floating point absolute difference. */
7949
7950static void
7951do_scalar_FABD (sim_cpu *cpu)
7952{
7953 /* instr [31,23] = 0111 1110 1
7954 instr [22] = float(0)/double(1)
7955 instr [21] = 1
7956 instr [20,16] = Rm
7957 instr [15,10] = 1101 01
7958 instr [9, 5] = Rn
7959 instr [4, 0] = Rd. */
7960
7961 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
7962 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7963 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7964
7965 NYI_assert (31, 23, 0x0FD);
7966 NYI_assert (21, 21, 1);
7967 NYI_assert (15, 10, 0x35);
7968
7969 if (uimm (aarch64_get_instr (cpu), 22, 22))
7970 aarch64_set_FP_double (cpu, rd,
7971 fabs (aarch64_get_FP_double (cpu, rn)
7972 - aarch64_get_FP_double (cpu, rm)));
7973 else
7974 aarch64_set_FP_float (cpu, rd,
7975 fabsf (aarch64_get_FP_float (cpu, rn)
7976 - aarch64_get_FP_float (cpu, rm)));
7977}
7978
7979static void
7980do_scalar_CMGT (sim_cpu *cpu)
7981{
7982 /* instr [31,21] = 0101 1110 111
7983 instr [20,16] = Rm
7984 instr [15,10] = 00 1101
7985 instr [9, 5] = Rn
7986 instr [4, 0] = Rd. */
7987
7988 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
7989 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7990 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7991
7992 NYI_assert (31, 21, 0x2F7);
7993 NYI_assert (15, 10, 0x0D);
7994
7995 aarch64_set_vec_u64 (cpu, rd, 0,
7996 aarch64_get_vec_u64 (cpu, rn, 0) >
7997 aarch64_get_vec_u64 (cpu, rm, 0) ? -1L : 0L);
7998}
7999
8000static void
8001do_scalar_USHR (sim_cpu *cpu)
8002{
8003 /* instr [31,23] = 0111 1111 0
8004 instr [22,16] = shift amount
8005 instr [15,10] = 0000 01
8006 instr [9, 5] = Rn
8007 instr [4, 0] = Rd. */
8008
8009 unsigned amount = 128 - uimm (aarch64_get_instr (cpu), 22, 16);
8010 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8011 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8012
8013 NYI_assert (31, 23, 0x0FE);
8014 NYI_assert (15, 10, 0x01);
8015
8016 aarch64_set_vec_u64 (cpu, rd, 0,
8017 aarch64_get_vec_u64 (cpu, rn, 0) >> amount);
8018}
8019
8020static void
8021do_scalar_SHL (sim_cpu *cpu)
8022{
8023 /* instr [31,23] = 0111 1101 0
8024 instr [22,16] = shift amount
8025 instr [15,10] = 0101 01
8026 instr [9, 5] = Rn
8027 instr [4, 0] = Rd. */
8028
8029 unsigned amount = uimm (aarch64_get_instr (cpu), 22, 16) - 64;
8030 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8031 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8032
8033 NYI_assert (31, 23, 0x0BE);
8034 NYI_assert (15, 10, 0x15);
8035
8036 if (uimm (aarch64_get_instr (cpu), 22, 22) == 0)
8037 HALT_UNALLOC;
8038
8039 aarch64_set_vec_u64 (cpu, rd, 0,
8040 aarch64_get_vec_u64 (cpu, rn, 0) << amount);
8041}
8042
8043/* FCMEQ FCMGT FCMGE. */
8044static void
8045do_scalar_FCM (sim_cpu *cpu)
8046{
8047 /* instr [31,30] = 01
8048 instr [29] = U
8049 instr [28,24] = 1 1110
8050 instr [23] = E
8051 instr [22] = size
8052 instr [21] = 1
8053 instr [20,16] = Rm
8054 instr [15,12] = 1110
8055 instr [11] = AC
8056 instr [10] = 1
8057 instr [9, 5] = Rn
8058 instr [4, 0] = Rd. */
8059
8060 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8061 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8062 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8063 unsigned EUac = (uimm (aarch64_get_instr (cpu), 23, 23) << 2)
8064 | (uimm (aarch64_get_instr (cpu), 29, 29) << 1)
8065 | uimm (aarch64_get_instr (cpu), 11, 11);
8066 unsigned result;
8067 float val1;
8068 float val2;
8069
8070 NYI_assert (31, 30, 1);
8071 NYI_assert (28, 24, 0x1E);
8072 NYI_assert (21, 21, 1);
8073 NYI_assert (15, 12, 0xE);
8074 NYI_assert (10, 10, 1);
8075
8076 if (uimm (aarch64_get_instr (cpu), 22, 22))
8077 {
8078 double val1 = aarch64_get_FP_double (cpu, rn);
8079 double val2 = aarch64_get_FP_double (cpu, rm);
8080
8081 switch (EUac)
8082 {
8083 case 0: /* 000 */
8084 result = val1 == val2;
8085 break;
8086
8087 case 3: /* 011 */
8088 val1 = fabs (val1);
8089 val2 = fabs (val2);
8090 /* Fall through. */
8091 case 2: /* 010 */
8092 result = val1 >= val2;
8093 break;
8094
8095 case 7: /* 111 */
8096 val1 = fabs (val1);
8097 val2 = fabs (val2);
8098 /* Fall through. */
8099 case 6: /* 110 */
8100 result = val1 > val2;
8101 break;
8102
8103 default:
8104 HALT_UNALLOC;
8105 }
8106
8107 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8108 return;
8109 }
8110
8111 val1 = aarch64_get_FP_float (cpu, rn);
8112 val2 = aarch64_get_FP_float (cpu, rm);
8113
8114 switch (EUac)
8115 {
8116 case 0: /* 000 */
8117 result = val1 == val2;
8118 break;
8119
8120 case 3: /* 011 */
8121 val1 = fabsf (val1);
8122 val2 = fabsf (val2);
8123 /* Fall through. */
8124 case 2: /* 010 */
8125 result = val1 >= val2;
8126 break;
8127
8128 case 7: /* 111 */
8129 val1 = fabsf (val1);
8130 val2 = fabsf (val2);
8131 /* Fall through. */
8132 case 6: /* 110 */
8133 result = val1 > val2;
8134 break;
8135
8136 default:
8137 HALT_UNALLOC;
8138 }
8139
8140 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8141}
8142
8143/* An alias of DUP. */
8144static void
8145do_scalar_MOV (sim_cpu *cpu)
8146{
8147 /* instr [31,21] = 0101 1110 000
8148 instr [20,16] = imm5
8149 instr [15,10] = 0000 01
8150 instr [9, 5] = Rn
8151 instr [4, 0] = Rd. */
8152
8153 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8154 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8155 unsigned index;
8156
8157 NYI_assert (31, 21, 0x2F0);
8158 NYI_assert (15, 10, 0x01);
8159
8160 if (uimm (aarch64_get_instr (cpu), 16, 16))
8161 {
8162 /* 8-bit. */
8163 index = uimm (aarch64_get_instr (cpu), 20, 17);
8164 aarch64_set_vec_u8
8165 (cpu, rd, 0, aarch64_get_vec_u8 (cpu, rn, index));
8166 }
8167 else if (uimm (aarch64_get_instr (cpu), 17, 17))
8168 {
8169 /* 16-bit. */
8170 index = uimm (aarch64_get_instr (cpu), 20, 18);
8171 aarch64_set_vec_u16
8172 (cpu, rd, 0, aarch64_get_vec_u16 (cpu, rn, index));
8173 }
8174 else if (uimm (aarch64_get_instr (cpu), 18, 18))
8175 {
8176 /* 32-bit. */
8177 index = uimm (aarch64_get_instr (cpu), 20, 19);
8178 aarch64_set_vec_u32
8179 (cpu, rd, 0, aarch64_get_vec_u32 (cpu, rn, index));
8180 }
8181 else if (uimm (aarch64_get_instr (cpu), 19, 19))
8182 {
8183 /* 64-bit. */
8184 index = uimm (aarch64_get_instr (cpu), 20, 20);
8185 aarch64_set_vec_u64
8186 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, index));
8187 }
8188 else
8189 HALT_UNALLOC;
8190}
8191
8192static void
8193do_double_add (sim_cpu *cpu)
8194{
8195 /* instr [28,25] = 1111. */
8196 unsigned Fd;
8197 unsigned Fm;
8198 unsigned Fn;
8199 double val1;
8200 double val2;
8201
8202 switch (uimm (aarch64_get_instr (cpu), 31, 23))
8203 {
8204 case 0xBC:
8205 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8206 {
8207 case 0x01: do_scalar_MOV (cpu); return;
8208 case 0x39: do_scalar_FCM (cpu); return;
8209 case 0x3B: do_scalar_FCM (cpu); return;
8210 }
8211 break;
8212
8213 case 0xBE: do_scalar_SHL (cpu); return;
8214
8215 case 0xFC:
8216 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8217 {
8218 case 0x36: do_scalar_FADDP (cpu); return;
8219 case 0x39: do_scalar_FCM (cpu); return;
8220 case 0x3B: do_scalar_FCM (cpu); return;
8221 }
8222 break;
8223
8224 case 0xFD:
8225 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8226 {
8227 case 0x0D: do_scalar_CMGT (cpu); return;
8228 case 0x35: do_scalar_FABD (cpu); return;
8229 case 0x39: do_scalar_FCM (cpu); return;
8230 case 0x3B: do_scalar_FCM (cpu); return;
8231 default:
8232 HALT_NYI;
8233 }
8234
8235 case 0xFE: do_scalar_USHR (cpu); return;
8236 default:
8237 break;
8238 }
8239
8240 /* instr [31,21] = 0101 1110 111
8241 instr [20,16] = Fn
8242 instr [15,10] = 1000 01
8243 instr [9,5] = Fm
8244 instr [4,0] = Fd. */
8245 if (uimm (aarch64_get_instr (cpu), 31, 21) != 0x2F7
8246 || uimm (aarch64_get_instr (cpu), 15, 10) != 0x21)
8247 HALT_NYI;
8248
8249 Fd = uimm (aarch64_get_instr (cpu), 4, 0);
8250 Fm = uimm (aarch64_get_instr (cpu), 9, 5);
8251 Fn = uimm (aarch64_get_instr (cpu), 20, 16);
8252
8253 val1 = aarch64_get_FP_double (cpu, Fm);
8254 val2 = aarch64_get_FP_double (cpu, Fn);
8255
8256 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8257}
8258
8259static void
8260dexAdvSIMD1 (sim_cpu *cpu)
8261{
8262 /* instr [28,25] = 1 111. */
8263
8264 /* we are currently only interested in the basic
8265 scalar fp routines which all have bit 30 = 0. */
8266 if (uimm (aarch64_get_instr (cpu), 30, 30))
8267 do_double_add (cpu);
8268
8269 /* instr[24] is set for FP data processing 3-source and clear for
8270 all other basic scalar fp instruction groups. */
8271 else if (uimm (aarch64_get_instr (cpu), 24, 24))
8272 dexSimpleFPDataProc3Source (cpu);
8273
8274 /* instr[21] is clear for floating <-> fixed conversions and set for
8275 all other basic scalar fp instruction groups. */
8276 else if (!uimm (aarch64_get_instr (cpu), 21, 21))
8277 dexSimpleFPFixedConvert (cpu);
8278
8279 /* instr[11,10] : 01 ==> cond compare, 10 ==> Data Proc 2 Source
8280 11 ==> cond select, 00 ==> other. */
8281 else
8282 switch (uimm (aarch64_get_instr (cpu), 11, 10))
8283 {
8284 case 1: dexSimpleFPCondCompare (cpu); return;
8285 case 2: dexSimpleFPDataProc2Source (cpu); return;
8286 case 3: dexSimpleFPCondSelect (cpu); return;
8287
8288 default:
8289 /* Now an ordered cascade of tests.
8290 FP immediate has aarch64_get_instr (cpu)[12] == 1.
8291 FP compare has aarch64_get_instr (cpu)[13] == 1.
8292 FP Data Proc 1 Source has aarch64_get_instr (cpu)[14] == 1.
8293 FP floating <--> integer conversions has aarch64_get_instr (cpu)[15] == 0. */
8294 if (uimm (aarch64_get_instr (cpu), 12, 12))
8295 dexSimpleFPImmediate (cpu);
8296
8297 else if (uimm (aarch64_get_instr (cpu), 13, 13))
8298 dexSimpleFPCompare (cpu);
8299
8300 else if (uimm (aarch64_get_instr (cpu), 14, 14))
8301 dexSimpleFPDataProc1Source (cpu);
8302
8303 else if (!uimm (aarch64_get_instr (cpu), 15, 15))
8304 dexSimpleFPIntegerConvert (cpu);
8305
8306 else
8307 /* If we get here then instr[15] == 1 which means UNALLOC. */
8308 HALT_UNALLOC;
8309 }
8310}
8311
8312/* PC relative addressing. */
8313
8314static void
8315pcadr (sim_cpu *cpu)
8316{
8317 /* instr[31] = op : 0 ==> ADR, 1 ==> ADRP
8318 instr[30,29] = immlo
8319 instr[23,5] = immhi. */
8320 uint64_t address;
8321 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8322 uint32_t isPage = uimm (aarch64_get_instr (cpu), 31, 31);
8323 union { int64_t u64; uint64_t s64; } imm;
8324 uint64_t offset;
8325
8326 imm.s64 = simm64 (aarch64_get_instr (cpu), 23, 5);
8327 offset = imm.u64;
8328 offset = (offset << 2) | uimm (aarch64_get_instr (cpu), 30, 29);
8329
8330 address = aarch64_get_PC (cpu);
8331
8332 if (isPage)
8333 {
8334 offset <<= 12;
8335 address &= ~0xfff;
8336 }
8337
8338 aarch64_set_reg_u64 (cpu, rd, NO_SP, address + offset);
8339}
8340
8341/* Specific decode and execute for group Data Processing Immediate. */
8342
8343static void
8344dexPCRelAddressing (sim_cpu *cpu)
8345{
8346 /* assert instr[28,24] = 10000. */
8347 pcadr (cpu);
8348}
8349
8350/* Immediate logical.
8351 The bimm32/64 argument is constructed by replicating a 2, 4, 8,
8352 16, 32 or 64 bit sequence pulled out at decode and possibly
8353 inverting it..
8354
8355 N.B. the output register (dest) can normally be Xn or SP
8356 the exception occurs for flag setting instructions which may
8357 only use Xn for the output (dest). The input register can
8358 never be SP. */
8359
8360/* 32 bit and immediate. */
8361static void
8362and32 (sim_cpu *cpu, uint32_t bimm)
8363{
8364 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8365 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8366
8367 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8368 aarch64_get_reg_u32 (cpu, rn, NO_SP) & bimm);
8369}
8370
8371/* 64 bit and immediate. */
8372static void
8373and64 (sim_cpu *cpu, uint64_t bimm)
8374{
8375 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8376 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8377
8378 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8379 aarch64_get_reg_u64 (cpu, rn, NO_SP) & bimm);
8380}
8381
8382/* 32 bit and immediate set flags. */
8383static void
8384ands32 (sim_cpu *cpu, uint32_t bimm)
8385{
8386 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8387 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8388
8389 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8390 uint32_t value2 = bimm;
8391
8392 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8393 set_flags_for_binop32 (cpu, value1 & value2);
8394}
8395
8396/* 64 bit and immediate set flags. */
8397static void
8398ands64 (sim_cpu *cpu, uint64_t bimm)
8399{
8400 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8401 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8402
8403 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8404 uint64_t value2 = bimm;
8405
8406 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8407 set_flags_for_binop64 (cpu, value1 & value2);
8408}
8409
8410/* 32 bit exclusive or immediate. */
8411static void
8412eor32 (sim_cpu *cpu, uint32_t bimm)
8413{
8414 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8415 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8416
8417 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8418 aarch64_get_reg_u32 (cpu, rn, NO_SP) ^ bimm);
8419}
8420
8421/* 64 bit exclusive or immediate. */
8422static void
8423eor64 (sim_cpu *cpu, uint64_t bimm)
8424{
8425 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8426 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8427
8428 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8429 aarch64_get_reg_u64 (cpu, rn, NO_SP) ^ bimm);
8430}
8431
8432/* 32 bit or immediate. */
8433static void
8434orr32 (sim_cpu *cpu, uint32_t bimm)
8435{
8436 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8437 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8438
8439 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8440 aarch64_get_reg_u32 (cpu, rn, NO_SP) | bimm);
8441}
8442
8443/* 64 bit or immediate. */
8444static void
8445orr64 (sim_cpu *cpu, uint64_t bimm)
8446{
8447 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8448 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8449
8450 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8451 aarch64_get_reg_u64 (cpu, rn, NO_SP) | bimm);
8452}
8453
8454/* Logical shifted register.
8455 These allow an optional LSL, ASR, LSR or ROR to the second source
8456 register with a count up to the register bit count.
8457 N.B register args may not be SP. */
8458
8459/* 32 bit AND shifted register. */
8460static void
8461and32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8462{
8463 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8464 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8465 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8466
8467 aarch64_set_reg_u64
8468 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8469 & shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8470}
8471
8472/* 64 bit AND shifted register. */
8473static void
8474and64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8475{
8476 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8477 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8478 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8479
8480 aarch64_set_reg_u64
8481 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8482 & shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8483}
8484
8485/* 32 bit AND shifted register setting flags. */
8486static void
8487ands32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8488{
8489 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8490 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8491 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8492
8493 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8494 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
8495 shift, count);
8496
8497 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8498 set_flags_for_binop32 (cpu, value1 & value2);
8499}
8500
8501/* 64 bit AND shifted register setting flags. */
8502static void
8503ands64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8504{
8505 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
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 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
8511 shift, count);
8512
8513 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8514 set_flags_for_binop64 (cpu, value1 & value2);
8515}
8516
8517/* 32 bit BIC shifted register. */
8518static void
8519bic32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8520{
8521 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8522 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8523 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8524
8525 aarch64_set_reg_u64
8526 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8527 & ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8528}
8529
8530/* 64 bit BIC shifted register. */
8531static void
8532bic64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8533{
8534 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8535 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8536 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8537
8538 aarch64_set_reg_u64
8539 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8540 & ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8541}
8542
8543/* 32 bit BIC shifted register setting flags. */
8544static void
8545bics32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8546{
8547 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8548 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8549 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8550
8551 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8552 uint32_t value2 = ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
8553 shift, count);
8554
8555 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8556 set_flags_for_binop32 (cpu, value1 & value2);
8557}
8558
8559/* 64 bit BIC shifted register setting flags. */
8560static void
8561bics64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8562{
8563 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8564 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8565 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8566
8567 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8568 uint64_t value2 = ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
8569 shift, count);
8570
8571 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8572 set_flags_for_binop64 (cpu, value1 & value2);
8573}
8574
8575/* 32 bit EON shifted register. */
8576static void
8577eon32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8578{
8579 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8580 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8581 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8582
8583 aarch64_set_reg_u64
8584 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8585 ^ ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8586}
8587
8588/* 64 bit EON shifted register. */
8589static void
8590eon64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8591{
8592 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8593 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8594 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8595
8596 aarch64_set_reg_u64
8597 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8598 ^ ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8599}
8600
8601/* 32 bit EOR shifted register. */
8602static void
8603eor32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8604{
8605 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8606 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8607 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8608
8609 aarch64_set_reg_u64
8610 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8611 ^ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8612}
8613
8614/* 64 bit EOR shifted register. */
8615static void
8616eor64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8617{
8618 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8619 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8620 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8621
8622 aarch64_set_reg_u64
8623 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8624 ^ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8625}
8626
8627/* 32 bit ORR shifted register. */
8628static void
8629orr32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8630{
8631 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8632 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8633 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8634
8635 aarch64_set_reg_u64
8636 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8637 | shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8638}
8639
8640/* 64 bit ORR shifted register. */
8641static void
8642orr64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8643{
8644 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8645 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8646 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8647
8648 aarch64_set_reg_u64
8649 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8650 | shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8651}
8652
8653/* 32 bit ORN shifted register. */
8654static void
8655orn32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8656{
8657 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8658 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8659 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8660
8661 aarch64_set_reg_u64
8662 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8663 | ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8664}
8665
8666/* 64 bit ORN shifted register. */
8667static void
8668orn64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8669{
8670 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8671 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8672 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8673
8674 aarch64_set_reg_u64
8675 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8676 | ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8677}
8678
8679static void
8680dexLogicalImmediate (sim_cpu *cpu)
8681{
8682 /* assert instr[28,23] = 1001000
8683 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8684 instr[30,29] = op : 0 ==> AND, 1 ==> ORR, 2 ==> EOR, 3 ==> ANDS
8685 instr[22] = N : used to construct immediate mask
8686 instr[21,16] = immr
8687 instr[15,10] = imms
8688 instr[9,5] = Rn
8689 instr[4,0] = Rd */
8690
8691 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
8692 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
8693 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
8694 /* uint32_t immr = uimm (aarch64_get_instr (cpu), 21, 16);. */
8695 /* uint32_t imms = uimm (aarch64_get_instr (cpu), 15, 10);. */
8696 uint32_t index = uimm (aarch64_get_instr (cpu), 22, 10);
8697 uint64_t bimm64 = LITable [index];
8698 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 30, 29);
8699
8700 if (~size & N)
8701 HALT_UNALLOC;
8702
8703 if (!bimm64)
8704 HALT_UNALLOC;
8705
8706 if (size == 0)
8707 {
8708 uint32_t bimm = (uint32_t) bimm64;
8709
8710 switch (dispatch)
8711 {
8712 case 0: and32 (cpu, bimm); return;
8713 case 1: orr32 (cpu, bimm); return;
8714 case 2: eor32 (cpu, bimm); return;
8715 case 3: ands32 (cpu, bimm); return;
8716 }
8717 }
8718 else
8719 {
8720 switch (dispatch)
8721 {
8722 case 0: and64 (cpu, bimm64); return;
8723 case 1: orr64 (cpu, bimm64); return;
8724 case 2: eor64 (cpu, bimm64); return;
8725 case 3: ands64 (cpu, bimm64); return;
8726 }
8727 }
8728 HALT_UNALLOC;
8729}
8730
8731/* Immediate move.
8732 The uimm argument is a 16 bit value to be inserted into the
8733 target register the pos argument locates the 16 bit word in the
8734 dest register i.e. it is in {0, 1} for 32 bit and {0, 1, 2,
8735 3} for 64 bit.
8736 N.B register arg may not be SP so it should be.
8737 accessed using the setGZRegisterXXX accessors. */
8738
8739/* 32 bit move 16 bit immediate zero remaining shorts. */
8740static void
8741movz32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8742{
8743 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8744
8745 aarch64_set_reg_u64 (cpu, rd, NO_SP, val << (pos * 16));
8746}
8747
8748/* 64 bit move 16 bit immediate zero remaining shorts. */
8749static void
8750movz64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8751{
8752 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8753
8754 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((uint64_t) val) << (pos * 16));
8755}
8756
8757/* 32 bit move 16 bit immediate negated. */
8758static void
8759movn32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8760{
8761 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8762
8763 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((val << (pos * 16)) ^ 0xffffffffU));
8764}
8765
8766/* 64 bit move 16 bit immediate negated. */
8767static void
8768movn64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8769{
8770 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8771
8772 aarch64_set_reg_u64
8773 (cpu, rd, NO_SP, ((((uint64_t) val) << (pos * 16))
8774 ^ 0xffffffffffffffffULL));
8775}
8776
8777/* 32 bit move 16 bit immediate keep remaining shorts. */
8778static void
8779movk32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8780{
8781 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8782 uint32_t current = aarch64_get_reg_u32 (cpu, rd, NO_SP);
8783 uint32_t value = val << (pos * 16);
8784 uint32_t mask = ~(0xffffU << (pos * 16));
8785
8786 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
8787}
8788
8789/* 64 bit move 16 it immediate keep remaining shorts. */
8790static void
8791movk64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8792{
8793 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8794 uint64_t current = aarch64_get_reg_u64 (cpu, rd, NO_SP);
8795 uint64_t value = (uint64_t) val << (pos * 16);
8796 uint64_t mask = ~(0xffffULL << (pos * 16));
8797
8798 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
8799}
8800
8801static void
8802dexMoveWideImmediate (sim_cpu *cpu)
8803{
8804 /* assert instr[28:23] = 100101
8805 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8806 instr[30,29] = op : 0 ==> MOVN, 1 ==> UNALLOC, 2 ==> MOVZ, 3 ==> MOVK
8807 instr[22,21] = shift : 00 == LSL#0, 01 = LSL#16, 10 = LSL#32, 11 = LSL#48
8808 instr[20,5] = uimm16
8809 instr[4,0] = Rd */
8810
8811 /* N.B. the (multiple of 16) shift is applied by the called routine,
8812 we just pass the multiplier. */
8813
8814 uint32_t imm;
8815 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
8816 uint32_t op = uimm (aarch64_get_instr (cpu), 30, 29);
8817 uint32_t shift = uimm (aarch64_get_instr (cpu), 22, 21);
8818
8819 /* 32 bit can only shift 0 or 1 lot of 16.
8820 anything else is an unallocated instruction. */
8821 if (size == 0 && (shift > 1))
8822 HALT_UNALLOC;
8823
8824 if (op == 1)
8825 HALT_UNALLOC;
8826
8827 imm = uimm (aarch64_get_instr (cpu), 20, 5);
8828
8829 if (size == 0)
8830 {
8831 if (op == 0)
8832 movn32 (cpu, imm, shift);
8833 else if (op == 2)
8834 movz32 (cpu, imm, shift);
8835 else
8836 movk32 (cpu, imm, shift);
8837 }
8838 else
8839 {
8840 if (op == 0)
8841 movn64 (cpu, imm, shift);
8842 else if (op == 2)
8843 movz64 (cpu, imm, shift);
8844 else
8845 movk64 (cpu, imm, shift);
8846 }
8847}
8848
8849/* Bitfield operations.
8850 These take a pair of bit positions r and s which are in {0..31}
8851 or {0..63} depending on the instruction word size.
8852 N.B register args may not be SP. */
8853
8854/* OK, we start with ubfm which just needs to pick
8855 some bits out of source zero the rest and write
8856 the result to dest. Just need two logical shifts. */
8857
8858/* 32 bit bitfield move, left and right of affected zeroed
8859 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8860static void
8861ubfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8862{
8863 unsigned rd;
8864 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8865 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8866
8867 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
8868 if (r <= s)
8869 {
8870 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
8871 We want only bits s:xxx:r at the bottom of the word
8872 so we LSL bit s up to bit 31 i.e. by 31 - s
8873 and then we LSR to bring bit 31 down to bit s - r
8874 i.e. by 31 + r - s. */
8875 value <<= 31 - s;
8876 value >>= 31 + r - s;
8877 }
8878 else
8879 {
8880 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0
8881 We want only bits s:xxx:0 starting at it 31-(r-1)
8882 so we LSL bit s up to bit 31 i.e. by 31 - s
8883 and then we LSL to bring bit 31 down to 31-(r-1)+s
8884 i.e. by r - (s + 1). */
8885 value <<= 31 - s;
8886 value >>= r - (s + 1);
8887 }
8888
8889 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8890 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8891}
8892
8893/* 64 bit bitfield move, left and right of affected zeroed
8894 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
8895static void
8896ubfm (sim_cpu *cpu, uint32_t r, uint32_t s)
8897{
8898 unsigned rd;
8899 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8900 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8901
8902 if (r <= s)
8903 {
8904 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
8905 We want only bits s:xxx:r at the bottom of the word.
8906 So we LSL bit s up to bit 63 i.e. by 63 - s
8907 and then we LSR to bring bit 63 down to bit s - r
8908 i.e. by 63 + r - s. */
8909 value <<= 63 - s;
8910 value >>= 63 + r - s;
8911 }
8912 else
8913 {
8914 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0.
8915 We want only bits s:xxx:0 starting at it 63-(r-1).
8916 So we LSL bit s up to bit 63 i.e. by 63 - s
8917 and then we LSL to bring bit 63 down to 63-(r-1)+s
8918 i.e. by r - (s + 1). */
8919 value <<= 63 - s;
8920 value >>= r - (s + 1);
8921 }
8922
8923 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8924 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8925}
8926
8927/* The signed versions need to insert sign bits
8928 on the left of the inserted bit field. so we do
8929 much the same as the unsigned version except we
8930 use an arithmetic shift right -- this just means
8931 we need to operate on signed values. */
8932
8933/* 32 bit bitfield move, left of affected sign-extended, right zeroed. */
8934/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8935static void
8936sbfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8937{
8938 unsigned rd;
8939 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8940 /* as per ubfm32 but use an ASR instead of an LSR. */
8941 int32_t value = aarch64_get_reg_s32 (cpu, rn, NO_SP);
8942
8943 if (r <= s)
8944 {
8945 value <<= 31 - s;
8946 value >>= 31 + r - s;
8947 }
8948 else
8949 {
8950 value <<= 31 - s;
8951 value >>= r - (s + 1);
8952 }
8953
8954 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8955 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8956}
8957
8958/* 64 bit bitfield move, left of affected sign-extended, right zeroed. */
8959/* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
8960static void
8961sbfm (sim_cpu *cpu, uint32_t r, uint32_t s)
8962{
8963 unsigned rd;
8964 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8965 /* acpu per ubfm but use an ASR instead of an LSR. */
8966 int64_t value = aarch64_get_reg_s64 (cpu, rn, NO_SP);
8967
8968 if (r <= s)
8969 {
8970 value <<= 63 - s;
8971 value >>= 63 + r - s;
8972 }
8973 else
8974 {
8975 value <<= 63 - s;
8976 value >>= r - (s + 1);
8977 }
8978
8979 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8980 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8981}
8982
8983/* Finally, these versions leave non-affected bits
8984 as is. so we need to generate the bits as per
8985 ubfm and also generate a mask to pick the
8986 bits from the original and computed values. */
8987
8988/* 32 bit bitfield move, non-affected bits left as is.
8989 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8990static void
8991bfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8992{
8993 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8994 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8995 uint32_t mask = -1;
8996 unsigned rd;
8997 uint32_t value2;
8998
8999 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
9000 if (r <= s)
9001 {
9002 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
9003 We want only bits s:xxx:r at the bottom of the word
9004 so we LSL bit s up to bit 31 i.e. by 31 - s
9005 and then we LSR to bring bit 31 down to bit s - r
9006 i.e. by 31 + r - s. */
9007 value <<= 31 - s;
9008 value >>= 31 + r - s;
9009 /* the mask must include the same bits. */
9010 mask <<= 31 - s;
9011 mask >>= 31 + r - s;
9012 }
9013 else
9014 {
9015 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0.
9016 We want only bits s:xxx:0 starting at it 31-(r-1)
9017 so we LSL bit s up to bit 31 i.e. by 31 - s
9018 and then we LSL to bring bit 31 down to 31-(r-1)+s
9019 i.e. by r - (s + 1). */
9020 value <<= 31 - s;
9021 value >>= r - (s + 1);
9022 /* The mask must include the same bits. */
9023 mask <<= 31 - s;
9024 mask >>= r - (s + 1);
9025 }
9026
9027 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9028 value2 = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9029
9030 value2 &= ~mask;
9031 value2 |= value;
9032
9033 aarch64_set_reg_u64
9034 (cpu, rd, NO_SP, (aarch64_get_reg_u32 (cpu, rd, NO_SP) & ~mask) | value);
9035}
9036
9037/* 64 bit bitfield move, non-affected bits left as is.
9038 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9039static void
9040bfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9041{
9042 unsigned rd;
9043 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9044 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9045 uint64_t mask = 0xffffffffffffffffULL;
9046
9047 if (r <= s)
9048 {
9049 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9050 We want only bits s:xxx:r at the bottom of the word
9051 so we LSL bit s up to bit 63 i.e. by 63 - s
9052 and then we LSR to bring bit 63 down to bit s - r
9053 i.e. by 63 + r - s. */
9054 value <<= 63 - s;
9055 value >>= 63 + r - s;
9056 /* The mask must include the same bits. */
9057 mask <<= 63 - s;
9058 mask >>= 63 + r - s;
9059 }
9060 else
9061 {
9062 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0
9063 We want only bits s:xxx:0 starting at it 63-(r-1)
9064 so we LSL bit s up to bit 63 i.e. by 63 - s
9065 and then we LSL to bring bit 63 down to 63-(r-1)+s
9066 i.e. by r - (s + 1). */
9067 value <<= 63 - s;
9068 value >>= r - (s + 1);
9069 /* The mask must include the same bits. */
9070 mask <<= 63 - s;
9071 mask >>= r - (s + 1);
9072 }
9073
9074 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9075 aarch64_set_reg_u64
9076 (cpu, rd, NO_SP, (aarch64_get_reg_u64 (cpu, rd, NO_SP) & ~mask) | value);
9077}
9078
9079static void
9080dexBitfieldImmediate (sim_cpu *cpu)
9081{
9082 /* assert instr[28:23] = 100110
9083 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9084 instr[30,29] = op : 0 ==> SBFM, 1 ==> BFM, 2 ==> UBFM, 3 ==> UNALLOC
9085 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit ow UNALLOC
9086 instr[21,16] = immr : 0xxxxx for 32 bit, xxxxxx for 64 bit
9087 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9088 instr[9,5] = Rn
9089 instr[4,0] = Rd */
9090
9091 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9092 uint32_t dispatch;
9093 uint32_t imms;
9094 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
9095 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
9096 /* 32 bit operations must have immr[5] = 0 and imms[5] = 0. */
9097 /* or else we have an UNALLOC. */
9098 uint32_t immr = uimm (aarch64_get_instr (cpu), 21, 16);
9099
9100 if (~size & N)
9101 HALT_UNALLOC;
9102
9103 if (!size && uimm (immr, 5, 5))
9104 HALT_UNALLOC;
9105
9106 imms = uimm (aarch64_get_instr (cpu), 15, 10);
9107 if (!size && uimm (imms, 5, 5))
9108 HALT_UNALLOC;
9109
9110 /* Switch on combined size and op. */
9111 dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
9112 switch (dispatch)
9113 {
9114 case 0: sbfm32 (cpu, immr, imms); return;
9115 case 1: bfm32 (cpu, immr, imms); return;
9116 case 2: ubfm32 (cpu, immr, imms); return;
9117 case 4: sbfm (cpu, immr, imms); return;
9118 case 5: bfm (cpu, immr, imms); return;
9119 case 6: ubfm (cpu, immr, imms); return;
9120 default: HALT_UNALLOC;
9121 }
9122}
9123
9124static void
9125do_EXTR_32 (sim_cpu *cpu)
9126{
9127 /* instr[31:21] = 00010011100
9128 instr[20,16] = Rm
9129 instr[15,10] = imms : 0xxxxx for 32 bit
9130 instr[9,5] = Rn
9131 instr[4,0] = Rd */
9132 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9133 unsigned imms = uimm (aarch64_get_instr (cpu), 15, 10) & 31;
9134 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9135 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
9136 uint64_t val1;
9137 uint64_t val2;
9138
9139 val1 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
9140 val1 >>= imms;
9141 val2 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9142 val2 <<= (32 - imms);
9143
9144 aarch64_set_reg_u64 (cpu, rd, NO_SP, val1 | val2);
9145}
9146
9147static void
9148do_EXTR_64 (sim_cpu *cpu)
9149{
9150 /* instr[31:21] = 10010011100
9151 instr[20,16] = Rm
9152 instr[15,10] = imms
9153 instr[9,5] = Rn
9154 instr[4,0] = Rd */
9155 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9156 unsigned imms = uimm (aarch64_get_instr (cpu), 15, 10) & 63;
9157 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9158 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
9159 uint64_t val;
9160
9161 val = aarch64_get_reg_u64 (cpu, rm, NO_SP);
9162 val >>= imms;
9163 val |= (aarch64_get_reg_u64 (cpu, rn, NO_SP) << (64 - imms));
9164
9165 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
9166}
9167
9168static void
9169dexExtractImmediate (sim_cpu *cpu)
9170{
9171 /* assert instr[28:23] = 100111
9172 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9173 instr[30,29] = op21 : 0 ==> EXTR, 1,2,3 ==> UNALLOC
9174 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit or UNALLOC
9175 instr[21] = op0 : must be 0 or UNALLOC
9176 instr[20,16] = Rm
9177 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9178 instr[9,5] = Rn
9179 instr[4,0] = Rd */
9180
9181 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9182 /* 64 bit operations must have N = 1 or else we have an UNALLOC. */
9183 uint32_t dispatch;
9184 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
9185 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
9186 /* 32 bit operations must have imms[5] = 0
9187 or else we have an UNALLOC. */
9188 uint32_t imms = uimm (aarch64_get_instr (cpu), 15, 10);
9189
9190 if (size ^ N)
9191 HALT_UNALLOC;
9192
9193 if (!size && uimm (imms, 5, 5))
9194 HALT_UNALLOC;
9195
9196 /* Switch on combined size and op. */
9197 dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
9198
9199 if (dispatch == 0)
9200 do_EXTR_32 (cpu);
9201
9202 else if (dispatch == 4)
9203 do_EXTR_64 (cpu);
9204
9205 else if (dispatch == 1)
9206 HALT_NYI;
9207 else
9208 HALT_UNALLOC;
9209}
9210
9211static void
9212dexDPImm (sim_cpu *cpu)
9213{
9214 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
9215 assert group == GROUP_DPIMM_1000 || grpoup == GROUP_DPIMM_1001
9216 bits [25,23] of a DPImm are the secondary dispatch vector. */
9217 uint32_t group2 = dispatchDPImm (aarch64_get_instr (cpu));
9218
9219 switch (group2)
9220 {
9221 case DPIMM_PCADR_000:
9222 case DPIMM_PCADR_001:
9223 dexPCRelAddressing (cpu);
9224 return;
9225
9226 case DPIMM_ADDSUB_010:
9227 case DPIMM_ADDSUB_011:
9228 dexAddSubtractImmediate (cpu);
9229 return;
9230
9231 case DPIMM_LOG_100:
9232 dexLogicalImmediate (cpu);
9233 return;
9234
9235 case DPIMM_MOV_101:
9236 dexMoveWideImmediate (cpu);
9237 return;
9238
9239 case DPIMM_BITF_110:
9240 dexBitfieldImmediate (cpu);
9241 return;
9242
9243 case DPIMM_EXTR_111:
9244 dexExtractImmediate (cpu);
9245 return;
9246
9247 default:
9248 /* Should never reach here. */
9249 HALT_NYI;
9250 }
9251}
9252
9253static void
9254dexLoadUnscaledImmediate (sim_cpu *cpu)
9255{
9256 /* instr[29,24] == 111_00
9257 instr[21] == 0
9258 instr[11,10] == 00
9259 instr[31,30] = size
9260 instr[26] = V
9261 instr[23,22] = opc
9262 instr[20,12] = simm9
9263 instr[9,5] = rn may be SP. */
9264 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9265 uint32_t V = uimm (aarch64_get_instr (cpu), 26, 26);
9266 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9267 | uimm (aarch64_get_instr (cpu), 23, 22));
9268 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
9269
9270 if (!V)
9271 {
9272 /* GReg operations. */
9273 switch (dispatch)
9274 {
9275 case 0: sturb (cpu, imm); return;
9276 case 1: ldurb32 (cpu, imm); return;
9277 case 2: ldursb64 (cpu, imm); return;
9278 case 3: ldursb32 (cpu, imm); return;
9279 case 4: sturh (cpu, imm); return;
9280 case 5: ldurh32 (cpu, imm); return;
9281 case 6: ldursh64 (cpu, imm); return;
9282 case 7: ldursh32 (cpu, imm); return;
9283 case 8: stur32 (cpu, imm); return;
9284 case 9: ldur32 (cpu, imm); return;
9285 case 10: ldursw (cpu, imm); return;
9286 case 12: stur64 (cpu, imm); return;
9287 case 13: ldur64 (cpu, imm); return;
9288
9289 case 14:
9290 /* PRFUM NYI. */
9291 HALT_NYI;
9292
9293 default:
9294 case 11:
9295 case 15:
9296 HALT_UNALLOC;
9297 }
9298 }
9299
9300 /* FReg operations. */
9301 switch (dispatch)
9302 {
9303 case 2: fsturq (cpu, imm); return;
9304 case 3: fldurq (cpu, imm); return;
9305 case 8: fsturs (cpu, imm); return;
9306 case 9: fldurs (cpu, imm); return;
9307 case 12: fsturd (cpu, imm); return;
9308 case 13: fldurd (cpu, imm); return;
9309
9310 case 0: /* STUR 8 bit FP. */
9311 case 1: /* LDUR 8 bit FP. */
9312 case 4: /* STUR 16 bit FP. */
9313 case 5: /* LDUR 8 bit FP. */
9314 HALT_NYI;
9315
9316 default:
9317 case 6:
9318 case 7:
9319 case 10:
9320 case 11:
9321 case 14:
9322 case 15:
9323 HALT_UNALLOC;
9324 }
9325}
9326
9327/* N.B. A preliminary note regarding all the ldrs<x>32
9328 instructions
9329
9330 The signed value loaded by these instructions is cast to unsigned
9331 before being assigned to aarch64_get_reg_u64 (cpu, N) i.e. to the
9332 64 bit element of the GReg union. this performs a 32 bit sign extension
9333 (as required) but avoids 64 bit sign extension, thus ensuring that the
9334 top half of the register word is zero. this is what the spec demands
9335 when a 32 bit load occurs. */
9336
9337/* 32 bit load sign-extended byte scaled unsigned 12 bit. */
9338static void
9339ldrsb32_abs (sim_cpu *cpu, uint32_t offset)
9340{
9341 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9342 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9343
9344 /* The target register may not be SP but the source may be
9345 there is no scaling required for a byte load. */
9346 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
9347 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9348 (int64_t) aarch64_get_mem_s8 (cpu, address));
9349}
9350
9351/* 32 bit load sign-extended byte scaled or unscaled zero-
9352 or sign-extended 32-bit register offset. */
9353static void
9354ldrsb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9355{
9356 unsigned int rm = uimm (aarch64_get_instr (cpu), 20, 16);
9357 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9358 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9359
9360 /* rn may reference SP, rm and rt must reference ZR. */
9361
9362 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9363 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9364 extension);
9365
9366 /* There is no scaling required for a byte load. */
9367 aarch64_set_reg_u64
9368 (cpu, rt, NO_SP, (int64_t) aarch64_get_mem_s8 (cpu, address
9369 + displacement));
9370}
9371
9372/* 32 bit load sign-extended byte unscaled signed 9 bit with
9373 pre- or post-writeback. */
9374static void
9375ldrsb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9376{
9377 uint64_t address;
9378 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9379 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9380
9381 if (rn == rt && wb != NoWriteBack)
9382 HALT_UNALLOC;
9383
9384 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9385
9386 if (wb == Pre)
9387 address += offset;
9388
9389 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9390 (int64_t) aarch64_get_mem_s8 (cpu, address));
9391
9392 if (wb == Post)
9393 address += offset;
9394
9395 if (wb != NoWriteBack)
9396 aarch64_set_reg_u64 (cpu, rn, NO_SP, address);
9397}
9398
9399/* 8 bit store scaled. */
9400static void
9401fstrb_abs (sim_cpu *cpu, uint32_t offset)
9402{
9403 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9404 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9405
9406 aarch64_set_mem_u8 (cpu,
9407 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
9408 aarch64_get_vec_u8 (cpu, st, 0));
9409}
9410
9411/* 8 bit store scaled or unscaled zero- or
9412 sign-extended 8-bit register offset. */
9413static void
9414fstrb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9415{
9416 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9417 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9418 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9419
9420 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9421 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9422 extension);
9423 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9424
9425 aarch64_set_mem_u8
9426 (cpu, address + displacement, aarch64_get_vec_u8 (cpu, st, 0));
9427}
9428
9429/* 16 bit store scaled. */
9430static void
9431fstrh_abs (sim_cpu *cpu, uint32_t offset)
9432{
9433 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9434 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9435
9436 aarch64_set_mem_u16
9437 (cpu,
9438 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16),
9439 aarch64_get_vec_u16 (cpu, st, 0));
9440}
9441
9442/* 16 bit store scaled or unscaled zero-
9443 or sign-extended 16-bit register offset. */
9444static void
9445fstrh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9446{
9447 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9448 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9449 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9450
9451 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9452 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9453 extension);
9454 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9455
9456 aarch64_set_mem_u16
9457 (cpu, address + displacement, aarch64_get_vec_u16 (cpu, st, 0));
9458}
9459
9460/* 32 bit store scaled unsigned 12 bit. */
9461static void
9462fstrs_abs (sim_cpu *cpu, uint32_t offset)
9463{
9464 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9465 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9466
9467 aarch64_set_mem_float
9468 (cpu,
9469 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
9470 aarch64_get_FP_float (cpu, st));
9471}
9472
9473/* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
9474static void
9475fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9476{
9477 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9478 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9479
9480 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9481
9482 if (wb != Post)
9483 address += offset;
9484
9485 aarch64_set_mem_float (cpu, address, aarch64_get_FP_float (cpu, st));
9486
9487 if (wb == Post)
9488 address += offset;
9489
9490 if (wb != NoWriteBack)
9491 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9492}
9493
9494/* 32 bit store scaled or unscaled zero-
9495 or sign-extended 32-bit register offset. */
9496static void
9497fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9498{
9499 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9500 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9501 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9502
9503 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9504 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9505 extension);
9506 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9507
9508 aarch64_set_mem_float
9509 (cpu, address + displacement, aarch64_get_FP_float (cpu, st));
9510}
9511
9512/* 64 bit store scaled unsigned 12 bit. */
9513static void
9514fstrd_abs (sim_cpu *cpu, uint32_t offset)
9515{
9516 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9517 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9518
9519 aarch64_set_mem_double
9520 (cpu,
9521 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
9522 aarch64_get_FP_double (cpu, st));
9523}
9524
9525/* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
9526static void
9527fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9528{
9529 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9530 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9531
9532 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9533
9534 if (wb != Post)
9535 address += offset;
9536
9537 aarch64_set_mem_double (cpu, address, aarch64_get_FP_double (cpu, st));
9538
9539 if (wb == Post)
9540 address += offset;
9541
9542 if (wb != NoWriteBack)
9543 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9544}
9545
9546/* 64 bit store scaled or unscaled zero-
9547 or sign-extended 32-bit register offset. */
9548static void
9549fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9550{
9551 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9552 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9553 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9554
9555 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9556 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9557 extension);
9558 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
9559
9560 aarch64_set_mem_double
9561 (cpu, address + displacement, aarch64_get_FP_double (cpu, st));
9562}
9563
9564/* 128 bit store scaled unsigned 12 bit. */
9565static void
9566fstrq_abs (sim_cpu *cpu, uint32_t offset)
9567{
9568 FRegister a;
9569 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9570 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9571 uint64_t addr;
9572
9573 aarch64_get_FP_long_double (cpu, st, & a);
9574
9575 addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
9576 aarch64_set_mem_long_double (cpu, addr, a);
9577}
9578
9579/* 128 bit store unscaled signed 9 bit with pre- or post-writeback. */
9580static void
9581fstrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9582{
9583 FRegister a;
9584 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9585 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9586 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9587
9588 if (wb != Post)
9589 address += offset;
9590
9591 aarch64_get_FP_long_double (cpu, st, & a);
9592 aarch64_set_mem_long_double (cpu, address, a);
9593
9594 if (wb == Post)
9595 address += offset;
9596
9597 if (wb != NoWriteBack)
9598 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9599}
9600
9601/* 128 bit store scaled or unscaled zero-
9602 or sign-extended 32-bit register offset. */
9603static void
9604fstrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9605{
9606 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9607 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9608 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9609
9610 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9611 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9612 extension);
9613 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
9614
9615 FRegister a;
9616
9617 aarch64_get_FP_long_double (cpu, st, & a);
9618 aarch64_set_mem_long_double (cpu, address + displacement, a);
9619}
9620
9621static void
9622dexLoadImmediatePrePost (sim_cpu *cpu)
9623{
9624 /* instr[29,24] == 111_00
9625 instr[21] == 0
9626 instr[11,10] == 00
9627 instr[31,30] = size
9628 instr[26] = V
9629 instr[23,22] = opc
9630 instr[20,12] = simm9
9631 instr[11] = wb : 0 ==> Post, 1 ==> Pre
9632 instr[9,5] = rn may be SP. */
9633 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9634 uint32_t V = uimm (aarch64_get_instr (cpu), 26, 26);
9635 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9636 | uimm (aarch64_get_instr (cpu), 23, 22));
9637 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
9638 WriteBack wb = writeback (aarch64_get_instr (cpu), 11);
9639
9640 if (!V)
9641 {
9642 /* GReg operations. */
9643 switch (dispatch)
9644 {
9645 case 0: strb_wb (cpu, imm, wb); return;
9646 case 1: ldrb32_wb (cpu, imm, wb); return;
9647 case 2: ldrsb_wb (cpu, imm, wb); return;
9648 case 3: ldrsb32_wb (cpu, imm, wb); return;
9649 case 4: strh_wb (cpu, imm, wb); return;
9650 case 5: ldrh32_wb (cpu, imm, wb); return;
9651 case 6: ldrsh64_wb (cpu, imm, wb); return;
9652 case 7: ldrsh32_wb (cpu, imm, wb); return;
9653 case 8: str32_wb (cpu, imm, wb); return;
9654 case 9: ldr32_wb (cpu, imm, wb); return;
9655 case 10: ldrsw_wb (cpu, imm, wb); return;
9656 case 12: str_wb (cpu, imm, wb); return;
9657 case 13: ldr_wb (cpu, imm, wb); return;
9658
9659 default:
9660 case 11:
9661 case 14:
9662 case 15:
9663 HALT_UNALLOC;
9664 }
9665 }
9666
9667 /* FReg operations. */
9668 switch (dispatch)
9669 {
9670 case 2: fstrq_wb (cpu, imm, wb); return;
9671 case 3: fldrq_wb (cpu, imm, wb); return;
9672 case 8: fstrs_wb (cpu, imm, wb); return;
9673 case 9: fldrs_wb (cpu, imm, wb); return;
9674 case 12: fstrd_wb (cpu, imm, wb); return;
9675 case 13: fldrd_wb (cpu, imm, wb); return;
9676
9677 case 0: /* STUR 8 bit FP. */
9678 case 1: /* LDUR 8 bit FP. */
9679 case 4: /* STUR 16 bit FP. */
9680 case 5: /* LDUR 8 bit FP. */
9681 HALT_NYI;
9682
9683 default:
9684 case 6:
9685 case 7:
9686 case 10:
9687 case 11:
9688 case 14:
9689 case 15:
9690 HALT_UNALLOC;
9691 }
9692}
9693
9694static void
9695dexLoadRegisterOffset (sim_cpu *cpu)
9696{
9697 /* instr[31,30] = size
9698 instr[29,27] = 111
9699 instr[26] = V
9700 instr[25,24] = 00
9701 instr[23,22] = opc
9702 instr[21] = 1
9703 instr[20,16] = rm
9704 instr[15,13] = option : 010 ==> UXTW, 011 ==> UXTX/LSL,
9705 110 ==> SXTW, 111 ==> SXTX,
9706 ow ==> RESERVED
9707 instr[12] = scaled
9708 instr[11,10] = 10
9709 instr[9,5] = rn
9710 instr[4,0] = rt. */
9711
9712 uint32_t V = uimm (aarch64_get_instr (cpu), 26,26);
9713 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9714 | uimm (aarch64_get_instr (cpu), 23, 22));
9715 Scaling scale = scaling (aarch64_get_instr (cpu), 12);
9716 Extension extensionType = extension (aarch64_get_instr (cpu), 13);
9717
9718 /* Check for illegal extension types. */
9719 if (uimm (extensionType, 1, 1) == 0)
9720 HALT_UNALLOC;
9721
9722 if (extensionType == UXTX || extensionType == SXTX)
9723 extensionType = NoExtension;
9724
9725 if (!V)
9726 {
9727 /* GReg operations. */
9728 switch (dispatch)
9729 {
9730 case 0: strb_scale_ext (cpu, scale, extensionType); return;
9731 case 1: ldrb32_scale_ext (cpu, scale, extensionType); return;
9732 case 2: ldrsb_scale_ext (cpu, scale, extensionType); return;
9733 case 3: ldrsb32_scale_ext (cpu, scale, extensionType); return;
9734 case 4: strh_scale_ext (cpu, scale, extensionType); return;
9735 case 5: ldrh32_scale_ext (cpu, scale, extensionType); return;
9736 case 6: ldrsh_scale_ext (cpu, scale, extensionType); return;
9737 case 7: ldrsh32_scale_ext (cpu, scale, extensionType); return;
9738 case 8: str32_scale_ext (cpu, scale, extensionType); return;
9739 case 9: ldr32_scale_ext (cpu, scale, extensionType); return;
9740 case 10: ldrsw_scale_ext (cpu, scale, extensionType); return;
9741 case 12: str_scale_ext (cpu, scale, extensionType); return;
9742 case 13: ldr_scale_ext (cpu, scale, extensionType); return;
9743 case 14: prfm_scale_ext (cpu, scale, extensionType); return;
9744
9745 default:
9746 case 11:
9747 case 15:
9748 HALT_UNALLOC;
9749 }
9750 }
9751
9752 /* FReg operations. */
9753 switch (dispatch)
9754 {
9755 case 1: /* LDUR 8 bit FP. */
9756 HALT_NYI;
9757 case 3: fldrq_scale_ext (cpu, scale, extensionType); return;
9758 case 5: /* LDUR 8 bit FP. */
9759 HALT_NYI;
9760 case 9: fldrs_scale_ext (cpu, scale, extensionType); return;
9761 case 13: fldrd_scale_ext (cpu, scale, extensionType); return;
9762
9763 case 0: fstrb_scale_ext (cpu, scale, extensionType); return;
9764 case 2: fstrq_scale_ext (cpu, scale, extensionType); return;
9765 case 4: fstrh_scale_ext (cpu, scale, extensionType); return;
9766 case 8: fstrs_scale_ext (cpu, scale, extensionType); return;
9767 case 12: fstrd_scale_ext (cpu, scale, extensionType); return;
9768
9769 default:
9770 case 6:
9771 case 7:
9772 case 10:
9773 case 11:
9774 case 14:
9775 case 15:
9776 HALT_UNALLOC;
9777 }
9778}
9779
9780static void
9781dexLoadUnsignedImmediate (sim_cpu *cpu)
9782{
9783 /* assert instr[29,24] == 111_01
9784 instr[31,30] = size
9785 instr[26] = V
9786 instr[23,22] = opc
9787 instr[21,10] = uimm12 : unsigned immediate offset
9788 instr[9,5] = rn may be SP. */
9789 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9790 uint32_t V = uimm (aarch64_get_instr (cpu), 26,26);
9791 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9792 | uimm (aarch64_get_instr (cpu), 23, 22));
9793 uint32_t imm = uimm (aarch64_get_instr (cpu), 21, 10);
9794
9795 if (!V)
9796 {
9797 /* GReg operations. */
9798 switch (dispatch)
9799 {
9800 case 0: strb_abs (cpu, imm); return;
9801 case 1: ldrb32_abs (cpu, imm); return;
9802 case 2: ldrsb_abs (cpu, imm); return;
9803 case 3: ldrsb32_abs (cpu, imm); return;
9804 case 4: strh_abs (cpu, imm); return;
9805 case 5: ldrh32_abs (cpu, imm); return;
9806 case 6: ldrsh_abs (cpu, imm); return;
9807 case 7: ldrsh32_abs (cpu, imm); return;
9808 case 8: str32_abs (cpu, imm); return;
9809 case 9: ldr32_abs (cpu, imm); return;
9810 case 10: ldrsw_abs (cpu, imm); return;
9811 case 12: str_abs (cpu, imm); return;
9812 case 13: ldr_abs (cpu, imm); return;
9813 case 14: prfm_abs (cpu, imm); return;
9814
9815 default:
9816 case 11:
9817 case 15:
9818 HALT_UNALLOC;
9819 }
9820 }
9821
9822 /* FReg operations. */
9823 switch (dispatch)
9824 {
9825 case 3: fldrq_abs (cpu, imm); return;
9826 case 9: fldrs_abs (cpu, imm); return;
9827 case 13: fldrd_abs (cpu, imm); return;
9828
9829 case 0: fstrb_abs (cpu, imm); return;
9830 case 2: fstrq_abs (cpu, imm); return;
9831 case 4: fstrh_abs (cpu, imm); return;
9832 case 8: fstrs_abs (cpu, imm); return;
9833 case 12: fstrd_abs (cpu, imm); return;
9834
9835 case 1: /* LDR 8 bit FP. */
9836 case 5: /* LDR 8 bit FP. */
9837 HALT_NYI;
9838
9839 default:
9840 case 6:
9841 case 7:
9842 case 10:
9843 case 11:
9844 case 14:
9845 case 15:
9846 HALT_UNALLOC;
9847 }
9848}
9849
9850static void
9851dexLoadExclusive (sim_cpu *cpu)
9852{
9853 /* assert instr[29:24] = 001000;
9854 instr[31,30] = size
9855 instr[23] = 0 if exclusive
9856 instr[22] = L : 1 if load, 0 if store
9857 instr[21] = 1 if pair
9858 instr[20,16] = Rs
9859 instr[15] = o0 : 1 if ordered
9860 instr[14,10] = Rt2
9861 instr[9,5] = Rn
9862 instr[4.0] = Rt. */
9863
9864 switch (uimm (aarch64_get_instr (cpu), 22, 21))
9865 {
9866 case 2: ldxr (cpu); return;
9867 case 0: stxr (cpu); return;
9868 default: HALT_NYI;
9869 }
9870}
9871
9872static void
9873dexLoadOther (sim_cpu *cpu)
9874{
9875 uint32_t dispatch;
9876
9877 /* instr[29,25] = 111_0
9878 instr[24] == 0 ==> dispatch, 1 ==> ldst reg unsigned immediate
9879 instr[21:11,10] is the secondary dispatch. */
9880 if (uimm (aarch64_get_instr (cpu), 24, 24))
9881 {
9882 dexLoadUnsignedImmediate (cpu);
9883 return;
9884 }
9885
9886 dispatch = ( (uimm (aarch64_get_instr (cpu), 21, 21) << 2)
9887 | uimm (aarch64_get_instr (cpu), 11, 10));
9888 switch (dispatch)
9889 {
9890 case 0: dexLoadUnscaledImmediate (cpu); return;
9891 case 1: dexLoadImmediatePrePost (cpu); return;
9892 case 3: dexLoadImmediatePrePost (cpu); return;
9893 case 6: dexLoadRegisterOffset (cpu); return;
9894
9895 default:
9896 case 2:
9897 case 4:
9898 case 5:
9899 case 7:
9900 HALT_NYI;
9901 }
9902}
9903
9904static void
9905store_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9906{
9907 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9908 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9909 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9910 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9911
9912 if ((rn == rd || rm == rd) && wb != NoWriteBack)
9913 HALT_UNALLOC; /* ??? */
9914
9915 offset <<= 2;
9916
9917 if (wb != Post)
9918 address += offset;
9919
9920 aarch64_set_mem_u32 (cpu, address,
9921 aarch64_get_reg_u32 (cpu, rm, NO_SP));
9922 aarch64_set_mem_u32 (cpu, address + 4,
9923 aarch64_get_reg_u32 (cpu, rn, NO_SP));
9924
9925 if (wb == Post)
9926 address += offset;
9927
9928 if (wb != NoWriteBack)
9929 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9930}
9931
9932static void
9933store_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9934{
9935 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9936 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9937 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9938 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9939
9940 if ((rn == rd || rm == rd) && wb != NoWriteBack)
9941 HALT_UNALLOC; /* ??? */
9942
9943 offset <<= 3;
9944
9945 if (wb != Post)
9946 address += offset;
9947
9948 aarch64_set_mem_u64 (cpu, address,
9949 aarch64_get_reg_u64 (cpu, rm, SP_OK));
9950 aarch64_set_mem_u64 (cpu, address + 8,
9951 aarch64_get_reg_u64 (cpu, rn, SP_OK));
9952
9953 if (wb == Post)
9954 address += offset;
9955
9956 if (wb != NoWriteBack)
9957 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9958}
9959
9960static void
9961load_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9962{
9963 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9964 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9965 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9966 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9967
9968 /* treat this as unalloc to make sure we don't do it. */
9969 if (rn == rm)
9970 HALT_UNALLOC;
9971
9972 offset <<= 2;
9973
9974 if (wb != Post)
9975 address += offset;
9976
9977 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u32 (cpu, address));
9978 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u32 (cpu, address + 4));
9979
9980 if (wb == Post)
9981 address += offset;
9982
9983 if (wb != NoWriteBack)
9984 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9985}
9986
9987static void
9988load_pair_s32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9989{
9990 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9991 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9992 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9993 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9994
9995 /* Treat this as unalloc to make sure we don't do it. */
9996 if (rn == rm)
9997 HALT_UNALLOC;
9998
9999 offset <<= 2;
10000
10001 if (wb != Post)
10002 address += offset;
10003
10004 aarch64_set_reg_s64 (cpu, rm, SP_OK, aarch64_get_mem_s32 (cpu, address));
10005 aarch64_set_reg_s64 (cpu, rn, SP_OK, aarch64_get_mem_s32 (cpu, address + 4));
10006
10007 if (wb == Post)
10008 address += offset;
10009
10010 if (wb != NoWriteBack)
10011 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10012}
10013
10014static void
10015load_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10016{
10017 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10018 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10019 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10020 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10021
10022 /* Treat this as unalloc to make sure we don't do it. */
10023 if (rn == rm)
10024 HALT_UNALLOC;
10025
10026 offset <<= 3;
10027
10028 if (wb != Post)
10029 address += offset;
10030
10031 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u64 (cpu, address));
10032 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u64 (cpu, address + 8));
10033
10034 if (wb == Post)
10035 address += offset;
10036
10037 if (wb != NoWriteBack)
10038 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10039}
10040
10041static void
10042dex_load_store_pair_gr (sim_cpu *cpu)
10043{
10044 /* instr[31,30] = size (10=> 64-bit, 01=> signed 32-bit, 00=> 32-bit)
10045 instr[29,25] = instruction encoding: 101_0
10046 instr[26] = V : 1 if fp 0 if gp
10047 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10048 instr[22] = load/store (1=> load)
10049 instr[21,15] = signed, scaled, offset
10050 instr[14,10] = Rn
10051 instr[ 9, 5] = Rd
10052 instr[ 4, 0] = Rm. */
10053
10054 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 3)
10055 | uimm (aarch64_get_instr (cpu), 24, 22));
10056 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10057
10058 switch (dispatch)
10059 {
10060 case 2: store_pair_u32 (cpu, offset, Post); return;
10061 case 3: load_pair_u32 (cpu, offset, Post); return;
10062 case 4: store_pair_u32 (cpu, offset, NoWriteBack); return;
10063 case 5: load_pair_u32 (cpu, offset, NoWriteBack); return;
10064 case 6: store_pair_u32 (cpu, offset, Pre); return;
10065 case 7: load_pair_u32 (cpu, offset, Pre); return;
10066
10067 case 11: load_pair_s32 (cpu, offset, Post); return;
10068 case 13: load_pair_s32 (cpu, offset, NoWriteBack); return;
10069 case 15: load_pair_s32 (cpu, offset, Pre); return;
10070
10071 case 18: store_pair_u64 (cpu, offset, Post); return;
10072 case 19: load_pair_u64 (cpu, offset, Post); return;
10073 case 20: store_pair_u64 (cpu, offset, NoWriteBack); return;
10074 case 21: load_pair_u64 (cpu, offset, NoWriteBack); return;
10075 case 22: store_pair_u64 (cpu, offset, Pre); return;
10076 case 23: load_pair_u64 (cpu, offset, Pre); return;
10077
10078 default:
10079 HALT_UNALLOC;
10080 }
10081}
10082
10083static void
10084store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10085{
10086 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10087 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10088 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10089 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10090
10091 offset <<= 2;
10092
10093 if (wb != Post)
10094 address += offset;
10095
10096 aarch64_set_mem_float (cpu, address, aarch64_get_FP_float (cpu, rm));
10097 aarch64_set_mem_float (cpu, address + 4, aarch64_get_FP_float (cpu, rn));
10098
10099 if (wb == Post)
10100 address += offset;
10101
10102 if (wb != NoWriteBack)
10103 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10104}
10105
10106static void
10107store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10108{
10109 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10110 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10111 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10112 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10113
10114 offset <<= 3;
10115
10116 if (wb != Post)
10117 address += offset;
10118
10119 aarch64_set_mem_double (cpu, address, aarch64_get_FP_double (cpu, rm));
10120 aarch64_set_mem_double (cpu, address + 8, aarch64_get_FP_double (cpu, rn));
10121
10122 if (wb == Post)
10123 address += offset;
10124
10125 if (wb != NoWriteBack)
10126 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10127}
10128
10129static void
10130store_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10131{
10132 FRegister a;
10133 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10134 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10135 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10136 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10137
10138 offset <<= 4;
10139
10140 if (wb != Post)
10141 address += offset;
10142
10143 aarch64_get_FP_long_double (cpu, rm, & a);
10144 aarch64_set_mem_long_double (cpu, address, a);
10145 aarch64_get_FP_long_double (cpu, rn, & a);
10146 aarch64_set_mem_long_double (cpu, address + 16, a);
10147
10148 if (wb == Post)
10149 address += offset;
10150
10151 if (wb != NoWriteBack)
10152 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10153}
10154
10155static void
10156load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10157{
10158 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10159 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10160 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10161 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10162
10163 if (rm == rn)
10164 HALT_UNALLOC;
10165
10166 offset <<= 2;
10167
10168 if (wb != Post)
10169 address += offset;
10170
10171 aarch64_set_FP_float (cpu, rm, aarch64_get_mem_float (cpu, address));
10172 aarch64_set_FP_float (cpu, rn, aarch64_get_mem_float (cpu, address + 4));
10173
10174 if (wb == Post)
10175 address += offset;
10176
10177 if (wb != NoWriteBack)
10178 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10179}
10180
10181static void
10182load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10183{
10184 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10185 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10186 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10187 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10188
10189 if (rm == rn)
10190 HALT_UNALLOC;
10191
10192 offset <<= 3;
10193
10194 if (wb != Post)
10195 address += offset;
10196
10197 aarch64_set_FP_double (cpu, rm, aarch64_get_mem_double (cpu, address));
10198 aarch64_set_FP_double (cpu, rn, aarch64_get_mem_double (cpu, address + 8));
10199
10200 if (wb == Post)
10201 address += offset;
10202
10203 if (wb != NoWriteBack)
10204 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10205}
10206
10207static void
10208load_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10209{
10210 FRegister a;
10211 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10212 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10213 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10214 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10215
10216 if (rm == rn)
10217 HALT_UNALLOC;
10218
10219 offset <<= 4;
10220
10221 if (wb != Post)
10222 address += offset;
10223
10224 aarch64_get_mem_long_double (cpu, address, & a);
10225 aarch64_set_FP_long_double (cpu, rm, a);
10226 aarch64_get_mem_long_double (cpu, address + 16, & a);
10227 aarch64_set_FP_long_double (cpu, rn, a);
10228
10229 if (wb == Post)
10230 address += offset;
10231
10232 if (wb != NoWriteBack)
10233 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10234}
10235
10236static void
10237dex_load_store_pair_fp (sim_cpu *cpu)
10238{
10239 /* instr[31,30] = size (10=> 128-bit, 01=> 64-bit, 00=> 32-bit)
10240 instr[29,25] = instruction encoding
10241 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10242 instr[22] = load/store (1=> load)
10243 instr[21,15] = signed, scaled, offset
10244 instr[14,10] = Rn
10245 instr[ 9, 5] = Rd
10246 instr[ 4, 0] = Rm */
10247
10248 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 3)
10249 | uimm (aarch64_get_instr (cpu), 24, 22));
10250 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10251
10252 switch (dispatch)
10253 {
10254 case 2: store_pair_float (cpu, offset, Post); return;
10255 case 3: load_pair_float (cpu, offset, Post); return;
10256 case 4: store_pair_float (cpu, offset, NoWriteBack); return;
10257 case 5: load_pair_float (cpu, offset, NoWriteBack); return;
10258 case 6: store_pair_float (cpu, offset, Pre); return;
10259 case 7: load_pair_float (cpu, offset, Pre); return;
10260
10261 case 10: store_pair_double (cpu, offset, Post); return;
10262 case 11: load_pair_double (cpu, offset, Post); return;
10263 case 12: store_pair_double (cpu, offset, NoWriteBack); return;
10264 case 13: load_pair_double (cpu, offset, NoWriteBack); return;
10265 case 14: store_pair_double (cpu, offset, Pre); return;
10266 case 15: load_pair_double (cpu, offset, Pre); return;
10267
10268 case 18: store_pair_long_double (cpu, offset, Post); return;
10269 case 19: load_pair_long_double (cpu, offset, Post); return;
10270 case 20: store_pair_long_double (cpu, offset, NoWriteBack); return;
10271 case 21: load_pair_long_double (cpu, offset, NoWriteBack); return;
10272 case 22: store_pair_long_double (cpu, offset, Pre); return;
10273 case 23: load_pair_long_double (cpu, offset, Pre); return;
10274
10275 default:
10276 HALT_UNALLOC;
10277 }
10278}
10279
10280static inline unsigned
10281vec_reg (unsigned v, unsigned o)
10282{
10283 return (v + o) & 0x3F;
10284}
10285
10286/* Load multiple N-element structures to N consecutive registers. */
10287static void
10288vec_load (sim_cpu *cpu, uint64_t address, unsigned N)
10289{
10290 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10291 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10292 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10293 unsigned i;
10294
10295 switch (size)
10296 {
10297 case 0: /* 8-bit operations. */
10298 if (all)
10299 for (i = 0; i < (16 * N); i++)
10300 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15,
10301 aarch64_get_mem_u8 (cpu, address + i));
10302 else
10303 for (i = 0; i < (8 * N); i++)
10304 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7,
10305 aarch64_get_mem_u8 (cpu, address + i));
10306 return;
10307
10308 case 1: /* 16-bit operations. */
10309 if (all)
10310 for (i = 0; i < (8 * N); i++)
10311 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7,
10312 aarch64_get_mem_u16 (cpu, address + i * 2));
10313 else
10314 for (i = 0; i < (4 * N); i++)
10315 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3,
10316 aarch64_get_mem_u16 (cpu, address + i * 2));
10317 return;
10318
10319 case 2: /* 32-bit operations. */
10320 if (all)
10321 for (i = 0; i < (4 * N); i++)
10322 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3,
10323 aarch64_get_mem_u32 (cpu, address + i * 4));
10324 else
10325 for (i = 0; i < (2 * N); i++)
10326 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1,
10327 aarch64_get_mem_u32 (cpu, address + i * 4));
10328 return;
10329
10330 case 3: /* 64-bit operations. */
10331 if (all)
10332 for (i = 0; i < (2 * N); i++)
10333 aarch64_set_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1,
10334 aarch64_get_mem_u64 (cpu, address + i * 8));
10335 else
10336 for (i = 0; i < N; i++)
10337 aarch64_set_vec_u64 (cpu, vec_reg (vd, i), 0,
10338 aarch64_get_mem_u64 (cpu, address + i * 8));
10339 return;
10340
10341 default:
10342 HALT_UNREACHABLE;
10343 }
10344}
10345
10346/* LD4: load multiple 4-element to four consecutive registers. */
10347static void
10348LD4 (sim_cpu *cpu, uint64_t address)
10349{
10350 vec_load (cpu, address, 4);
10351}
10352
10353/* LD3: load multiple 3-element structures to three consecutive registers. */
10354static void
10355LD3 (sim_cpu *cpu, uint64_t address)
10356{
10357 vec_load (cpu, address, 3);
10358}
10359
10360/* LD2: load multiple 2-element structures to two consecutive registers. */
10361static void
10362LD2 (sim_cpu *cpu, uint64_t address)
10363{
10364 vec_load (cpu, address, 2);
10365}
10366
10367/* Load multiple 1-element structures into one register. */
10368static void
10369LD1_1 (sim_cpu *cpu, uint64_t address)
10370{
10371 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10372 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10373 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10374 unsigned i;
10375
10376 switch (size)
10377 {
10378 case 0:
10379 /* LD1 {Vd.16b}, addr, #16 */
10380 /* LD1 {Vd.8b}, addr, #8 */
10381 for (i = 0; i < (all ? 16 : 8); i++)
10382 aarch64_set_vec_u8 (cpu, vd, i,
10383 aarch64_get_mem_u8 (cpu, address + i));
10384 return;
10385
10386 case 1:
10387 /* LD1 {Vd.8h}, addr, #16 */
10388 /* LD1 {Vd.4h}, addr, #8 */
10389 for (i = 0; i < (all ? 8 : 4); i++)
10390 aarch64_set_vec_u16 (cpu, vd, i,
10391 aarch64_get_mem_u16 (cpu, address + i * 2));
10392 return;
10393
10394 case 2:
10395 /* LD1 {Vd.4s}, addr, #16 */
10396 /* LD1 {Vd.2s}, addr, #8 */
10397 for (i = 0; i < (all ? 4 : 2); i++)
10398 aarch64_set_vec_u32 (cpu, vd, i,
10399 aarch64_get_mem_u32 (cpu, address + i * 4));
10400 return;
10401
10402 case 3:
10403 /* LD1 {Vd.2d}, addr, #16 */
10404 /* LD1 {Vd.1d}, addr, #8 */
10405 for (i = 0; i < (all ? 2 : 1); i++)
10406 aarch64_set_vec_u64 (cpu, vd, i,
10407 aarch64_get_mem_u64 (cpu, address + i * 8));
10408 return;
10409
10410 default:
10411 HALT_UNREACHABLE;
10412 }
10413}
10414
10415/* Load multiple 1-element structures into two registers. */
10416static void
10417LD1_2 (sim_cpu *cpu, uint64_t address)
10418{
10419 /* FIXME: This algorithm is *exactly* the same as the LD2 version.
10420 So why have two different instructions ? There must be something
10421 wrong somewhere. */
10422 vec_load (cpu, address, 2);
10423}
10424
10425/* Load multiple 1-element structures into three registers. */
10426static void
10427LD1_3 (sim_cpu *cpu, uint64_t address)
10428{
10429 /* FIXME: This algorithm is *exactly* the same as the LD3 version.
10430 So why have two different instructions ? There must be something
10431 wrong somewhere. */
10432 vec_load (cpu, address, 3);
10433}
10434
10435/* Load multiple 1-element structures into four registers. */
10436static void
10437LD1_4 (sim_cpu *cpu, uint64_t address)
10438{
10439 /* FIXME: This algorithm is *exactly* the same as the LD4 version.
10440 So why have two different instructions ? There must be something
10441 wrong somewhere. */
10442 vec_load (cpu, address, 4);
10443}
10444
10445/* Store multiple N-element structures to N consecutive registers. */
10446static void
10447vec_store (sim_cpu *cpu, uint64_t address, unsigned N)
10448{
10449 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10450 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10451 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10452 unsigned i;
10453
10454 switch (size)
10455 {
10456 case 0: /* 8-bit operations. */
10457 if (all)
10458 for (i = 0; i < (16 * N); i++)
10459 aarch64_set_mem_u8
10460 (cpu, address + i,
10461 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15));
10462 else
10463 for (i = 0; i < (8 * N); i++)
10464 aarch64_set_mem_u8
10465 (cpu, address + i,
10466 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7));
10467 return;
10468
10469 case 1: /* 16-bit operations. */
10470 if (all)
10471 for (i = 0; i < (8 * N); i++)
10472 aarch64_set_mem_u16
10473 (cpu, address + i * 2,
10474 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7));
10475 else
10476 for (i = 0; i < (4 * N); i++)
10477 aarch64_set_mem_u16
10478 (cpu, address + i * 2,
10479 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3));
10480 return;
10481
10482 case 2: /* 32-bit operations. */
10483 if (all)
10484 for (i = 0; i < (4 * N); i++)
10485 aarch64_set_mem_u32
10486 (cpu, address + i * 4,
10487 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3));
10488 else
10489 for (i = 0; i < (2 * N); i++)
10490 aarch64_set_mem_u32
10491 (cpu, address + i * 4,
10492 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1));
10493 return;
10494
10495 case 3: /* 64-bit operations. */
10496 if (all)
10497 for (i = 0; i < (2 * N); i++)
10498 aarch64_set_mem_u64
10499 (cpu, address + i * 8,
10500 aarch64_get_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1));
10501 else
10502 for (i = 0; i < N; i++)
10503 aarch64_set_mem_u64
10504 (cpu, address + i * 8,
10505 aarch64_get_vec_u64 (cpu, vec_reg (vd, i), 0));
10506 return;
10507
10508 default:
10509 HALT_UNREACHABLE;
10510 }
10511}
10512
10513/* Store multiple 4-element structure to four consecutive registers. */
10514static void
10515ST4 (sim_cpu *cpu, uint64_t address)
10516{
10517 vec_store (cpu, address, 4);
10518}
10519
10520/* Store multiple 3-element structures to three consecutive registers. */
10521static void
10522ST3 (sim_cpu *cpu, uint64_t address)
10523{
10524 vec_store (cpu, address, 3);
10525}
10526
10527/* Store multiple 2-element structures to two consecutive registers. */
10528static void
10529ST2 (sim_cpu *cpu, uint64_t address)
10530{
10531 vec_store (cpu, address, 2);
10532}
10533
10534/* Store multiple 1-element structures into one register. */
10535static void
10536ST1_1 (sim_cpu *cpu, uint64_t address)
10537{
10538 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10539 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10540 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10541 unsigned i;
10542
10543 switch (size)
10544 {
10545 case 0:
10546 for (i = 0; i < (all ? 16 : 8); i++)
10547 aarch64_set_mem_u8 (cpu, address + i,
10548 aarch64_get_vec_u8 (cpu, vd, i));
10549 return;
10550
10551 case 1:
10552 for (i = 0; i < (all ? 8 : 4); i++)
10553 aarch64_set_mem_u16 (cpu, address + i * 2,
10554 aarch64_get_vec_u16 (cpu, vd, i));
10555 return;
10556
10557 case 2:
10558 for (i = 0; i < (all ? 4 : 2); i++)
10559 aarch64_set_mem_u32 (cpu, address + i * 4,
10560 aarch64_get_vec_u32 (cpu, vd, i));
10561 return;
10562
10563 case 3:
10564 for (i = 0; i < (all ? 2 : 1); i++)
10565 aarch64_set_mem_u64 (cpu, address + i * 8,
10566 aarch64_get_vec_u64 (cpu, vd, i));
10567 return;
10568
10569 default:
10570 HALT_UNREACHABLE;
10571 }
10572}
10573
10574/* Store multiple 1-element structures into two registers. */
10575static void
10576ST1_2 (sim_cpu *cpu, uint64_t address)
10577{
10578 /* FIXME: This algorithm is *exactly* the same as the ST2 version.
10579 So why have two different instructions ? There must be
10580 something wrong somewhere. */
10581 vec_store (cpu, address, 2);
10582}
10583
10584/* Store multiple 1-element structures into three registers. */
10585static void
10586ST1_3 (sim_cpu *cpu, uint64_t address)
10587{
10588 /* FIXME: This algorithm is *exactly* the same as the ST3 version.
10589 So why have two different instructions ? There must be
10590 something wrong somewhere. */
10591 vec_store (cpu, address, 3);
10592}
10593
10594/* Store multiple 1-element structures into four registers. */
10595static void
10596ST1_4 (sim_cpu *cpu, uint64_t address)
10597{
10598 /* FIXME: This algorithm is *exactly* the same as the ST4 version.
10599 So why have two different instructions ? There must be
10600 something wrong somewhere. */
10601 vec_store (cpu, address, 4);
10602}
10603
10604static void
10605do_vec_LDnR (sim_cpu *cpu, uint64_t address)
10606{
10607 /* instr[31] = 0
10608 instr[30] = element selector 0=>half, 1=>all elements
10609 instr[29,24] = 00 1101
10610 instr[23] = 0=>simple, 1=>post
10611 instr[22] = 1
10612 instr[21] = width: LD1R-or-LD3R (0) / LD2R-or-LD4R (1)
10613 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
10614 11111 (immediate post inc)
10615 instr[15,14] = 11
10616 instr[13] = width: LD1R-or-LD2R (0) / LD3R-or-LD4R (1)
10617 instr[12] = 0
10618 instr[11,10] = element size 00=> byte(b), 01=> half(h),
10619 10=> word(s), 11=> double(d)
10620 instr[9,5] = address
10621 instr[4,0] = Vd */
10622
10623 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
10624 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10625 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10626 int i;
10627
10628 NYI_assert (29, 24, 0x0D);
10629 NYI_assert (22, 22, 1);
10630 NYI_assert (15, 14, 3);
10631 NYI_assert (12, 12, 0);
10632
10633 switch ((uimm (aarch64_get_instr (cpu), 13, 13) << 1)
10634 | uimm (aarch64_get_instr (cpu), 21, 21))
10635 {
10636 case 0: /* LD1R. */
10637 switch (size)
10638 {
10639 case 0:
10640 {
10641 uint8_t val = aarch64_get_mem_u8 (cpu, address);
10642 for (i = 0; i < (full ? 16 : 8); i++)
10643 aarch64_set_vec_u8 (cpu, vd, i, val);
10644 break;
10645 }
10646
10647 case 1:
10648 {
10649 uint16_t val = aarch64_get_mem_u16 (cpu, address);
10650 for (i = 0; i < (full ? 8 : 4); i++)
10651 aarch64_set_vec_u16 (cpu, vd, i, val);
10652 break;
10653 }
10654
10655 case 2:
10656 {
10657 uint32_t val = aarch64_get_mem_u32 (cpu, address);
10658 for (i = 0; i < (full ? 4 : 2); i++)
10659 aarch64_set_vec_u32 (cpu, vd, i, val);
10660 break;
10661 }
10662
10663 case 3:
10664 {
10665 uint64_t val = aarch64_get_mem_u64 (cpu, address);
10666 for (i = 0; i < (full ? 2 : 1); i++)
10667 aarch64_set_vec_u64 (cpu, vd, i, val);
10668 break;
10669 }
10670
10671 default:
10672 HALT_UNALLOC;
10673 }
10674 break;
10675
10676 case 1: /* LD2R. */
10677 switch (size)
10678 {
10679 case 0:
10680 {
10681 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10682 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10683
10684 for (i = 0; i < (full ? 16 : 8); i++)
10685 {
10686 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10687 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10688 }
10689 break;
10690 }
10691
10692 case 1:
10693 {
10694 uint16_t val1 = aarch64_get_mem_u16 (cpu, address);
10695 uint16_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10696
10697 for (i = 0; i < (full ? 8 : 4); i++)
10698 {
10699 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10700 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10701 }
10702 break;
10703 }
10704
10705 case 2:
10706 {
10707 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10708 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10709
10710 for (i = 0; i < (full ? 4 : 2); i++)
10711 {
10712 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10713 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10714 }
10715 break;
10716 }
10717
10718 case 3:
10719 {
10720 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10721 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10722
10723 for (i = 0; i < (full ? 2 : 1); i++)
10724 {
10725 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10726 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10727 }
10728 break;
10729 }
10730
10731 default:
10732 HALT_UNALLOC;
10733 }
10734 break;
10735
10736 case 2: /* LD3R. */
10737 switch (size)
10738 {
10739 case 0:
10740 {
10741 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10742 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10743 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
10744
10745 for (i = 0; i < (full ? 16 : 8); i++)
10746 {
10747 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10748 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10749 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
10750 }
10751 }
10752 break;
10753
10754 case 1:
10755 {
10756 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
10757 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10758 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
10759
10760 for (i = 0; i < (full ? 8 : 4); i++)
10761 {
10762 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10763 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10764 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
10765 }
10766 }
10767 break;
10768
10769 case 2:
10770 {
10771 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10772 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10773 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
10774
10775 for (i = 0; i < (full ? 4 : 2); i++)
10776 {
10777 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10778 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10779 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
10780 }
10781 }
10782 break;
10783
10784 case 3:
10785 {
10786 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10787 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10788 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
10789
10790 for (i = 0; i < (full ? 2 : 1); i++)
10791 {
10792 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10793 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10794 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
10795 }
10796 }
10797 break;
10798
10799 default:
10800 HALT_UNALLOC;
10801 }
10802 break;
10803
10804 case 3: /* LD4R. */
10805 switch (size)
10806 {
10807 case 0:
10808 {
10809 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10810 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10811 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
10812 uint8_t val4 = aarch64_get_mem_u8 (cpu, address + 3);
10813
10814 for (i = 0; i < (full ? 16 : 8); i++)
10815 {
10816 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10817 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10818 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
10819 aarch64_set_vec_u8 (cpu, vd + 3, 0, val4);
10820 }
10821 }
10822 break;
10823
10824 case 1:
10825 {
10826 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
10827 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10828 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
10829 uint32_t val4 = aarch64_get_mem_u16 (cpu, address + 6);
10830
10831 for (i = 0; i < (full ? 8 : 4); i++)
10832 {
10833 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10834 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10835 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
10836 aarch64_set_vec_u16 (cpu, vd + 3, 0, val4);
10837 }
10838 }
10839 break;
10840
10841 case 2:
10842 {
10843 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10844 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10845 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
10846 uint32_t val4 = aarch64_get_mem_u32 (cpu, address + 12);
10847
10848 for (i = 0; i < (full ? 4 : 2); i++)
10849 {
10850 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10851 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10852 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
10853 aarch64_set_vec_u32 (cpu, vd + 3, 0, val4);
10854 }
10855 }
10856 break;
10857
10858 case 3:
10859 {
10860 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10861 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10862 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
10863 uint64_t val4 = aarch64_get_mem_u64 (cpu, address + 24);
10864
10865 for (i = 0; i < (full ? 2 : 1); i++)
10866 {
10867 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10868 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10869 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
10870 aarch64_set_vec_u64 (cpu, vd + 3, 0, val4);
10871 }
10872 }
10873 break;
10874
10875 default:
10876 HALT_UNALLOC;
10877 }
10878 break;
10879
10880 default:
10881 HALT_UNALLOC;
10882 }
10883}
10884
10885static void
10886do_vec_load_store (sim_cpu *cpu)
10887{
10888 /* {LD|ST}<N> {Vd..Vd+N}, vaddr
10889
10890 instr[31] = 0
10891 instr[30] = element selector 0=>half, 1=>all elements
10892 instr[29,25] = 00110
10893 instr[24] = ?
10894 instr[23] = 0=>simple, 1=>post
10895 instr[22] = 0=>store, 1=>load
10896 instr[21] = 0 (LDn) / small(0)-large(1) selector (LDnR)
10897 instr[20,16] = 00000 (simple), Vinc (reg-post-inc, no SP),
10898 11111 (immediate post inc)
10899 instr[15,12] = elements and destinations. eg for load:
10900 0000=>LD4 => load multiple 4-element to
10901 four consecutive registers
10902 0100=>LD3 => load multiple 3-element to
10903 three consecutive registers
10904 1000=>LD2 => load multiple 2-element to
10905 two consecutive registers
10906 0010=>LD1 => load multiple 1-element to
10907 four consecutive registers
10908 0110=>LD1 => load multiple 1-element to
10909 three consecutive registers
10910 1010=>LD1 => load multiple 1-element to
10911 two consecutive registers
10912 0111=>LD1 => load multiple 1-element to
10913 one register
10914 1100=>LDR1,LDR2
10915 1110=>LDR3,LDR4
10916 instr[11,10] = element size 00=> byte(b), 01=> half(h),
10917 10=> word(s), 11=> double(d)
10918 instr[9,5] = Vn, can be SP
10919 instr[4,0] = Vd */
10920
10921 int post;
10922 int load;
10923 unsigned vn;
10924 uint64_t address;
10925 int type;
10926
10927 if (uimm (aarch64_get_instr (cpu), 31, 31) != 0
10928 || uimm (aarch64_get_instr (cpu), 29, 25) != 0x06)
10929 HALT_NYI;
10930
10931 type = uimm (aarch64_get_instr (cpu), 15, 12);
10932 if (type != 0xE && type != 0xE && uimm (aarch64_get_instr (cpu), 21, 21) != 0)
10933 HALT_NYI;
10934
10935 post = uimm (aarch64_get_instr (cpu), 23, 23);
10936 load = uimm (aarch64_get_instr (cpu), 22, 22);
10937 vn = uimm (aarch64_get_instr (cpu), 9, 5);
10938 address = aarch64_get_reg_u64 (cpu, vn, SP_OK);
10939
10940 if (post)
10941 {
10942 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
10943
10944 if (vm == R31)
10945 {
10946 unsigned sizeof_operation;
10947
10948 switch (type)
10949 {
10950 case 0: sizeof_operation = 32; break;
10951 case 4: sizeof_operation = 24; break;
10952 case 8: sizeof_operation = 16; break;
10953
10954 case 0xC:
10955 sizeof_operation = uimm (aarch64_get_instr (cpu), 21, 21) ? 2 : 1;
10956 sizeof_operation <<= uimm (aarch64_get_instr (cpu), 11, 10);
10957 break;
10958
10959 case 0xE:
10960 sizeof_operation = uimm (aarch64_get_instr (cpu), 21, 21) ? 8 : 4;
10961 sizeof_operation <<= uimm (aarch64_get_instr (cpu), 11, 10);
10962 break;
10963
2e8cf49e 10964 case 7:
57aa1742
NC
10965 /* One register, immediate offset variant. */
10966 sizeof_operation = 8;
10967 break;
10968
10969 case 10:
10970 /* Two registers, immediate offset variant. */
10971 sizeof_operation = 16;
10972 break;
10973
10974 case 6:
10975 /* Three registers, immediate offset variant. */
10976 sizeof_operation = 24;
10977 break;
10978
10979 case 2:
10980 /* Four registers, immediate offset variant. */
10981 sizeof_operation = 32;
2e8cf49e
NC
10982 break;
10983
10984 default:
10985 HALT_UNALLOC;
10986 }
10987
10988 if (uimm (aarch64_get_instr (cpu), 30, 30))
10989 sizeof_operation *= 2;
10990
10991 aarch64_set_reg_u64 (cpu, vn, SP_OK, address + sizeof_operation);
10992 }
10993 else
10994 aarch64_set_reg_u64 (cpu, vn, SP_OK,
10995 address + aarch64_get_reg_u64 (cpu, vm, NO_SP));
10996 }
10997 else
10998 {
10999 NYI_assert (20, 16, 0);
11000 }
11001
11002 if (load)
11003 {
11004 switch (type)
11005 {
11006 case 0: LD4 (cpu, address); return;
11007 case 4: LD3 (cpu, address); return;
11008 case 8: LD2 (cpu, address); return;
11009 case 2: LD1_4 (cpu, address); return;
11010 case 6: LD1_3 (cpu, address); return;
11011 case 10: LD1_2 (cpu, address); return;
11012 case 7: LD1_1 (cpu, address); return;
11013
11014 case 0xE:
11015 case 0xC: do_vec_LDnR (cpu, address); return;
11016
11017 default:
11018 HALT_NYI;
11019 }
11020 }
11021
11022 /* Stores. */
11023 switch (type)
11024 {
11025 case 0: ST4 (cpu, address); return;
11026 case 4: ST3 (cpu, address); return;
11027 case 8: ST2 (cpu, address); return;
11028 case 2: ST1_4 (cpu, address); return;
11029 case 6: ST1_3 (cpu, address); return;
11030 case 10: ST1_2 (cpu, address); return;
11031 case 7: ST1_1 (cpu, address); return;
11032 default:
11033 HALT_NYI;
11034 }
11035}
11036
11037static void
11038dexLdSt (sim_cpu *cpu)
11039{
11040 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
11041 assert group == GROUP_LDST_0100 || group == GROUP_LDST_0110 ||
11042 group == GROUP_LDST_1100 || group == GROUP_LDST_1110
11043 bits [29,28:26] of a LS are the secondary dispatch vector. */
11044 uint32_t group2 = dispatchLS (aarch64_get_instr (cpu));
11045
11046 switch (group2)
11047 {
11048 case LS_EXCL_000:
11049 dexLoadExclusive (cpu); return;
11050
11051 case LS_LIT_010:
11052 case LS_LIT_011:
11053 dexLoadLiteral (cpu); return;
11054
11055 case LS_OTHER_110:
11056 case LS_OTHER_111:
11057 dexLoadOther (cpu); return;
11058
11059 case LS_ADVSIMD_001:
11060 do_vec_load_store (cpu); return;
11061
11062 case LS_PAIR_100:
11063 dex_load_store_pair_gr (cpu); return;
11064
11065 case LS_PAIR_101:
11066 dex_load_store_pair_fp (cpu); return;
11067
11068 default:
11069 /* Should never reach here. */
11070 HALT_NYI;
11071 }
11072}
11073
11074/* Specific decode and execute for group Data Processing Register. */
11075
11076static void
11077dexLogicalShiftedRegister (sim_cpu *cpu)
11078{
11079 /* assert instr[28:24] = 01010
11080 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11081 instr[30,29:21] = op,N : 000 ==> AND, 001 ==> BIC,
11082 010 ==> ORR, 011 ==> ORN
11083 100 ==> EOR, 101 ==> EON,
11084 110 ==> ANDS, 111 ==> BICS
11085 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> ROR
11086 instr[15,10] = count : must be 0xxxxx for 32 bit
11087 instr[9,5] = Rn
11088 instr[4,0] = Rd */
11089
11090 /* unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16); */
11091 uint32_t dispatch;
11092 Shift shiftType;
11093 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
11094
11095 /* 32 bit operations must have count[5] = 0. */
11096 /* or else we have an UNALLOC. */
11097 uint32_t count = uimm (aarch64_get_instr (cpu), 15, 10);
11098
11099 if (!size && uimm (count, 5, 5))
11100 HALT_UNALLOC;
11101
11102 shiftType = shift (aarch64_get_instr (cpu), 22);
11103
11104 /* dispatch on size:op:N i.e aarch64_get_instr (cpu)[31,29:21]. */
11105 dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 29) << 1)
11106 | uimm (aarch64_get_instr (cpu), 21, 21));
11107
11108 switch (dispatch)
11109 {
11110 case 0: and32_shift (cpu, shiftType, count); return;
11111 case 1: bic32_shift (cpu, shiftType, count); return;
11112 case 2: orr32_shift (cpu, shiftType, count); return;
11113 case 3: orn32_shift (cpu, shiftType, count); return;
11114 case 4: eor32_shift (cpu, shiftType, count); return;
11115 case 5: eon32_shift (cpu, shiftType, count); return;
11116 case 6: ands32_shift (cpu, shiftType, count); return;
11117 case 7: bics32_shift (cpu, shiftType, count); return;
11118 case 8: and64_shift (cpu, shiftType, count); return;
11119 case 9: bic64_shift (cpu, shiftType, count); return;
11120 case 10:orr64_shift (cpu, shiftType, count); return;
11121 case 11:orn64_shift (cpu, shiftType, count); return;
11122 case 12:eor64_shift (cpu, shiftType, count); return;
11123 case 13:eon64_shift (cpu, shiftType, count); return;
11124 case 14:ands64_shift (cpu, shiftType, count); return;
11125 case 15:bics64_shift (cpu, shiftType, count); return;
11126 default: HALT_UNALLOC;
11127 }
11128}
11129
11130/* 32 bit conditional select. */
11131static void
11132csel32 (sim_cpu *cpu, CondCode cc)
11133{
11134 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11135 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11136 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11137
11138 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11139 testConditionCode (cpu, cc)
11140 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11141 : aarch64_get_reg_u32 (cpu, rm, NO_SP));
11142}
11143
11144/* 64 bit conditional select. */
11145static void
11146csel64 (sim_cpu *cpu, CondCode cc)
11147{
11148 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11149 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11150 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11151
11152 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11153 testConditionCode (cpu, cc)
11154 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11155 : aarch64_get_reg_u64 (cpu, rm, NO_SP));
11156}
11157
11158/* 32 bit conditional increment. */
11159static void
11160csinc32 (sim_cpu *cpu, CondCode cc)
11161{
11162 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11163 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11164 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11165
11166 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11167 testConditionCode (cpu, cc)
11168 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11169 : aarch64_get_reg_u32 (cpu, rm, NO_SP) + 1);
11170}
11171
11172/* 64 bit conditional increment. */
11173static void
11174csinc64 (sim_cpu *cpu, CondCode cc)
11175{
11176 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11177 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11178 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11179
11180 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11181 testConditionCode (cpu, cc)
11182 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11183 : aarch64_get_reg_u64 (cpu, rm, NO_SP) + 1);
11184}
11185
11186/* 32 bit conditional invert. */
11187static void
11188csinv32 (sim_cpu *cpu, CondCode cc)
11189{
11190 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11191 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11192 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11193
11194 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11195 testConditionCode (cpu, cc)
11196 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11197 : ~ aarch64_get_reg_u32 (cpu, rm, NO_SP));
11198}
11199
11200/* 64 bit conditional invert. */
11201static void
11202csinv64 (sim_cpu *cpu, CondCode cc)
11203{
11204 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11205 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11206 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11207
11208 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11209 testConditionCode (cpu, cc)
11210 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11211 : ~ aarch64_get_reg_u64 (cpu, rm, NO_SP));
11212}
11213
11214/* 32 bit conditional negate. */
11215static void
11216csneg32 (sim_cpu *cpu, CondCode cc)
11217{
11218 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11219 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11220 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11221
11222 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11223 testConditionCode (cpu, cc)
11224 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11225 : - aarch64_get_reg_u32 (cpu, rm, NO_SP));
11226}
11227
11228/* 64 bit conditional negate. */
11229static void
11230csneg64 (sim_cpu *cpu, CondCode cc)
11231{
11232 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11233 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11234 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11235
11236 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11237 testConditionCode (cpu, cc)
11238 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11239 : - aarch64_get_reg_u64 (cpu, rm, NO_SP));
11240}
11241
11242static void
11243dexCondSelect (sim_cpu *cpu)
11244{
11245 /* assert instr[28,21] = 11011011
11246 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11247 instr[30:11,10] = op : 000 ==> CSEL, 001 ==> CSINC,
11248 100 ==> CSINV, 101 ==> CSNEG,
11249 _1_ ==> UNALLOC
11250 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11251 instr[15,12] = cond
11252 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC */
11253
11254 CondCode cc;
11255 uint32_t dispatch;
11256 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11257 uint32_t op2 = uimm (aarch64_get_instr (cpu), 11, 10);
11258
11259 if (S == 1)
11260 HALT_UNALLOC;
11261
11262 if (op2 & 0x2)
11263 HALT_UNALLOC;
11264
11265 cc = condcode (aarch64_get_instr (cpu), 12);
11266 dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 1) | op2);
11267
11268 switch (dispatch)
11269 {
11270 case 0: csel32 (cpu, cc); return;
11271 case 1: csinc32 (cpu, cc); return;
11272 case 2: csinv32 (cpu, cc); return;
11273 case 3: csneg32 (cpu, cc); return;
11274 case 4: csel64 (cpu, cc); return;
11275 case 5: csinc64 (cpu, cc); return;
11276 case 6: csinv64 (cpu, cc); return;
11277 case 7: csneg64 (cpu, cc); return;
11278 default: HALT_UNALLOC;
11279 }
11280}
11281
11282/* Some helpers for counting leading 1 or 0 bits. */
11283
11284/* Counts the number of leading bits which are the same
11285 in a 32 bit value in the range 1 to 32. */
11286static uint32_t
11287leading32 (uint32_t value)
11288{
11289 int32_t mask= 0xffff0000;
11290 uint32_t count= 16; /* Counts number of bits set in mask. */
11291 uint32_t lo = 1; /* Lower bound for number of sign bits. */
11292 uint32_t hi = 32; /* Upper bound for number of sign bits. */
11293
11294 while (lo + 1 < hi)
11295 {
11296 int32_t test = (value & mask);
11297
11298 if (test == 0 || test == mask)
11299 {
11300 lo = count;
11301 count = (lo + hi) / 2;
11302 mask >>= (count - lo);
11303 }
11304 else
11305 {
11306 hi = count;
11307 count = (lo + hi) / 2;
11308 mask <<= hi - count;
11309 }
11310 }
11311
11312 if (lo != hi)
11313 {
11314 int32_t test;
11315
11316 mask >>= 1;
11317 test = (value & mask);
11318
11319 if (test == 0 || test == mask)
11320 count = hi;
11321 else
11322 count = lo;
11323 }
11324
11325 return count;
11326}
11327
11328/* Counts the number of leading bits which are the same
11329 in a 64 bit value in the range 1 to 64. */
11330static uint64_t
11331leading64 (uint64_t value)
11332{
11333 int64_t mask= 0xffffffff00000000LL;
11334 uint64_t count = 32; /* Counts number of bits set in mask. */
11335 uint64_t lo = 1; /* Lower bound for number of sign bits. */
11336 uint64_t hi = 64; /* Upper bound for number of sign bits. */
11337
11338 while (lo + 1 < hi)
11339 {
11340 int64_t test = (value & mask);
11341
11342 if (test == 0 || test == mask)
11343 {
11344 lo = count;
11345 count = (lo + hi) / 2;
11346 mask >>= (count - lo);
11347 }
11348 else
11349 {
11350 hi = count;
11351 count = (lo + hi) / 2;
11352 mask <<= hi - count;
11353 }
11354 }
11355
11356 if (lo != hi)
11357 {
11358 int64_t test;
11359
11360 mask >>= 1;
11361 test = (value & mask);
11362
11363 if (test == 0 || test == mask)
11364 count = hi;
11365 else
11366 count = lo;
11367 }
11368
11369 return count;
11370}
11371
11372/* Bit operations. */
11373/* N.B register args may not be SP. */
11374
11375/* 32 bit count leading sign bits. */
11376static void
11377cls32 (sim_cpu *cpu)
11378{
11379 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11380 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11381
11382 /* N.B. the result needs to exclude the leading bit. */
11383 aarch64_set_reg_u64
11384 (cpu, rd, NO_SP, leading32 (aarch64_get_reg_u32 (cpu, rn, NO_SP)) - 1);
11385}
11386
11387/* 64 bit count leading sign bits. */
11388static void
11389cls64 (sim_cpu *cpu)
11390{
11391 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11392 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11393
11394 /* N.B. the result needs to exclude the leading bit. */
11395 aarch64_set_reg_u64
11396 (cpu, rd, NO_SP, leading64 (aarch64_get_reg_u64 (cpu, rn, NO_SP)) - 1);
11397}
11398
11399/* 32 bit count leading zero bits. */
11400static void
11401clz32 (sim_cpu *cpu)
11402{
11403 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11404 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11405 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11406
11407 /* if the sign (top) bit is set then the count is 0. */
11408 if (pick32 (value, 31, 31))
11409 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11410 else
11411 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading32 (value));
11412}
11413
11414/* 64 bit count leading zero bits. */
11415static void
11416clz64 (sim_cpu *cpu)
11417{
11418 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11419 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11420 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11421
11422 /* if the sign (top) bit is set then the count is 0. */
11423 if (pick64 (value, 63, 63))
11424 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11425 else
11426 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading64 (value));
11427}
11428
11429/* 32 bit reverse bits. */
11430static void
11431rbit32 (sim_cpu *cpu)
11432{
11433 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11434 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11435 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11436 uint32_t result = 0;
11437 int i;
11438
11439 for (i = 0; i < 32; i++)
11440 {
11441 result <<= 1;
11442 result |= (value & 1);
11443 value >>= 1;
11444 }
11445 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11446}
11447
11448/* 64 bit reverse bits. */
11449static void
11450rbit64 (sim_cpu *cpu)
11451{
11452 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11453 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11454 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11455 uint64_t result = 0;
11456 int i;
11457
11458 for (i = 0; i < 64; i++)
11459 {
11460 result <<= 1;
57aa1742 11461 result |= (value & 1UL);
2e8cf49e
NC
11462 value >>= 1;
11463 }
11464 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11465}
11466
11467/* 32 bit reverse bytes. */
11468static void
11469rev32 (sim_cpu *cpu)
11470{
11471 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11472 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11473 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11474 uint32_t result = 0;
11475 int i;
11476
11477 for (i = 0; i < 4; i++)
11478 {
11479 result <<= 8;
11480 result |= (value & 0xff);
11481 value >>= 8;
11482 }
11483 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11484}
11485
11486/* 64 bit reverse bytes. */
11487static void
11488rev64 (sim_cpu *cpu)
11489{
11490 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11491 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11492 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11493 uint64_t result = 0;
11494 int i;
11495
11496 for (i = 0; i < 8; i++)
11497 {
11498 result <<= 8;
11499 result |= (value & 0xffULL);
11500 value >>= 8;
11501 }
11502 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11503}
11504
11505/* 32 bit reverse shorts. */
11506/* N.B.this reverses the order of the bytes in each half word. */
11507static void
11508revh32 (sim_cpu *cpu)
11509{
11510 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11511 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11512 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11513 uint32_t result = 0;
11514 int i;
11515
11516 for (i = 0; i < 2; i++)
11517 {
11518 result <<= 8;
11519 result |= (value & 0x00ff00ff);
11520 value >>= 8;
11521 }
11522 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11523}
11524
11525/* 64 bit reverse shorts. */
11526/* N.B.this reverses the order of the bytes in each half word. */
11527static void
11528revh64 (sim_cpu *cpu)
11529{
11530 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11531 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11532 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11533 uint64_t result = 0;
11534 int i;
11535
11536 for (i = 0; i < 2; i++)
11537 {
11538 result <<= 8;
11539 result |= (value & 0x00ff00ff00ff00ffULL);
11540 value >>= 8;
11541 }
11542 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11543}
11544
11545static void
11546dexDataProc1Source (sim_cpu *cpu)
11547{
11548 /* assert instr[30] == 1
11549 aarch64_get_instr (cpu)[28,21] == 111010110
11550 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11551 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11552 instr[20,16] = opcode2 : 00000 ==> ok, ow ==> UNALLOC
11553 instr[15,10] = opcode : 000000 ==> RBIT, 000001 ==> REV16,
11554 000010 ==> REV, 000011 ==> UNALLOC
11555 000100 ==> CLZ, 000101 ==> CLS
11556 ow ==> UNALLOC
11557 instr[9,5] = rn : may not be SP
11558 instr[4,0] = rd : may not be SP. */
11559
11560 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11561 uint32_t opcode2 = uimm (aarch64_get_instr (cpu), 20, 16);
11562 uint32_t opcode = uimm (aarch64_get_instr (cpu), 15, 10);
11563 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 31) << 3) | opcode);
11564
11565 if (S == 1)
11566 HALT_UNALLOC;
11567
11568 if (opcode2 != 0)
11569 HALT_UNALLOC;
11570
11571 if (opcode & 0x38)
11572 HALT_UNALLOC;
11573
11574 switch (dispatch)
11575 {
11576 case 0: rbit32 (cpu); return;
11577 case 1: revh32 (cpu); return;
11578 case 2: rev32 (cpu); return;
11579 case 4: clz32 (cpu); return;
11580 case 5: cls32 (cpu); return;
11581 case 8: rbit64 (cpu); return;
11582 case 9: revh64 (cpu); return;
11583 case 10:rev32 (cpu); return;
11584 case 11:rev64 (cpu); return;
11585 case 12:clz64 (cpu); return;
11586 case 13:cls64 (cpu); return;
11587 default: HALT_UNALLOC;
11588 }
11589}
11590
11591/* Variable shift.
11592 Shifts by count supplied in register.
11593 N.B register args may not be SP.
11594 These all use the shifted auxiliary function for
11595 simplicity and clarity. Writing the actual shift
11596 inline would avoid a branch and so be faster but
11597 would also necessitate getting signs right. */
11598
11599/* 32 bit arithmetic shift right. */
11600static void
11601asrv32 (sim_cpu *cpu)
11602{
11603 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11604 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11605 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11606
11607 aarch64_set_reg_u64
11608 (cpu, rd, NO_SP,
11609 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ASR,
11610 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11611}
11612
11613/* 64 bit arithmetic shift right. */
11614static void
11615asrv64 (sim_cpu *cpu)
11616{
11617 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11618 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11619 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11620
11621 aarch64_set_reg_u64
11622 (cpu, rd, NO_SP,
11623 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ASR,
11624 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11625}
11626
11627/* 32 bit logical shift left. */
11628static void
11629lslv32 (sim_cpu *cpu)
11630{
11631 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11632 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11633 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11634
11635 aarch64_set_reg_u64
11636 (cpu, rd, NO_SP,
11637 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSL,
11638 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11639}
11640
11641/* 64 bit arithmetic shift left. */
11642static void
11643lslv64 (sim_cpu *cpu)
11644{
11645 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11646 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11647 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11648
11649 aarch64_set_reg_u64
11650 (cpu, rd, NO_SP,
11651 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSL,
11652 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11653}
11654
11655/* 32 bit logical shift right. */
11656static void
11657lsrv32 (sim_cpu *cpu)
11658{
11659 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11660 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11661 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11662
11663 aarch64_set_reg_u64
11664 (cpu, rd, NO_SP,
11665 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSR,
11666 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11667}
11668
11669/* 64 bit logical shift right. */
11670static void
11671lsrv64 (sim_cpu *cpu)
11672{
11673 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11674 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11675 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11676
11677 aarch64_set_reg_u64
11678 (cpu, rd, NO_SP,
11679 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSR,
11680 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11681}
11682
11683/* 32 bit rotate right. */
11684static void
11685rorv32 (sim_cpu *cpu)
11686{
11687 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11688 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11689 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11690
11691 aarch64_set_reg_u64
11692 (cpu, rd, NO_SP,
11693 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ROR,
11694 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11695}
11696
11697/* 64 bit rotate right. */
11698static void
11699rorv64 (sim_cpu *cpu)
11700{
11701 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11702 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11703 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11704
11705 aarch64_set_reg_u64
11706 (cpu, rd, NO_SP,
11707 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ROR,
11708 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11709}
11710
11711
11712/* divide. */
11713
11714/* 32 bit signed divide. */
11715static void
11716cpuiv32 (sim_cpu *cpu)
11717{
11718 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11719 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11720 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11721 /* N.B. the pseudo-code does the divide using 64 bit data. */
11722 /* TODO : check that this rounds towards zero as required. */
11723 int64_t dividend = aarch64_get_reg_s32 (cpu, rn, NO_SP);
11724 int64_t divisor = aarch64_get_reg_s32 (cpu, rm, NO_SP);
11725
11726 aarch64_set_reg_s64 (cpu, rd, NO_SP,
11727 divisor ? ((int32_t) (dividend / divisor)) : 0);
11728}
11729
11730/* 64 bit signed divide. */
11731static void
11732cpuiv64 (sim_cpu *cpu)
11733{
11734 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11735 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11736 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11737
11738 /* TODO : check that this rounds towards zero as required. */
11739 int64_t divisor = aarch64_get_reg_s64 (cpu, rm, NO_SP);
11740
11741 aarch64_set_reg_s64
11742 (cpu, rd, NO_SP,
11743 divisor ? (aarch64_get_reg_s64 (cpu, rn, NO_SP) / divisor) : 0);
11744}
11745
11746/* 32 bit unsigned divide. */
11747static void
11748udiv32 (sim_cpu *cpu)
11749{
11750 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11751 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11752 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11753
11754 /* N.B. the pseudo-code does the divide using 64 bit data. */
11755 uint64_t dividend = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11756 uint64_t divisor = aarch64_get_reg_u32 (cpu, rm, NO_SP);
11757
11758 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11759 divisor ? (uint32_t) (dividend / divisor) : 0);
11760}
11761
11762/* 64 bit unsigned divide. */
11763static void
11764udiv64 (sim_cpu *cpu)
11765{
11766 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11767 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11768 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11769
11770 /* TODO : check that this rounds towards zero as required. */
11771 uint64_t divisor = aarch64_get_reg_u64 (cpu, rm, NO_SP);
11772
11773 aarch64_set_reg_u64
11774 (cpu, rd, NO_SP,
11775 divisor ? (aarch64_get_reg_u64 (cpu, rn, NO_SP) / divisor) : 0);
11776}
11777
11778static void
11779dexDataProc2Source (sim_cpu *cpu)
11780{
11781 /* assert instr[30] == 0
11782 instr[28,21] == 11010110
11783 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11784 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11785 instr[15,10] = opcode : 000010 ==> UDIV, 000011 ==> CPUIV,
11786 001000 ==> LSLV, 001001 ==> LSRV
11787 001010 ==> ASRV, 001011 ==> RORV
11788 ow ==> UNALLOC. */
11789
11790 uint32_t dispatch;
11791 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11792 uint32_t opcode = uimm (aarch64_get_instr (cpu), 15, 10);
11793
11794 if (S == 1)
11795 HALT_UNALLOC;
11796
11797 if (opcode & 0x34)
11798 HALT_UNALLOC;
11799
11800 dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 31) << 3)
11801 | (uimm (opcode, 3, 3) << 2)
11802 | uimm (opcode, 1, 0));
11803 switch (dispatch)
11804 {
11805 case 2: udiv32 (cpu); return;
11806 case 3: cpuiv32 (cpu); return;
11807 case 4: lslv32 (cpu); return;
11808 case 5: lsrv32 (cpu); return;
11809 case 6: asrv32 (cpu); return;
11810 case 7: rorv32 (cpu); return;
11811 case 10: udiv64 (cpu); return;
11812 case 11: cpuiv64 (cpu); return;
11813 case 12: lslv64 (cpu); return;
11814 case 13: lsrv64 (cpu); return;
11815 case 14: asrv64 (cpu); return;
11816 case 15: rorv64 (cpu); return;
11817 default: HALT_UNALLOC;
11818 }
11819}
11820
11821
11822/* Multiply. */
11823
11824/* 32 bit multiply and add. */
11825static void
11826madd32 (sim_cpu *cpu)
11827{
11828 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11829 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11830 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11831 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11832
11833 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11834 aarch64_get_reg_u32 (cpu, ra, NO_SP)
11835 + aarch64_get_reg_u32 (cpu, rn, NO_SP)
11836 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
11837}
11838
11839/* 64 bit multiply and add. */
11840static void
11841madd64 (sim_cpu *cpu)
11842{
11843 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11844 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11845 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11846 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11847
11848 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11849 aarch64_get_reg_u64 (cpu, ra, NO_SP)
11850 + aarch64_get_reg_u64 (cpu, rn, NO_SP)
11851 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
11852}
11853
11854/* 32 bit multiply and sub. */
11855static void
11856msub32 (sim_cpu *cpu)
11857{
11858 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11859 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11860 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11861 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11862
11863 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11864 aarch64_get_reg_u32 (cpu, ra, NO_SP)
11865 - aarch64_get_reg_u32 (cpu, rn, NO_SP)
11866 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
11867}
11868
11869/* 64 bit multiply and sub. */
11870static void
11871msub64 (sim_cpu *cpu)
11872{
11873 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11874 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11875 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11876 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11877
11878 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11879 aarch64_get_reg_u64 (cpu, ra, NO_SP)
11880 - aarch64_get_reg_u64 (cpu, rn, NO_SP)
11881 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
11882}
11883
11884/* Signed multiply add long -- source, source2 : 32 bit, source3 : 64 bit. */
11885static void
11886smaddl (sim_cpu *cpu)
11887{
11888 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11889 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11890 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11891 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11892
11893 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
11894 obtain a 64 bit product. */
11895 aarch64_set_reg_s64
11896 (cpu, rd, NO_SP,
11897 aarch64_get_reg_s64 (cpu, ra, NO_SP)
11898 + ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
11899 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
11900}
11901
11902/* Signed multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
11903static void
11904smsubl (sim_cpu *cpu)
11905{
11906 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11907 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11908 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11909 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11910
11911 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
11912 obtain a 64 bit product. */
11913 aarch64_set_reg_s64
11914 (cpu, rd, NO_SP,
11915 aarch64_get_reg_s64 (cpu, ra, NO_SP)
11916 - ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
11917 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
11918}
11919
11920/* Integer Multiply/Divide. */
11921
11922/* First some macros and a helper function. */
11923/* Macros to test or access elements of 64 bit words. */
11924
11925/* Mask used to access lo 32 bits of 64 bit unsigned int. */
11926#define LOW_WORD_MASK ((1ULL << 32) - 1)
11927/* Return the lo 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
11928#define lowWordToU64(_value_u64) ((_value_u64) & LOW_WORD_MASK)
11929/* Return the hi 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
11930#define highWordToU64(_value_u64) ((_value_u64) >> 32)
11931
11932/* Offset of sign bit in 64 bit signed integger. */
11933#define SIGN_SHIFT_U64 63
11934/* The sign bit itself -- also identifies the minimum negative int value. */
11935#define SIGN_BIT_U64 (1UL << SIGN_SHIFT_U64)
11936/* Return true if a 64 bit signed int presented as an unsigned int is the
11937 most negative value. */
11938#define isMinimumU64(_value_u64) ((_value_u64) == SIGN_BIT_U64)
11939/* Return true (non-zero) if a 64 bit signed int presented as an unsigned
11940 int has its sign bit set to false. */
11941#define isSignSetU64(_value_u64) ((_value_u64) & SIGN_BIT_U64)
11942/* Return 1L or -1L according to whether a 64 bit signed int presented as
11943 an unsigned int has its sign bit set or not. */
11944#define signOfU64(_value_u64) (1L + (((value_u64) >> SIGN_SHIFT_U64) * -2L)
11945/* Clear the sign bit of a 64 bit signed int presented as an unsigned int. */
11946#define clearSignU64(_value_u64) ((_value_u64) &= ~SIGN_BIT_U64)
11947
11948/* Multiply two 64 bit ints and return.
11949 the hi 64 bits of the 128 bit product. */
11950
11951static uint64_t
11952mul64hi (uint64_t value1, uint64_t value2)
11953{
11954 uint64_t resultmid1;
11955 uint64_t result;
11956 uint64_t value1_lo = lowWordToU64 (value1);
11957 uint64_t value1_hi = highWordToU64 (value1) ;
11958 uint64_t value2_lo = lowWordToU64 (value2);
11959 uint64_t value2_hi = highWordToU64 (value2);
11960
11961 /* Cross-multiply and collect results. */
11962
11963 uint64_t xproductlo = value1_lo * value2_lo;
11964 uint64_t xproductmid1 = value1_lo * value2_hi;
11965 uint64_t xproductmid2 = value1_hi * value2_lo;
11966 uint64_t xproducthi = value1_hi * value2_hi;
11967 uint64_t carry = 0;
11968 /* Start accumulating 64 bit results. */
11969 /* Drop bottom half of lowest cross-product. */
11970 uint64_t resultmid = xproductlo >> 32;
11971 /* Add in middle products. */
11972 resultmid = resultmid + xproductmid1;
11973
11974 /* Check for overflow. */
11975 if (resultmid < xproductmid1)
11976 /* Carry over 1 into top cross-product. */
11977 carry++;
11978
11979 resultmid1 = resultmid + xproductmid2;
11980
11981 /* Check for overflow. */
11982 if (resultmid1 < xproductmid2)
11983 /* Carry over 1 into top cross-product. */
11984 carry++;
11985
11986 /* Drop lowest 32 bits of middle cross-product. */
11987 result = resultmid1 >> 32;
11988
11989 /* Add top cross-product plus and any carry. */
11990 result += xproducthi + carry;
11991
11992 return result;
11993}
11994
11995/* Signed multiply high, source, source2 :
11996 64 bit, dest <-- high 64-bit of result. */
11997static void
11998smulh (sim_cpu *cpu)
11999{
12000 uint64_t uresult;
12001 int64_t result;
12002 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12003 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12004 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12005 GReg ra = greg (aarch64_get_instr (cpu), 10);
12006 int64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
12007 int64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
12008 uint64_t uvalue1;
12009 uint64_t uvalue2;
12010 int64_t signum = 1;
12011
12012 if (ra != R31)
12013 HALT_UNALLOC;
12014
12015 /* Convert to unsigned and use the unsigned mul64hi routine
12016 the fix the sign up afterwards. */
12017 if (value1 < 0)
12018 {
12019 signum *= -1L;
12020 uvalue1 = -value1;
12021 }
12022 else
12023 {
12024 uvalue1 = value1;
12025 }
12026
12027 if (value2 < 0)
12028 {
12029 signum *= -1L;
12030 uvalue2 = -value2;
12031 }
12032 else
12033 {
12034 uvalue2 = value2;
12035 }
12036
12037 uresult = mul64hi (uvalue1, uvalue2);
12038 result = uresult;
12039 result *= signum;
12040
12041 aarch64_set_reg_s64 (cpu, rd, NO_SP, result);
12042}
12043
12044/* Unsigned multiply add long -- source, source2 :
12045 32 bit, source3 : 64 bit. */
12046static void
12047umaddl (sim_cpu *cpu)
12048{
12049 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12050 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
12051 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12052 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12053
12054 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12055 obtain a 64 bit product. */
12056 aarch64_set_reg_u64
12057 (cpu, rd, NO_SP,
12058 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12059 + ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12060 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12061}
12062
12063/* Unsigned multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12064static void
12065umsubl (sim_cpu *cpu)
12066{
12067 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12068 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
12069 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12070 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12071
12072 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12073 obtain a 64 bit product. */
12074 aarch64_set_reg_u64
12075 (cpu, rd, NO_SP,
12076 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12077 - ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12078 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12079}
12080
12081/* Unsigned multiply high, source, source2 :
12082 64 bit, dest <-- high 64-bit of result. */
12083static void
12084umulh (sim_cpu *cpu)
12085{
12086 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12087 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12088 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12089 GReg ra = greg (aarch64_get_instr (cpu), 10);
12090
12091 if (ra != R31)
12092 HALT_UNALLOC;
12093
12094 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12095 mul64hi (aarch64_get_reg_u64 (cpu, rn, NO_SP),
12096 aarch64_get_reg_u64 (cpu, rm, NO_SP)));
12097}
12098
12099static void
12100dexDataProc3Source (sim_cpu *cpu)
12101{
12102 /* assert instr[28,24] == 11011. */
12103 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit (for rd at least)
12104 instr[30,29] = op54 : 00 ==> ok, ow ==> UNALLOC
12105 instr[23,21] = op31 : 111 ==> UNALLOC, o2 ==> ok
12106 instr[15] = o0 : 0/1 ==> ok
12107 instr[23,21:15] ==> op : 0000 ==> MADD, 0001 ==> MSUB, (32/64 bit)
12108 0010 ==> SMADDL, 0011 ==> SMSUBL, (64 bit only)
12109 0100 ==> SMULH, (64 bit only)
12110 1010 ==> UMADDL, 1011 ==> UNSUBL, (64 bit only)
12111 1100 ==> UMULH (64 bit only)
12112 ow ==> UNALLOC. */
12113
12114 uint32_t dispatch;
12115 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
12116 uint32_t op54 = uimm (aarch64_get_instr (cpu), 30, 29);
12117 uint32_t op31 = uimm (aarch64_get_instr (cpu), 23, 21);
12118 uint32_t o0 = uimm (aarch64_get_instr (cpu), 15, 15);
12119
12120 if (op54 != 0)
12121 HALT_UNALLOC;
12122
12123 if (size == 0)
12124 {
12125 if (op31 != 0)
12126 HALT_UNALLOC;
12127
12128 if (o0 == 0)
12129 madd32 (cpu);
12130 else
12131 msub32 (cpu);
12132 return;
12133 }
12134
12135 dispatch = (op31 << 1) | o0;
12136
12137 switch (dispatch)
12138 {
12139 case 0: madd64 (cpu); return;
12140 case 1: msub64 (cpu); return;
12141 case 2: smaddl (cpu); return;
12142 case 3: smsubl (cpu); return;
12143 case 4: smulh (cpu); return;
12144 case 10: umaddl (cpu); return;
12145 case 11: umsubl (cpu); return;
12146 case 12: umulh (cpu); return;
12147 default: HALT_UNALLOC;
12148 }
12149}
12150
12151static void
12152dexDPReg (sim_cpu *cpu)
12153{
12154 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12155 assert group == GROUP_DPREG_0101 || group == GROUP_DPREG_1101
12156 bits [28:24:21] of a DPReg are the secondary dispatch vector. */
12157 uint32_t group2 = dispatchDPReg (aarch64_get_instr (cpu));
12158
12159 switch (group2)
12160 {
12161 case DPREG_LOG_000:
12162 case DPREG_LOG_001:
12163 dexLogicalShiftedRegister (cpu); return;
12164
12165 case DPREG_ADDSHF_010:
12166 dexAddSubtractShiftedRegister (cpu); return;
12167
12168 case DPREG_ADDEXT_011:
12169 dexAddSubtractExtendedRegister (cpu); return;
12170
12171 case DPREG_ADDCOND_100:
12172 {
12173 /* This set bundles a variety of different operations. */
12174 /* Check for. */
12175 /* 1) add/sub w carry. */
12176 uint32_t mask1 = 0x1FE00000U;
12177 uint32_t val1 = 0x1A000000U;
12178 /* 2) cond compare register/immediate. */
12179 uint32_t mask2 = 0x1FE00000U;
12180 uint32_t val2 = 0x1A400000U;
12181 /* 3) cond select. */
12182 uint32_t mask3 = 0x1FE00000U;
12183 uint32_t val3 = 0x1A800000U;
12184 /* 4) data proc 1/2 source. */
12185 uint32_t mask4 = 0x1FE00000U;
12186 uint32_t val4 = 0x1AC00000U;
12187
12188 if ((aarch64_get_instr (cpu) & mask1) == val1)
12189 dexAddSubtractWithCarry (cpu);
12190
12191 else if ((aarch64_get_instr (cpu) & mask2) == val2)
12192 CondCompare (cpu);
12193
12194 else if ((aarch64_get_instr (cpu) & mask3) == val3)
12195 dexCondSelect (cpu);
12196
12197 else if ((aarch64_get_instr (cpu) & mask4) == val4)
12198 {
12199 /* Bit 30 is clear for data proc 2 source
12200 and set for data proc 1 source. */
12201 if (aarch64_get_instr (cpu) & (1U << 30))
12202 dexDataProc1Source (cpu);
12203 else
12204 dexDataProc2Source (cpu);
12205 }
12206
12207 else
12208 /* Should not reach here. */
12209 HALT_NYI;
12210
12211 return;
12212 }
12213
12214 case DPREG_3SRC_110:
12215 dexDataProc3Source (cpu); return;
12216
12217 case DPREG_UNALLOC_101:
12218 HALT_UNALLOC;
12219
12220 case DPREG_3SRC_111:
12221 dexDataProc3Source (cpu); return;
12222
12223 default:
12224 /* Should never reach here. */
12225 HALT_NYI;
12226 }
12227}
12228
12229/* Unconditional Branch immediate.
12230 Offset is a PC-relative byte offset in the range +/- 128MiB.
12231 The offset is assumed to be raw from the decode i.e. the
12232 simulator is expected to scale them from word offsets to byte. */
12233
12234/* Unconditional branch. */
12235static void
12236buc (sim_cpu *cpu, int32_t offset)
12237{
12238 aarch64_set_next_PC_by_offset (cpu, offset);
12239}
12240
12241static unsigned stack_depth = 0;
12242
12243/* Unconditional branch and link -- writes return PC to LR. */
12244static void
12245bl (sim_cpu *cpu, int32_t offset)
12246{
12247 aarch64_save_LR (cpu);
12248 aarch64_set_next_PC_by_offset (cpu, offset);
12249
12250 if (TRACE_BRANCH_P (cpu))
12251 {
12252 ++ stack_depth;
12253 TRACE_BRANCH (cpu,
12254 " %*scall %" PRIx64 " [%s]"
12255 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12256 stack_depth, " ", aarch64_get_next_PC (cpu),
12257 aarch64_get_func (aarch64_get_next_PC (cpu)),
12258 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12259 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12260 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12261 );
12262 }
12263}
12264
12265/* Unconditional Branch register.
12266 Branch/return address is in source register. */
12267
12268/* Unconditional branch. */
12269static void
12270br (sim_cpu *cpu)
12271{
12272 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12273 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12274}
12275
12276/* Unconditional branch and link -- writes return PC to LR. */
12277static void
12278blr (sim_cpu *cpu)
12279{
12280 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12281
12282 /* The pseudo code in the spec says we update LR before fetching.
12283 the value from the rn. */
12284 aarch64_save_LR (cpu);
12285 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12286
12287 if (TRACE_BRANCH_P (cpu))
12288 {
12289 ++ stack_depth;
12290 TRACE_BRANCH (cpu,
12291 " %*scall %" PRIx64 " [%s]"
12292 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12293 stack_depth, " ", aarch64_get_next_PC (cpu),
12294 aarch64_get_func (aarch64_get_next_PC (cpu)),
12295 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12296 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12297 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12298 );
12299 }
12300}
12301
12302/* Return -- assembler will default source to LR this is functionally
12303 equivalent to br but, presumably, unlike br it side effects the
12304 branch predictor. */
12305static void
12306ret (sim_cpu *cpu)
12307{
12308 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12309 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12310
12311 if (TRACE_BRANCH_P (cpu))
12312 {
12313 TRACE_BRANCH (cpu,
12314 " %*sreturn [result: %" PRIx64 "]",
12315 stack_depth, " ", aarch64_get_reg_u64 (cpu, 0, NO_SP));
12316 -- stack_depth;
12317 }
12318}
12319
12320/* NOP -- we implement this and call it from the decode in case we
12321 want to intercept it later. */
12322
12323static void
12324nop (sim_cpu *cpu)
12325{
12326}
12327
12328/* Data synchronization barrier. */
12329
12330static void
12331dsb (sim_cpu *cpu)
12332{
12333}
12334
12335/* Data memory barrier. */
12336
12337static void
12338dmb (sim_cpu *cpu)
12339{
12340}
12341
12342/* Instruction synchronization barrier. */
12343
12344static void
12345isb (sim_cpu *cpu)
12346{
12347}
12348
12349static void
12350dexBranchImmediate (sim_cpu *cpu)
12351{
12352 /* assert instr[30,26] == 00101
12353 instr[31] ==> 0 == B, 1 == BL
12354 instr[25,0] == imm26 branch offset counted in words. */
12355
12356 uint32_t top = uimm (aarch64_get_instr (cpu), 31, 31);
12357 /* We have a 26 byte signed word offset which we need to pass to the
12358 execute routine as a signed byte offset. */
12359 int32_t offset = simm32 (aarch64_get_instr (cpu), 25, 0) << 2;
12360
12361 if (top)
12362 bl (cpu, offset);
12363 else
12364 buc (cpu, offset);
12365}
12366
12367/* Control Flow. */
12368
12369/* Conditional branch
12370
12371 Offset is a PC-relative byte offset in the range +/- 1MiB pos is
12372 a bit position in the range 0 .. 63
12373
12374 cc is a CondCode enum value as pulled out of the decode
12375
12376 N.B. any offset register (source) can only be Xn or Wn. */
12377
12378static void
12379bcc (sim_cpu *cpu, int32_t offset, CondCode cc)
12380{
12381 /* the test returns TRUE if CC is met. */
12382 if (testConditionCode (cpu, cc))
12383 aarch64_set_next_PC_by_offset (cpu, offset);
12384}
12385
12386/* 32 bit branch on register non-zero. */
12387static void
12388cbnz32 (sim_cpu *cpu, int32_t offset)
12389{
12390 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12391
12392 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) != 0)
12393 aarch64_set_next_PC_by_offset (cpu, offset);
12394}
12395
12396/* 64 bit branch on register zero. */
12397static void
12398cbnz (sim_cpu *cpu, int32_t offset)
12399{
12400 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12401
12402 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) != 0)
12403 aarch64_set_next_PC_by_offset (cpu, offset);
12404}
12405
12406/* 32 bit branch on register non-zero. */
12407static void
12408cbz32 (sim_cpu *cpu, int32_t offset)
12409{
12410 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12411
12412 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) == 0)
12413 aarch64_set_next_PC_by_offset (cpu, offset);
12414}
12415
12416/* 64 bit branch on register zero. */
12417static void
12418cbz (sim_cpu *cpu, int32_t offset)
12419{
12420 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12421
12422 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) == 0)
12423 aarch64_set_next_PC_by_offset (cpu, offset);
12424}
12425
12426/* Branch on register bit test non-zero -- one size fits all. */
12427static void
12428tbnz (sim_cpu *cpu, uint32_t pos, int32_t offset)
12429{
12430 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12431
12432 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) & (1 << pos))
12433 aarch64_set_next_PC_by_offset (cpu, offset);
12434}
12435
12436/* branch on register bit test zero -- one size fits all. */
12437static void
12438tbz (sim_cpu *cpu, uint32_t pos, int32_t offset)
12439{
12440 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12441
12442 if (!(aarch64_get_reg_u64 (cpu, rt, NO_SP) & (1 << pos)))
12443 aarch64_set_next_PC_by_offset (cpu, offset);
12444}
12445
12446static void
12447dexCompareBranchImmediate (sim_cpu *cpu)
12448{
12449 /* instr[30,25] = 01 1010
12450 instr[31] = size : 0 ==> 32, 1 ==> 64
12451 instr[24] = op : 0 ==> CBZ, 1 ==> CBNZ
12452 instr[23,5] = simm19 branch offset counted in words
12453 instr[4,0] = rt */
12454
12455 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
12456 uint32_t op = uimm (aarch64_get_instr (cpu), 24, 24);
12457 int32_t offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
12458
12459 if (size == 0)
12460 {
12461 if (op == 0)
12462 cbz32 (cpu, offset);
12463 else
12464 cbnz32 (cpu, offset);
12465 }
12466 else
12467 {
12468 if (op == 0)
12469 cbz (cpu, offset);
12470 else
12471 cbnz (cpu, offset);
12472 }
12473}
12474
12475static void
12476dexTestBranchImmediate (sim_cpu *cpu)
12477{
12478 /* instr[31] = b5 : bit 5 of test bit idx
12479 instr[30,25] = 01 1011
12480 instr[24] = op : 0 ==> TBZ, 1 == TBNZ
12481 instr[23,19] = b40 : bits 4 to 0 of test bit idx
12482 instr[18,5] = simm14 : signed offset counted in words
12483 instr[4,0] = uimm5 */
12484
12485 uint32_t pos = ((uimm (aarch64_get_instr (cpu), 31, 31) << 4)
12486 | uimm (aarch64_get_instr (cpu), 23,19));
12487 int32_t offset = simm32 (aarch64_get_instr (cpu), 18, 5) << 2;
12488
12489 NYI_assert (30, 25, 0x1b);
12490
12491 if (uimm (aarch64_get_instr (cpu), 24, 24) == 0)
12492 tbz (cpu, pos, offset);
12493 else
12494 tbnz (cpu, pos, offset);
12495}
12496
12497static void
12498dexCondBranchImmediate (sim_cpu *cpu)
12499{
12500 /* instr[31,25] = 010 1010
12501 instr[24] = op1; op => 00 ==> B.cond
12502 instr[23,5] = simm19 : signed offset counted in words
12503 instr[4] = op0
12504 instr[3,0] = cond */
12505
12506 int32_t offset;
12507 CondCode cc;
12508 uint32_t op = ((uimm (aarch64_get_instr (cpu), 24, 24) << 1)
12509 | uimm (aarch64_get_instr (cpu), 4, 4));
12510
12511 NYI_assert (31, 25, 0x2a);
12512
12513 if (op != 0)
12514 HALT_UNALLOC;
12515
12516 offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
12517 cc = condcode (aarch64_get_instr (cpu), 0);
12518
12519 bcc (cpu, offset, cc);
12520}
12521
12522static void
12523dexBranchRegister (sim_cpu *cpu)
12524{
12525 /* instr[31,25] = 110 1011
12526 instr[24,21] = op : 0 ==> BR, 1 => BLR, 2 => RET, 3 => ERET, 4 => DRPS
12527 instr[20,16] = op2 : must be 11111
12528 instr[15,10] = op3 : must be 000000
12529 instr[4,0] = op2 : must be 11111. */
12530
12531 uint32_t op = uimm (aarch64_get_instr (cpu), 24, 21);
12532 uint32_t op2 = uimm (aarch64_get_instr (cpu), 20, 16);
12533 uint32_t op3 = uimm (aarch64_get_instr (cpu), 15, 10);
12534 uint32_t op4 = uimm (aarch64_get_instr (cpu), 4, 0);
12535
12536 NYI_assert (31, 25, 0x6b);
12537
12538 if (op2 != 0x1F || op3 != 0 || op4 != 0)
12539 HALT_UNALLOC;
12540
12541 if (op == 0)
12542 br (cpu);
12543
12544 else if (op == 1)
12545 blr (cpu);
12546
12547 else if (op == 2)
12548 ret (cpu);
12549
12550 else
12551 {
12552 /* ERET and DRPS accept 0b11111 for rn = aarch64_get_instr (cpu)[4,0]. */
12553 /* anything else is unallocated. */
12554 uint32_t rn = greg (aarch64_get_instr (cpu), 0);
12555
12556 if (rn != 0x1f)
12557 HALT_UNALLOC;
12558
12559 if (op == 4 || op == 5)
12560 HALT_NYI;
12561
12562 HALT_UNALLOC;
12563 }
12564}
12565
12566/* FIXME: We should get the Angel SWI values from ../../libgloss/aarch64/svc.h
12567 but this may not be available. So instead we define the values we need
12568 here. */
12569#define AngelSVC_Reason_Open 0x01
12570#define AngelSVC_Reason_Close 0x02
12571#define AngelSVC_Reason_Write 0x05
12572#define AngelSVC_Reason_Read 0x06
12573#define AngelSVC_Reason_IsTTY 0x09
12574#define AngelSVC_Reason_Seek 0x0A
12575#define AngelSVC_Reason_FLen 0x0C
12576#define AngelSVC_Reason_Remove 0x0E
12577#define AngelSVC_Reason_Rename 0x0F
12578#define AngelSVC_Reason_Clock 0x10
12579#define AngelSVC_Reason_Time 0x11
12580#define AngelSVC_Reason_System 0x12
12581#define AngelSVC_Reason_Errno 0x13
12582#define AngelSVC_Reason_GetCmdLine 0x15
12583#define AngelSVC_Reason_HeapInfo 0x16
12584#define AngelSVC_Reason_ReportException 0x18
12585#define AngelSVC_Reason_Elapsed 0x30
12586
12587
12588static void
12589handle_halt (sim_cpu *cpu, uint32_t val)
12590{
12591 uint64_t result = 0;
12592
12593 if (val != 0xf000)
12594 {
12595 TRACE_SYSCALL (cpu, " HLT [0x%x]", val);
12596 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12597 sim_stopped, SIM_SIGTRAP);
12598 }
12599
12600 /* We have encountered an Angel SVC call. See if we can process it. */
12601 switch (aarch64_get_reg_u32 (cpu, 0, NO_SP))
12602 {
12603 case AngelSVC_Reason_HeapInfo:
12604 {
12605 /* Get the values. */
12606 uint64_t stack_top = aarch64_get_stack_start (cpu);
12607 uint64_t heap_base = aarch64_get_heap_start (cpu);
12608
12609 /* Get the pointer */
12610 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12611 ptr = aarch64_get_mem_u64 (cpu, ptr);
12612
12613 /* Fill in the memory block. */
12614 /* Start addr of heap. */
12615 aarch64_set_mem_u64 (cpu, ptr + 0, heap_base);
12616 /* End addr of heap. */
12617 aarch64_set_mem_u64 (cpu, ptr + 8, stack_top);
12618 /* Lowest stack addr. */
12619 aarch64_set_mem_u64 (cpu, ptr + 16, heap_base);
12620 /* Initial stack addr. */
12621 aarch64_set_mem_u64 (cpu, ptr + 24, stack_top);
12622
12623 TRACE_SYSCALL (cpu, " AngelSVC: Get Heap Info");
12624 }
12625 break;
12626
12627 case AngelSVC_Reason_Open:
12628 {
12629 /* Get the pointer */
12630 /* uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);. */
12631 /* FIXME: For now we just assume that we will only be asked
12632 to open the standard file descriptors. */
12633 static int fd = 0;
12634 result = fd ++;
12635
12636 TRACE_SYSCALL (cpu, " AngelSVC: Open file %d", fd - 1);
12637 }
12638 break;
12639
12640 case AngelSVC_Reason_Close:
12641 {
12642 uint64_t fh = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12643 TRACE_SYSCALL (cpu, " AngelSVC: Close file %d", (int) fh);
12644 result = 0;
12645 }
12646 break;
12647
12648 case AngelSVC_Reason_Errno:
12649 result = 0;
12650 TRACE_SYSCALL (cpu, " AngelSVC: Get Errno");
12651 break;
12652
12653 case AngelSVC_Reason_Clock:
12654 result =
12655#ifdef CLOCKS_PER_SEC
12656 (CLOCKS_PER_SEC >= 100)
12657 ? (clock () / (CLOCKS_PER_SEC / 100))
12658 : ((clock () * 100) / CLOCKS_PER_SEC)
12659#else
12660 /* Presume unix... clock() returns microseconds. */
12661 (clock () / 10000)
12662#endif
12663 ;
12664 TRACE_SYSCALL (cpu, " AngelSVC: Get Clock");
12665 break;
12666
12667 case AngelSVC_Reason_GetCmdLine:
12668 {
12669 /* Get the pointer */
12670 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12671 ptr = aarch64_get_mem_u64 (cpu, ptr);
12672
12673 /* FIXME: No command line for now. */
12674 aarch64_set_mem_u64 (cpu, ptr, 0);
12675 TRACE_SYSCALL (cpu, " AngelSVC: Get Command Line");
12676 }
12677 break;
12678
12679 case AngelSVC_Reason_IsTTY:
12680 result = 1;
12681 TRACE_SYSCALL (cpu, " AngelSVC: IsTTY ?");
12682 break;
12683
12684 case AngelSVC_Reason_Write:
12685 {
12686 /* Get the pointer */
12687 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12688 /* Get the write control block. */
12689 uint64_t fd = aarch64_get_mem_u64 (cpu, ptr);
12690 uint64_t buf = aarch64_get_mem_u64 (cpu, ptr + 8);
12691 uint64_t len = aarch64_get_mem_u64 (cpu, ptr + 16);
12692
12693 TRACE_SYSCALL (cpu, "write of %" PRIx64 " bytes from %"
12694 PRIx64 " on descriptor %" PRIx64,
12695 len, buf, fd);
12696
12697 if (len > 1280)
12698 {
12699 TRACE_SYSCALL (cpu,
12700 " AngelSVC: Write: Suspiciously long write: %ld",
12701 (long) len);
12702 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12703 sim_stopped, SIM_SIGBUS);
12704 }
12705 else if (fd == 1)
12706 {
12707 printf ("%.*s", (int) len, aarch64_get_mem_ptr (cpu, buf));
2e8cf49e
NC
12708 }
12709 else if (fd == 2)
12710 {
12711 TRACE (cpu, 0, "\n");
12712 sim_io_eprintf (CPU_STATE (cpu), "%.*s",
12713 (int) len, aarch64_get_mem_ptr (cpu, buf));
12714 TRACE (cpu, 0, "\n");
12715 }
12716 else
12717 {
12718 TRACE_SYSCALL (cpu,
12719 " AngelSVC: Write: Unexpected file handle: %d",
12720 (int) fd);
12721 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12722 sim_stopped, SIM_SIGABRT);
12723 }
12724 }
12725 break;
12726
12727 case AngelSVC_Reason_ReportException:
12728 {
12729 /* Get the pointer */
12730 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12731 /*ptr = aarch64_get_mem_u64 (cpu, ptr);. */
12732 uint64_t type = aarch64_get_mem_u64 (cpu, ptr);
12733 uint64_t state = aarch64_get_mem_u64 (cpu, ptr + 8);
12734
12735 TRACE_SYSCALL (cpu,
12736 "Angel Exception: type 0x%" PRIx64 " state %" PRIx64,
12737 type, state);
12738
12739 if (type == 0x20026)
12740 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12741 sim_exited, state);
12742 else
12743 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12744 sim_stopped, SIM_SIGINT);
12745 }
12746 break;
12747
12748 case AngelSVC_Reason_Read:
12749 case AngelSVC_Reason_FLen:
12750 case AngelSVC_Reason_Seek:
12751 case AngelSVC_Reason_Remove:
12752 case AngelSVC_Reason_Time:
12753 case AngelSVC_Reason_System:
12754 case AngelSVC_Reason_Rename:
12755 case AngelSVC_Reason_Elapsed:
12756 default:
12757 TRACE_SYSCALL (cpu, " HLT [Unknown angel %x]",
12758 aarch64_get_reg_u32 (cpu, 0, NO_SP));
12759 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12760 sim_stopped, SIM_SIGTRAP);
12761 }
12762
12763 aarch64_set_reg_u64 (cpu, 0, NO_SP, result);
12764}
12765
12766static void
12767dexExcpnGen (sim_cpu *cpu)
12768{
12769 /* instr[31:24] = 11010100
12770 instr[23,21] = opc : 000 ==> GEN EXCPN, 001 ==> BRK
12771 010 ==> HLT, 101 ==> DBG GEN EXCPN
12772 instr[20,5] = imm16
12773 instr[4,2] = opc2 000 ==> OK, ow ==> UNALLOC
12774 instr[1,0] = LL : discriminates opc */
12775
12776 uint32_t opc = uimm (aarch64_get_instr (cpu), 23, 21);
12777 uint32_t imm16 = uimm (aarch64_get_instr (cpu), 20, 5);
12778 uint32_t opc2 = uimm (aarch64_get_instr (cpu), 4, 2);
12779 uint32_t LL;
12780
12781 NYI_assert (31, 24, 0xd4);
12782
12783 if (opc2 != 0)
12784 HALT_UNALLOC;
12785
12786 LL = uimm (aarch64_get_instr (cpu), 1, 0);
12787
12788 /* We only implement HLT and BRK for now. */
12789 if (opc == 1 && LL == 0)
12790 {
12791 TRACE_EVENTS (cpu, " BRK [0x%x]", imm16);
12792 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12793 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
12794 }
12795
12796 if (opc == 2 && LL == 0)
12797 handle_halt (cpu, imm16);
12798
12799 else if (opc == 0 || opc == 5)
12800 HALT_NYI;
12801
12802 else
12803 HALT_UNALLOC;
12804}
12805
caa8d700
NC
12806/* Stub for accessing system registers.
12807 We implement support for the DCZID register since this is used
12808 by the C library's memset function. */
12809
12810static uint64_t
12811system_get (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
12812 unsigned crm, unsigned op2)
12813{
12814 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 7)
12815 /* DCZID_EL0 - the Data Cache Zero ID register.
12816 We do not support DC ZVA at the moment, so
12817 we return a value with the disable bit set. */
12818 return ((uint64_t) 1) << 4;
12819
12820 HALT_NYI;
12821}
12822
12823static void
12824do_mrs (sim_cpu *cpu)
12825{
12826 /* instr[31:20] = 1101 01010 0011
12827 instr[19] = op0
12828 instr[18,16] = op1
12829 instr[15,12] = CRn
12830 instr[11,8] = CRm
12831 instr[7,5] = op2
12832 instr[4,0] = Rt */
12833 unsigned sys_op0 = uimm (aarch64_get_instr (cpu), 19, 19) + 2;
12834 unsigned sys_op1 = uimm (aarch64_get_instr (cpu), 18, 16);
12835 unsigned sys_crn = uimm (aarch64_get_instr (cpu), 15, 12);
12836 unsigned sys_crm = uimm (aarch64_get_instr (cpu), 11, 8);
12837 unsigned sys_op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12838 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12839
12840 aarch64_set_reg_u64 (cpu, rt, NO_SP,
12841 system_get (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2));
12842}
12843
2e8cf49e
NC
12844static void
12845dexSystem (sim_cpu *cpu)
12846{
12847 /* instr[31:22] = 1101 01010 0
12848 instr[21] = L
12849 instr[20,19] = op0
12850 instr[18,16] = op1
12851 instr[15,12] = CRn
12852 instr[11,8] = CRm
12853 instr[7,5] = op2
12854 instr[4,0] = uimm5 */
12855
12856 /* We are interested in HINT, DSB, DMB and ISB
12857
12858 Hint #0 encodes NOOP (this is the only hint we care about)
12859 L == 0, op0 == 0, op1 = 011, CRn = 0010, Rt = 11111,
12860 CRm op2 != 0000 000 OR CRm op2 == 0000 000 || CRm op > 0000 101
12861
12862 DSB, DMB, ISB are data store barrier, data memory barrier and
12863 instruction store barrier, respectively, where
12864
12865 L == 0, op0 == 0, op1 = 011, CRn = 0011, Rt = 11111,
12866 op2 : DSB ==> 100, DMB ==> 101, ISB ==> 110
12867 CRm<3:2> ==> domain, CRm<1:0> ==> types,
12868 domain : 00 ==> OuterShareable, 01 ==> Nonshareable,
12869 10 ==> InerShareable, 11 ==> FullSystem
12870 types : 01 ==> Reads, 10 ==> Writes,
12871 11 ==> All, 00 ==> All (domain == FullSystem). */
12872
12873 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12874 uint32_t l_op0_op1_crn = uimm (aarch64_get_instr (cpu), 21, 12);
12875
12876 NYI_assert (31, 22, 0x354);
12877
12878 switch (l_op0_op1_crn)
12879 {
12880 case 0x032:
12881 if (rt == 0x1F)
12882 {
12883 /* NOP has CRm != 0000 OR. */
12884 /* (CRm == 0000 AND (op2 == 000 OR op2 > 101)). */
12885 uint32_t crm = uimm (aarch64_get_instr (cpu), 11, 8);
12886 uint32_t op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12887
12888 if (crm != 0 || (op2 == 0 || op2 > 5))
12889 {
12890 /* Actually call nop method so we can reimplement it later. */
12891 nop (cpu);
12892 return;
12893 }
12894 }
12895 HALT_NYI;
12896
12897 case 0x033:
12898 {
12899 uint32_t op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12900
12901 switch (op2)
12902 {
caa8d700 12903 case 2: HALT_NYI;
2e8cf49e
NC
12904 case 4: dsb (cpu); return;
12905 case 5: dmb (cpu); return;
12906 case 6: isb (cpu); return;
12907 case 7:
12908 default: HALT_UNALLOC;
12909 }
12910 }
12911
12912 case 0x3B0:
12913 /* MRS Wt, sys-reg. */
caa8d700 12914 do_mrs (cpu);
2e8cf49e
NC
12915 return;
12916
12917 case 0x3B4:
12918 case 0x3BD:
12919 /* MRS Xt, sys-reg. */
caa8d700 12920 do_mrs (cpu);
2e8cf49e
NC
12921 return;
12922
12923 case 0x0B7:
12924 /* DC <type>, x<n>. */
caa8d700 12925 HALT_NYI;
2e8cf49e
NC
12926 return;
12927
12928 default:
caa8d700
NC
12929 /* if (uimm (aarch64_get_instr (cpu), 21, 20) == 0x1)
12930 MRS Xt, sys-reg. */
2e8cf49e 12931 HALT_NYI;
caa8d700 12932 return;
2e8cf49e
NC
12933 }
12934}
12935
12936static void
12937dexBr (sim_cpu *cpu)
12938{
12939 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12940 assert group == GROUP_BREXSYS_1010 || group == GROUP_BREXSYS_1011
12941 bits [31,29] of a BrExSys are the secondary dispatch vector. */
12942 uint32_t group2 = dispatchBrExSys (aarch64_get_instr (cpu));
12943
12944 switch (group2)
12945 {
12946 case BR_IMM_000:
12947 return dexBranchImmediate (cpu);
12948
12949 case BR_IMMCMP_001:
12950 /* Compare has bit 25 clear while test has it set. */
12951 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12952 dexCompareBranchImmediate (cpu);
12953 else
12954 dexTestBranchImmediate (cpu);
12955 return;
12956
12957 case BR_IMMCOND_010:
12958 /* This is a conditional branch if bit 25 is clear otherwise
12959 unallocated. */
12960 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12961 dexCondBranchImmediate (cpu);
12962 else
12963 HALT_UNALLOC;
12964 return;
12965
12966 case BR_UNALLOC_011:
12967 HALT_UNALLOC;
12968
12969 case BR_IMM_100:
12970 dexBranchImmediate (cpu);
12971 return;
12972
12973 case BR_IMMCMP_101:
12974 /* Compare has bit 25 clear while test has it set. */
12975 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12976 dexCompareBranchImmediate (cpu);
12977 else
12978 dexTestBranchImmediate (cpu);
12979 return;
12980
12981 case BR_REG_110:
12982 /* Unconditional branch reg has bit 25 set. */
12983 if (uimm (aarch64_get_instr (cpu), 25, 25))
12984 dexBranchRegister (cpu);
12985
12986 /* This includes both Excpn Gen, System and unalloc operations.
12987 We need to decode the Excpn Gen operation BRK so we can plant
12988 debugger entry points.
12989 Excpn Gen operations have aarch64_get_instr (cpu)[24] = 0.
12990 we need to decode at least one of the System operations NOP
12991 which is an alias for HINT #0.
12992 System operations have aarch64_get_instr (cpu)[24,22] = 100. */
12993 else if (uimm (aarch64_get_instr (cpu), 24, 24) == 0)
12994 dexExcpnGen (cpu);
12995
12996 else if (uimm (aarch64_get_instr (cpu), 24, 22) == 4)
12997 dexSystem (cpu);
12998
12999 else
13000 HALT_UNALLOC;
13001
13002 return;
13003
13004 case BR_UNALLOC_111:
13005 HALT_UNALLOC;
13006
13007 default:
13008 /* Should never reach here. */
13009 HALT_NYI;
13010 }
13011}
13012
13013static void
13014aarch64_decode_and_execute (sim_cpu *cpu, uint64_t pc)
13015{
13016 /* We need to check if gdb wants an in here. */
13017 /* checkBreak (cpu);. */
13018
13019 uint64_t group = dispatchGroup (aarch64_get_instr (cpu));
13020
13021 switch (group)
13022 {
13023 case GROUP_PSEUDO_0000: dexPseudo (cpu); break;
13024 case GROUP_LDST_0100: dexLdSt (cpu); break;
13025 case GROUP_DPREG_0101: dexDPReg (cpu); break;
13026 case GROUP_LDST_0110: dexLdSt (cpu); break;
13027 case GROUP_ADVSIMD_0111: dexAdvSIMD0 (cpu); break;
13028 case GROUP_DPIMM_1000: dexDPImm (cpu); break;
13029 case GROUP_DPIMM_1001: dexDPImm (cpu); break;
13030 case GROUP_BREXSYS_1010: dexBr (cpu); break;
13031 case GROUP_BREXSYS_1011: dexBr (cpu); break;
13032 case GROUP_LDST_1100: dexLdSt (cpu); break;
13033 case GROUP_DPREG_1101: dexDPReg (cpu); break;
13034 case GROUP_LDST_1110: dexLdSt (cpu); break;
13035 case GROUP_ADVSIMD_1111: dexAdvSIMD1 (cpu); break;
13036
13037 case GROUP_UNALLOC_0001:
13038 case GROUP_UNALLOC_0010:
13039 case GROUP_UNALLOC_0011:
13040 HALT_UNALLOC;
13041
13042 default:
13043 /* Should never reach here. */
13044 HALT_NYI;
13045 }
13046}
13047
13048static bfd_boolean
13049aarch64_step (sim_cpu *cpu)
13050{
13051 uint64_t pc = aarch64_get_PC (cpu);
13052
13053 if (pc == TOP_LEVEL_RETURN_PC)
13054 return FALSE;
13055
13056 aarch64_set_next_PC (cpu, pc + 4);
13057 aarch64_get_instr (cpu) = aarch64_get_mem_u32 (cpu, pc);
13058
57aa1742 13059 TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %08x", pc,
1a846c62
MF
13060 aarch64_get_instr (cpu));
13061 TRACE_DISASM (cpu, pc);
2e8cf49e
NC
13062
13063 aarch64_decode_and_execute (cpu, pc);
13064
13065 return TRUE;
13066}
13067
13068void
13069aarch64_run (SIM_DESC sd)
13070{
13071 sim_cpu *cpu = STATE_CPU (sd, 0);
13072
13073 while (aarch64_step (cpu))
13074 aarch64_update_PC (cpu);
13075
13076 sim_engine_halt (sd, NULL, NULL, aarch64_get_PC (cpu),
13077 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13078}
13079
13080void
13081aarch64_init (sim_cpu *cpu, uint64_t pc)
13082{
13083 uint64_t sp = aarch64_get_stack_start (cpu);
13084
13085 /* Install SP, FP and PC and set LR to -20
13086 so we can detect a top-level return. */
13087 aarch64_set_reg_u64 (cpu, SP, SP_OK, sp);
13088 aarch64_set_reg_u64 (cpu, FP, SP_OK, sp);
13089 aarch64_set_reg_u64 (cpu, LR, SP_OK, TOP_LEVEL_RETURN_PC);
13090 aarch64_set_next_PC (cpu, pc);
13091 aarch64_update_PC (cpu);
13092 aarch64_init_LIT_table ();
13093}