sim: aarch64: drop syscall.h include to fix build
[deliverable/binutils-gdb.git] / sim / aarch64 / simulator.c
1 /* simulator.c -- Interface for the AArch64 simulator.
2
3 Copyright (C) 2015-2016 Free Software Foundation, Inc.
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>
27 #include <math.h>
28 #include <time.h>
29 #include <limits.h>
30
31 #include "dis-asm.h"
32
33 #include "simulator.h"
34 #include "cpustate.h"
35 #include "memory.h"
36
37 #define NO_SP 0
38 #define SP_OK 1
39
40 bfd_boolean disas = FALSE;
41
42 #define TST(_flag) (aarch64_test_CPSR_bit (cpu, _flag))
43 #define IS_SET(_X) ( TST (( _X )))
44 #define IS_CLEAR(_X) (!TST (( _X )))
45
46 #define HALT_UNALLOC \
47 do \
48 { \
49 if (TRACE_INSN_P (cpu)) \
50 { \
51 aarch64_print_insn (CPU_STATE (cpu), aarch64_get_PC (cpu)); \
52 TRACE_INSN (cpu, \
53 "Unallocated instruction detected at sim line %d,"\
54 " exe addr %" PRIx64, \
55 __LINE__, aarch64_get_PC (cpu)); \
56 } \
57 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
58 sim_stopped, SIM_SIGILL); \
59 } \
60 while (0)
61
62 #define HALT_NYI \
63 do \
64 { \
65 if (TRACE_INSN_P (cpu)) \
66 { \
67 aarch64_print_insn (CPU_STATE (cpu), aarch64_get_PC (cpu)); \
68 TRACE_INSN (cpu, \
69 "Unimplemented instruction detected at sim line %d,"\
70 " exe addr %" PRIx64, \
71 __LINE__, aarch64_get_PC (cpu)); \
72 } \
73 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
74 sim_stopped, SIM_SIGABRT); \
75 } \
76 while (0)
77
78 #define NYI_assert(HI, LO, EXPECTED) \
79 do \
80 { \
81 if (uimm (aarch64_get_instr (cpu), (HI), (LO)) != (EXPECTED)) \
82 HALT_NYI; \
83 } \
84 while (0)
85
86 #define HALT_UNREACHABLE \
87 do \
88 { \
89 TRACE_EVENTS (cpu, "ISE: unreachable code point"); \
90 sim_engine_abort (NULL, cpu, aarch64_get_PC (cpu), "Internal Error"); \
91 } \
92 while (0)
93
94 /* Helper functions used by expandLogicalImmediate. */
95
96 /* for i = 1, ... N result<i-1> = 1 other bits are zero */
97 static inline uint64_t
98 ones (int N)
99 {
100 return (N == 64 ? (uint64_t)-1UL : ((1UL << N) - 1));
101 }
102
103 /* result<0> to val<N> */
104 static inline uint64_t
105 pickbit (uint64_t val, int N)
106 {
107 return pickbits64 (val, N, N);
108 }
109
110 static uint64_t
111 expand_logical_immediate (uint32_t S, uint32_t R, uint32_t N)
112 {
113 uint64_t mask;
114 uint64_t imm;
115 unsigned simd_size;
116
117 /* The immediate value is S+1 bits to 1, left rotated by SIMDsize - R
118 (in other words, right rotated by R), then replicated. */
119 if (N != 0)
120 {
121 simd_size = 64;
122 mask = 0xffffffffffffffffull;
123 }
124 else
125 {
126 switch (S)
127 {
128 case 0x00 ... 0x1f: /* 0xxxxx */ simd_size = 32; break;
129 case 0x20 ... 0x2f: /* 10xxxx */ simd_size = 16; S &= 0xf; break;
130 case 0x30 ... 0x37: /* 110xxx */ simd_size = 8; S &= 0x7; break;
131 case 0x38 ... 0x3b: /* 1110xx */ simd_size = 4; S &= 0x3; break;
132 case 0x3c ... 0x3d: /* 11110x */ simd_size = 2; S &= 0x1; break;
133 default: return 0;
134 }
135 mask = (1ull << simd_size) - 1;
136 /* Top bits are IGNORED. */
137 R &= simd_size - 1;
138 }
139
140 /* NOTE: if S = simd_size - 1 we get 0xf..f which is rejected. */
141 if (S == simd_size - 1)
142 return 0;
143
144 /* S+1 consecutive bits to 1. */
145 /* NOTE: S can't be 63 due to detection above. */
146 imm = (1ull << (S + 1)) - 1;
147
148 /* Rotate to the left by simd_size - R. */
149 if (R != 0)
150 imm = ((imm << (simd_size - R)) & mask) | (imm >> R);
151
152 /* Replicate the value according to SIMD size. */
153 switch (simd_size)
154 {
155 case 2: imm = (imm << 2) | imm;
156 case 4: imm = (imm << 4) | imm;
157 case 8: imm = (imm << 8) | imm;
158 case 16: imm = (imm << 16) | imm;
159 case 32: imm = (imm << 32) | imm;
160 case 64: break;
161 default: return 0;
162 }
163
164 return imm;
165 }
166
167 /* Instr[22,10] encodes N immr and imms. we want a lookup table
168 for each possible combination i.e. 13 bits worth of int entries. */
169 #define LI_TABLE_SIZE (1 << 13)
170 static uint64_t LITable[LI_TABLE_SIZE];
171
172 void
173 aarch64_init_LIT_table (void)
174 {
175 unsigned index;
176
177 for (index = 0; index < LI_TABLE_SIZE; index++)
178 {
179 uint32_t N = uimm (index, 12, 12);
180 uint32_t immr = uimm (index, 11, 6);
181 uint32_t imms = uimm (index, 5, 0);
182
183 LITable [index] = expand_logical_immediate (imms, immr, N);
184 }
185 }
186
187 static void
188 dexNotify (sim_cpu *cpu)
189 {
190 /* instr[14,0] == type : 0 ==> method entry, 1 ==> method reentry
191 2 ==> exit Java, 3 ==> start next bytecode. */
192 uint32_t type = uimm (aarch64_get_instr (cpu), 14, 0);
193
194 TRACE_EVENTS (cpu, "Notify Insn encountered, type = 0x%x", type);
195
196 switch (type)
197 {
198 case 0:
199 /* aarch64_notifyMethodEntry (aarch64_get_reg_u64 (cpu, R23, 0),
200 aarch64_get_reg_u64 (cpu, R22, 0)); */
201 break;
202 case 1:
203 /* aarch64_notifyMethodReentry (aarch64_get_reg_u64 (cpu, R23, 0),
204 aarch64_get_reg_u64 (cpu, R22, 0)); */
205 break;
206 case 2:
207 /* aarch64_notifyMethodExit (); */
208 break;
209 case 3:
210 /* aarch64_notifyBCStart (aarch64_get_reg_u64 (cpu, R23, 0),
211 aarch64_get_reg_u64 (cpu, R22, 0)); */
212 break;
213 }
214 }
215
216 /* secondary decode within top level groups */
217
218 static void
219 dexPseudo (sim_cpu *cpu)
220 {
221 /* assert instr[28,27] = 00
222
223 We provide 2 pseudo instructions:
224
225 HALT stops execution of the simulator causing an immediate
226 return to the x86 code which entered it.
227
228 CALLOUT initiates recursive entry into x86 code. A register
229 argument holds the address of the x86 routine. Immediate
230 values in the instruction identify the number of general
231 purpose and floating point register arguments to be passed
232 and the type of any value to be returned. */
233
234 uint32_t PSEUDO_HALT = 0xE0000000U;
235 uint32_t PSEUDO_CALLOUT = 0x00018000U;
236 uint32_t PSEUDO_CALLOUTR = 0x00018001U;
237 uint32_t PSEUDO_NOTIFY = 0x00014000U;
238 uint32_t dispatch;
239
240 if (aarch64_get_instr (cpu) == PSEUDO_HALT)
241 {
242 TRACE_EVENTS (cpu, " Pseudo Halt Instruction");
243 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
244 sim_stopped, SIM_SIGTRAP);
245 }
246
247 dispatch = uimm (aarch64_get_instr (cpu), 31, 15);
248
249 /* We do not handle callouts at the moment. */
250 if (dispatch == PSEUDO_CALLOUT || dispatch == PSEUDO_CALLOUTR)
251 {
252 TRACE_EVENTS (cpu, " Callout");
253 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
254 sim_stopped, SIM_SIGABRT);
255 }
256
257 else if (dispatch == PSEUDO_NOTIFY)
258 dexNotify (cpu);
259
260 else
261 HALT_UNALLOC;
262 }
263
264 /* Load-store single register (unscaled offset)
265 These instructions employ a base register plus an unscaled signed
266 9 bit offset.
267
268 N.B. the base register (source) can be Xn or SP. all other
269 registers may not be SP. */
270
271 /* 32 bit load 32 bit unscaled signed 9 bit. */
272 static void
273 ldur32 (sim_cpu *cpu, int32_t offset)
274 {
275 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
276 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
277
278 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
279 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
280 + offset));
281 }
282
283 /* 64 bit load 64 bit unscaled signed 9 bit. */
284 static void
285 ldur64 (sim_cpu *cpu, int32_t offset)
286 {
287 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
288 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
289
290 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
291 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
292 + offset));
293 }
294
295 /* 32 bit load zero-extended byte unscaled signed 9 bit. */
296 static void
297 ldurb32 (sim_cpu *cpu, int32_t offset)
298 {
299 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
300 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
301
302 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8
303 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
304 + offset));
305 }
306
307 /* 32 bit load sign-extended byte unscaled signed 9 bit. */
308 static void
309 ldursb32 (sim_cpu *cpu, int32_t offset)
310 {
311 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
312 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
313
314 aarch64_set_reg_u64 (cpu, rt, NO_SP, (uint32_t) aarch64_get_mem_s8
315 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
316 + offset));
317 }
318
319 /* 64 bit load sign-extended byte unscaled signed 9 bit. */
320 static void
321 ldursb64 (sim_cpu *cpu, int32_t offset)
322 {
323 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
324 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
325
326 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s8
327 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
328 + offset));
329 }
330
331 /* 32 bit load zero-extended short unscaled signed 9 bit */
332 static void
333 ldurh32 (sim_cpu *cpu, int32_t offset)
334 {
335 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
336 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
337
338 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_mem_u16
339 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
340 + offset));
341 }
342
343 /* 32 bit load sign-extended short unscaled signed 9 bit */
344 static void
345 ldursh32 (sim_cpu *cpu, int32_t offset)
346 {
347 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
348 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
349
350 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s16
351 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
352 + offset));
353 }
354
355 /* 64 bit load sign-extended short unscaled signed 9 bit */
356 static void
357 ldursh64 (sim_cpu *cpu, int32_t offset)
358 {
359 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
360 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
361
362 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s16
363 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
364 + offset));
365 }
366
367 /* 64 bit load sign-extended word unscaled signed 9 bit */
368 static void
369 ldursw (sim_cpu *cpu, int32_t offset)
370 {
371 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
372 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
373
374 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s32
375 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
376 + offset));
377 }
378
379 /* N.B. with stores the value in source is written to the address
380 identified by source2 modified by offset. */
381
382 /* 32 bit store 32 bit unscaled signed 9 bit. */
383 static void
384 stur32 (sim_cpu *cpu, int32_t offset)
385 {
386 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
387 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
388
389 aarch64_set_mem_u32 (cpu,
390 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
391 aarch64_get_reg_u32 (cpu, rd, NO_SP));
392 }
393
394 /* 64 bit store 64 bit unscaled signed 9 bit */
395 static void
396 stur64 (sim_cpu *cpu, int32_t offset)
397 {
398 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
399 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
400
401 aarch64_set_mem_u64 (cpu,
402 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
403 aarch64_get_reg_u64 (cpu, rd, NO_SP));
404 }
405
406 /* 32 bit store byte unscaled signed 9 bit */
407 static void
408 sturb (sim_cpu *cpu, int32_t offset)
409 {
410 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
411 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
412
413 aarch64_set_mem_u8 (cpu,
414 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
415 aarch64_get_reg_u8 (cpu, rd, NO_SP));
416 }
417
418 /* 32 bit store short unscaled signed 9 bit */
419 static void
420 sturh (sim_cpu *cpu, int32_t offset)
421 {
422 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
423 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
424
425 aarch64_set_mem_u16 (cpu,
426 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
427 aarch64_get_reg_u16 (cpu, rd, NO_SP));
428 }
429
430 /* Load single register pc-relative label
431 Offset is a signed 19 bit immediate count in words
432 rt may not be SP. */
433
434 /* 32 bit pc-relative load */
435 static void
436 ldr32_pcrel (sim_cpu *cpu, int32_t offset)
437 {
438 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
439
440 aarch64_set_reg_u64 (cpu, rd, NO_SP,
441 aarch64_get_mem_u32
442 (cpu, aarch64_get_PC (cpu) + offset * 4));
443 }
444
445 /* 64 bit pc-relative load */
446 static void
447 ldr_pcrel (sim_cpu *cpu, int32_t offset)
448 {
449 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
450
451 aarch64_set_reg_u64 (cpu, rd, NO_SP,
452 aarch64_get_mem_u64
453 (cpu, aarch64_get_PC (cpu) + offset * 4));
454 }
455
456 /* sign extended 32 bit pc-relative load */
457 static void
458 ldrsw_pcrel (sim_cpu *cpu, int32_t offset)
459 {
460 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
461
462 aarch64_set_reg_u64 (cpu, rd, NO_SP,
463 aarch64_get_mem_s32
464 (cpu, aarch64_get_PC (cpu) + offset * 4));
465 }
466
467 /* float pc-relative load */
468 static void
469 fldrs_pcrel (sim_cpu *cpu, int32_t offset)
470 {
471 unsigned int rd = uimm (aarch64_get_instr (cpu), 4, 0);
472
473 aarch64_set_FP_float (cpu, rd,
474 aarch64_get_mem_float
475 (cpu, aarch64_get_PC (cpu) + offset * 4));
476 }
477
478 /* double pc-relative load */
479 static void
480 fldrd_pcrel (sim_cpu *cpu, int32_t offset)
481 {
482 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
483
484 aarch64_set_FP_double (cpu, st,
485 aarch64_get_mem_double
486 (cpu, aarch64_get_PC (cpu) + offset * 4));
487 }
488
489 /* long double pc-relative load. */
490 static void
491 fldrq_pcrel (sim_cpu *cpu, int32_t offset)
492 {
493 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
494 uint64_t addr = aarch64_get_PC (cpu) + offset * 4;
495 FRegister a;
496
497 aarch64_get_mem_long_double (cpu, addr, & a);
498 aarch64_set_FP_long_double (cpu, st, a);
499 }
500
501 /* This can be used to scale an offset by applying
502 the requisite shift. the second argument is either
503 16, 32 or 64. */
504
505 #define SCALE(_offset, _elementSize) \
506 ((_offset) << ScaleShift ## _elementSize)
507
508 /* This can be used to optionally scale a register derived offset
509 by applying the requisite shift as indicated by the Scaling
510 argument. the second argument is either Byte, Short, Word
511 or Long. The third argument is either Scaled or Unscaled.
512 N.B. when _Scaling is Scaled the shift gets ANDed with
513 all 1s while when it is Unscaled it gets ANDed with 0. */
514
515 #define OPT_SCALE(_offset, _elementType, _Scaling) \
516 ((_offset) << (_Scaling ? ScaleShift ## _elementType : 0))
517
518 /* This can be used to zero or sign extend a 32 bit register derived
519 value to a 64 bit value. the first argument must be the value as
520 a uint32_t and the second must be either UXTW or SXTW. The result
521 is returned as an int64_t. */
522
523 static inline int64_t
524 extend (uint32_t value, Extension extension)
525 {
526 union
527 {
528 uint32_t u;
529 int32_t n;
530 } x;
531
532 /* A branchless variant of this ought to be possible. */
533 if (extension == UXTW || extension == NoExtension)
534 return value;
535
536 x.u = value;
537 return x.n;
538 }
539
540 /* Scalar Floating Point
541
542 FP load/store single register (4 addressing modes)
543
544 N.B. the base register (source) can be the stack pointer.
545 The secondary source register (source2) can only be an Xn register. */
546
547 /* Load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
548 static void
549 fldrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
550 {
551 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
552 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
553 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
554
555 if (wb != Post)
556 address += offset;
557
558 aarch64_set_FP_float (cpu, st, aarch64_get_mem_float (cpu, address));
559 if (wb == Post)
560 address += offset;
561
562 if (wb != NoWriteBack)
563 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
564 }
565
566 /* Load 32 bit scaled unsigned 12 bit. */
567 static void
568 fldrs_abs (sim_cpu *cpu, uint32_t offset)
569 {
570 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
571 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
572
573 aarch64_set_FP_float (cpu, st,
574 aarch64_get_mem_float
575 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
576 + SCALE (offset, 32)));
577 }
578
579 /* Load 32 bit scaled or unscaled zero- or sign-extended
580 32-bit register offset. */
581 static void
582 fldrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
583 {
584 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
585 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
586 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
587 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
588 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
589 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
590
591 aarch64_set_FP_float (cpu, st,
592 aarch64_get_mem_float
593 (cpu, address + displacement));
594 }
595
596 /* Load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
597 static void
598 fldrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
599 {
600 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
601 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
602 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
603
604 if (wb != Post)
605 address += offset;
606
607 aarch64_set_FP_double (cpu, st, aarch64_get_mem_double (cpu, address));
608
609 if (wb == Post)
610 address += offset;
611
612 if (wb != NoWriteBack)
613 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
614 }
615
616 /* Load 64 bit scaled unsigned 12 bit. */
617 static void
618 fldrd_abs (sim_cpu *cpu, uint32_t offset)
619 {
620 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
621 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
622 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64);
623
624 aarch64_set_FP_double (cpu, st, aarch64_get_mem_double (cpu, address));
625 }
626
627 /* Load 64 bit scaled or unscaled zero- or sign-extended 32-bit register offset. */
628 static void
629 fldrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
630 {
631 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
632 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
633 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
634
635 fldrd_wb (cpu, displacement, NoWriteBack);
636 }
637
638 /* Load 128 bit unscaled signed 9 bit with pre- or post-writeback. */
639 static void
640 fldrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
641 {
642 FRegister a;
643 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
644 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
645 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
646
647 if (wb != Post)
648 address += offset;
649
650 aarch64_get_mem_long_double (cpu, address, & a);
651 aarch64_set_FP_long_double (cpu, st, a);
652
653 if (wb == Post)
654 address += offset;
655
656 if (wb != NoWriteBack)
657 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
658 }
659
660 /* Load 128 bit scaled unsigned 12 bit. */
661 static void
662 fldrq_abs (sim_cpu *cpu, uint32_t offset)
663 {
664 FRegister a;
665 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
666 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
667 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
668
669 aarch64_get_mem_long_double (cpu, address, & a);
670 aarch64_set_FP_long_double (cpu, st, a);
671 }
672
673 /* Load 128 bit scaled or unscaled zero- or sign-extended 32-bit register offset */
674 static void
675 fldrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
676 {
677 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
678 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
679 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
680
681 fldrq_wb (cpu, displacement, NoWriteBack);
682 }
683
684 /* Memory Access
685
686 load-store single register
687 There are four addressing modes available here which all employ a
688 64 bit source (base) register.
689
690 N.B. the base register (source) can be the stack pointer.
691 The secondary source register (source2)can only be an Xn register.
692
693 Scaled, 12-bit, unsigned immediate offset, without pre- and
694 post-index options.
695 Unscaled, 9-bit, signed immediate offset with pre- or post-index
696 writeback.
697 scaled or unscaled 64-bit register offset.
698 scaled or unscaled 32-bit extended register offset.
699
700 All offsets are assumed to be raw from the decode i.e. the
701 simulator is expected to adjust scaled offsets based on the
702 accessed data size with register or extended register offset
703 versions the same applies except that in the latter case the
704 operation may also require a sign extend.
705
706 A separate method is provided for each possible addressing mode. */
707
708 /* 32 bit load 32 bit scaled unsigned 12 bit */
709 static void
710 ldr32_abs (sim_cpu *cpu, uint32_t offset)
711 {
712 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
713 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
714
715 /* The target register may not be SP but the source may be. */
716 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
717 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
718 + SCALE (offset, 32)));
719 }
720
721 /* 32 bit load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
722 static void
723 ldr32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
724 {
725 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
726 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
727 uint64_t address;
728
729 if (rn == rt && wb != NoWriteBack)
730 HALT_UNALLOC;
731
732 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
733
734 if (wb != Post)
735 address += offset;
736
737 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
738
739 if (wb == Post)
740 address += offset;
741
742 if (wb != NoWriteBack)
743 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
744 }
745
746 /* 32 bit load 32 bit scaled or unscaled
747 zero- or sign-extended 32-bit register offset */
748 static void
749 ldr32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
750 {
751 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
752 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
753 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
754 /* rn may reference SP, rm and rt must reference ZR */
755
756 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
757 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
758 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
759
760 aarch64_set_reg_u64 (cpu, rt, NO_SP,
761 aarch64_get_mem_u32 (cpu, address + displacement));
762 }
763
764 /* 64 bit load 64 bit scaled unsigned 12 bit */
765 static void
766 ldr_abs (sim_cpu *cpu, uint32_t offset)
767 {
768 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
769 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
770
771 /* The target register may not be SP but the source may be. */
772 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
773 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
774 + SCALE (offset, 64)));
775 }
776
777 /* 64 bit load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
778 static void
779 ldr_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
780 {
781 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
782 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
783 uint64_t address;
784
785 if (rn == rt && wb != NoWriteBack)
786 HALT_UNALLOC;
787
788 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
789
790 if (wb != Post)
791 address += offset;
792
793 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
794
795 if (wb == Post)
796 address += offset;
797
798 if (wb != NoWriteBack)
799 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
800 }
801
802 /* 64 bit load 64 bit scaled or unscaled zero-
803 or sign-extended 32-bit register offset. */
804 static void
805 ldr_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
806 {
807 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
808 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
809 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
810 /* rn may reference SP, rm and rt must reference ZR */
811
812 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
813 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
814 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
815
816 aarch64_set_reg_u64 (cpu, rt, NO_SP,
817 aarch64_get_mem_u64 (cpu, address + displacement));
818 }
819
820 /* 32 bit load zero-extended byte scaled unsigned 12 bit. */
821 static void
822 ldrb32_abs (sim_cpu *cpu, uint32_t offset)
823 {
824 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
825 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
826
827 /* The target register may not be SP but the source may be
828 there is no scaling required for a byte load. */
829 aarch64_set_reg_u64 (cpu, rt, NO_SP,
830 aarch64_get_mem_u8
831 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
832 }
833
834 /* 32 bit load zero-extended byte unscaled signed 9 bit with pre- or post-writeback. */
835 static void
836 ldrb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
837 {
838 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
839 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
840 uint64_t address;
841
842 if (rn == rt && wb != NoWriteBack)
843 HALT_UNALLOC;
844
845 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
846
847 if (wb != Post)
848 address += offset;
849
850 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
851
852 if (wb == Post)
853 address += offset;
854
855 if (wb != NoWriteBack)
856 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
857 }
858
859 /* 32 bit load zero-extended byte scaled or unscaled zero-
860 or sign-extended 32-bit register offset. */
861 static void
862 ldrb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
863 {
864 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
865 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
866 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
867 /* rn may reference SP, rm and rt must reference ZR */
868
869 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
870 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
871 extension);
872
873 /* There is no scaling required for a byte load. */
874 aarch64_set_reg_u64 (cpu, rt, NO_SP,
875 aarch64_get_mem_u8 (cpu, address + displacement));
876 }
877
878 /* 64 bit load sign-extended byte unscaled signed 9 bit
879 with pre- or post-writeback. */
880 static void
881 ldrsb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
882 {
883 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
884 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
885 uint64_t address;
886
887 if (rn == rt && wb != NoWriteBack)
888 HALT_UNALLOC;
889
890 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
891
892 if (wb != Post)
893 address += offset;
894
895 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s8 (cpu, address));
896
897 if (wb == Post)
898 address += offset;
899
900 if (wb != NoWriteBack)
901 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
902 }
903
904 /* 64 bit load sign-extended byte scaled unsigned 12 bit. */
905 static void
906 ldrsb_abs (sim_cpu *cpu, uint32_t offset)
907 {
908 ldrsb_wb (cpu, offset, NoWriteBack);
909 }
910
911 /* 64 bit load sign-extended byte scaled or unscaled zero-
912 or sign-extended 32-bit register offset. */
913 static void
914 ldrsb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
915 {
916 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
917 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
918 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
919 /* rn may reference SP, rm and rt must reference ZR */
920
921 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
922 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
923 extension);
924 /* There is no scaling required for a byte load. */
925 aarch64_set_reg_u64 (cpu, rt, NO_SP,
926 aarch64_get_mem_s8 (cpu, address + displacement));
927 }
928
929 /* 32 bit load zero-extended short scaled unsigned 12 bit. */
930 static void
931 ldrh32_abs (sim_cpu *cpu, uint32_t offset)
932 {
933 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
934 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
935
936 /* The target register may not be SP but the source may be. */
937 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16
938 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
939 + SCALE (offset, 16)));
940 }
941
942 /* 32 bit load zero-extended short unscaled signed 9 bit
943 with pre- or post-writeback. */
944 static void
945 ldrh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
946 {
947 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
948 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
949 uint64_t address;
950
951 if (rn == rt && wb != NoWriteBack)
952 HALT_UNALLOC;
953
954 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
955
956 if (wb != Post)
957 address += offset;
958
959 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
960
961 if (wb == Post)
962 address += offset;
963
964 if (wb != NoWriteBack)
965 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
966 }
967
968 /* 32 bit load zero-extended short scaled or unscaled zero-
969 or sign-extended 32-bit register offset. */
970 static void
971 ldrh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
972 {
973 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
974 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
975 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
976 /* rn may reference SP, rm and rt must reference ZR */
977
978 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
979 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
980 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
981
982 aarch64_set_reg_u64 (cpu, rt, NO_SP,
983 aarch64_get_mem_u16 (cpu, address + displacement));
984 }
985
986 /* 32 bit load sign-extended short scaled unsigned 12 bit. */
987 static void
988 ldrsh32_abs (sim_cpu *cpu, uint32_t offset)
989 {
990 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
991 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
992
993 /* The target register may not be SP but the source may be. */
994 aarch64_set_reg_u64 (cpu, rt, NO_SP, (uint32_t) aarch64_get_mem_s16
995 (cpu,
996 aarch64_get_reg_u64 (cpu, rn, SP_OK)
997 + SCALE (offset, 16)));
998 }
999
1000 /* 32 bit load sign-extended short unscaled signed 9 bit
1001 with pre- or post-writeback. */
1002 static void
1003 ldrsh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1004 {
1005 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1006 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1007 uint64_t address;
1008
1009 if (rn == rt && wb != NoWriteBack)
1010 HALT_UNALLOC;
1011
1012 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1013
1014 if (wb != Post)
1015 address += offset;
1016
1017 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1018 (uint32_t) aarch64_get_mem_s16 (cpu, address));
1019
1020 if (wb == Post)
1021 address += offset;
1022
1023 if (wb != NoWriteBack)
1024 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1025 }
1026
1027 /* 32 bit load sign-extended short scaled or unscaled zero-
1028 or sign-extended 32-bit register offset. */
1029 static void
1030 ldrsh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1031 {
1032 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1033 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1034 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1035 /* rn may reference SP, rm and rt must reference ZR */
1036
1037 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1038 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1039 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1040
1041 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1042 (uint32_t) aarch64_get_mem_s16
1043 (cpu, address + displacement));
1044 }
1045
1046 /* 64 bit load sign-extended short scaled unsigned 12 bit. */
1047 static void
1048 ldrsh_abs (sim_cpu *cpu, uint32_t offset)
1049 {
1050 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1051 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1052
1053 /* The target register may not be SP but the source may be. */
1054 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s16
1055 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1056 + SCALE (offset, 16)));
1057 }
1058
1059 /* 64 bit load sign-extended short unscaled signed 9 bit
1060 with pre- or post-writeback. */
1061 static void
1062 ldrsh64_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1063 {
1064 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1065 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1066 uint64_t address;
1067
1068 if (rn == rt && wb != NoWriteBack)
1069 HALT_UNALLOC;
1070
1071 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1072
1073 if (wb != Post)
1074 address += offset;
1075
1076 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s16 (cpu, address));
1077
1078 if (wb == Post)
1079 address += offset;
1080
1081 if (wb != NoWriteBack)
1082 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1083 }
1084
1085 /* 64 bit load sign-extended short scaled or unscaled zero-
1086 or sign-extended 32-bit register offset. */
1087 static void
1088 ldrsh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1089 {
1090 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1091 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1092 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1093 /* rn may reference SP, rm and rt must reference ZR */
1094
1095 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1096 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1097 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1098
1099 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1100 aarch64_get_mem_s16 (cpu, address + displacement));
1101 }
1102
1103 /* 64 bit load sign-extended 32 bit scaled unsigned 12 bit. */
1104 static void
1105 ldrsw_abs (sim_cpu *cpu, uint32_t offset)
1106 {
1107 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1108 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1109
1110 /* The target register may not be SP but the source may be. */
1111 return aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32
1112 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1113 + SCALE (offset, 32)));
1114 }
1115
1116 /* 64 bit load sign-extended 32 bit unscaled signed 9 bit
1117 with pre- or post-writeback. */
1118 static void
1119 ldrsw_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1120 {
1121 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1122 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1123 uint64_t address;
1124
1125 if (rn == rt && wb != NoWriteBack)
1126 HALT_UNALLOC;
1127
1128 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1129
1130 if (wb != Post)
1131 address += offset;
1132
1133 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32 (cpu, address));
1134
1135 if (wb == Post)
1136 address += offset;
1137
1138 if (wb != NoWriteBack)
1139 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1140 }
1141
1142 /* 64 bit load sign-extended 32 bit scaled or unscaled zero-
1143 or sign-extended 32-bit register offset. */
1144 static void
1145 ldrsw_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1146 {
1147 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1148 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1149 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1150 /* rn may reference SP, rm and rt must reference ZR */
1151
1152 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1153 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1154 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1155
1156 aarch64_set_reg_s64 (cpu, rt, NO_SP,
1157 aarch64_get_mem_s32 (cpu, address + displacement));
1158 }
1159
1160 /* N.B. with stores the value in source is written to the
1161 address identified by source2 modified by source3/offset. */
1162
1163 /* 32 bit store scaled unsigned 12 bit. */
1164 static void
1165 str32_abs (sim_cpu *cpu, uint32_t offset)
1166 {
1167 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1168 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1169
1170 /* The target register may not be SP but the source may be. */
1171 aarch64_set_mem_u32 (cpu, (aarch64_get_reg_u64 (cpu, rn, SP_OK)
1172 + SCALE (offset, 32)),
1173 aarch64_get_reg_u32 (cpu, rt, NO_SP));
1174 }
1175
1176 /* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
1177 static void
1178 str32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1179 {
1180 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1181 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1182 uint64_t address;
1183
1184 if (rn == rt && wb != NoWriteBack)
1185 HALT_UNALLOC;
1186
1187 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1188 if (wb != Post)
1189 address += offset;
1190
1191 aarch64_set_mem_u32 (cpu, address, aarch64_get_reg_u32 (cpu, rt, NO_SP));
1192
1193 if (wb == Post)
1194 address += offset;
1195
1196 if (wb != NoWriteBack)
1197 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1198 }
1199
1200 /* 32 bit store scaled or unscaled zero- or
1201 sign-extended 32-bit register offset. */
1202 static void
1203 str32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1204 {
1205 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1206 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1207 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1208
1209 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1210 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1211 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1212
1213 aarch64_set_mem_u32 (cpu, address + displacement,
1214 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1215 }
1216
1217 /* 64 bit store scaled unsigned 12 bit. */
1218 static void
1219 str_abs (sim_cpu *cpu, uint32_t offset)
1220 {
1221 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1222 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1223
1224 aarch64_set_mem_u64 (cpu,
1225 aarch64_get_reg_u64 (cpu, rn, SP_OK)
1226 + SCALE (offset, 64),
1227 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1228 }
1229
1230 /* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
1231 static void
1232 str_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1233 {
1234 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1235 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1236 uint64_t address;
1237
1238 if (rn == rt && wb != NoWriteBack)
1239 HALT_UNALLOC;
1240
1241 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1242
1243 if (wb != Post)
1244 address += offset;
1245
1246 aarch64_set_mem_u64 (cpu, address, aarch64_get_reg_u64 (cpu, rt, NO_SP));
1247
1248 if (wb == Post)
1249 address += offset;
1250
1251 if (wb != NoWriteBack)
1252 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1253 }
1254
1255 /* 64 bit store scaled or unscaled zero-
1256 or sign-extended 32-bit register offset. */
1257 static void
1258 str_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1259 {
1260 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1261 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1262 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1263 /* rn may reference SP, rm and rt must reference ZR */
1264
1265 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1266 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1267 extension);
1268 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1269
1270 aarch64_set_mem_u64 (cpu, address + displacement,
1271 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1272 }
1273
1274 /* 32 bit store byte scaled unsigned 12 bit. */
1275 static void
1276 strb_abs (sim_cpu *cpu, uint32_t offset)
1277 {
1278 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1279 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1280
1281 /* The target register may not be SP but the source may be.
1282 There is no scaling required for a byte load. */
1283 aarch64_set_mem_u8 (cpu,
1284 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
1285 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1286 }
1287
1288 /* 32 bit store byte unscaled signed 9 bit with pre- or post-writeback. */
1289 static void
1290 strb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1291 {
1292 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1293 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1294 uint64_t address;
1295
1296 if (rn == rt && wb != NoWriteBack)
1297 HALT_UNALLOC;
1298
1299 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1300
1301 if (wb != Post)
1302 address += offset;
1303
1304 aarch64_set_mem_u8 (cpu, address, aarch64_get_reg_u8 (cpu, rt, NO_SP));
1305
1306 if (wb == Post)
1307 address += offset;
1308
1309 if (wb != NoWriteBack)
1310 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1311 }
1312
1313 /* 32 bit store byte scaled or unscaled zero-
1314 or sign-extended 32-bit register offset. */
1315 static void
1316 strb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1317 {
1318 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1319 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1320 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1321 /* rn may reference SP, rm and rt must reference ZR */
1322
1323 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1324 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1325 extension);
1326
1327 /* There is no scaling required for a byte load. */
1328 aarch64_set_mem_u8 (cpu, address + displacement,
1329 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1330 }
1331
1332 /* 32 bit store short scaled unsigned 12 bit. */
1333 static void
1334 strh_abs (sim_cpu *cpu, uint32_t offset)
1335 {
1336 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1337 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1338
1339 /* The target register may not be SP but the source may be. */
1340 aarch64_set_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1341 + SCALE (offset, 16),
1342 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1343 }
1344
1345 /* 32 bit store short unscaled signed 9 bit with pre- or post-writeback. */
1346 static void
1347 strh_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1348 {
1349 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1350 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1351 uint64_t address;
1352
1353 if (rn == rt && wb != NoWriteBack)
1354 HALT_UNALLOC;
1355
1356 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1357
1358 if (wb != Post)
1359 address += offset;
1360
1361 aarch64_set_mem_u16 (cpu, address, aarch64_get_reg_u16 (cpu, rt, NO_SP));
1362
1363 if (wb == Post)
1364 address += offset;
1365
1366 if (wb != NoWriteBack)
1367 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1368 }
1369
1370 /* 32 bit store short scaled or unscaled zero-
1371 or sign-extended 32-bit register offset. */
1372 static void
1373 strh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1374 {
1375 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1376 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1377 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1378 /* rn may reference SP, rm and rt must reference ZR */
1379
1380 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1381 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1382 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1383
1384 aarch64_set_mem_u16 (cpu, address + displacement,
1385 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1386 }
1387
1388 /* Prefetch unsigned 12 bit. */
1389 static void
1390 prfm_abs (sim_cpu *cpu, uint32_t offset)
1391 {
1392 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1393 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1394 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1395 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1396 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1397 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1398 ow ==> UNALLOC
1399 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1400 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK)
1401 + SCALE (offset, 64). */
1402
1403 /* TODO : implement prefetch of address. */
1404 }
1405
1406 /* Prefetch scaled or unscaled zero- or sign-extended 32-bit register offset. */
1407 static void
1408 prfm_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1409 {
1410 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1411 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1412 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1413 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1414 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1415 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1416 ow ==> UNALLOC
1417 rn may reference SP, rm may only reference ZR
1418 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1419 uint64_t base = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1420 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1421 extension);
1422 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1423 uint64_t address = base + displacement. */
1424
1425 /* TODO : implement prefetch of address */
1426 }
1427
1428 /* 64 bit pc-relative prefetch. */
1429 static void
1430 prfm_pcrel (sim_cpu *cpu, int32_t offset)
1431 {
1432 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1433 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1434 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1435 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1436 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1437 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1438 ow ==> UNALLOC
1439 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1440 uint64_t address = aarch64_get_PC (cpu) + offset. */
1441
1442 /* TODO : implement this */
1443 }
1444
1445 /* Load-store exclusive. */
1446
1447 static void
1448 ldxr (sim_cpu *cpu)
1449 {
1450 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1451 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1452 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1453 int size = uimm (aarch64_get_instr (cpu), 31, 30);
1454 /* int ordered = uimm (aarch64_get_instr (cpu), 15, 15); */
1455 /* int exclusive = ! uimm (aarch64_get_instr (cpu), 23, 23); */
1456
1457 switch (size)
1458 {
1459 case 0:
1460 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
1461 break;
1462 case 1:
1463 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
1464 break;
1465 case 2:
1466 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
1467 break;
1468 case 3:
1469 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
1470 break;
1471 default:
1472 HALT_UNALLOC;
1473 }
1474 }
1475
1476 static void
1477 stxr (sim_cpu *cpu)
1478 {
1479 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1480 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1481 unsigned rs = uimm (aarch64_get_instr (cpu), 20, 16);
1482 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1483 int size = uimm (aarch64_get_instr (cpu), 31, 30);
1484 uint64_t data = aarch64_get_reg_u64 (cpu, rt, NO_SP);
1485
1486 switch (size)
1487 {
1488 case 0: aarch64_set_mem_u8 (cpu, address, data); break;
1489 case 1: aarch64_set_mem_u16 (cpu, address, data); break;
1490 case 2: aarch64_set_mem_u32 (cpu, address, data); break;
1491 case 3: aarch64_set_mem_u64 (cpu, address, data); break;
1492 default: HALT_UNALLOC;
1493 }
1494
1495 aarch64_set_reg_u64 (cpu, rs, NO_SP, 0); /* Always exclusive... */
1496 }
1497
1498 static void
1499 dexLoadLiteral (sim_cpu *cpu)
1500 {
1501 /* instr[29,27] == 011
1502 instr[25,24] == 00
1503 instr[31,30:26] = opc: 000 ==> LDRW, 001 ==> FLDRS
1504 010 ==> LDRX, 011 ==> FLDRD
1505 100 ==> LDRSW, 101 ==> FLDRQ
1506 110 ==> PRFM, 111 ==> UNALLOC
1507 instr[26] ==> V : 0 ==> GReg, 1 ==> FReg
1508 instr[23, 5] == simm19 */
1509
1510 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
1511 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 1)
1512 | uimm (aarch64_get_instr (cpu), 26, 26));
1513 int32_t imm = simm32 (aarch64_get_instr (cpu), 23, 5);
1514
1515 switch (dispatch)
1516 {
1517 case 0: ldr32_pcrel (cpu, imm); break;
1518 case 1: fldrs_pcrel (cpu, imm); break;
1519 case 2: ldr_pcrel (cpu, imm); break;
1520 case 3: fldrd_pcrel (cpu, imm); break;
1521 case 4: ldrsw_pcrel (cpu, imm); break;
1522 case 5: fldrq_pcrel (cpu, imm); break;
1523 case 6: prfm_pcrel (cpu, imm); break;
1524 case 7:
1525 default:
1526 HALT_UNALLOC;
1527 }
1528 }
1529
1530 /* Immediate arithmetic
1531 The aimm argument is a 12 bit unsigned value or a 12 bit unsigned
1532 value left shifted by 12 bits (done at decode).
1533
1534 N.B. the register args (dest, source) can normally be Xn or SP.
1535 the exception occurs for flag setting instructions which may
1536 only use Xn for the output (dest). */
1537
1538 /* 32 bit add immediate. */
1539 static void
1540 add32 (sim_cpu *cpu, uint32_t aimm)
1541 {
1542 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1543 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1544
1545 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1546 aarch64_get_reg_u32 (cpu, rn, SP_OK) + aimm);
1547 }
1548
1549 /* 64 bit add immediate. */
1550 static void
1551 add64 (sim_cpu *cpu, uint32_t aimm)
1552 {
1553 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1554 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1555
1556 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1557 aarch64_get_reg_u64 (cpu, rn, SP_OK) + aimm);
1558 }
1559
1560 static void
1561 set_flags_for_add32 (sim_cpu *cpu, int32_t value1, int32_t value2)
1562 {
1563 int32_t result = value1 + value2;
1564 int64_t sresult = (int64_t) value1 + (int64_t) value2;
1565 uint64_t uresult = (uint64_t)(uint32_t) value1
1566 + (uint64_t)(uint32_t) value2;
1567 uint32_t flags = 0;
1568
1569 if (result == 0)
1570 flags |= Z;
1571
1572 if (result & (1 << 31))
1573 flags |= N;
1574
1575 if (uresult != result)
1576 flags |= C;
1577
1578 if (sresult != result)
1579 flags |= V;
1580
1581 aarch64_set_CPSR (cpu, flags);
1582 }
1583
1584 static void
1585 set_flags_for_add64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1586 {
1587 int64_t sval1 = value1;
1588 int64_t sval2 = value2;
1589 uint64_t result = value1 + value2;
1590 int64_t sresult = sval1 + sval2;
1591 uint32_t flags = 0;
1592
1593 if (result == 0)
1594 flags |= Z;
1595
1596 if (result & (1ULL << 63))
1597 flags |= N;
1598
1599 if (sval1 < 0)
1600 {
1601 if (sval2 < 0)
1602 {
1603 /* Negative plus a negative. Overflow happens if
1604 the result is greater than either of the operands. */
1605 if (sresult > sval1 || sresult > sval2)
1606 flags |= V;
1607 }
1608 /* else Negative plus a positive. Overflow cannot happen. */
1609 }
1610 else /* value1 is +ve. */
1611 {
1612 if (sval2 < 0)
1613 {
1614 /* Overflow can only occur if we computed "0 - MININT". */
1615 if (sval1 == 0 && sval2 == (1LL << 63))
1616 flags |= V;
1617 }
1618 else
1619 {
1620 /* Postive plus positive - overflow has happened if the
1621 result is smaller than either of the operands. */
1622 if (result < value1 || result < value2)
1623 flags |= V | C;
1624 }
1625 }
1626
1627 aarch64_set_CPSR (cpu, flags);
1628 }
1629
1630 #define NEG(a) (((a) & signbit) == signbit)
1631 #define POS(a) (((a) & signbit) == 0)
1632
1633 static void
1634 set_flags_for_sub32 (sim_cpu *cpu, uint32_t value1, uint32_t value2)
1635 {
1636 uint32_t result = value1 - value2;
1637 uint32_t flags = 0;
1638 uint32_t signbit = 1ULL << 31;
1639
1640 if (result == 0)
1641 flags |= Z;
1642
1643 if (NEG (result))
1644 flags |= N;
1645
1646 if ( (NEG (value1) && POS (value2))
1647 || (NEG (value1) && POS (result))
1648 || (POS (value2) && POS (result)))
1649 flags |= C;
1650
1651 if ( (NEG (value1) && POS (value2) && POS (result))
1652 || (POS (value1) && NEG (value2) && NEG (result)))
1653 flags |= V;
1654
1655 aarch64_set_CPSR (cpu, flags);
1656 }
1657
1658 static void
1659 set_flags_for_sub64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1660 {
1661 uint64_t result = value1 - value2;
1662 uint32_t flags = 0;
1663 uint64_t signbit = 1ULL << 63;
1664
1665 if (result == 0)
1666 flags |= Z;
1667
1668 if (NEG (result))
1669 flags |= N;
1670
1671 if ( (NEG (value1) && POS (value2))
1672 || (NEG (value1) && POS (result))
1673 || (POS (value2) && POS (result)))
1674 flags |= C;
1675
1676 if ( (NEG (value1) && POS (value2) && POS (result))
1677 || (POS (value1) && NEG (value2) && NEG (result)))
1678 flags |= V;
1679
1680 aarch64_set_CPSR (cpu, flags);
1681 }
1682
1683 static void
1684 set_flags_for_binop32 (sim_cpu *cpu, uint32_t result)
1685 {
1686 uint32_t flags = 0;
1687
1688 if (result == 0)
1689 flags |= Z;
1690 else
1691 flags &= ~ Z;
1692
1693 if (result & (1 << 31))
1694 flags |= N;
1695 else
1696 flags &= ~ N;
1697
1698 aarch64_set_CPSR (cpu, flags);
1699 }
1700
1701 static void
1702 set_flags_for_binop64 (sim_cpu *cpu, uint64_t result)
1703 {
1704 uint32_t flags = 0;
1705
1706 if (result == 0)
1707 flags |= Z;
1708 else
1709 flags &= ~ Z;
1710
1711 if (result & (1ULL << 63))
1712 flags |= N;
1713 else
1714 flags &= ~ N;
1715
1716 aarch64_set_CPSR (cpu, flags);
1717 }
1718
1719 /* 32 bit add immediate set flags. */
1720 static void
1721 adds32 (sim_cpu *cpu, uint32_t aimm)
1722 {
1723 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1724 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1725 /* TODO : do we need to worry about signs here? */
1726 int32_t value1 = aarch64_get_reg_s32 (cpu, rn, SP_OK);
1727
1728 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + aimm);
1729 set_flags_for_add32 (cpu, value1, aimm);
1730 }
1731
1732 /* 64 bit add immediate set flags. */
1733 static void
1734 adds64 (sim_cpu *cpu, uint32_t aimm)
1735 {
1736 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1737 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1738 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1739 uint64_t value2 = aimm;
1740
1741 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1742 set_flags_for_add64 (cpu, value1, value2);
1743 }
1744
1745 /* 32 bit sub immediate. */
1746 static void
1747 sub32 (sim_cpu *cpu, uint32_t aimm)
1748 {
1749 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1750 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1751
1752 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1753 aarch64_get_reg_u32 (cpu, rn, SP_OK) - aimm);
1754 }
1755
1756 /* 64 bit sub immediate. */
1757 static void
1758 sub64 (sim_cpu *cpu, uint32_t aimm)
1759 {
1760 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1761 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1762
1763 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1764 aarch64_get_reg_u64 (cpu, rn, SP_OK) - aimm);
1765 }
1766
1767 /* 32 bit sub immediate set flags. */
1768 static void
1769 subs32 (sim_cpu *cpu, uint32_t aimm)
1770 {
1771 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1772 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1773 uint32_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1774 uint32_t value2 = aimm;
1775
1776 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1777 set_flags_for_sub32 (cpu, value1, value2);
1778 }
1779
1780 /* 64 bit sub immediate set flags. */
1781 static void
1782 subs64 (sim_cpu *cpu, uint32_t aimm)
1783 {
1784 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1785 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1786 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1787 uint32_t value2 = aimm;
1788
1789 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1790 set_flags_for_sub64 (cpu, value1, value2);
1791 }
1792
1793 /* Data Processing Register. */
1794
1795 /* First two helpers to perform the shift operations. */
1796
1797 static inline uint32_t
1798 shifted32 (uint32_t value, Shift shift, uint32_t count)
1799 {
1800 switch (shift)
1801 {
1802 default:
1803 case LSL:
1804 return (value << count);
1805 case LSR:
1806 return (value >> count);
1807 case ASR:
1808 {
1809 int32_t svalue = value;
1810 return (svalue >> count);
1811 }
1812 case ROR:
1813 {
1814 uint32_t top = value >> count;
1815 uint32_t bottom = value << (32 - count);
1816 return (bottom | top);
1817 }
1818 }
1819 }
1820
1821 static inline uint64_t
1822 shifted64 (uint64_t value, Shift shift, uint32_t count)
1823 {
1824 switch (shift)
1825 {
1826 default:
1827 case LSL:
1828 return (value << count);
1829 case LSR:
1830 return (value >> count);
1831 case ASR:
1832 {
1833 int64_t svalue = value;
1834 return (svalue >> count);
1835 }
1836 case ROR:
1837 {
1838 uint64_t top = value >> count;
1839 uint64_t bottom = value << (64 - count);
1840 return (bottom | top);
1841 }
1842 }
1843 }
1844
1845 /* Arithmetic shifted register.
1846 These allow an optional LSL, ASR or LSR to the second source
1847 register with a count up to the register bit count.
1848
1849 N.B register args may not be SP. */
1850
1851 /* 32 bit ADD shifted register. */
1852 static void
1853 add32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1854 {
1855 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1856 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1857 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1858
1859 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1860 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1861 + shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1862 shift, count));
1863 }
1864
1865 /* 64 bit ADD shifted register. */
1866 static void
1867 add64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1868 {
1869 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1870 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1871 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1872
1873 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1874 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1875 + shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1876 shift, count));
1877 }
1878
1879 /* 32 bit ADD shifted register setting flags. */
1880 static void
1881 adds32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1882 {
1883 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1884 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1885 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1886
1887 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1888 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1889 shift, count);
1890
1891 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1892 set_flags_for_add32 (cpu, value1, value2);
1893 }
1894
1895 /* 64 bit ADD shifted register setting flags. */
1896 static void
1897 adds64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1898 {
1899 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1900 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1901 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1902
1903 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1904 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1905 shift, count);
1906
1907 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1908 set_flags_for_add64 (cpu, value1, value2);
1909 }
1910
1911 /* 32 bit SUB shifted register. */
1912 static void
1913 sub32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1914 {
1915 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1916 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1917 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1918
1919 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1920 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1921 - shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1922 shift, count));
1923 }
1924
1925 /* 64 bit SUB shifted register. */
1926 static void
1927 sub64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1928 {
1929 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1930 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1931 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1932
1933 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1934 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1935 - shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1936 shift, count));
1937 }
1938
1939 /* 32 bit SUB shifted register setting flags. */
1940 static void
1941 subs32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1942 {
1943 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1944 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1945 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1946
1947 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1948 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1949 shift, count);
1950
1951 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1952 set_flags_for_sub32 (cpu, value1, value2);
1953 }
1954
1955 /* 64 bit SUB shifted register setting flags. */
1956 static void
1957 subs64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1958 {
1959 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1960 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1961 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1962
1963 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1964 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1965 shift, count);
1966
1967 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1968 set_flags_for_sub64 (cpu, value1, value2);
1969 }
1970
1971 /* First a couple more helpers to fetch the
1972 relevant source register element either
1973 sign or zero extended as required by the
1974 extension value. */
1975
1976 static uint32_t
1977 extreg32 (sim_cpu *cpu, unsigned int lo, Extension extension)
1978 {
1979 switch (extension)
1980 {
1981 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
1982 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
1983 case UXTW: /* Fall through. */
1984 case UXTX: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
1985 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
1986 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
1987 case SXTW: /* Fall through. */
1988 case SXTX: /* Fall through. */
1989 default: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
1990 }
1991 }
1992
1993 static uint64_t
1994 extreg64 (sim_cpu *cpu, unsigned int lo, Extension extension)
1995 {
1996 switch (extension)
1997 {
1998 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
1999 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
2000 case UXTW: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
2001 case UXTX: return aarch64_get_reg_u64 (cpu, lo, NO_SP);
2002 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
2003 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
2004 case SXTW: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
2005 case SXTX:
2006 default: return aarch64_get_reg_s64 (cpu, lo, NO_SP);
2007 }
2008 }
2009
2010 /* Arithmetic extending register
2011 These allow an optional sign extension of some portion of the
2012 second source register followed by an optional left shift of
2013 between 1 and 4 bits (i.e. a shift of 0-4 bits???)
2014
2015 N.B output (dest) and first input arg (source) may normally be Xn
2016 or SP. However, for flag setting operations dest can only be
2017 Xn. Second input registers are always Xn. */
2018
2019 /* 32 bit ADD extending register. */
2020 static void
2021 add32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2022 {
2023 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2024 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2025 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2026
2027 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2028 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2029 + (extreg32 (cpu, rm, extension) << shift));
2030 }
2031
2032 /* 64 bit ADD extending register.
2033 N.B. This subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2034 static void
2035 add64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2036 {
2037 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2038 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2039 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2040
2041 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2042 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2043 + (extreg64 (cpu, rm, extension) << shift));
2044 }
2045
2046 /* 32 bit ADD extending register setting flags. */
2047 static void
2048 adds32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2049 {
2050 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2051 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2052 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2053
2054 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2055 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2056
2057 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2058 set_flags_for_add32 (cpu, value1, value2);
2059 }
2060
2061 /* 64 bit ADD extending register setting flags */
2062 /* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2063 static void
2064 adds64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2065 {
2066 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2067 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2068 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2069
2070 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2071 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2072
2073 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2074 set_flags_for_add64 (cpu, value1, value2);
2075 }
2076
2077 /* 32 bit SUB extending register. */
2078 static void
2079 sub32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2080 {
2081 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2082 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2083 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2084
2085 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2086 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2087 - (extreg32 (cpu, rm, extension) << shift));
2088 }
2089
2090 /* 64 bit SUB extending register. */
2091 /* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2092 static void
2093 sub64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2094 {
2095 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2096 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2097 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2098
2099 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2100 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2101 - (extreg64 (cpu, rm, extension) << shift));
2102 }
2103
2104 /* 32 bit SUB extending register setting flags. */
2105 static void
2106 subs32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2107 {
2108 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2109 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2110 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2111
2112 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2113 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2114
2115 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2116 set_flags_for_sub32 (cpu, value1, value2);
2117 }
2118
2119 /* 64 bit SUB extending register setting flags */
2120 /* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2121 static void
2122 subs64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2123 {
2124 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2125 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2126 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2127
2128 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2129 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2130
2131 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2132 set_flags_for_sub64 (cpu, value1, value2);
2133 }
2134
2135 static void
2136 dexAddSubtractImmediate (sim_cpu *cpu)
2137 {
2138 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2139 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2140 instr[29] = set : 0 ==> no flags, 1 ==> set flags
2141 instr[28,24] = 10001
2142 instr[23,22] = shift : 00 == LSL#0, 01 = LSL#12 1x = UNALLOC
2143 instr[21,10] = uimm12
2144 instr[9,5] = Rn
2145 instr[4,0] = Rd */
2146
2147 /* N.B. the shift is applied at decode before calling the add/sub routine. */
2148 uint32_t shift = uimm (aarch64_get_instr (cpu), 23, 22);
2149 uint32_t imm = uimm (aarch64_get_instr (cpu), 21, 10);
2150 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2151
2152 NYI_assert (28, 24, 0x11);
2153
2154 if (shift > 1)
2155 HALT_UNALLOC;
2156
2157 if (shift)
2158 imm <<= 12;
2159
2160 switch (dispatch)
2161 {
2162 case 0: add32 (cpu, imm); break;
2163 case 1: adds32 (cpu, imm); break;
2164 case 2: sub32 (cpu, imm); break;
2165 case 3: subs32 (cpu, imm); break;
2166 case 4: add64 (cpu, imm); break;
2167 case 5: adds64 (cpu, imm); break;
2168 case 6: sub64 (cpu, imm); break;
2169 case 7: subs64 (cpu, imm); break;
2170 default:
2171 HALT_UNALLOC;
2172 }
2173 }
2174
2175 static void
2176 dexAddSubtractShiftedRegister (sim_cpu *cpu)
2177 {
2178 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2179 instr[30,29] = op : 00 ==> ADD, 01 ==> ADDS, 10 ==> SUB, 11 ==> SUBS
2180 instr[28,24] = 01011
2181 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> UNALLOC
2182 instr[21] = 0
2183 instr[20,16] = Rm
2184 instr[15,10] = count : must be 0xxxxx for 32 bit
2185 instr[9,5] = Rn
2186 instr[4,0] = Rd */
2187
2188 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
2189 /* 32 bit operations must have count[5] = 0
2190 or else we have an UNALLOC. */
2191 uint32_t count = uimm (aarch64_get_instr (cpu), 15, 10);
2192 /* Shift encoded as ROR is unallocated. */
2193 Shift shiftType = shift (aarch64_get_instr (cpu), 22);
2194 /* Dispatch on size:op i.e aarch64_get_instr (cpu)[31,29]. */
2195 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2196
2197 NYI_assert (28, 24, 0x0B);
2198 NYI_assert (21, 21, 0);
2199
2200 if (shiftType == ROR)
2201 HALT_UNALLOC;
2202
2203 if (!size && uimm (count, 5, 5))
2204 HALT_UNALLOC;
2205
2206 switch (dispatch)
2207 {
2208 case 0: add32_shift (cpu, shiftType, count); break;
2209 case 1: adds32_shift (cpu, shiftType, count); break;
2210 case 2: sub32_shift (cpu, shiftType, count); break;
2211 case 3: subs32_shift (cpu, shiftType, count); break;
2212 case 4: add64_shift (cpu, shiftType, count); break;
2213 case 5: adds64_shift (cpu, shiftType, count); break;
2214 case 6: sub64_shift (cpu, shiftType, count); break;
2215 case 7: subs64_shift (cpu, shiftType, count); break;
2216 default:
2217 HALT_UNALLOC;
2218 }
2219 }
2220
2221 static void
2222 dexAddSubtractExtendedRegister (sim_cpu *cpu)
2223 {
2224 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2225 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2226 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2227 instr[28,24] = 01011
2228 instr[23,22] = opt : 0 ==> ok, 1,2,3 ==> UNALLOC
2229 instr[21] = 1
2230 instr[20,16] = Rm
2231 instr[15,13] = option : 000 ==> UXTB, 001 ==> UXTH,
2232 000 ==> LSL|UXTW, 001 ==> UXTZ,
2233 000 ==> SXTB, 001 ==> SXTH,
2234 000 ==> SXTW, 001 ==> SXTX,
2235 instr[12,10] = shift : 0,1,2,3,4 ==> ok, 5,6,7 ==> UNALLOC
2236 instr[9,5] = Rn
2237 instr[4,0] = Rd */
2238
2239 Extension extensionType = extension (aarch64_get_instr (cpu), 13);
2240 uint32_t shift = uimm (aarch64_get_instr (cpu), 12, 10);
2241 /* dispatch on size:op:set? i.e aarch64_get_instr (cpu)[31,29] */
2242 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2243
2244 NYI_assert (28, 24, 0x0B);
2245 NYI_assert (21, 21, 1);
2246
2247 /* Shift may not exceed 4. */
2248 if (shift > 4)
2249 HALT_UNALLOC;
2250
2251 switch (dispatch)
2252 {
2253 case 0: add32_ext (cpu, extensionType, shift); break;
2254 case 1: adds32_ext (cpu, extensionType, shift); break;
2255 case 2: sub32_ext (cpu, extensionType, shift); break;
2256 case 3: subs32_ext (cpu, extensionType, shift); break;
2257 case 4: add64_ext (cpu, extensionType, shift); break;
2258 case 5: adds64_ext (cpu, extensionType, shift); break;
2259 case 6: sub64_ext (cpu, extensionType, shift); break;
2260 case 7: subs64_ext (cpu, extensionType, shift); break;
2261 default: HALT_UNALLOC;
2262 }
2263 }
2264
2265 /* Conditional data processing
2266 Condition register is implicit 3rd source. */
2267
2268 /* 32 bit add with carry. */
2269 /* N.B register args may not be SP. */
2270
2271 static void
2272 adc32 (sim_cpu *cpu)
2273 {
2274 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2275 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2276 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2277
2278 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2279 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2280 + aarch64_get_reg_u32 (cpu, rm, NO_SP)
2281 + IS_SET (C));
2282 }
2283
2284 /* 64 bit add with carry */
2285 static void
2286 adc64 (sim_cpu *cpu)
2287 {
2288 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2289 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2290 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2291
2292 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2293 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2294 + aarch64_get_reg_u64 (cpu, rm, NO_SP)
2295 + IS_SET (C));
2296 }
2297
2298 /* 32 bit add with carry setting flags. */
2299 static void
2300 adcs32 (sim_cpu *cpu)
2301 {
2302 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2303 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2304 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2305
2306 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2307 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2308 uint32_t carry = IS_SET (C);
2309
2310 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2311 set_flags_for_add32 (cpu, value1, value2 + carry);
2312 }
2313
2314 /* 64 bit add with carry setting flags. */
2315 static void
2316 adcs64 (sim_cpu *cpu)
2317 {
2318 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2319 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2320 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2321
2322 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2323 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2324 uint64_t carry = IS_SET (C);
2325
2326 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2327 set_flags_for_add64 (cpu, value1, value2 + carry);
2328 }
2329
2330 /* 32 bit sub with carry. */
2331 static void
2332 sbc32 (sim_cpu *cpu)
2333 {
2334 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2335 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2336 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2337
2338 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2339 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2340 - aarch64_get_reg_u32 (cpu, rm, NO_SP)
2341 - 1 + IS_SET (C));
2342 }
2343
2344 /* 64 bit sub with carry */
2345 static void
2346 sbc64 (sim_cpu *cpu)
2347 {
2348 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2349 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2350 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2351
2352 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2353 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2354 - aarch64_get_reg_u64 (cpu, rm, NO_SP)
2355 - 1 + IS_SET (C));
2356 }
2357
2358 /* 32 bit sub with carry setting flags */
2359 static void
2360 sbcs32 (sim_cpu *cpu)
2361 {
2362 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2363 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2364 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2365
2366 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2367 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2368 uint32_t carry = IS_SET (C);
2369 uint32_t result = value1 - value2 + 1 - carry;
2370
2371 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2372 set_flags_for_sub32 (cpu, value1, value2 + 1 - carry);
2373 }
2374
2375 /* 64 bit sub with carry setting flags */
2376 static void
2377 sbcs64 (sim_cpu *cpu)
2378 {
2379 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2380 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2381 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2382
2383 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2384 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2385 uint64_t carry = IS_SET (C);
2386 uint64_t result = value1 - value2 + 1 - carry;
2387
2388 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2389 set_flags_for_sub64 (cpu, value1, value2 + 1 - carry);
2390 }
2391
2392 static void
2393 dexAddSubtractWithCarry (sim_cpu *cpu)
2394 {
2395 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2396 instr[30] = op : 0 ==> ADC, 1 ==> SBC
2397 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2398 instr[28,21] = 1 1010 000
2399 instr[20,16] = Rm
2400 instr[15,10] = op2 : 00000 ==> ok, ow ==> UNALLOC
2401 instr[9,5] = Rn
2402 instr[4,0] = Rd */
2403
2404 uint32_t op2 = uimm (aarch64_get_instr (cpu), 15, 10);
2405 /* Dispatch on size:op:set? i.e aarch64_get_instr (cpu)[31,29] */
2406 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2407
2408 NYI_assert (28, 21, 0xD0);
2409
2410 if (op2 != 0)
2411 HALT_UNALLOC;
2412
2413 switch (dispatch)
2414 {
2415 case 0: adc32 (cpu); break;
2416 case 1: adcs32 (cpu); break;
2417 case 2: sbc32 (cpu); break;
2418 case 3: sbcs32 (cpu); break;
2419 case 4: adc64 (cpu); break;
2420 case 5: adcs64 (cpu); break;
2421 case 6: sbc64 (cpu); break;
2422 case 7: sbcs64 (cpu); break;
2423 default: HALT_UNALLOC;
2424 }
2425 }
2426
2427 static uint32_t
2428 testConditionCode (sim_cpu *cpu, CondCode cc)
2429 {
2430 /* This should be reduceable to branchless logic
2431 by some careful testing of bits in CC followed
2432 by the requisite masking and combining of bits
2433 from the flag register.
2434
2435 For now we do it with a switch. */
2436 int res;
2437
2438 switch (cc)
2439 {
2440 case EQ: res = IS_SET (Z); break;
2441 case NE: res = IS_CLEAR (Z); break;
2442 case CS: res = IS_SET (C); break;
2443 case CC: res = IS_CLEAR (C); break;
2444 case MI: res = IS_SET (N); break;
2445 case PL: res = IS_CLEAR (N); break;
2446 case VS: res = IS_SET (V); break;
2447 case VC: res = IS_CLEAR (V); break;
2448 case HI: res = IS_SET (C) && IS_CLEAR (Z); break;
2449 case LS: res = IS_CLEAR (C) || IS_SET (Z); break;
2450 case GE: res = IS_SET (N) == IS_SET (V); break;
2451 case LT: res = IS_SET (N) != IS_SET (V); break;
2452 case GT: res = IS_CLEAR (Z) && (IS_SET (N) == IS_SET (V)); break;
2453 case LE: res = IS_SET (Z) || (IS_SET (N) != IS_SET (V)); break;
2454 case AL:
2455 case NV:
2456 default:
2457 res = 1;
2458 break;
2459 }
2460 return res;
2461 }
2462
2463 static void
2464 CondCompare (sim_cpu *cpu) /* aka: ccmp and ccmn */
2465 {
2466 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2467 instr[30] = compare with positive (0) or negative value (1)
2468 instr[29,21] = 1 1101 0010
2469 instr[20,16] = Rm or const
2470 instr[15,12] = cond
2471 instr[11] = compare reg (0) or const (1)
2472 instr[10] = 0
2473 instr[9,5] = Rn
2474 instr[4] = 0
2475 instr[3,0] = value for CPSR bits if the comparison does not take place. */
2476 signed int negate;
2477 unsigned rm;
2478 unsigned rn;
2479
2480 NYI_assert (29, 21, 0x1d2);
2481 NYI_assert (10, 10, 0);
2482 NYI_assert (4, 4, 0);
2483
2484 if (! testConditionCode (cpu, uimm (aarch64_get_instr (cpu), 15, 12)))
2485 {
2486 aarch64_set_CPSR (cpu, uimm (aarch64_get_instr (cpu), 3, 0));
2487 return;
2488 }
2489
2490 negate = uimm (aarch64_get_instr (cpu), 30, 30) ? -1 : 1;
2491 rm = uimm (aarch64_get_instr (cpu), 20, 16);
2492 rn = uimm (aarch64_get_instr (cpu), 9, 5);
2493
2494 if (uimm (aarch64_get_instr (cpu), 31, 31))
2495 {
2496 if (uimm (aarch64_get_instr (cpu), 11, 11))
2497 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2498 negate * (uint64_t) rm);
2499 else
2500 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2501 negate * aarch64_get_reg_u64 (cpu, rm, SP_OK));
2502 }
2503 else
2504 {
2505 if (uimm (aarch64_get_instr (cpu), 11, 11))
2506 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2507 negate * rm);
2508 else
2509 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2510 negate * aarch64_get_reg_u32 (cpu, rm, SP_OK));
2511 }
2512 }
2513
2514 static void
2515 do_vec_MOV_whole_vector (sim_cpu *cpu)
2516 {
2517 /* MOV Vd.T, Vs.T (alias for ORR Vd.T, Vn.T, Vm.T where Vn == Vm)
2518
2519 instr[31] = 0
2520 instr[30] = half(0)/full(1)
2521 instr[29,21] = 001110101
2522 instr[20,16] = Vs
2523 instr[15,10] = 000111
2524 instr[9,5] = Vs
2525 instr[4,0] = Vd */
2526
2527 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2528 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2529
2530 NYI_assert (29, 21, 0x075);
2531 NYI_assert (15, 10, 0x07);
2532
2533 if (uimm (aarch64_get_instr (cpu), 20, 16) != vs)
2534 HALT_NYI;
2535
2536 if (uimm (aarch64_get_instr (cpu), 30, 30))
2537 aarch64_set_vec_u64 (cpu, vd, 1, aarch64_get_vec_u64 (cpu, vs, 1));
2538
2539 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vs, 0));
2540 }
2541
2542 static void
2543 do_vec_MOV_into_scalar (sim_cpu *cpu)
2544 {
2545 /* instr[31] = 0
2546 instr[30] = word(0)/long(1)
2547 instr[29,21] = 00 1110 000
2548 instr[20,18] = element size and index
2549 instr[17,10] = 00 0011 11
2550 instr[9,5] = V source
2551 instr[4,0] = R dest */
2552
2553 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2554 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2555
2556 NYI_assert (29, 21, 0x070);
2557 NYI_assert (17, 10, 0x0F);
2558
2559 switch (uimm (aarch64_get_instr (cpu), 20, 18))
2560 {
2561 case 0x2:
2562 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 0));
2563 break;
2564
2565 case 0x6:
2566 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 1));
2567 break;
2568
2569 case 0x1:
2570 case 0x3:
2571 case 0x5:
2572 case 0x7:
2573 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u32
2574 (cpu, vs, uimm (aarch64_get_instr (cpu), 20, 19)));
2575 break;
2576
2577 default:
2578 HALT_NYI;
2579 }
2580 }
2581
2582 static void
2583 do_vec_INS (sim_cpu *cpu)
2584 {
2585 /* instr[31,21] = 01001110000
2586 instr[20,16] = element size and index
2587 instr[15,10] = 000111
2588 instr[9,5] = W source
2589 instr[4,0] = V dest */
2590
2591 int index;
2592 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
2593 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2594
2595 NYI_assert (31, 21, 0x270);
2596 NYI_assert (15, 10, 0x07);
2597
2598 if (uimm (aarch64_get_instr (cpu), 16, 16))
2599 {
2600 index = uimm (aarch64_get_instr (cpu), 20, 17);
2601 aarch64_set_vec_u8 (cpu, vd, index,
2602 aarch64_get_reg_u8 (cpu, rs, NO_SP));
2603 }
2604 else if (uimm (aarch64_get_instr (cpu), 17, 17))
2605 {
2606 index = uimm (aarch64_get_instr (cpu), 20, 18);
2607 aarch64_set_vec_u16 (cpu, vd, index,
2608 aarch64_get_reg_u16 (cpu, rs, NO_SP));
2609 }
2610 else if (uimm (aarch64_get_instr (cpu), 18, 18))
2611 {
2612 index = uimm (aarch64_get_instr (cpu), 20, 19);
2613 aarch64_set_vec_u32 (cpu, vd, index,
2614 aarch64_get_reg_u32 (cpu, rs, NO_SP));
2615 }
2616 else if (uimm (aarch64_get_instr (cpu), 19, 19))
2617 {
2618 index = uimm (aarch64_get_instr (cpu), 20, 20);
2619 aarch64_set_vec_u64 (cpu, vd, index,
2620 aarch64_get_reg_u64 (cpu, rs, NO_SP));
2621 }
2622 else
2623 HALT_NYI;
2624 }
2625
2626 static void
2627 do_vec_DUP_vector_into_vector (sim_cpu *cpu)
2628 {
2629 /* instr[31] = 0
2630 instr[30] = half(0)/full(1)
2631 instr[29,21] = 00 1110 000
2632 instr[20,16] = element size and index
2633 instr[15,10] = 0000 01
2634 instr[9,5] = V source
2635 instr[4,0] = V dest. */
2636
2637 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
2638 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2639 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2640 int i, index;
2641
2642 NYI_assert (29, 21, 0x070);
2643 NYI_assert (15, 10, 0x01);
2644
2645 if (uimm (aarch64_get_instr (cpu), 16, 16))
2646 {
2647 index = uimm (aarch64_get_instr (cpu), 20, 17);
2648
2649 for (i = 0; i < (full ? 16 : 8); i++)
2650 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, index));
2651 }
2652 else if (uimm (aarch64_get_instr (cpu), 17, 17))
2653 {
2654 index = uimm (aarch64_get_instr (cpu), 20, 18);
2655
2656 for (i = 0; i < (full ? 8 : 4); i++)
2657 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, index));
2658 }
2659 else if (uimm (aarch64_get_instr (cpu), 18, 18))
2660 {
2661 index = uimm (aarch64_get_instr (cpu), 20, 19);
2662
2663 for (i = 0; i < (full ? 4 : 2); i++)
2664 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, index));
2665 }
2666 else
2667 {
2668 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
2669 HALT_UNALLOC;
2670
2671 if (! full)
2672 HALT_UNALLOC;
2673
2674 index = uimm (aarch64_get_instr (cpu), 20, 20);
2675
2676 for (i = 0; i < 2; i++)
2677 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, index));
2678 }
2679 }
2680
2681 static void
2682 do_vec_TBL (sim_cpu *cpu)
2683 {
2684 /* instr[31] = 0
2685 instr[30] = half(0)/full(1)
2686 instr[29,21] = 00 1110 000
2687 instr[20,16] = Vm
2688 instr[15] = 0
2689 instr[14,13] = vec length
2690 instr[12,10] = 000
2691 instr[9,5] = V start
2692 instr[4,0] = V dest */
2693
2694 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2695 int len = uimm (aarch64_get_instr (cpu), 14, 13) + 1;
2696 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2697 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2698 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2699 unsigned i;
2700
2701 NYI_assert (29, 21, 0x070);
2702 NYI_assert (12, 10, 0);
2703
2704 for (i = 0; i < (full ? 16 : 8); i++)
2705 {
2706 unsigned int selector = aarch64_get_vec_u8 (cpu, vm, i);
2707 uint8_t val;
2708
2709 if (selector < 16)
2710 val = aarch64_get_vec_u8 (cpu, vn, selector);
2711 else if (selector < 32)
2712 val = len < 2 ? 0 : aarch64_get_vec_u8 (cpu, vn + 1, selector - 16);
2713 else if (selector < 48)
2714 val = len < 3 ? 0 : aarch64_get_vec_u8 (cpu, vn + 2, selector - 32);
2715 else if (selector < 64)
2716 val = len < 4 ? 0 : aarch64_get_vec_u8 (cpu, vn + 3, selector - 48);
2717 else
2718 val = 0;
2719
2720 aarch64_set_vec_u8 (cpu, vd, i, val);
2721 }
2722 }
2723
2724 static void
2725 do_vec_TRN (sim_cpu *cpu)
2726 {
2727 /* instr[31] = 0
2728 instr[30] = half(0)/full(1)
2729 instr[29,24] = 00 1110
2730 instr[23,22] = size
2731 instr[21] = 0
2732 instr[20,16] = Vm
2733 instr[15] = 0
2734 instr[14] = TRN1 (0) / TRN2 (1)
2735 instr[13,10] = 1010
2736 instr[9,5] = V source
2737 instr[4,0] = V dest. */
2738
2739 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2740 int second = uimm (aarch64_get_instr (cpu), 14, 14);
2741 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2742 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2743 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2744 unsigned i;
2745
2746 NYI_assert (29, 24, 0x0E);
2747 NYI_assert (13, 10, 0xA);
2748
2749 switch (uimm (aarch64_get_instr (cpu), 23, 22))
2750 {
2751 case 0:
2752 for (i = 0; i < (full ? 8 : 4); i++)
2753 {
2754 aarch64_set_vec_u8
2755 (cpu, vd, i * 2,
2756 aarch64_get_vec_u8 (cpu, second ? vm : vn, i * 2));
2757 aarch64_set_vec_u8
2758 (cpu, vd, 1 * 2 + 1,
2759 aarch64_get_vec_u8 (cpu, second ? vn : vm, i * 2 + 1));
2760 }
2761 break;
2762
2763 case 1:
2764 for (i = 0; i < (full ? 4 : 2); i++)
2765 {
2766 aarch64_set_vec_u16
2767 (cpu, vd, i * 2,
2768 aarch64_get_vec_u16 (cpu, second ? vm : vn, i * 2));
2769 aarch64_set_vec_u16
2770 (cpu, vd, 1 * 2 + 1,
2771 aarch64_get_vec_u16 (cpu, second ? vn : vm, i * 2 + 1));
2772 }
2773 break;
2774
2775 case 2:
2776 aarch64_set_vec_u32
2777 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, second ? vm : vn, 0));
2778 aarch64_set_vec_u32
2779 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, second ? vn : vm, 1));
2780 aarch64_set_vec_u32
2781 (cpu, vd, 2, aarch64_get_vec_u32 (cpu, second ? vm : vn, 2));
2782 aarch64_set_vec_u32
2783 (cpu, vd, 3, aarch64_get_vec_u32 (cpu, second ? vn : vm, 3));
2784 break;
2785
2786 case 3:
2787 if (! full)
2788 HALT_UNALLOC;
2789
2790 aarch64_set_vec_u64 (cpu, vd, 0,
2791 aarch64_get_vec_u64 (cpu, second ? vm : vn, 0));
2792 aarch64_set_vec_u64 (cpu, vd, 1,
2793 aarch64_get_vec_u64 (cpu, second ? vn : vm, 1));
2794 break;
2795
2796 default:
2797 HALT_UNALLOC;
2798 }
2799 }
2800
2801 static void
2802 do_vec_DUP_scalar_into_vector (sim_cpu *cpu)
2803 {
2804 /* instr[31] = 0
2805 instr[30] = 0=> zero top 64-bits, 1=> duplicate into top 64-bits
2806 [must be 1 for 64-bit xfer]
2807 instr[29,20] = 00 1110 0000
2808 instr[19,16] = element size: 0001=> 8-bits, 0010=> 16-bits,
2809 0100=> 32-bits. 1000=>64-bits
2810 instr[15,10] = 0000 11
2811 instr[9,5] = W source
2812 instr[4,0] = V dest. */
2813
2814 unsigned i;
2815 unsigned Vd = uimm (aarch64_get_instr (cpu), 4, 0);
2816 unsigned Rs = uimm (aarch64_get_instr (cpu), 9, 5);
2817 int both = uimm (aarch64_get_instr (cpu), 30, 30);
2818
2819 NYI_assert (29, 20, 0x0E0);
2820 NYI_assert (15, 10, 0x03);
2821
2822 switch (uimm (aarch64_get_instr (cpu), 19, 16))
2823 {
2824 case 1:
2825 for (i = 0; i < (both ? 16 : 8); i++)
2826 aarch64_set_vec_u8 (cpu, Vd, i, aarch64_get_reg_u8 (cpu, Rs, NO_SP));
2827 break;
2828
2829 case 2:
2830 for (i = 0; i < (both ? 8 : 4); i++)
2831 aarch64_set_vec_u16 (cpu, Vd, i, aarch64_get_reg_u16 (cpu, Rs, NO_SP));
2832 break;
2833
2834 case 4:
2835 for (i = 0; i < (both ? 4 : 2); i++)
2836 aarch64_set_vec_u32 (cpu, Vd, i, aarch64_get_reg_u32 (cpu, Rs, NO_SP));
2837 break;
2838
2839 case 8:
2840 if (!both)
2841 HALT_NYI;
2842 aarch64_set_vec_u64 (cpu, Vd, 0, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2843 aarch64_set_vec_u64 (cpu, Vd, 1, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2844 break;
2845
2846 default:
2847 HALT_NYI;
2848 }
2849 }
2850
2851 static void
2852 do_vec_UZP (sim_cpu *cpu)
2853 {
2854 /* instr[31] = 0
2855 instr[30] = half(0)/full(1)
2856 instr[29,24] = 00 1110
2857 instr[23,22] = size: byte(00), half(01), word (10), long (11)
2858 instr[21] = 0
2859 instr[20,16] = Vm
2860 instr[15] = 0
2861 instr[14] = lower (0) / upper (1)
2862 instr[13,10] = 0110
2863 instr[9,5] = Vn
2864 instr[4,0] = Vd. */
2865
2866 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2867 int upper = uimm (aarch64_get_instr (cpu), 14, 14);
2868
2869 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2870 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2871 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2872
2873 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2874 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2875 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2876 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2877
2878 uint64_t val1 = 0;
2879 uint64_t val2 = 0;
2880
2881 uint64_t input1 = upper ? val_n1 : val_m1;
2882 uint64_t input2 = upper ? val_n2 : val_m2;
2883 unsigned i;
2884
2885 NYI_assert (29, 24, 0x0E);
2886 NYI_assert (21, 21, 0);
2887 NYI_assert (15, 15, 0);
2888 NYI_assert (13, 10, 6);
2889
2890 switch (uimm (aarch64_get_instr (cpu), 23, 23))
2891 {
2892 case 0:
2893 for (i = 0; i < 8; i++)
2894 {
2895 val1 |= (input1 >> (i * 8)) & (0xFFULL << (i * 8));
2896 val2 |= (input2 >> (i * 8)) & (0xFFULL << (i * 8));
2897 }
2898 break;
2899
2900 case 1:
2901 for (i = 0; i < 4; i++)
2902 {
2903 val1 |= (input1 >> (i * 16)) & (0xFFFFULL << (i * 16));
2904 val2 |= (input2 >> (i * 16)) & (0xFFFFULL << (i * 16));
2905 }
2906 break;
2907
2908 case 2:
2909 val1 = ((input1 & 0xFFFFFFFF) | ((input1 >> 32) & 0xFFFFFFFF00000000ULL));
2910 val2 = ((input2 & 0xFFFFFFFF) | ((input2 >> 32) & 0xFFFFFFFF00000000ULL));
2911
2912 case 3:
2913 val1 = input1;
2914 val2 = input2;
2915 break;
2916 }
2917
2918 aarch64_set_vec_u64 (cpu, vd, 0, val1);
2919 if (full)
2920 aarch64_set_vec_u64 (cpu, vd, 1, val2);
2921 }
2922
2923 static void
2924 do_vec_ZIP (sim_cpu *cpu)
2925 {
2926 /* instr[31] = 0
2927 instr[30] = half(0)/full(1)
2928 instr[29,24] = 00 1110
2929 instr[23,22] = size: byte(00), hald(01), word (10), long (11)
2930 instr[21] = 0
2931 instr[20,16] = Vm
2932 instr[15] = 0
2933 instr[14] = lower (0) / upper (1)
2934 instr[13,10] = 1110
2935 instr[9,5] = Vn
2936 instr[4,0] = Vd. */
2937
2938 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2939 int upper = uimm (aarch64_get_instr (cpu), 14, 14);
2940
2941 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2942 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2943 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2944
2945 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2946 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2947 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2948 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2949
2950 uint64_t val1 = 0;
2951 uint64_t val2 = 0;
2952
2953 uint64_t input1 = upper ? val_n1 : val_m1;
2954 uint64_t input2 = upper ? val_n2 : val_m2;
2955
2956 NYI_assert (29, 24, 0x0E);
2957 NYI_assert (21, 21, 0);
2958 NYI_assert (15, 15, 0);
2959 NYI_assert (13, 10, 0xE);
2960
2961 switch (uimm (aarch64_get_instr (cpu), 23, 23))
2962 {
2963 case 0:
2964 val1 =
2965 ((input1 << 0) & (0xFF << 0))
2966 | ((input2 << 8) & (0xFF << 8))
2967 | ((input1 << 8) & (0xFF << 16))
2968 | ((input2 << 16) & (0xFF << 24))
2969 | ((input1 << 16) & (0xFFULL << 32))
2970 | ((input2 << 24) & (0xFFULL << 40))
2971 | ((input1 << 24) & (0xFFULL << 48))
2972 | ((input2 << 32) & (0xFFULL << 56));
2973
2974 val2 =
2975 ((input1 >> 32) & (0xFF << 0))
2976 | ((input2 >> 24) & (0xFF << 8))
2977 | ((input1 >> 24) & (0xFF << 16))
2978 | ((input2 >> 16) & (0xFF << 24))
2979 | ((input1 >> 16) & (0xFFULL << 32))
2980 | ((input2 >> 8) & (0xFFULL << 40))
2981 | ((input1 >> 8) & (0xFFULL << 48))
2982 | ((input2 >> 0) & (0xFFULL << 56));
2983 break;
2984
2985 case 1:
2986 val1 =
2987 ((input1 << 0) & (0xFFFF << 0))
2988 | ((input2 << 16) & (0xFFFF << 16))
2989 | ((input1 << 16) & (0xFFFFULL << 32))
2990 | ((input2 << 32) & (0xFFFFULL << 48));
2991
2992 val2 =
2993 ((input1 >> 32) & (0xFFFF << 0))
2994 | ((input2 >> 16) & (0xFFFF << 16))
2995 | ((input1 >> 16) & (0xFFFFULL << 32))
2996 | ((input2 >> 0) & (0xFFFFULL << 48));
2997 break;
2998
2999 case 2:
3000 val1 = (input1 & 0xFFFFFFFFULL) | (input2 << 32);
3001 val2 = (input2 & 0xFFFFFFFFULL) | (input1 << 32);
3002 break;
3003
3004 case 3:
3005 val1 = input1;
3006 val2 = input2;
3007 break;
3008 }
3009
3010 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3011 if (full)
3012 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3013 }
3014
3015 /* Floating point immediates are encoded in 8 bits.
3016 fpimm[7] = sign bit.
3017 fpimm[6:4] = signed exponent.
3018 fpimm[3:0] = fraction (assuming leading 1).
3019 i.e. F = s * 1.f * 2^(e - b). */
3020
3021 static float
3022 fp_immediate_for_encoding_32 (uint32_t imm8)
3023 {
3024 float u;
3025 uint32_t s, e, f, i;
3026
3027 s = (imm8 >> 7) & 0x1;
3028 e = (imm8 >> 4) & 0x7;
3029 f = imm8 & 0xf;
3030
3031 /* The fp value is s * n/16 * 2r where n is 16+e. */
3032 u = (16.0 + f) / 16.0;
3033
3034 /* N.B. exponent is signed. */
3035 if (e < 4)
3036 {
3037 int epos = e;
3038
3039 for (i = 0; i <= epos; i++)
3040 u *= 2.0;
3041 }
3042 else
3043 {
3044 int eneg = 7 - e;
3045
3046 for (i = 0; i < eneg; i++)
3047 u /= 2.0;
3048 }
3049
3050 if (s)
3051 u = - u;
3052
3053 return u;
3054 }
3055
3056 static double
3057 fp_immediate_for_encoding_64 (uint32_t imm8)
3058 {
3059 double u;
3060 uint32_t s, e, f, i;
3061
3062 s = (imm8 >> 7) & 0x1;
3063 e = (imm8 >> 4) & 0x7;
3064 f = imm8 & 0xf;
3065
3066 /* The fp value is s * n/16 * 2r where n is 16+e. */
3067 u = (16.0 + f) / 16.0;
3068
3069 /* N.B. exponent is signed. */
3070 if (e < 4)
3071 {
3072 int epos = e;
3073
3074 for (i = 0; i <= epos; i++)
3075 u *= 2.0;
3076 }
3077 else
3078 {
3079 int eneg = 7 - e;
3080
3081 for (i = 0; i < eneg; i++)
3082 u /= 2.0;
3083 }
3084
3085 if (s)
3086 u = - u;
3087
3088 return u;
3089 }
3090
3091 static void
3092 do_vec_MOV_immediate (sim_cpu *cpu)
3093 {
3094 /* instr[31] = 0
3095 instr[30] = full/half selector
3096 instr[29,19] = 00111100000
3097 instr[18,16] = high 3 bits of uimm8
3098 instr[15,12] = size & shift:
3099 0000 => 32-bit
3100 0010 => 32-bit + LSL#8
3101 0100 => 32-bit + LSL#16
3102 0110 => 32-bit + LSL#24
3103 1010 => 16-bit + LSL#8
3104 1000 => 16-bit
3105 1101 => 32-bit + MSL#16
3106 1100 => 32-bit + MSL#8
3107 1110 => 8-bit
3108 1111 => double
3109 instr[11,10] = 01
3110 instr[9,5] = low 5-bits of uimm8
3111 instr[4,0] = Vd. */
3112
3113 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3114 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3115 unsigned val = uimm (aarch64_get_instr (cpu), 18, 16) << 5
3116 | uimm (aarch64_get_instr (cpu), 9, 5);
3117 unsigned i;
3118
3119 NYI_assert (29, 19, 0x1E0);
3120 NYI_assert (11, 10, 1);
3121
3122 switch (uimm (aarch64_get_instr (cpu), 15, 12))
3123 {
3124 case 0x0: /* 32-bit, no shift. */
3125 case 0x2: /* 32-bit, shift by 8. */
3126 case 0x4: /* 32-bit, shift by 16. */
3127 case 0x6: /* 32-bit, shift by 24. */
3128 val <<= (8 * uimm (aarch64_get_instr (cpu), 14, 13));
3129 for (i = 0; i < (full ? 4 : 2); i++)
3130 aarch64_set_vec_u32 (cpu, vd, i, val);
3131 break;
3132
3133 case 0xa: /* 16-bit, shift by 8. */
3134 val <<= 8;
3135 /* Fall through. */
3136 case 0x8: /* 16-bit, no shift. */
3137 for (i = 0; i < (full ? 8 : 4); i++)
3138 aarch64_set_vec_u16 (cpu, vd, i, val);
3139 /* Fall through. */
3140 case 0xd: /* 32-bit, mask shift by 16. */
3141 val <<= 8;
3142 val |= 0xFF;
3143 /* Fall through. */
3144 case 0xc: /* 32-bit, mask shift by 8. */
3145 val <<= 8;
3146 val |= 0xFF;
3147 for (i = 0; i < (full ? 4 : 2); i++)
3148 aarch64_set_vec_u32 (cpu, vd, i, val);
3149 break;
3150
3151 case 0xe: /* 8-bit, no shift. */
3152 for (i = 0; i < (full ? 16 : 8); i++)
3153 aarch64_set_vec_u8 (cpu, vd, i, val);
3154 break;
3155
3156 case 0xf: /* FMOV Vs.{2|4}S, #fpimm. */
3157 {
3158 float u = fp_immediate_for_encoding_32 (val);
3159 for (i = 0; i < (full ? 4 : 2); i++)
3160 aarch64_set_vec_float (cpu, vd, i, u);
3161 break;
3162 }
3163
3164 default:
3165 HALT_NYI;
3166 }
3167 }
3168
3169 static void
3170 do_vec_MVNI (sim_cpu *cpu)
3171 {
3172 /* instr[31] = 0
3173 instr[30] = full/half selector
3174 instr[29,19] = 10111100000
3175 instr[18,16] = high 3 bits of uimm8
3176 instr[15,12] = selector
3177 instr[11,10] = 01
3178 instr[9,5] = low 5-bits of uimm8
3179 instr[4,0] = Vd. */
3180
3181 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3182 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3183 unsigned val = uimm (aarch64_get_instr (cpu), 18, 16) << 5
3184 | uimm (aarch64_get_instr (cpu), 9, 5);
3185 unsigned i;
3186
3187 NYI_assert (29, 19, 0x5E0);
3188 NYI_assert (11, 10, 1);
3189
3190 switch (uimm (aarch64_get_instr (cpu), 15, 12))
3191 {
3192 case 0x0: /* 32-bit, no shift. */
3193 case 0x2: /* 32-bit, shift by 8. */
3194 case 0x4: /* 32-bit, shift by 16. */
3195 case 0x6: /* 32-bit, shift by 24. */
3196 val <<= (8 * uimm (aarch64_get_instr (cpu), 14, 13));
3197 val = ~ val;
3198 for (i = 0; i < (full ? 4 : 2); i++)
3199 aarch64_set_vec_u32 (cpu, vd, i, val);
3200 return;
3201
3202 case 0xa: /* 16-bit, 8 bit shift. */
3203 val <<= 8;
3204 case 0x8: /* 16-bit, no shift. */
3205 val = ~ val;
3206 for (i = 0; i < (full ? 8 : 4); i++)
3207 aarch64_set_vec_u16 (cpu, vd, i, val);
3208 return;
3209
3210 case 0xd: /* 32-bit, mask shift by 16. */
3211 val <<= 8;
3212 val |= 0xFF;
3213 case 0xc: /* 32-bit, mask shift by 8. */
3214 val <<= 8;
3215 val |= 0xFF;
3216 val = ~ val;
3217 for (i = 0; i < (full ? 4 : 2); i++)
3218 aarch64_set_vec_u32 (cpu, vd, i, val);
3219 return;
3220
3221 case 0xE: /* MOVI Dn, #mask64 */
3222 {
3223 uint64_t mask = 0;
3224
3225 for (i = 0; i < 8; i++)
3226 if (val & (1 << i))
3227 mask |= (0xF << (i * 4));
3228 aarch64_set_vec_u64 (cpu, vd, 0, mask);
3229 aarch64_set_vec_u64 (cpu, vd, 1, 0);
3230 return;
3231 }
3232
3233 case 0xf: /* FMOV Vd.2D, #fpimm. */
3234 {
3235 double u = fp_immediate_for_encoding_64 (val);
3236
3237 if (! full)
3238 HALT_UNALLOC;
3239
3240 aarch64_set_vec_double (cpu, vd, 0, u);
3241 aarch64_set_vec_double (cpu, vd, 1, u);
3242 return;
3243 }
3244
3245 default:
3246 HALT_NYI;
3247 }
3248 }
3249
3250 #define ABS(A) ((A) < 0 ? - (A) : (A))
3251
3252 static void
3253 do_vec_ABS (sim_cpu *cpu)
3254 {
3255 /* instr[31] = 0
3256 instr[30] = half(0)/full(1)
3257 instr[29,24] = 00 1110
3258 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3259 instr[21,10] = 10 0000 1011 10
3260 instr[9,5] = Vn
3261 instr[4.0] = Vd. */
3262
3263 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3264 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3265 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
3266 unsigned i;
3267
3268 NYI_assert (29, 24, 0x0E);
3269 NYI_assert (21, 10, 0x82E);
3270
3271 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3272 {
3273 case 0:
3274 for (i = 0; i < (full ? 16 : 8); i++)
3275 aarch64_set_vec_s8 (cpu, vd, i,
3276 ABS (aarch64_get_vec_s8 (cpu, vn, i)));
3277 break;
3278
3279 case 1:
3280 for (i = 0; i < (full ? 8 : 4); i++)
3281 aarch64_set_vec_s16 (cpu, vd, i,
3282 ABS (aarch64_get_vec_s16 (cpu, vn, i)));
3283 break;
3284
3285 case 2:
3286 for (i = 0; i < (full ? 4 : 2); i++)
3287 aarch64_set_vec_s32 (cpu, vd, i,
3288 ABS (aarch64_get_vec_s32 (cpu, vn, i)));
3289 break;
3290
3291 case 3:
3292 if (! full)
3293 HALT_NYI;
3294 for (i = 0; i < 2; i++)
3295 aarch64_set_vec_s64 (cpu, vd, i,
3296 ABS (aarch64_get_vec_s64 (cpu, vn, i)));
3297 break;
3298 }
3299 }
3300
3301 static void
3302 do_vec_ADDV (sim_cpu *cpu)
3303 {
3304 /* instr[31] = 0
3305 instr[30] = full/half selector
3306 instr[29,24] = 00 1110
3307 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3308 instr[21,10] = 11 0001 1011 10
3309 instr[9,5] = Vm
3310 instr[4.0] = Rd. */
3311
3312 unsigned vm = uimm (aarch64_get_instr (cpu), 9, 5);
3313 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
3314 unsigned i;
3315 uint64_t val = 0;
3316 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3317
3318 NYI_assert (29, 24, 0x0E);
3319 NYI_assert (21, 10, 0xC6E);
3320
3321 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3322 {
3323 case 0:
3324 for (i = 0; i < (full ? 16 : 8); i++)
3325 val += aarch64_get_vec_u8 (cpu, vm, i);
3326 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3327 return;
3328
3329 case 1:
3330 for (i = 0; i < (full ? 8 : 4); i++)
3331 val += aarch64_get_vec_u16 (cpu, vm, i);
3332 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3333 return;
3334
3335 case 2:
3336 for (i = 0; i < (full ? 4 : 2); i++)
3337 val += aarch64_get_vec_u32 (cpu, vm, i);
3338 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3339 return;
3340
3341 case 3:
3342 if (! full)
3343 HALT_UNALLOC;
3344 val = aarch64_get_vec_u64 (cpu, vm, 0);
3345 val += aarch64_get_vec_u64 (cpu, vm, 1);
3346 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3347 return;
3348
3349 default:
3350 HALT_UNREACHABLE;
3351 }
3352 }
3353
3354 static void
3355 do_vec_ins_2 (sim_cpu *cpu)
3356 {
3357 /* instr[31,21] = 01001110000
3358 instr[20,18] = size & element selector
3359 instr[17,14] = 0000
3360 instr[13] = direction: to vec(0), from vec (1)
3361 instr[12,10] = 111
3362 instr[9,5] = Vm
3363 instr[4,0] = Vd. */
3364
3365 unsigned elem;
3366 unsigned vm = uimm (aarch64_get_instr (cpu), 9, 5);
3367 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3368
3369 NYI_assert (31, 21, 0x270);
3370 NYI_assert (17, 14, 0);
3371 NYI_assert (12, 10, 7);
3372
3373 if (uimm (aarch64_get_instr (cpu), 13, 13) == 1)
3374 {
3375 if (uimm (aarch64_get_instr (cpu), 18, 18) == 1)
3376 {
3377 /* 32-bit moves. */
3378 elem = uimm (aarch64_get_instr (cpu), 20, 19);
3379 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3380 aarch64_get_vec_u32 (cpu, vm, elem));
3381 }
3382 else
3383 {
3384 /* 64-bit moves. */
3385 if (uimm (aarch64_get_instr (cpu), 19, 19) != 1)
3386 HALT_NYI;
3387
3388 elem = uimm (aarch64_get_instr (cpu), 20, 20);
3389 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3390 aarch64_get_vec_u64 (cpu, vm, elem));
3391 }
3392 }
3393 else
3394 {
3395 if (uimm (aarch64_get_instr (cpu), 18, 18) == 1)
3396 {
3397 /* 32-bit moves. */
3398 elem = uimm (aarch64_get_instr (cpu), 20, 19);
3399 aarch64_set_vec_u32 (cpu, vd, elem,
3400 aarch64_get_reg_u32 (cpu, vm, NO_SP));
3401 }
3402 else
3403 {
3404 /* 64-bit moves. */
3405 if (uimm (aarch64_get_instr (cpu), 19, 19) != 1)
3406 HALT_NYI;
3407
3408 elem = uimm (aarch64_get_instr (cpu), 20, 20);
3409 aarch64_set_vec_u64 (cpu, vd, elem,
3410 aarch64_get_reg_u64 (cpu, vm, NO_SP));
3411 }
3412 }
3413 }
3414
3415 static void
3416 do_vec_mull (sim_cpu *cpu)
3417 {
3418 /* instr[31] = 0
3419 instr[30] = lower(0)/upper(1) selector
3420 instr[29] = signed(0)/unsigned(1)
3421 instr[28,24] = 0 1110
3422 instr[23,22] = size: 8-bit (00), 16-bit (01), 32-bit (10)
3423 instr[21] = 1
3424 instr[20,16] = Vm
3425 instr[15,10] = 11 0000
3426 instr[9,5] = Vn
3427 instr[4.0] = Vd. */
3428
3429 int unsign = uimm (aarch64_get_instr (cpu), 29, 29);
3430 int bias = uimm (aarch64_get_instr (cpu), 30, 30);
3431 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3432 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3433 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3434 unsigned i;
3435
3436 NYI_assert (28, 24, 0x0E);
3437 NYI_assert (15, 10, 0x30);
3438
3439 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3440 {
3441 case 0:
3442 if (bias)
3443 bias = 8;
3444 if (unsign)
3445 for (i = 0; i < 8; i++)
3446 aarch64_set_vec_u16 (cpu, vd, i,
3447 aarch64_get_vec_u8 (cpu, vn, i + bias)
3448 * aarch64_get_vec_u8 (cpu, vm, i + bias));
3449 else
3450 for (i = 0; i < 8; i++)
3451 aarch64_set_vec_s16 (cpu, vd, i,
3452 aarch64_get_vec_s8 (cpu, vn, i + bias)
3453 * aarch64_get_vec_s8 (cpu, vm, i + bias));
3454 return;
3455
3456 case 1:
3457 if (bias)
3458 bias = 4;
3459 if (unsign)
3460 for (i = 0; i < 4; i++)
3461 aarch64_set_vec_u32 (cpu, vd, i,
3462 aarch64_get_vec_u16 (cpu, vn, i + bias)
3463 * aarch64_get_vec_u16 (cpu, vm, i + bias));
3464 else
3465 for (i = 0; i < 4; i++)
3466 aarch64_set_vec_s32 (cpu, vd, i,
3467 aarch64_get_vec_s16 (cpu, vn, i + bias)
3468 * aarch64_get_vec_s16 (cpu, vm, i + bias));
3469 return;
3470
3471 case 2:
3472 if (bias)
3473 bias = 2;
3474 if (unsign)
3475 for (i = 0; i < 2; i++)
3476 aarch64_set_vec_u64 (cpu, vd, i,
3477 (uint64_t) aarch64_get_vec_u32 (cpu, vn,
3478 i + bias)
3479 * (uint64_t) aarch64_get_vec_u32 (cpu, vm,
3480 i + bias));
3481 else
3482 for (i = 0; i < 2; i++)
3483 aarch64_set_vec_s64 (cpu, vd, i,
3484 aarch64_get_vec_s32 (cpu, vn, i + bias)
3485 * aarch64_get_vec_s32 (cpu, vm, i + bias));
3486 return;
3487
3488 case 3:
3489 default:
3490 HALT_NYI;
3491 }
3492 }
3493
3494 static void
3495 do_vec_fadd (sim_cpu *cpu)
3496 {
3497 /* instr[31] = 0
3498 instr[30] = half(0)/full(1)
3499 instr[29,24] = 001110
3500 instr[23] = FADD(0)/FSUB(1)
3501 instr[22] = float (0)/double(1)
3502 instr[21] = 1
3503 instr[20,16] = Vm
3504 instr[15,10] = 110101
3505 instr[9,5] = Vn
3506 instr[4.0] = Vd. */
3507
3508 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3509 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3510 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3511 unsigned i;
3512 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3513
3514 NYI_assert (29, 24, 0x0E);
3515 NYI_assert (21, 21, 1);
3516 NYI_assert (15, 10, 0x35);
3517
3518 if (uimm (aarch64_get_instr (cpu), 23, 23))
3519 {
3520 if (uimm (aarch64_get_instr (cpu), 22, 22))
3521 {
3522 if (! full)
3523 HALT_NYI;
3524
3525 for (i = 0; i < 2; i++)
3526 aarch64_set_vec_double (cpu, vd, i,
3527 aarch64_get_vec_double (cpu, vn, i)
3528 - aarch64_get_vec_double (cpu, vm, i));
3529 }
3530 else
3531 {
3532 for (i = 0; i < (full ? 4 : 2); i++)
3533 aarch64_set_vec_float (cpu, vd, i,
3534 aarch64_get_vec_float (cpu, vn, i)
3535 - aarch64_get_vec_float (cpu, vm, i));
3536 }
3537 }
3538 else
3539 {
3540 if (uimm (aarch64_get_instr (cpu), 22, 22))
3541 {
3542 if (! full)
3543 HALT_NYI;
3544
3545 for (i = 0; i < 2; i++)
3546 aarch64_set_vec_double (cpu, vd, i,
3547 aarch64_get_vec_double (cpu, vm, i)
3548 + aarch64_get_vec_double (cpu, vn, i));
3549 }
3550 else
3551 {
3552 for (i = 0; i < (full ? 4 : 2); i++)
3553 aarch64_set_vec_float (cpu, vd, i,
3554 aarch64_get_vec_float (cpu, vm, i)
3555 + aarch64_get_vec_float (cpu, vn, i));
3556 }
3557 }
3558 }
3559
3560 static void
3561 do_vec_add (sim_cpu *cpu)
3562 {
3563 /* instr[31] = 0
3564 instr[30] = full/half selector
3565 instr[29,24] = 001110
3566 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3567 instr[21] = 1
3568 instr[20,16] = Vn
3569 instr[15,10] = 100001
3570 instr[9,5] = Vm
3571 instr[4.0] = Vd. */
3572
3573 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3574 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3575 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3576 unsigned i;
3577 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3578
3579 NYI_assert (29, 24, 0x0E);
3580 NYI_assert (21, 21, 1);
3581 NYI_assert (15, 10, 0x21);
3582
3583 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3584 {
3585 case 0:
3586 for (i = 0; i < (full ? 16 : 8); i++)
3587 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
3588 + aarch64_get_vec_u8 (cpu, vm, i));
3589 return;
3590
3591 case 1:
3592 for (i = 0; i < (full ? 8 : 4); i++)
3593 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
3594 + aarch64_get_vec_u16 (cpu, vm, i));
3595 return;
3596
3597 case 2:
3598 for (i = 0; i < (full ? 4 : 2); i++)
3599 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
3600 + aarch64_get_vec_u32 (cpu, vm, i));
3601 return;
3602
3603 case 3:
3604 if (! full)
3605 HALT_UNALLOC;
3606 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vn, 0)
3607 + aarch64_get_vec_u64 (cpu, vm, 0));
3608 aarch64_set_vec_u64 (cpu, vd, 1,
3609 aarch64_get_vec_u64 (cpu, vn, 1)
3610 + aarch64_get_vec_u64 (cpu, vm, 1));
3611 return;
3612
3613 default:
3614 HALT_UNREACHABLE;
3615 }
3616 }
3617
3618 static void
3619 do_vec_mul (sim_cpu *cpu)
3620 {
3621 /* instr[31] = 0
3622 instr[30] = full/half selector
3623 instr[29,24] = 00 1110
3624 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3625 instr[21] = 1
3626 instr[20,16] = Vn
3627 instr[15,10] = 10 0111
3628 instr[9,5] = Vm
3629 instr[4.0] = Vd. */
3630
3631 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3632 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3633 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3634 unsigned i;
3635 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3636
3637 NYI_assert (29, 24, 0x0E);
3638 NYI_assert (21, 21, 1);
3639 NYI_assert (15, 10, 0x27);
3640
3641 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3642 {
3643 case 0:
3644 for (i = 0; i < (full ? 16 : 8); i++)
3645 {
3646 uint16_t val = aarch64_get_vec_u8 (cpu, vn, i);
3647 val *= aarch64_get_vec_u8 (cpu, vm, i);
3648
3649 aarch64_set_vec_u16 (cpu, vd, i, val);
3650 }
3651 return;
3652
3653 case 1:
3654 for (i = 0; i < (full ? 8 : 4); i++)
3655 {
3656 uint32_t val = aarch64_get_vec_u16 (cpu, vn, i);
3657 val *= aarch64_get_vec_u16 (cpu, vm, i);
3658
3659 aarch64_set_vec_u32 (cpu, vd, i, val);
3660 }
3661 return;
3662
3663 case 2:
3664 for (i = 0; i < (full ? 4 : 2); i++)
3665 {
3666 uint64_t val = aarch64_get_vec_u32 (cpu, vn, i);
3667 val *= aarch64_get_vec_u32 (cpu, vm, i);
3668
3669 aarch64_set_vec_u64 (cpu, vd, i, val);
3670 }
3671 return;
3672
3673 default:
3674 case 3:
3675 HALT_UNALLOC;
3676 }
3677 }
3678
3679 static void
3680 do_vec_MLA (sim_cpu *cpu)
3681 {
3682 /* instr[31] = 0
3683 instr[30] = full/half selector
3684 instr[29,24] = 00 1110
3685 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3686 instr[21] = 1
3687 instr[20,16] = Vn
3688 instr[15,10] = 1001 01
3689 instr[9,5] = Vm
3690 instr[4.0] = Vd. */
3691
3692 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3693 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3694 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3695 unsigned i;
3696 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3697
3698 NYI_assert (29, 24, 0x0E);
3699 NYI_assert (21, 21, 1);
3700 NYI_assert (15, 10, 0x25);
3701
3702 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3703 {
3704 case 0:
3705 for (i = 0; i < (full ? 16 : 8); i++)
3706 {
3707 uint16_t val = aarch64_get_vec_u8 (cpu, vn, i);
3708 val *= aarch64_get_vec_u8 (cpu, vm, i);
3709 val += aarch64_get_vec_u8 (cpu, vd, i);
3710
3711 aarch64_set_vec_u16 (cpu, vd, i, val);
3712 }
3713 return;
3714
3715 case 1:
3716 for (i = 0; i < (full ? 8 : 4); i++)
3717 {
3718 uint32_t val = aarch64_get_vec_u16 (cpu, vn, i);
3719 val *= aarch64_get_vec_u16 (cpu, vm, i);
3720 val += aarch64_get_vec_u16 (cpu, vd, i);
3721
3722 aarch64_set_vec_u32 (cpu, vd, i, val);
3723 }
3724 return;
3725
3726 case 2:
3727 for (i = 0; i < (full ? 4 : 2); i++)
3728 {
3729 uint64_t val = aarch64_get_vec_u32 (cpu, vn, i);
3730 val *= aarch64_get_vec_u32 (cpu, vm, i);
3731 val += aarch64_get_vec_u32 (cpu, vd, i);
3732
3733 aarch64_set_vec_u64 (cpu, vd, i, val);
3734 }
3735 return;
3736
3737 default:
3738 case 3:
3739 HALT_UNALLOC;
3740 }
3741 }
3742
3743 static float
3744 fmaxnm (float a, float b)
3745 {
3746 if (fpclassify (a) == FP_NORMAL)
3747 {
3748 if (fpclassify (b) == FP_NORMAL)
3749 return a > b ? a : b;
3750 return a;
3751 }
3752 else if (fpclassify (b) == FP_NORMAL)
3753 return b;
3754 return a;
3755 }
3756
3757 static float
3758 fminnm (float a, float b)
3759 {
3760 if (fpclassify (a) == FP_NORMAL)
3761 {
3762 if (fpclassify (b) == FP_NORMAL)
3763 return a < b ? a : b;
3764 return a;
3765 }
3766 else if (fpclassify (b) == FP_NORMAL)
3767 return b;
3768 return a;
3769 }
3770
3771 static double
3772 dmaxnm (double a, double b)
3773 {
3774 if (fpclassify (a) == FP_NORMAL)
3775 {
3776 if (fpclassify (b) == FP_NORMAL)
3777 return a > b ? a : b;
3778 return a;
3779 }
3780 else if (fpclassify (b) == FP_NORMAL)
3781 return b;
3782 return a;
3783 }
3784
3785 static double
3786 dminnm (double a, double b)
3787 {
3788 if (fpclassify (a) == FP_NORMAL)
3789 {
3790 if (fpclassify (b) == FP_NORMAL)
3791 return a < b ? a : b;
3792 return a;
3793 }
3794 else if (fpclassify (b) == FP_NORMAL)
3795 return b;
3796 return a;
3797 }
3798
3799 static void
3800 do_vec_FminmaxNMP (sim_cpu *cpu)
3801 {
3802 /* aarch64_get_instr (cpu)[31] = 0
3803 aarch64_get_instr (cpu)[30] = half (0)/full (1)
3804 aarch64_get_instr (cpu)[29,24] = 10 1110
3805 aarch64_get_instr (cpu)[23] = max(0)/min(1)
3806 aarch64_get_instr (cpu)[22] = float (0)/double (1)
3807 aarch64_get_instr (cpu)[21] = 1
3808 aarch64_get_instr (cpu)[20,16] = Vn
3809 aarch64_get_instr (cpu)[15,10] = 1100 01
3810 aarch64_get_instr (cpu)[9,5] = Vm
3811 aarch64_get_instr (cpu)[4.0] = Vd. */
3812
3813 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3814 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3815 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3816 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3817
3818 NYI_assert (29, 24, 0x2E);
3819 NYI_assert (21, 21, 1);
3820 NYI_assert (15, 10, 0x31);
3821
3822 if (uimm (aarch64_get_instr (cpu), 22, 22))
3823 {
3824 double (* fn)(double, double) = uimm (aarch64_get_instr (cpu), 23, 23)
3825 ? dminnm : dmaxnm;
3826
3827 if (! full)
3828 HALT_NYI;
3829 aarch64_set_vec_double (cpu, vd, 0,
3830 fn (aarch64_get_vec_double (cpu, vn, 0),
3831 aarch64_get_vec_double (cpu, vn, 1)));
3832 aarch64_set_vec_double (cpu, vd, 0,
3833 fn (aarch64_get_vec_double (cpu, vm, 0),
3834 aarch64_get_vec_double (cpu, vm, 1)));
3835 }
3836 else
3837 {
3838 float (* fn)(float, float) = uimm (aarch64_get_instr (cpu), 23, 23)
3839 ? fminnm : fmaxnm;
3840
3841 aarch64_set_vec_float (cpu, vd, 0,
3842 fn (aarch64_get_vec_float (cpu, vn, 0),
3843 aarch64_get_vec_float (cpu, vn, 1)));
3844 if (full)
3845 aarch64_set_vec_float (cpu, vd, 1,
3846 fn (aarch64_get_vec_float (cpu, vn, 2),
3847 aarch64_get_vec_float (cpu, vn, 3)));
3848
3849 aarch64_set_vec_float (cpu, vd, (full ? 2 : 1),
3850 fn (aarch64_get_vec_float (cpu, vm, 0),
3851 aarch64_get_vec_float (cpu, vm, 1)));
3852 if (full)
3853 aarch64_set_vec_float (cpu, vd, 3,
3854 fn (aarch64_get_vec_float (cpu, vm, 2),
3855 aarch64_get_vec_float (cpu, vm, 3)));
3856 }
3857 }
3858
3859 static void
3860 do_vec_AND (sim_cpu *cpu)
3861 {
3862 /* instr[31] = 0
3863 instr[30] = half (0)/full (1)
3864 instr[29,21] = 001110001
3865 instr[20,16] = Vm
3866 instr[15,10] = 000111
3867 instr[9,5] = Vn
3868 instr[4.0] = Vd. */
3869
3870 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3871 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3872 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3873 unsigned i;
3874 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3875
3876 NYI_assert (29, 21, 0x071);
3877 NYI_assert (15, 10, 0x07);
3878
3879 for (i = 0; i < (full ? 4 : 2); i++)
3880 aarch64_set_vec_u32 (cpu, vd, i,
3881 aarch64_get_vec_u32 (cpu, vn, i)
3882 & aarch64_get_vec_u32 (cpu, vm, i));
3883 }
3884
3885 static void
3886 do_vec_BSL (sim_cpu *cpu)
3887 {
3888 /* instr[31] = 0
3889 instr[30] = half (0)/full (1)
3890 instr[29,21] = 101110011
3891 instr[20,16] = Vm
3892 instr[15,10] = 000111
3893 instr[9,5] = Vn
3894 instr[4.0] = Vd. */
3895
3896 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3897 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3898 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3899 unsigned i;
3900 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3901
3902 NYI_assert (29, 21, 0x173);
3903 NYI_assert (15, 10, 0x07);
3904
3905 for (i = 0; i < (full ? 16 : 8); i++)
3906 aarch64_set_vec_u8 (cpu, vd, i,
3907 ( aarch64_get_vec_u8 (cpu, vd, i)
3908 & aarch64_get_vec_u8 (cpu, vn, i))
3909 | ((~ aarch64_get_vec_u8 (cpu, vd, i))
3910 & aarch64_get_vec_u8 (cpu, vm, i)));
3911 }
3912
3913 static void
3914 do_vec_EOR (sim_cpu *cpu)
3915 {
3916 /* instr[31] = 0
3917 instr[30] = half (0)/full (1)
3918 instr[29,21] = 10 1110 001
3919 instr[20,16] = Vm
3920 instr[15,10] = 000111
3921 instr[9,5] = Vn
3922 instr[4.0] = Vd. */
3923
3924 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3925 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3926 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3927 unsigned i;
3928 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3929
3930 NYI_assert (29, 21, 0x171);
3931 NYI_assert (15, 10, 0x07);
3932
3933 for (i = 0; i < (full ? 4 : 2); i++)
3934 aarch64_set_vec_u32 (cpu, vd, i,
3935 aarch64_get_vec_u32 (cpu, vn, i)
3936 ^ aarch64_get_vec_u32 (cpu, vm, i));
3937 }
3938
3939 static void
3940 do_vec_bit (sim_cpu *cpu)
3941 {
3942 /* instr[31] = 0
3943 instr[30] = half (0)/full (1)
3944 instr[29,23] = 10 1110 1
3945 instr[22] = BIT (0) / BIF (1)
3946 instr[21] = 1
3947 instr[20,16] = Vm
3948 instr[15,10] = 0001 11
3949 instr[9,5] = Vn
3950 instr[4.0] = Vd. */
3951
3952 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3953 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3954 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3955 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
3956 unsigned test_false = uimm (aarch64_get_instr (cpu), 22, 22);
3957 unsigned i;
3958
3959 NYI_assert (29, 23, 0x5D);
3960 NYI_assert (21, 21, 1);
3961 NYI_assert (15, 10, 0x07);
3962
3963 if (test_false)
3964 {
3965 for (i = 0; i < (full ? 16 : 8); i++)
3966 if (aarch64_get_vec_u32 (cpu, vn, i) == 0)
3967 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
3968 }
3969 else
3970 {
3971 for (i = 0; i < (full ? 16 : 8); i++)
3972 if (aarch64_get_vec_u32 (cpu, vn, i) != 0)
3973 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
3974 }
3975 }
3976
3977 static void
3978 do_vec_ORN (sim_cpu *cpu)
3979 {
3980 /* instr[31] = 0
3981 instr[30] = half (0)/full (1)
3982 instr[29,21] = 00 1110 111
3983 instr[20,16] = Vm
3984 instr[15,10] = 00 0111
3985 instr[9,5] = Vn
3986 instr[4.0] = Vd. */
3987
3988 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3989 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3990 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3991 unsigned i;
3992 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3993
3994 NYI_assert (29, 21, 0x077);
3995 NYI_assert (15, 10, 0x07);
3996
3997 for (i = 0; i < (full ? 16 : 8); i++)
3998 aarch64_set_vec_u8 (cpu, vd, i,
3999 aarch64_get_vec_u8 (cpu, vn, i)
4000 | ~ aarch64_get_vec_u8 (cpu, vm, i));
4001 }
4002
4003 static void
4004 do_vec_ORR (sim_cpu *cpu)
4005 {
4006 /* instr[31] = 0
4007 instr[30] = half (0)/full (1)
4008 instr[29,21] = 00 1110 101
4009 instr[20,16] = Vm
4010 instr[15,10] = 0001 11
4011 instr[9,5] = Vn
4012 instr[4.0] = Vd. */
4013
4014 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4015 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4016 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4017 unsigned i;
4018 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4019
4020 NYI_assert (29, 21, 0x075);
4021 NYI_assert (15, 10, 0x07);
4022
4023 for (i = 0; i < (full ? 16 : 8); i++)
4024 aarch64_set_vec_u8 (cpu, vd, i,
4025 aarch64_get_vec_u8 (cpu, vn, i)
4026 | aarch64_get_vec_u8 (cpu, vm, i));
4027 }
4028
4029 static void
4030 do_vec_BIC (sim_cpu *cpu)
4031 {
4032 /* instr[31] = 0
4033 instr[30] = half (0)/full (1)
4034 instr[29,21] = 00 1110 011
4035 instr[20,16] = Vm
4036 instr[15,10] = 00 0111
4037 instr[9,5] = Vn
4038 instr[4.0] = Vd. */
4039
4040 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4041 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4042 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4043 unsigned i;
4044 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4045
4046 NYI_assert (29, 21, 0x073);
4047 NYI_assert (15, 10, 0x07);
4048
4049 for (i = 0; i < (full ? 16 : 8); i++)
4050 aarch64_set_vec_u8 (cpu, vd, i,
4051 aarch64_get_vec_u8 (cpu, vn, i)
4052 & ~ aarch64_get_vec_u8 (cpu, vm, i));
4053 }
4054
4055 static void
4056 do_vec_XTN (sim_cpu *cpu)
4057 {
4058 /* instr[31] = 0
4059 instr[30] = first part (0)/ second part (1)
4060 instr[29,24] = 00 1110
4061 instr[23,22] = size: byte(00), half(01), word (10)
4062 instr[21,10] = 1000 0100 1010
4063 instr[9,5] = Vs
4064 instr[4,0] = Vd. */
4065
4066 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4067 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4068 unsigned bias = uimm (aarch64_get_instr (cpu), 30, 30);
4069 unsigned i;
4070
4071 NYI_assert (29, 24, 0x0E);
4072 NYI_assert (21, 10, 0x84A);
4073
4074 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4075 {
4076 case 0:
4077 if (bias)
4078 for (i = 0; i < 8; i++)
4079 aarch64_set_vec_u8 (cpu, vd, i + 8,
4080 aarch64_get_vec_u16 (cpu, vs, i) >> 8);
4081 else
4082 for (i = 0; i < 8; i++)
4083 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i));
4084 return;
4085
4086 case 1:
4087 if (bias)
4088 for (i = 0; i < 4; i++)
4089 aarch64_set_vec_u16 (cpu, vd, i + 4,
4090 aarch64_get_vec_u32 (cpu, vs, i) >> 16);
4091 else
4092 for (i = 0; i < 4; i++)
4093 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, i));
4094 return;
4095
4096 case 2:
4097 if (bias)
4098 for (i = 0; i < 2; i++)
4099 aarch64_set_vec_u32 (cpu, vd, i + 4,
4100 aarch64_get_vec_u64 (cpu, vs, i) >> 32);
4101 else
4102 for (i = 0; i < 2; i++)
4103 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, i));
4104 return;
4105
4106 default:
4107 HALT_UNALLOC;
4108 }
4109 }
4110
4111 #define MAX(A,B) ((A) > (B) ? (A) : (B))
4112 #define MIN(A,B) ((A) < (B) ? (A) : (B))
4113
4114 static void
4115 do_vec_maxv (sim_cpu *cpu)
4116 {
4117 /* instr[31] = 0
4118 instr[30] = half(0)/full(1)
4119 instr[29] = signed (0)/unsigned(1)
4120 instr[28,24] = 0 1110
4121 instr[23,22] = size: byte(00), half(01), word (10)
4122 instr[21] = 1
4123 instr[20,17] = 1 000
4124 instr[16] = max(0)/min(1)
4125 instr[15,10] = 1010 10
4126 instr[9,5] = V source
4127 instr[4.0] = R dest. */
4128
4129 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4130 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
4131 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4132 unsigned i;
4133
4134 NYI_assert (28, 24, 0x0E);
4135 NYI_assert (21, 21, 1);
4136 NYI_assert (20, 17, 8);
4137 NYI_assert (15, 10, 0x2A);
4138
4139 switch ((uimm (aarch64_get_instr (cpu), 29, 29) << 1)
4140 | uimm (aarch64_get_instr (cpu), 16, 16))
4141 {
4142 case 0: /* SMAXV. */
4143 {
4144 int64_t smax;
4145 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4146 {
4147 case 0:
4148 smax = aarch64_get_vec_s8 (cpu, vs, 0);
4149 for (i = 1; i < (full ? 16 : 8); i++)
4150 smax = MAX (smax, aarch64_get_vec_s8 (cpu, vs, i));
4151 break;
4152 case 1:
4153 smax = aarch64_get_vec_s16 (cpu, vs, 0);
4154 for (i = 1; i < (full ? 8 : 4); i++)
4155 smax = MAX (smax, aarch64_get_vec_s16 (cpu, vs, i));
4156 break;
4157 case 2:
4158 smax = aarch64_get_vec_s32 (cpu, vs, 0);
4159 for (i = 1; i < (full ? 4 : 2); i++)
4160 smax = MAX (smax, aarch64_get_vec_s32 (cpu, vs, i));
4161 break;
4162 default:
4163 case 3:
4164 HALT_UNALLOC;
4165 }
4166 aarch64_set_reg_s64 (cpu, rd, NO_SP, smax);
4167 return;
4168 }
4169
4170 case 1: /* SMINV. */
4171 {
4172 int64_t smin;
4173 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4174 {
4175 case 0:
4176 smin = aarch64_get_vec_s8 (cpu, vs, 0);
4177 for (i = 1; i < (full ? 16 : 8); i++)
4178 smin = MIN (smin, aarch64_get_vec_s8 (cpu, vs, i));
4179 break;
4180 case 1:
4181 smin = aarch64_get_vec_s16 (cpu, vs, 0);
4182 for (i = 1; i < (full ? 8 : 4); i++)
4183 smin = MIN (smin, aarch64_get_vec_s16 (cpu, vs, i));
4184 break;
4185 case 2:
4186 smin = aarch64_get_vec_s32 (cpu, vs, 0);
4187 for (i = 1; i < (full ? 4 : 2); i++)
4188 smin = MIN (smin, aarch64_get_vec_s32 (cpu, vs, i));
4189 break;
4190 default:
4191 case 3:
4192 HALT_UNALLOC;
4193 }
4194 aarch64_set_reg_s64 (cpu, rd, NO_SP, smin);
4195 return;
4196 }
4197
4198 case 2: /* UMAXV. */
4199 {
4200 uint64_t umax;
4201 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4202 {
4203 case 0:
4204 umax = aarch64_get_vec_u8 (cpu, vs, 0);
4205 for (i = 1; i < (full ? 16 : 8); i++)
4206 umax = MAX (umax, aarch64_get_vec_u8 (cpu, vs, i));
4207 break;
4208 case 1:
4209 umax = aarch64_get_vec_u16 (cpu, vs, 0);
4210 for (i = 1; i < (full ? 8 : 4); i++)
4211 umax = MAX (umax, aarch64_get_vec_u16 (cpu, vs, i));
4212 break;
4213 case 2:
4214 umax = aarch64_get_vec_u32 (cpu, vs, 0);
4215 for (i = 1; i < (full ? 4 : 2); i++)
4216 umax = MAX (umax, aarch64_get_vec_u32 (cpu, vs, i));
4217 break;
4218 default:
4219 case 3:
4220 HALT_UNALLOC;
4221 }
4222 aarch64_set_reg_u64 (cpu, rd, NO_SP, umax);
4223 return;
4224 }
4225
4226 case 3: /* UMINV. */
4227 {
4228 uint64_t umin;
4229 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4230 {
4231 case 0:
4232 umin = aarch64_get_vec_u8 (cpu, vs, 0);
4233 for (i = 1; i < (full ? 16 : 8); i++)
4234 umin = MIN (umin, aarch64_get_vec_u8 (cpu, vs, i));
4235 break;
4236 case 1:
4237 umin = aarch64_get_vec_u16 (cpu, vs, 0);
4238 for (i = 1; i < (full ? 8 : 4); i++)
4239 umin = MIN (umin, aarch64_get_vec_u16 (cpu, vs, i));
4240 break;
4241 case 2:
4242 umin = aarch64_get_vec_u32 (cpu, vs, 0);
4243 for (i = 1; i < (full ? 4 : 2); i++)
4244 umin = MIN (umin, aarch64_get_vec_u32 (cpu, vs, i));
4245 break;
4246 default:
4247 case 3:
4248 HALT_UNALLOC;
4249 }
4250 aarch64_set_reg_u64 (cpu, rd, NO_SP, umin);
4251 return;
4252 }
4253
4254 default:
4255 HALT_UNALLOC;
4256 }
4257 }
4258
4259 static void
4260 do_vec_fminmaxV (sim_cpu *cpu)
4261 {
4262 /* instr[31,24] = 0110 1110
4263 instr[23] = max(0)/min(1)
4264 instr[22,14] = 011 0000 11
4265 instr[13,12] = nm(00)/normal(11)
4266 instr[11,10] = 10
4267 instr[9,5] = V source
4268 instr[4.0] = R dest. */
4269
4270 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4271 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
4272 unsigned i;
4273 float res = aarch64_get_vec_float (cpu, vs, 0);
4274
4275 NYI_assert (31, 24, 0x6E);
4276 NYI_assert (22, 14, 0x0C3);
4277 NYI_assert (11, 10, 2);
4278
4279 if (uimm (aarch64_get_instr (cpu), 23, 23))
4280 {
4281 switch (uimm (aarch64_get_instr (cpu), 13, 12))
4282 {
4283 case 0: /* FMNINNMV. */
4284 for (i = 1; i < 4; i++)
4285 res = fminnm (res, aarch64_get_vec_float (cpu, vs, i));
4286 break;
4287
4288 case 3: /* FMINV. */
4289 for (i = 1; i < 4; i++)
4290 res = MIN (res, aarch64_get_vec_float (cpu, vs, i));
4291 break;
4292
4293 default:
4294 HALT_NYI;
4295 }
4296 }
4297 else
4298 {
4299 switch (uimm (aarch64_get_instr (cpu), 13, 12))
4300 {
4301 case 0: /* FMNAXNMV. */
4302 for (i = 1; i < 4; i++)
4303 res = fmaxnm (res, aarch64_get_vec_float (cpu, vs, i));
4304 break;
4305
4306 case 3: /* FMAXV. */
4307 for (i = 1; i < 4; i++)
4308 res = MAX (res, aarch64_get_vec_float (cpu, vs, i));
4309 break;
4310
4311 default:
4312 HALT_NYI;
4313 }
4314 }
4315
4316 aarch64_set_FP_float (cpu, rd, res);
4317 }
4318
4319 static void
4320 do_vec_Fminmax (sim_cpu *cpu)
4321 {
4322 /* instr[31] = 0
4323 instr[30] = half(0)/full(1)
4324 instr[29,24] = 00 1110
4325 instr[23] = max(0)/min(1)
4326 instr[22] = float(0)/double(1)
4327 instr[21] = 1
4328 instr[20,16] = Vm
4329 instr[15,14] = 11
4330 instr[13,12] = nm(00)/normal(11)
4331 instr[11,10] = 01
4332 instr[9,5] = Vn
4333 instr[4,0] = Vd. */
4334
4335 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4336 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4337 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4338 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4339 unsigned min = uimm (aarch64_get_instr (cpu), 23, 23);
4340 unsigned i;
4341
4342 NYI_assert (29, 24, 0x0E);
4343 NYI_assert (21, 21, 1);
4344 NYI_assert (15, 14, 3);
4345 NYI_assert (11, 10, 1);
4346
4347 if (uimm (aarch64_get_instr (cpu), 22, 22))
4348 {
4349 double (* func)(double, double);
4350
4351 if (! full)
4352 HALT_NYI;
4353
4354 if (uimm (aarch64_get_instr (cpu), 13, 12) == 0)
4355 func = min ? dminnm : dmaxnm;
4356 else if (uimm (aarch64_get_instr (cpu), 13, 12) == 3)
4357 func = min ? fmin : fmax;
4358 else
4359 HALT_NYI;
4360
4361 for (i = 0; i < 2; i++)
4362 aarch64_set_vec_double (cpu, vd, i,
4363 func (aarch64_get_vec_double (cpu, vn, i),
4364 aarch64_get_vec_double (cpu, vm, i)));
4365 }
4366 else
4367 {
4368 float (* func)(float, float);
4369
4370 if (uimm (aarch64_get_instr (cpu), 13, 12) == 0)
4371 func = min ? fminnm : fmaxnm;
4372 else if (uimm (aarch64_get_instr (cpu), 13, 12) == 3)
4373 func = min ? fminf : fmaxf;
4374 else
4375 HALT_NYI;
4376
4377 for (i = 0; i < (full ? 4 : 2); i++)
4378 aarch64_set_vec_float (cpu, vd, i,
4379 func (aarch64_get_vec_float (cpu, vn, i),
4380 aarch64_get_vec_float (cpu, vm, i)));
4381 }
4382 }
4383
4384 static void
4385 do_vec_SCVTF (sim_cpu *cpu)
4386 {
4387 /* instr[31] = 0
4388 instr[30] = Q
4389 instr[29,23] = 00 1110 0
4390 instr[22] = float(0)/double(1)
4391 instr[21,10] = 10 0001 1101 10
4392 instr[9,5] = Vn
4393 instr[4,0] = Vd. */
4394
4395 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4396 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4397 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4398 unsigned size = uimm (aarch64_get_instr (cpu), 22, 22);
4399 unsigned i;
4400
4401 NYI_assert (29, 23, 0x1C);
4402 NYI_assert (21, 10, 0x876);
4403
4404 if (size)
4405 {
4406 if (! full)
4407 HALT_UNALLOC;
4408
4409 for (i = 0; i < 2; i++)
4410 {
4411 double val = (double) aarch64_get_vec_u64 (cpu, vn, i);
4412 aarch64_set_vec_double (cpu, vd, i, val);
4413 }
4414 }
4415 else
4416 {
4417 for (i = 0; i < (full ? 4 : 2); i++)
4418 {
4419 float val = (float) aarch64_get_vec_u32 (cpu, vn, i);
4420 aarch64_set_vec_float (cpu, vd, i, val);
4421 }
4422 }
4423 }
4424
4425 #define VEC_CMP(SOURCE, CMP) \
4426 do \
4427 { \
4428 switch (size) \
4429 { \
4430 case 0: \
4431 for (i = 0; i < (full ? 16 : 8); i++) \
4432 aarch64_set_vec_u8 (cpu, vd, i, \
4433 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4434 CMP \
4435 aarch64_get_vec_##SOURCE##8 (cpu, vm, i) \
4436 ? -1 : 0); \
4437 return; \
4438 case 1: \
4439 for (i = 0; i < (full ? 8 : 4); i++) \
4440 aarch64_set_vec_u16 (cpu, vd, i, \
4441 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4442 CMP \
4443 aarch64_get_vec_##SOURCE##16 (cpu, vm, i) \
4444 ? -1 : 0); \
4445 return; \
4446 case 2: \
4447 for (i = 0; i < (full ? 4 : 2); i++) \
4448 aarch64_set_vec_u32 (cpu, vd, i, \
4449 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4450 CMP \
4451 aarch64_get_vec_##SOURCE##32 (cpu, vm, i) \
4452 ? -1 : 0); \
4453 return; \
4454 case 3: \
4455 if (! full) \
4456 HALT_UNALLOC; \
4457 for (i = 0; i < 2; i++) \
4458 aarch64_set_vec_u64 (cpu, vd, i, \
4459 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4460 CMP \
4461 aarch64_get_vec_##SOURCE##64 (cpu, vm, i) \
4462 ? -1ULL : 0); \
4463 return; \
4464 default: \
4465 HALT_UNALLOC; \
4466 } \
4467 } \
4468 while (0)
4469
4470 #define VEC_CMP0(SOURCE, CMP) \
4471 do \
4472 { \
4473 switch (size) \
4474 { \
4475 case 0: \
4476 for (i = 0; i < (full ? 16 : 8); i++) \
4477 aarch64_set_vec_u8 (cpu, vd, i, \
4478 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4479 CMP 0 ? -1 : 0); \
4480 return; \
4481 case 1: \
4482 for (i = 0; i < (full ? 8 : 4); i++) \
4483 aarch64_set_vec_u16 (cpu, vd, i, \
4484 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4485 CMP 0 ? -1 : 0); \
4486 return; \
4487 case 2: \
4488 for (i = 0; i < (full ? 4 : 2); i++) \
4489 aarch64_set_vec_u32 (cpu, vd, i, \
4490 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4491 CMP 0 ? -1 : 0); \
4492 return; \
4493 case 3: \
4494 if (! full) \
4495 HALT_UNALLOC; \
4496 for (i = 0; i < 2; i++) \
4497 aarch64_set_vec_u64 (cpu, vd, i, \
4498 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4499 CMP 0 ? -1ULL : 0); \
4500 return; \
4501 default: \
4502 HALT_UNALLOC; \
4503 } \
4504 } \
4505 while (0)
4506
4507 #define VEC_FCMP0(CMP) \
4508 do \
4509 { \
4510 if (vm != 0) \
4511 HALT_NYI; \
4512 if (uimm (aarch64_get_instr (cpu), 22, 22)) \
4513 { \
4514 if (! full) \
4515 HALT_NYI; \
4516 for (i = 0; i < 2; i++) \
4517 aarch64_set_vec_u64 (cpu, vd, i, \
4518 aarch64_get_vec_double (cpu, vn, i) \
4519 CMP 0.0 ? -1 : 0); \
4520 } \
4521 else \
4522 { \
4523 for (i = 0; i < (full ? 4 : 2); i++) \
4524 aarch64_set_vec_u32 (cpu, vd, i, \
4525 aarch64_get_vec_float (cpu, vn, i) \
4526 CMP 0.0 ? -1 : 0); \
4527 } \
4528 return; \
4529 } \
4530 while (0)
4531
4532 #define VEC_FCMP(CMP) \
4533 do \
4534 { \
4535 if (uimm (aarch64_get_instr (cpu), 22, 22)) \
4536 { \
4537 if (! full) \
4538 HALT_NYI; \
4539 for (i = 0; i < 2; i++) \
4540 aarch64_set_vec_u64 (cpu, vd, i, \
4541 aarch64_get_vec_double (cpu, vn, i) \
4542 CMP \
4543 aarch64_get_vec_double (cpu, vm, i) \
4544 ? -1 : 0); \
4545 } \
4546 else \
4547 { \
4548 for (i = 0; i < (full ? 4 : 2); i++) \
4549 aarch64_set_vec_u32 (cpu, vd, i, \
4550 aarch64_get_vec_float (cpu, vn, i) \
4551 CMP \
4552 aarch64_get_vec_float (cpu, vm, i) \
4553 ? -1 : 0); \
4554 } \
4555 return; \
4556 } \
4557 while (0)
4558
4559 static void
4560 do_vec_compare (sim_cpu *cpu)
4561 {
4562 /* instr[31] = 0
4563 instr[30] = half(0)/full(1)
4564 instr[29] = part-of-comparison-type
4565 instr[28,24] = 0 1110
4566 instr[23,22] = size of integer compares: byte(00), half(01), word (10), long (11)
4567 type of float compares: single (-0) / double (-1)
4568 instr[21] = 1
4569 instr[20,16] = Vm or 00000 (compare vs 0)
4570 instr[15,10] = part-of-comparison-type
4571 instr[9,5] = Vn
4572 instr[4.0] = Vd. */
4573
4574 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4575 int size = uimm (aarch64_get_instr (cpu), 23, 22);
4576 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4577 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4578 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4579 unsigned i;
4580
4581 NYI_assert (28, 24, 0x0E);
4582 NYI_assert (21, 21, 1);
4583
4584 if ((uimm (aarch64_get_instr (cpu), 11, 11)
4585 && uimm (aarch64_get_instr (cpu), 14, 14))
4586 || ((uimm (aarch64_get_instr (cpu), 11, 11) == 0
4587 && uimm (aarch64_get_instr (cpu), 10, 10) == 0)))
4588 {
4589 /* A compare vs 0. */
4590 if (vm != 0)
4591 {
4592 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x2A)
4593 do_vec_maxv (cpu);
4594 else if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x32
4595 || uimm (aarch64_get_instr (cpu), 15, 10) == 0x3E)
4596 do_vec_fminmaxV (cpu);
4597 else if (uimm (aarch64_get_instr (cpu), 29, 23) == 0x1C
4598 && uimm (aarch64_get_instr (cpu), 21, 10) == 0x876)
4599 do_vec_SCVTF (cpu);
4600 else
4601 HALT_NYI;
4602 return;
4603 }
4604 }
4605
4606 if (uimm (aarch64_get_instr (cpu), 14, 14))
4607 {
4608 /* A floating point compare. */
4609 unsigned decode = (uimm (aarch64_get_instr (cpu), 29, 29) << 5)
4610 | (uimm (aarch64_get_instr (cpu), 23, 23) << 4)
4611 | uimm (aarch64_get_instr (cpu), 13, 10);
4612
4613 NYI_assert (15, 15, 1);
4614
4615 switch (decode)
4616 {
4617 case /* 0b010010: GT#0 */ 0x12: VEC_FCMP0 (>);
4618 case /* 0b110010: GE#0 */ 0x32: VEC_FCMP0 (>=);
4619 case /* 0b010110: EQ#0 */ 0x16: VEC_FCMP0 (==);
4620 case /* 0b110110: LE#0 */ 0x36: VEC_FCMP0 (<=);
4621 case /* 0b011010: LT#0 */ 0x1A: VEC_FCMP0 (<);
4622 case /* 0b111001: GT */ 0x39: VEC_FCMP (>);
4623 case /* 0b101001: GE */ 0x29: VEC_FCMP (>=);
4624 case /* 0b001001: EQ */ 0x09: VEC_FCMP (==);
4625
4626 default:
4627 HALT_NYI;
4628 }
4629 }
4630 else
4631 {
4632 unsigned decode = (uimm (aarch64_get_instr (cpu), 29, 29) << 6)
4633 | uimm (aarch64_get_instr (cpu), 15, 10);
4634
4635 switch (decode)
4636 {
4637 case 0x0D: /* 0001101 GT */ VEC_CMP (s, > );
4638 case 0x0F: /* 0001111 GE */ VEC_CMP (s, >= );
4639 case 0x22: /* 0100010 GT #0 */ VEC_CMP0 (s, > );
4640 case 0x26: /* 0100110 EQ #0 */ VEC_CMP0 (s, == );
4641 case 0x2A: /* 0101010 LT #0 */ VEC_CMP0 (s, < );
4642 case 0x4D: /* 1001101 HI */ VEC_CMP (u, > );
4643 case 0x4F: /* 1001111 HS */ VEC_CMP (u, >= );
4644 case 0x62: /* 1100010 GE #0 */ VEC_CMP0 (s, >= );
4645 case 0x63: /* 1100011 EQ */ VEC_CMP (u, == );
4646 case 0x66: /* 1100110 LE #0 */ VEC_CMP0 (s, <= );
4647 default:
4648 if (vm == 0)
4649 HALT_NYI;
4650 do_vec_maxv (cpu);
4651 }
4652 }
4653 }
4654
4655 static void
4656 do_vec_SSHL (sim_cpu *cpu)
4657 {
4658 /* instr[31] = 0
4659 instr[30] = first part (0)/ second part (1)
4660 instr[29,24] = 00 1110
4661 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4662 instr[21] = 1
4663 instr[20,16] = Vm
4664 instr[15,10] = 0100 01
4665 instr[9,5] = Vn
4666 instr[4,0] = Vd. */
4667
4668 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4669 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4670 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4671 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4672 unsigned i;
4673
4674 NYI_assert (29, 24, 0x0E);
4675 NYI_assert (21, 21, 1);
4676 NYI_assert (15, 10, 0x11);
4677
4678 /* FIXME: What is a signed shift left in this context ?. */
4679
4680 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4681 {
4682 case 0:
4683 for (i = 0; i < (full ? 16 : 8); i++)
4684 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4685 << aarch64_get_vec_s8 (cpu, vm, i));
4686 return;
4687
4688 case 1:
4689 for (i = 0; i < (full ? 8 : 4); i++)
4690 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4691 << aarch64_get_vec_s16 (cpu, vm, i));
4692 return;
4693
4694 case 2:
4695 for (i = 0; i < (full ? 4 : 2); i++)
4696 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4697 << aarch64_get_vec_s32 (cpu, vm, i));
4698 return;
4699
4700 case 3:
4701 if (! full)
4702 HALT_UNALLOC;
4703 for (i = 0; i < 2; i++)
4704 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4705 << aarch64_get_vec_s64 (cpu, vm, i));
4706 return;
4707
4708 default:
4709 HALT_NYI;
4710 }
4711 }
4712
4713 static void
4714 do_vec_USHL (sim_cpu *cpu)
4715 {
4716 /* instr[31] = 0
4717 instr[30] = first part (0)/ second part (1)
4718 instr[29,24] = 10 1110
4719 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4720 instr[21] = 1
4721 instr[20,16] = Vm
4722 instr[15,10] = 0100 01
4723 instr[9,5] = Vn
4724 instr[4,0] = Vd */
4725
4726 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4727 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4728 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4729 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4730 unsigned i;
4731
4732 NYI_assert (29, 24, 0x2E);
4733 NYI_assert (15, 10, 0x11);
4734
4735 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4736 {
4737 case 0:
4738 for (i = 0; i < (full ? 16 : 8); i++)
4739 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4740 << aarch64_get_vec_u8 (cpu, vm, i));
4741 return;
4742
4743 case 1:
4744 for (i = 0; i < (full ? 8 : 4); i++)
4745 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4746 << aarch64_get_vec_u16 (cpu, vm, i));
4747 return;
4748
4749 case 2:
4750 for (i = 0; i < (full ? 4 : 2); i++)
4751 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4752 << aarch64_get_vec_u32 (cpu, vm, i));
4753 return;
4754
4755 case 3:
4756 if (! full)
4757 HALT_UNALLOC;
4758 for (i = 0; i < 2; i++)
4759 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4760 << aarch64_get_vec_u64 (cpu, vm, i));
4761 return;
4762
4763 default:
4764 HALT_NYI;
4765 }
4766 }
4767
4768 static void
4769 do_vec_FMLA (sim_cpu *cpu)
4770 {
4771 /* instr[31] = 0
4772 instr[30] = full/half selector
4773 instr[29,23] = 0011100
4774 instr[22] = size: 0=>float, 1=>double
4775 instr[21] = 1
4776 instr[20,16] = Vn
4777 instr[15,10] = 1100 11
4778 instr[9,5] = Vm
4779 instr[4.0] = Vd. */
4780
4781 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4782 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4783 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4784 unsigned i;
4785 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4786
4787 NYI_assert (29, 23, 0x1C);
4788 NYI_assert (21, 21, 1);
4789 NYI_assert (15, 10, 0x33);
4790
4791 if (uimm (aarch64_get_instr (cpu), 22, 22))
4792 {
4793 if (! full)
4794 HALT_UNALLOC;
4795 for (i = 0; i < 2; i++)
4796 aarch64_set_vec_double (cpu, vd, i,
4797 aarch64_get_vec_double (cpu, vn, i) *
4798 aarch64_get_vec_double (cpu, vm, i) +
4799 aarch64_get_vec_double (cpu, vd, i));
4800 }
4801 else
4802 {
4803 for (i = 0; i < (full ? 4 : 2); i++)
4804 aarch64_set_vec_float (cpu, vd, i,
4805 aarch64_get_vec_float (cpu, vn, i) *
4806 aarch64_get_vec_float (cpu, vm, i) +
4807 aarch64_get_vec_float (cpu, vd, i));
4808 }
4809 }
4810
4811 static void
4812 do_vec_max (sim_cpu *cpu)
4813 {
4814 /* instr[31] = 0
4815 instr[30] = full/half selector
4816 instr[29] = SMAX (0) / UMAX (1)
4817 instr[28,24] = 0 1110
4818 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4819 instr[21] = 1
4820 instr[20,16] = Vn
4821 instr[15,10] = 0110 01
4822 instr[9,5] = Vm
4823 instr[4.0] = Vd. */
4824
4825 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4826 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4827 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4828 unsigned i;
4829 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4830
4831 NYI_assert (28, 24, 0x0E);
4832 NYI_assert (21, 21, 1);
4833 NYI_assert (15, 10, 0x19);
4834
4835 if (uimm (aarch64_get_instr (cpu), 29, 29))
4836 {
4837 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4838 {
4839 case 0:
4840 for (i = 0; i < (full ? 16 : 8); i++)
4841 aarch64_set_vec_u8 (cpu, vd, i,
4842 aarch64_get_vec_u8 (cpu, vn, i)
4843 > aarch64_get_vec_u8 (cpu, vm, i)
4844 ? aarch64_get_vec_u8 (cpu, vn, i)
4845 : aarch64_get_vec_u8 (cpu, vm, i));
4846 return;
4847
4848 case 1:
4849 for (i = 0; i < (full ? 8 : 4); i++)
4850 aarch64_set_vec_u16 (cpu, vd, i,
4851 aarch64_get_vec_u16 (cpu, vn, i)
4852 > aarch64_get_vec_u16 (cpu, vm, i)
4853 ? aarch64_get_vec_u16 (cpu, vn, i)
4854 : aarch64_get_vec_u16 (cpu, vm, i));
4855 return;
4856
4857 case 2:
4858 for (i = 0; i < (full ? 4 : 2); i++)
4859 aarch64_set_vec_u32 (cpu, vd, i,
4860 aarch64_get_vec_u32 (cpu, vn, i)
4861 > aarch64_get_vec_u32 (cpu, vm, i)
4862 ? aarch64_get_vec_u32 (cpu, vn, i)
4863 : aarch64_get_vec_u32 (cpu, vm, i));
4864 return;
4865
4866 default:
4867 case 3:
4868 HALT_UNALLOC;
4869 }
4870 }
4871 else
4872 {
4873 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4874 {
4875 case 0:
4876 for (i = 0; i < (full ? 16 : 8); i++)
4877 aarch64_set_vec_s8 (cpu, vd, i,
4878 aarch64_get_vec_s8 (cpu, vn, i)
4879 > aarch64_get_vec_s8 (cpu, vm, i)
4880 ? aarch64_get_vec_s8 (cpu, vn, i)
4881 : aarch64_get_vec_s8 (cpu, vm, i));
4882 return;
4883
4884 case 1:
4885 for (i = 0; i < (full ? 8 : 4); i++)
4886 aarch64_set_vec_s16 (cpu, vd, i,
4887 aarch64_get_vec_s16 (cpu, vn, i)
4888 > aarch64_get_vec_s16 (cpu, vm, i)
4889 ? aarch64_get_vec_s16 (cpu, vn, i)
4890 : aarch64_get_vec_s16 (cpu, vm, i));
4891 return;
4892
4893 case 2:
4894 for (i = 0; i < (full ? 4 : 2); i++)
4895 aarch64_set_vec_s32 (cpu, vd, i,
4896 aarch64_get_vec_s32 (cpu, vn, i)
4897 > aarch64_get_vec_s32 (cpu, vm, i)
4898 ? aarch64_get_vec_s32 (cpu, vn, i)
4899 : aarch64_get_vec_s32 (cpu, vm, i));
4900 return;
4901
4902 default:
4903 case 3:
4904 HALT_UNALLOC;
4905 }
4906 }
4907 }
4908
4909 static void
4910 do_vec_min (sim_cpu *cpu)
4911 {
4912 /* instr[31] = 0
4913 instr[30] = full/half selector
4914 instr[29] = SMIN (0) / UMIN (1)
4915 instr[28,24] = 0 1110
4916 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4917 instr[21] = 1
4918 instr[20,16] = Vn
4919 instr[15,10] = 0110 11
4920 instr[9,5] = Vm
4921 instr[4.0] = Vd. */
4922
4923 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4924 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4925 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4926 unsigned i;
4927 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4928
4929 NYI_assert (28, 24, 0x0E);
4930 NYI_assert (21, 21, 1);
4931 NYI_assert (15, 10, 0x1B);
4932
4933 if (uimm (aarch64_get_instr (cpu), 29, 29))
4934 {
4935 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4936 {
4937 case 0:
4938 for (i = 0; i < (full ? 16 : 8); i++)
4939 aarch64_set_vec_u8 (cpu, vd, i,
4940 aarch64_get_vec_u8 (cpu, vn, i)
4941 < aarch64_get_vec_u8 (cpu, vm, i)
4942 ? aarch64_get_vec_u8 (cpu, vn, i)
4943 : aarch64_get_vec_u8 (cpu, vm, i));
4944 return;
4945
4946 case 1:
4947 for (i = 0; i < (full ? 8 : 4); i++)
4948 aarch64_set_vec_u16 (cpu, vd, i,
4949 aarch64_get_vec_u16 (cpu, vn, i)
4950 < aarch64_get_vec_u16 (cpu, vm, i)
4951 ? aarch64_get_vec_u16 (cpu, vn, i)
4952 : aarch64_get_vec_u16 (cpu, vm, i));
4953 return;
4954
4955 case 2:
4956 for (i = 0; i < (full ? 4 : 2); i++)
4957 aarch64_set_vec_u32 (cpu, vd, i,
4958 aarch64_get_vec_u32 (cpu, vn, i)
4959 < aarch64_get_vec_u32 (cpu, vm, i)
4960 ? aarch64_get_vec_u32 (cpu, vn, i)
4961 : aarch64_get_vec_u32 (cpu, vm, i));
4962 return;
4963
4964 default:
4965 case 3:
4966 HALT_UNALLOC;
4967 }
4968 }
4969 else
4970 {
4971 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4972 {
4973 case 0:
4974 for (i = 0; i < (full ? 16 : 8); i++)
4975 aarch64_set_vec_s8 (cpu, vd, i,
4976 aarch64_get_vec_s8 (cpu, vn, i)
4977 < aarch64_get_vec_s8 (cpu, vm, i)
4978 ? aarch64_get_vec_s8 (cpu, vn, i)
4979 : aarch64_get_vec_s8 (cpu, vm, i));
4980 return;
4981
4982 case 1:
4983 for (i = 0; i < (full ? 8 : 4); i++)
4984 aarch64_set_vec_s16 (cpu, vd, i,
4985 aarch64_get_vec_s16 (cpu, vn, i)
4986 < aarch64_get_vec_s16 (cpu, vm, i)
4987 ? aarch64_get_vec_s16 (cpu, vn, i)
4988 : aarch64_get_vec_s16 (cpu, vm, i));
4989 return;
4990
4991 case 2:
4992 for (i = 0; i < (full ? 4 : 2); i++)
4993 aarch64_set_vec_s32 (cpu, vd, i,
4994 aarch64_get_vec_s32 (cpu, vn, i)
4995 < aarch64_get_vec_s32 (cpu, vm, i)
4996 ? aarch64_get_vec_s32 (cpu, vn, i)
4997 : aarch64_get_vec_s32 (cpu, vm, i));
4998 return;
4999
5000 default:
5001 case 3:
5002 HALT_UNALLOC;
5003 }
5004 }
5005 }
5006
5007 static void
5008 do_vec_sub_long (sim_cpu *cpu)
5009 {
5010 /* instr[31] = 0
5011 instr[30] = lower (0) / upper (1)
5012 instr[29] = signed (0) / unsigned (1)
5013 instr[28,24] = 0 1110
5014 instr[23,22] = size: bytes (00), half (01), word (10)
5015 instr[21] = 1
5016 insrt[20,16] = Vm
5017 instr[15,10] = 0010 00
5018 instr[9,5] = Vn
5019 instr[4,0] = V dest. */
5020
5021 unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
5022 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5023 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5024 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5025 unsigned bias = 0;
5026 unsigned i;
5027
5028 NYI_assert (28, 24, 0x0E);
5029 NYI_assert (21, 21, 1);
5030 NYI_assert (15, 10, 0x08);
5031
5032 if (size == 3)
5033 HALT_UNALLOC;
5034
5035 switch (uimm (aarch64_get_instr (cpu), 30, 29))
5036 {
5037 case 2: /* SSUBL2. */
5038 bias = 2;
5039 case 0: /* SSUBL. */
5040 switch (size)
5041 {
5042 case 0:
5043 bias *= 3;
5044 for (i = 0; i < 8; i++)
5045 aarch64_set_vec_s16 (cpu, vd, i,
5046 aarch64_get_vec_s8 (cpu, vn, i + bias)
5047 - aarch64_get_vec_s8 (cpu, vm, i + bias));
5048 break;
5049
5050 case 1:
5051 bias *= 2;
5052 for (i = 0; i < 4; i++)
5053 aarch64_set_vec_s32 (cpu, vd, i,
5054 aarch64_get_vec_s16 (cpu, vn, i + bias)
5055 - aarch64_get_vec_s16 (cpu, vm, i + bias));
5056 break;
5057
5058 case 2:
5059 for (i = 0; i < 2; i++)
5060 aarch64_set_vec_s64 (cpu, vd, i,
5061 aarch64_get_vec_s32 (cpu, vn, i + bias)
5062 - aarch64_get_vec_s32 (cpu, vm, i + bias));
5063 break;
5064
5065 default:
5066 HALT_UNALLOC;
5067 }
5068 break;
5069
5070 case 3: /* USUBL2. */
5071 bias = 2;
5072 case 1: /* USUBL. */
5073 switch (size)
5074 {
5075 case 0:
5076 bias *= 3;
5077 for (i = 0; i < 8; i++)
5078 aarch64_set_vec_u16 (cpu, vd, i,
5079 aarch64_get_vec_u8 (cpu, vn, i + bias)
5080 - aarch64_get_vec_u8 (cpu, vm, i + bias));
5081 break;
5082
5083 case 1:
5084 bias *= 2;
5085 for (i = 0; i < 4; i++)
5086 aarch64_set_vec_u32 (cpu, vd, i,
5087 aarch64_get_vec_u16 (cpu, vn, i + bias)
5088 - aarch64_get_vec_u16 (cpu, vm, i + bias));
5089 break;
5090
5091 case 2:
5092 for (i = 0; i < 2; i++)
5093 aarch64_set_vec_u64 (cpu, vd, i,
5094 aarch64_get_vec_u32 (cpu, vn, i + bias)
5095 - aarch64_get_vec_u32 (cpu, vm, i + bias));
5096 break;
5097
5098 default:
5099 HALT_UNALLOC;
5100 }
5101 break;
5102 }
5103 }
5104
5105 #define DO_ADDP(FN) \
5106 do \
5107 { \
5108 for (i = 0; i < range; i++) \
5109 { \
5110 aarch64_set_vec_##FN (cpu, vd, i, \
5111 aarch64_get_vec_##FN (cpu, vn, i * 2) \
5112 + aarch64_get_vec_##FN (cpu, vn, i * 2 + 1)); \
5113 aarch64_set_vec_##FN (cpu, vd, i + range, \
5114 aarch64_get_vec_##FN (cpu, vm, i * 2) \
5115 + aarch64_get_vec_##FN (cpu, vm, i * 2 + 1)); \
5116 } \
5117 } \
5118 while (0)
5119
5120 static void
5121 do_vec_ADDP (sim_cpu *cpu)
5122 {
5123 /* instr[31] = 0
5124 instr[30] = half(0)/full(1)
5125 instr[29,24] = 00 1110
5126 instr[23,22] = size: bytes (00), half (01), word (10), long (11)
5127 instr[21] = 1
5128 insrt[20,16] = Vm
5129 instr[15,10] = 1011 11
5130 instr[9,5] = Vn
5131 instr[4,0] = V dest. */
5132
5133 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5134 unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
5135 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5136 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5137 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5138 unsigned i, range;
5139
5140 NYI_assert (29, 24, 0x0E);
5141 NYI_assert (21, 21, 1);
5142 NYI_assert (15, 10, 0x2F);
5143
5144 switch (size)
5145 {
5146 case 0:
5147 range = full ? 8 : 4;
5148 DO_ADDP (u8);
5149 return;
5150
5151 case 1:
5152 range = full ? 4 : 2;
5153 DO_ADDP (u16);
5154 return;
5155
5156 case 2:
5157 range = full ? 2 : 1;
5158 DO_ADDP (u32);
5159 return;
5160
5161 case 3:
5162 if (! full)
5163 HALT_UNALLOC;
5164 range = 1;
5165 DO_ADDP (u64);
5166 return;
5167
5168 default:
5169 HALT_NYI;
5170 }
5171 }
5172
5173 static void
5174 do_vec_UMOV (sim_cpu *cpu)
5175 {
5176 /* instr[31] = 0
5177 instr[30] = 32-bit(0)/64-bit(1)
5178 instr[29,21] = 00 1110 000
5179 insrt[20,16] = size & index
5180 instr[15,10] = 0011 11
5181 instr[9,5] = V source
5182 instr[4,0] = R dest. */
5183
5184 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5185 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
5186 unsigned index;
5187
5188 NYI_assert (29, 21, 0x070);
5189 NYI_assert (15, 10, 0x0F);
5190
5191 if (uimm (aarch64_get_instr (cpu), 16, 16))
5192 {
5193 /* Byte transfer. */
5194 index = uimm (aarch64_get_instr (cpu), 20, 17);
5195 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5196 aarch64_get_vec_u8 (cpu, vs, index));
5197 }
5198 else if (uimm (aarch64_get_instr (cpu), 17, 17))
5199 {
5200 index = uimm (aarch64_get_instr (cpu), 20, 18);
5201 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5202 aarch64_get_vec_u16 (cpu, vs, index));
5203 }
5204 else if (uimm (aarch64_get_instr (cpu), 18, 18))
5205 {
5206 index = uimm (aarch64_get_instr (cpu), 20, 19);
5207 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5208 aarch64_get_vec_u32 (cpu, vs, index));
5209 }
5210 else
5211 {
5212 if (uimm (aarch64_get_instr (cpu), 30, 30) != 1)
5213 HALT_UNALLOC;
5214
5215 index = uimm (aarch64_get_instr (cpu), 20, 20);
5216 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5217 aarch64_get_vec_u64 (cpu, vs, index));
5218 }
5219 }
5220
5221 static void
5222 do_vec_FABS (sim_cpu *cpu)
5223 {
5224 /* instr[31] = 0
5225 instr[30] = half(0)/full(1)
5226 instr[29,23] = 00 1110 1
5227 instr[22] = float(0)/double(1)
5228 instr[21,16] = 10 0000
5229 instr[15,10] = 1111 10
5230 instr[9,5] = Vn
5231 instr[4,0] = Vd. */
5232
5233 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5234 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5235 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5236 unsigned i;
5237
5238 NYI_assert (29, 23, 0x1D);
5239 NYI_assert (21, 10, 0x83E);
5240
5241 if (uimm (aarch64_get_instr (cpu), 22, 22))
5242 {
5243 if (! full)
5244 HALT_NYI;
5245
5246 for (i = 0; i < 2; i++)
5247 aarch64_set_vec_double (cpu, vd, i,
5248 fabs (aarch64_get_vec_double (cpu, vn, i)));
5249 }
5250 else
5251 {
5252 for (i = 0; i < (full ? 4 : 2); i++)
5253 aarch64_set_vec_float (cpu, vd, i,
5254 fabsf (aarch64_get_vec_float (cpu, vn, i)));
5255 }
5256 }
5257
5258 static void
5259 do_vec_FCVTZS (sim_cpu *cpu)
5260 {
5261 /* instr[31] = 0
5262 instr[30] = half (0) / all (1)
5263 instr[29,23] = 00 1110 1
5264 instr[22] = single (0) / double (1)
5265 instr[21,10] = 10 0001 1011 10
5266 instr[9,5] = Rn
5267 instr[4,0] = Rd. */
5268
5269 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
5270 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
5271 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5272 unsigned i;
5273
5274 NYI_assert (31, 31, 0);
5275 NYI_assert (29, 23, 0x1D);
5276 NYI_assert (21, 10, 0x86E);
5277
5278 if (uimm (aarch64_get_instr (cpu), 22, 22))
5279 {
5280 if (! full)
5281 HALT_UNALLOC;
5282
5283 for (i = 0; i < 2; i++)
5284 aarch64_set_vec_s64 (cpu, rd, i,
5285 (int64_t) aarch64_get_vec_double (cpu, rn, i));
5286 }
5287 else
5288 for (i = 0; i < (full ? 4 : 2); i++)
5289 aarch64_set_vec_s32 (cpu, rd, i,
5290 (int32_t) aarch64_get_vec_float (cpu, rn, i));
5291 }
5292
5293 static void
5294 do_vec_op1 (sim_cpu *cpu)
5295 {
5296 /* instr[31] = 0
5297 instr[30] = half/full
5298 instr[29,24] = 00 1110
5299 instr[23,21] = ???
5300 instr[20,16] = Vm
5301 instr[15,10] = sub-opcode
5302 instr[9,5] = Vn
5303 instr[4,0] = Vd */
5304 NYI_assert (29, 24, 0x0E);
5305
5306 if (uimm (aarch64_get_instr (cpu), 21, 21) == 0)
5307 {
5308 if (uimm (aarch64_get_instr (cpu), 23, 22) == 0)
5309 {
5310 if (uimm (aarch64_get_instr (cpu), 30, 30) == 1
5311 && uimm (aarch64_get_instr (cpu), 17, 14) == 0
5312 && uimm (aarch64_get_instr (cpu), 12, 10) == 7)
5313 return do_vec_ins_2 (cpu);
5314
5315 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5316 {
5317 case 0x01: do_vec_DUP_vector_into_vector (cpu); return;
5318 case 0x03: do_vec_DUP_scalar_into_vector (cpu); return;
5319 case 0x07: do_vec_INS (cpu); return;
5320 case 0x0A: do_vec_TRN (cpu); return;
5321
5322 case 0x0F:
5323 if (uimm (aarch64_get_instr (cpu), 17, 16) == 0)
5324 {
5325 do_vec_MOV_into_scalar (cpu);
5326 return;
5327 }
5328 break;
5329
5330 case 0x00:
5331 case 0x08:
5332 case 0x10:
5333 case 0x18:
5334 do_vec_TBL (cpu); return;
5335
5336 case 0x06:
5337 case 0x16:
5338 do_vec_UZP (cpu); return;
5339
5340 case 0x0E:
5341 case 0x1E:
5342 do_vec_ZIP (cpu); return;
5343
5344 default:
5345 HALT_NYI;
5346 }
5347 }
5348
5349 switch (uimm (aarch64_get_instr (cpu), 13, 10))
5350 {
5351 case 0x6: do_vec_UZP (cpu); return;
5352 case 0xE: do_vec_ZIP (cpu); return;
5353 case 0xA: do_vec_TRN (cpu); return;
5354 case 0xF: do_vec_UMOV (cpu); return;
5355 default: HALT_NYI;
5356 }
5357 }
5358
5359 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5360 {
5361 case 0x07:
5362 switch (uimm (aarch64_get_instr (cpu), 23, 21))
5363 {
5364 case 1: do_vec_AND (cpu); return;
5365 case 3: do_vec_BIC (cpu); return;
5366 case 5: do_vec_ORR (cpu); return;
5367 case 7: do_vec_ORN (cpu); return;
5368 default: HALT_NYI;
5369 }
5370
5371 case 0x08: do_vec_sub_long (cpu); return;
5372 case 0x0a: do_vec_XTN (cpu); return;
5373 case 0x11: do_vec_SSHL (cpu); return;
5374 case 0x19: do_vec_max (cpu); return;
5375 case 0x1B: do_vec_min (cpu); return;
5376 case 0x21: do_vec_add (cpu); return;
5377 case 0x25: do_vec_MLA (cpu); return;
5378 case 0x27: do_vec_mul (cpu); return;
5379 case 0x2F: do_vec_ADDP (cpu); return;
5380 case 0x30: do_vec_mull (cpu); return;
5381 case 0x33: do_vec_FMLA (cpu); return;
5382 case 0x35: do_vec_fadd (cpu); return;
5383
5384 case 0x2E:
5385 switch (uimm (aarch64_get_instr (cpu), 20, 16))
5386 {
5387 case 0x00: do_vec_ABS (cpu); return;
5388 case 0x01: do_vec_FCVTZS (cpu); return;
5389 case 0x11: do_vec_ADDV (cpu); return;
5390 default: HALT_NYI;
5391 }
5392
5393 case 0x31:
5394 case 0x3B:
5395 do_vec_Fminmax (cpu); return;
5396
5397 case 0x0D:
5398 case 0x0F:
5399 case 0x22:
5400 case 0x23:
5401 case 0x26:
5402 case 0x2A:
5403 case 0x32:
5404 case 0x36:
5405 case 0x39:
5406 case 0x3A:
5407 do_vec_compare (cpu); return;
5408
5409 case 0x3E:
5410 do_vec_FABS (cpu); return;
5411
5412 default:
5413 HALT_NYI;
5414 }
5415 }
5416
5417 static void
5418 do_vec_xtl (sim_cpu *cpu)
5419 {
5420 /* instr[31] = 0
5421 instr[30,29] = SXTL (00), UXTL (01), SXTL2 (10), UXTL2 (11)
5422 instr[28,22] = 0 1111 00
5423 instr[21,16] = size & shift (USHLL, SSHLL, USHLL2, SSHLL2)
5424 instr[15,10] = 1010 01
5425 instr[9,5] = V source
5426 instr[4,0] = V dest. */
5427
5428 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5429 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5430 unsigned i, shift, bias = 0;
5431
5432 NYI_assert (28, 22, 0x3C);
5433 NYI_assert (15, 10, 0x29);
5434
5435 switch (uimm (aarch64_get_instr (cpu), 30, 29))
5436 {
5437 case 2: /* SXTL2, SSHLL2. */
5438 bias = 2;
5439 case 0: /* SXTL, SSHLL. */
5440 if (uimm (aarch64_get_instr (cpu), 21, 21))
5441 {
5442 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5443 aarch64_set_vec_s64
5444 (cpu, vd, 0, aarch64_get_vec_s32 (cpu, vs, bias) << shift);
5445 aarch64_set_vec_s64
5446 (cpu, vd, 1, aarch64_get_vec_s32 (cpu, vs, bias + 1) << shift);
5447 }
5448 else if (uimm (aarch64_get_instr (cpu), 20, 20))
5449 {
5450 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5451 bias *= 2;
5452 for (i = 0; i < 4; i++)
5453 aarch64_set_vec_s32
5454 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vs, i + bias) << shift);
5455 }
5456 else
5457 {
5458 NYI_assert (19, 19, 1);
5459
5460 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5461 bias *= 3;
5462 for (i = 0; i < 8; i++)
5463 aarch64_set_vec_s16
5464 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vs, i + bias) << shift);
5465 }
5466 return;
5467
5468 case 3: /* UXTL2, USHLL2. */
5469 bias = 2;
5470 case 1: /* UXTL, USHLL. */
5471 if (uimm (aarch64_get_instr (cpu), 21, 21))
5472 {
5473 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5474 aarch64_set_vec_u64
5475 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, vs, bias) << shift);
5476 aarch64_set_vec_u64
5477 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, vs, bias + 1) << shift);
5478 }
5479 else if (uimm (aarch64_get_instr (cpu), 20, 20))
5480 {
5481 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5482 bias *= 2;
5483 for (i = 0; i < 4; i++)
5484 aarch64_set_vec_u32
5485 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i + bias) << shift);
5486 }
5487 else
5488 {
5489 NYI_assert (19, 19, 1);
5490
5491 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5492 bias *= 3;
5493 for (i = 0; i < 8; i++)
5494 aarch64_set_vec_u16
5495 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, i + bias) << shift);
5496 }
5497 return;
5498
5499 default:
5500 HALT_NYI;
5501 }
5502 }
5503
5504 static void
5505 do_vec_SHL (sim_cpu *cpu)
5506 {
5507 /* instr [31] = 0
5508 instr [30] = half(0)/full(1)
5509 instr [29,23] = 001 1110
5510 instr [22,16] = size and shift amount
5511 instr [15,10] = 01 0101
5512 instr [9, 5] = Vs
5513 instr [4, 0] = Vd. */
5514
5515 int shift;
5516 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5517 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5518 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5519 unsigned i;
5520
5521 NYI_assert (29, 23, 0x1E);
5522 NYI_assert (15, 10, 0x15);
5523
5524 if (uimm (aarch64_get_instr (cpu), 22, 22))
5525 {
5526 shift = uimm (aarch64_get_instr (cpu), 21, 16) - 1;
5527
5528 if (full == 0)
5529 HALT_UNALLOC;
5530
5531 for (i = 0; i < 2; i++)
5532 {
5533 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5534 aarch64_set_vec_u64 (cpu, vd, i, val << shift);
5535 }
5536
5537 return;
5538 }
5539
5540 if (uimm (aarch64_get_instr (cpu), 21, 21))
5541 {
5542 shift = uimm (aarch64_get_instr (cpu), 20, 16) - 1;
5543
5544 for (i = 0; i < (full ? 4 : 2); i++)
5545 {
5546 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5547 aarch64_set_vec_u32 (cpu, vd, i, val << shift);
5548 }
5549
5550 return;
5551 }
5552
5553 if (uimm (aarch64_get_instr (cpu), 20, 20))
5554 {
5555 shift = uimm (aarch64_get_instr (cpu), 19, 16) - 1;
5556
5557 for (i = 0; i < (full ? 8 : 4); i++)
5558 {
5559 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5560 aarch64_set_vec_u16 (cpu, vd, i, val << shift);
5561 }
5562
5563 return;
5564 }
5565
5566 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
5567 HALT_UNALLOC;
5568
5569 shift = uimm (aarch64_get_instr (cpu), 18, 16) - 1;
5570
5571 for (i = 0; i < (full ? 16 : 8); i++)
5572 {
5573 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5574 aarch64_set_vec_u8 (cpu, vd, i, val << shift);
5575 }
5576 }
5577
5578 static void
5579 do_vec_SSHR_USHR (sim_cpu *cpu)
5580 {
5581 /* instr [31] = 0
5582 instr [30] = half(0)/full(1)
5583 instr [29] = signed(0)/unsigned(1)
5584 instr [28,23] = 01 1110
5585 instr [22,16] = size and shift amount
5586 instr [15,10] = 0000 01
5587 instr [9, 5] = Vs
5588 instr [4, 0] = Vd. */
5589
5590 int shift;
5591 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5592 int sign = uimm (aarch64_get_instr (cpu), 29, 29);
5593 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5594 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5595 unsigned i;
5596
5597 NYI_assert (28, 23, 0x1E);
5598 NYI_assert (15, 10, 0x01);
5599
5600 if (uimm (aarch64_get_instr (cpu), 22, 22))
5601 {
5602 shift = uimm (aarch64_get_instr (cpu), 21, 16);
5603
5604 if (full == 0)
5605 HALT_UNALLOC;
5606
5607 if (sign)
5608 for (i = 0; i < 2; i++)
5609 {
5610 int64_t val = aarch64_get_vec_s64 (cpu, vs, i);
5611 aarch64_set_vec_s64 (cpu, vd, i, val >> shift);
5612 }
5613 else
5614 for (i = 0; i < 2; i++)
5615 {
5616 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5617 aarch64_set_vec_u64 (cpu, vd, i, val >> shift);
5618 }
5619
5620 return;
5621 }
5622
5623 if (uimm (aarch64_get_instr (cpu), 21, 21))
5624 {
5625 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5626
5627 if (sign)
5628 for (i = 0; i < (full ? 4 : 2); i++)
5629 {
5630 int32_t val = aarch64_get_vec_s32 (cpu, vs, i);
5631 aarch64_set_vec_s32 (cpu, vd, i, val >> shift);
5632 }
5633 else
5634 for (i = 0; i < (full ? 4 : 2); i++)
5635 {
5636 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5637 aarch64_set_vec_u32 (cpu, vd, i, val >> shift);
5638 }
5639
5640 return;
5641 }
5642
5643 if (uimm (aarch64_get_instr (cpu), 20, 20))
5644 {
5645 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5646
5647 if (sign)
5648 for (i = 0; i < (full ? 8 : 4); i++)
5649 {
5650 int16_t val = aarch64_get_vec_s16 (cpu, vs, i);
5651 aarch64_set_vec_s16 (cpu, vd, i, val >> shift);
5652 }
5653 else
5654 for (i = 0; i < (full ? 8 : 4); i++)
5655 {
5656 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5657 aarch64_set_vec_u16 (cpu, vd, i, val >> shift);
5658 }
5659
5660 return;
5661 }
5662
5663 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
5664 HALT_UNALLOC;
5665
5666 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5667
5668 if (sign)
5669 for (i = 0; i < (full ? 16 : 8); i++)
5670 {
5671 int8_t val = aarch64_get_vec_s8 (cpu, vs, i);
5672 aarch64_set_vec_s8 (cpu, vd, i, val >> shift);
5673 }
5674 else
5675 for (i = 0; i < (full ? 16 : 8); i++)
5676 {
5677 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5678 aarch64_set_vec_u8 (cpu, vd, i, val >> shift);
5679 }
5680 }
5681
5682 static void
5683 do_vec_op2 (sim_cpu *cpu)
5684 {
5685 /* instr[31] = 0
5686 instr[30] = half/full
5687 instr[29,24] = 00 1111
5688 instr[23] = ?
5689 instr[22,16] = element size & index
5690 instr[15,10] = sub-opcode
5691 instr[9,5] = Vm
5692 instr[4.0] = Vd */
5693
5694 NYI_assert (29, 24, 0x0F);
5695
5696 if (uimm (aarch64_get_instr (cpu), 23, 23) != 0)
5697 HALT_NYI;
5698
5699 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5700 {
5701 case 0x01: do_vec_SSHR_USHR (cpu); return;
5702 case 0x15: do_vec_SHL (cpu); return;
5703 case 0x29: do_vec_xtl (cpu); return;
5704 default: HALT_NYI;
5705 }
5706 }
5707
5708 static void
5709 do_vec_neg (sim_cpu *cpu)
5710 {
5711 /* instr[31] = 0
5712 instr[30] = full(1)/half(0)
5713 instr[29,24] = 10 1110
5714 instr[23,22] = size: byte(00), half (01), word (10), long (11)
5715 instr[21,10] = 1000 0010 1110
5716 instr[9,5] = Vs
5717 instr[4,0] = Vd */
5718
5719 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5720 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5721 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5722 unsigned i;
5723
5724 NYI_assert (29, 24, 0x2E);
5725 NYI_assert (21, 10, 0x82E);
5726
5727 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5728 {
5729 case 0:
5730 for (i = 0; i < (full ? 16 : 8); i++)
5731 aarch64_set_vec_s8 (cpu, vd, i, - aarch64_get_vec_s8 (cpu, vs, i));
5732 return;
5733
5734 case 1:
5735 for (i = 0; i < (full ? 8 : 4); i++)
5736 aarch64_set_vec_s16 (cpu, vd, i, - aarch64_get_vec_s16 (cpu, vs, i));
5737 return;
5738
5739 case 2:
5740 for (i = 0; i < (full ? 4 : 2); i++)
5741 aarch64_set_vec_s32 (cpu, vd, i, - aarch64_get_vec_s32 (cpu, vs, i));
5742 return;
5743
5744 case 3:
5745 if (! full)
5746 HALT_NYI;
5747 for (i = 0; i < 2; i++)
5748 aarch64_set_vec_s64 (cpu, vd, i, - aarch64_get_vec_s64 (cpu, vs, i));
5749 return;
5750
5751 default:
5752 HALT_UNREACHABLE;
5753 }
5754 }
5755
5756 static void
5757 do_vec_sqrt (sim_cpu *cpu)
5758 {
5759 /* instr[31] = 0
5760 instr[30] = full(1)/half(0)
5761 instr[29,23] = 101 1101
5762 instr[22] = single(0)/double(1)
5763 instr[21,10] = 1000 0111 1110
5764 instr[9,5] = Vs
5765 instr[4,0] = Vd. */
5766
5767 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5768 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5769 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5770 unsigned i;
5771
5772 NYI_assert (29, 23, 0x5B);
5773 NYI_assert (21, 10, 0x87E);
5774
5775 if (uimm (aarch64_get_instr (cpu), 22, 22) == 0)
5776 for (i = 0; i < (full ? 4 : 2); i++)
5777 aarch64_set_vec_float (cpu, vd, i,
5778 sqrtf (aarch64_get_vec_float (cpu, vs, i)));
5779 else
5780 for (i = 0; i < 2; i++)
5781 aarch64_set_vec_double (cpu, vd, i,
5782 sqrt (aarch64_get_vec_double (cpu, vs, i)));
5783 }
5784
5785 static void
5786 do_vec_mls_indexed (sim_cpu *cpu)
5787 {
5788 /* instr[31] = 0
5789 instr[30] = half(0)/full(1)
5790 instr[29,24] = 10 1111
5791 instr[23,22] = 16-bit(01)/32-bit(10)
5792 instr[21,20+11] = index (if 16-bit)
5793 instr[21+11] = index (if 32-bit)
5794 instr[20,16] = Vm
5795 instr[15,12] = 0100
5796 instr[11] = part of index
5797 instr[10] = 0
5798 instr[9,5] = Vs
5799 instr[4,0] = Vd. */
5800
5801 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5802 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5803 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5804 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5805 unsigned i;
5806
5807 NYI_assert (15, 12, 4);
5808 NYI_assert (10, 10, 0);
5809
5810 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5811 {
5812 case 1:
5813 {
5814 unsigned elem;
5815 uint32_t val;
5816
5817 if (vm > 15)
5818 HALT_NYI;
5819
5820 elem = (uimm (aarch64_get_instr (cpu), 21, 20) << 1)
5821 | uimm (aarch64_get_instr (cpu), 11, 11);
5822 val = aarch64_get_vec_u16 (cpu, vm, elem);
5823
5824 for (i = 0; i < (full ? 8 : 4); i++)
5825 aarch64_set_vec_u32 (cpu, vd, i,
5826 aarch64_get_vec_u32 (cpu, vd, i) -
5827 (aarch64_get_vec_u32 (cpu, vs, i) * val));
5828 return;
5829 }
5830
5831 case 2:
5832 {
5833 unsigned elem = (uimm (aarch64_get_instr (cpu), 21, 21) << 1)
5834 | uimm (aarch64_get_instr (cpu), 11, 11);
5835 uint64_t val = aarch64_get_vec_u32 (cpu, vm, elem);
5836
5837 for (i = 0; i < (full ? 4 : 2); i++)
5838 aarch64_set_vec_u64 (cpu, vd, i,
5839 aarch64_get_vec_u64 (cpu, vd, i) -
5840 (aarch64_get_vec_u64 (cpu, vs, i) * val));
5841 return;
5842 }
5843
5844 case 0:
5845 case 3:
5846 default:
5847 HALT_NYI;
5848 }
5849 }
5850
5851 static void
5852 do_vec_SUB (sim_cpu *cpu)
5853 {
5854 /* instr [31] = 0
5855 instr [30] = half(0)/full(1)
5856 instr [29,24] = 10 1110
5857 instr [23,22] = size: byte(00, half(01), word (10), long (11)
5858 instr [21] = 1
5859 instr [20,16] = Vm
5860 instr [15,10] = 10 0001
5861 instr [9, 5] = Vn
5862 instr [4, 0] = Vd. */
5863
5864 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5865 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5866 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5867 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5868 unsigned i;
5869
5870 NYI_assert (29, 24, 0x2E);
5871 NYI_assert (21, 21, 1);
5872 NYI_assert (15, 10, 0x21);
5873
5874 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5875 {
5876 case 0:
5877 for (i = 0; i < (full ? 16 : 8); i++)
5878 aarch64_set_vec_s8 (cpu, vd, i,
5879 aarch64_get_vec_s8 (cpu, vn, i)
5880 - aarch64_get_vec_s8 (cpu, vm, i));
5881 return;
5882
5883 case 1:
5884 for (i = 0; i < (full ? 8 : 4); i++)
5885 aarch64_set_vec_s16 (cpu, vd, i,
5886 aarch64_get_vec_s16 (cpu, vn, i)
5887 - aarch64_get_vec_s16 (cpu, vm, i));
5888 return;
5889
5890 case 2:
5891 for (i = 0; i < (full ? 4 : 2); i++)
5892 aarch64_set_vec_s32 (cpu, vd, i,
5893 aarch64_get_vec_s32 (cpu, vn, i)
5894 - aarch64_get_vec_s32 (cpu, vm, i));
5895 return;
5896
5897 case 3:
5898 if (full == 0)
5899 HALT_UNALLOC;
5900
5901 for (i = 0; i < 2; i++)
5902 aarch64_set_vec_s64 (cpu, vd, i,
5903 aarch64_get_vec_s64 (cpu, vn, i)
5904 - aarch64_get_vec_s64 (cpu, vm, i));
5905 return;
5906
5907 default:
5908 HALT_UNREACHABLE;
5909 }
5910 }
5911
5912 static void
5913 do_vec_MLS (sim_cpu *cpu)
5914 {
5915 /* instr [31] = 0
5916 instr [30] = half(0)/full(1)
5917 instr [29,24] = 10 1110
5918 instr [23,22] = size: byte(00, half(01), word (10)
5919 instr [21] = 1
5920 instr [20,16] = Vm
5921 instr [15,10] = 10 0101
5922 instr [9, 5] = Vn
5923 instr [4, 0] = Vd. */
5924
5925 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5926 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5927 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5928 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5929 unsigned i;
5930
5931 NYI_assert (29, 24, 0x2E);
5932 NYI_assert (21, 21, 1);
5933 NYI_assert (15, 10, 0x25);
5934
5935 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5936 {
5937 case 0:
5938 for (i = 0; i < (full ? 16 : 8); i++)
5939 aarch64_set_vec_u8 (cpu, vd, i,
5940 (aarch64_get_vec_u8 (cpu, vn, i)
5941 * aarch64_get_vec_u8 (cpu, vm, i))
5942 - aarch64_get_vec_u8 (cpu, vd, i));
5943 return;
5944
5945 case 1:
5946 for (i = 0; i < (full ? 8 : 4); i++)
5947 aarch64_set_vec_u16 (cpu, vd, i,
5948 (aarch64_get_vec_u16 (cpu, vn, i)
5949 * aarch64_get_vec_u16 (cpu, vm, i))
5950 - aarch64_get_vec_u16 (cpu, vd, i));
5951 return;
5952
5953 case 2:
5954 for (i = 0; i < (full ? 4 : 2); i++)
5955 aarch64_set_vec_u32 (cpu, vd, i,
5956 (aarch64_get_vec_u32 (cpu, vn, i)
5957 * aarch64_get_vec_u32 (cpu, vm, i))
5958 - aarch64_get_vec_u32 (cpu, vd, i));
5959 return;
5960
5961 default:
5962 HALT_UNALLOC;
5963 }
5964 }
5965
5966 static void
5967 do_vec_FDIV (sim_cpu *cpu)
5968 {
5969 /* instr [31] = 0
5970 instr [30] = half(0)/full(1)
5971 instr [29,23] = 10 1110 0
5972 instr [22] = float()/double(1)
5973 instr [21] = 1
5974 instr [20,16] = Vm
5975 instr [15,10] = 1111 11
5976 instr [9, 5] = Vn
5977 instr [4, 0] = Vd. */
5978
5979 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5980 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5981 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5982 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5983 unsigned i;
5984
5985 NYI_assert (29, 23, 0x5C);
5986 NYI_assert (21, 21, 1);
5987 NYI_assert (15, 10, 0x3F);
5988
5989 if (uimm (aarch64_get_instr (cpu), 22, 22))
5990 {
5991 if (! full)
5992 HALT_UNALLOC;
5993
5994 for (i = 0; i < 2; i++)
5995 aarch64_set_vec_double (cpu, vd, i,
5996 aarch64_get_vec_double (cpu, vn, i)
5997 / aarch64_get_vec_double (cpu, vm, i));
5998 }
5999 else
6000 for (i = 0; i < (full ? 4 : 2); i++)
6001 aarch64_set_vec_float (cpu, vd, i,
6002 aarch64_get_vec_float (cpu, vn, i)
6003 / aarch64_get_vec_float (cpu, vm, i));
6004 }
6005
6006 static void
6007 do_vec_FMUL (sim_cpu *cpu)
6008 {
6009 /* instr [31] = 0
6010 instr [30] = half(0)/full(1)
6011 instr [29,23] = 10 1110 0
6012 instr [22] = float(0)/double(1)
6013 instr [21] = 1
6014 instr [20,16] = Vm
6015 instr [15,10] = 1101 11
6016 instr [9, 5] = Vn
6017 instr [4, 0] = Vd. */
6018
6019 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6020 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6021 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6022 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6023 unsigned i;
6024
6025 NYI_assert (29, 23, 0x5C);
6026 NYI_assert (21, 21, 1);
6027 NYI_assert (15, 10, 0x37);
6028
6029 if (uimm (aarch64_get_instr (cpu), 22, 22))
6030 {
6031 if (! full)
6032 HALT_UNALLOC;
6033
6034 for (i = 0; i < 2; i++)
6035 aarch64_set_vec_double (cpu, vd, i,
6036 aarch64_get_vec_double (cpu, vn, i)
6037 * aarch64_get_vec_double (cpu, vm, i));
6038 }
6039 else
6040 for (i = 0; i < (full ? 4 : 2); i++)
6041 aarch64_set_vec_float (cpu, vd, i,
6042 aarch64_get_vec_float (cpu, vn, i)
6043 * aarch64_get_vec_float (cpu, vm, i));
6044 }
6045
6046 static void
6047 do_vec_FADDP (sim_cpu *cpu)
6048 {
6049 /* instr [31] = 0
6050 instr [30] = half(0)/full(1)
6051 instr [29,23] = 10 1110 0
6052 instr [22] = float(0)/double(1)
6053 instr [21] = 1
6054 instr [20,16] = Vm
6055 instr [15,10] = 1101 01
6056 instr [9, 5] = Vn
6057 instr [4, 0] = Vd. */
6058
6059 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6060 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6061 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6062 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6063
6064 NYI_assert (29, 23, 0x5C);
6065 NYI_assert (21, 21, 1);
6066 NYI_assert (15, 10, 0x35);
6067
6068 if (uimm (aarch64_get_instr (cpu), 22, 22))
6069 {
6070 if (! full)
6071 HALT_UNALLOC;
6072
6073 aarch64_set_vec_double (cpu, vd, 0, aarch64_get_vec_double (cpu, vn, 0)
6074 + aarch64_get_vec_double (cpu, vn, 1));
6075 aarch64_set_vec_double (cpu, vd, 1, aarch64_get_vec_double (cpu, vm, 0)
6076 + aarch64_get_vec_double (cpu, vm, 1));
6077 }
6078 else
6079 {
6080 aarch64_set_vec_float (cpu, vd, 0, aarch64_get_vec_float (cpu, vn, 0)
6081 + aarch64_get_vec_float (cpu, vn, 1));
6082 if (full)
6083 aarch64_set_vec_float (cpu, vd, 1, aarch64_get_vec_float (cpu, vn, 2)
6084 + aarch64_get_vec_float (cpu, vn, 3));
6085 aarch64_set_vec_float (cpu, vd, full ? 2 : 1,
6086 aarch64_get_vec_float (cpu, vm, 0)
6087 + aarch64_get_vec_float (cpu, vm, 1));
6088 if (full)
6089 aarch64_set_vec_float (cpu, vd, 3,
6090 aarch64_get_vec_float (cpu, vm, 2)
6091 + aarch64_get_vec_float (cpu, vm, 3));
6092 }
6093 }
6094
6095 static void
6096 do_vec_FSQRT (sim_cpu *cpu)
6097 {
6098 /* instr[31] = 0
6099 instr[30] = half(0)/full(1)
6100 instr[29,23] = 10 1110 1
6101 instr[22] = single(0)/double(1)
6102 instr[21,10] = 10 0001 1111 10
6103 instr[9,5] = Vsrc
6104 instr[4,0] = Vdest. */
6105
6106 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6107 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6108 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6109 int i;
6110
6111 NYI_assert (29, 23, 0x5D);
6112 NYI_assert (21, 10, 0x87E);
6113
6114 if (uimm (aarch64_get_instr (cpu), 22, 22))
6115 {
6116 if (! full)
6117 HALT_UNALLOC;
6118
6119 for (i = 0; i < 2; i++)
6120 aarch64_set_vec_double (cpu, vd, i,
6121 sqrt (aarch64_get_vec_double (cpu, vn, i)));
6122 }
6123 else
6124 {
6125 for (i = 0; i < (full ? 4 : 2); i++)
6126 aarch64_set_vec_float (cpu, vd, i,
6127 sqrtf (aarch64_get_vec_float (cpu, vn, i)));
6128 }
6129 }
6130
6131 static void
6132 do_vec_FNEG (sim_cpu *cpu)
6133 {
6134 /* instr[31] = 0
6135 instr[30] = half (0)/full (1)
6136 instr[29,23] = 10 1110 1
6137 instr[22] = single (0)/double (1)
6138 instr[21,10] = 10 0000 1111 10
6139 instr[9,5] = Vsrc
6140 instr[4,0] = Vdest. */
6141
6142 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6143 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6144 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6145 int i;
6146
6147 NYI_assert (29, 23, 0x5D);
6148 NYI_assert (21, 10, 0x83E);
6149
6150 if (uimm (aarch64_get_instr (cpu), 22, 22))
6151 {
6152 if (! full)
6153 HALT_UNALLOC;
6154
6155 for (i = 0; i < 2; i++)
6156 aarch64_set_vec_double (cpu, vd, i,
6157 - aarch64_get_vec_double (cpu, vn, i));
6158 }
6159 else
6160 {
6161 for (i = 0; i < (full ? 4 : 2); i++)
6162 aarch64_set_vec_float (cpu, vd, i,
6163 - aarch64_get_vec_float (cpu, vn, i));
6164 }
6165 }
6166
6167 static void
6168 do_vec_NOT (sim_cpu *cpu)
6169 {
6170 /* instr[31] = 0
6171 instr[30] = half (0)/full (1)
6172 instr[29,21] = 10 1110 001
6173 instr[20,16] = 0 0000
6174 instr[15,10] = 0101 10
6175 instr[9,5] = Vn
6176 instr[4.0] = Vd. */
6177
6178 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6179 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6180 unsigned i;
6181 int full = uimm (aarch64_get_instr (cpu), 30, 30);
6182
6183 NYI_assert (29, 10, 0xB8816);
6184
6185 for (i = 0; i < (full ? 16 : 8); i++)
6186 aarch64_set_vec_u8 (cpu, vd, i, ~ aarch64_get_vec_u8 (cpu, vn, i));
6187 }
6188
6189 static void
6190 do_vec_MOV_element (sim_cpu *cpu)
6191 {
6192 /* instr[31,21] = 0110 1110 000
6193 instr[20,16] = size & dest index
6194 instr[15] = 0
6195 instr[14,11] = source index
6196 instr[10] = 1
6197 instr[9,5] = Vs
6198 instr[4.0] = Vd. */
6199
6200 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
6201 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6202 unsigned src_index;
6203 unsigned dst_index;
6204
6205 NYI_assert (31, 21, 0x370);
6206 NYI_assert (15, 15, 0);
6207 NYI_assert (10, 10, 1);
6208
6209 if (uimm (aarch64_get_instr (cpu), 16, 16))
6210 {
6211 /* Move a byte. */
6212 src_index = uimm (aarch64_get_instr (cpu), 14, 11);
6213 dst_index = uimm (aarch64_get_instr (cpu), 20, 17);
6214 aarch64_set_vec_u8 (cpu, vd, dst_index,
6215 aarch64_get_vec_u8 (cpu, vs, src_index));
6216 }
6217 else if (uimm (aarch64_get_instr (cpu), 17, 17))
6218 {
6219 /* Move 16-bits. */
6220 NYI_assert (11, 11, 0);
6221 src_index = uimm (aarch64_get_instr (cpu), 14, 12);
6222 dst_index = uimm (aarch64_get_instr (cpu), 20, 18);
6223 aarch64_set_vec_u16 (cpu, vd, dst_index,
6224 aarch64_get_vec_u16 (cpu, vs, src_index));
6225 }
6226 else if (uimm (aarch64_get_instr (cpu), 18, 18))
6227 {
6228 /* Move 32-bits. */
6229 NYI_assert (12, 11, 0);
6230 src_index = uimm (aarch64_get_instr (cpu), 14, 13);
6231 dst_index = uimm (aarch64_get_instr (cpu), 20, 19);
6232 aarch64_set_vec_u32 (cpu, vd, dst_index,
6233 aarch64_get_vec_u32 (cpu, vs, src_index));
6234 }
6235 else
6236 {
6237 NYI_assert (19, 19, 1);
6238 NYI_assert (13, 11, 0);
6239 src_index = uimm (aarch64_get_instr (cpu), 14, 14);
6240 dst_index = uimm (aarch64_get_instr (cpu), 20, 20);
6241 aarch64_set_vec_u64 (cpu, vd, dst_index,
6242 aarch64_get_vec_u64 (cpu, vs, src_index));
6243 }
6244 }
6245
6246 static void
6247 dexAdvSIMD0 (sim_cpu *cpu)
6248 {
6249 /* instr [28,25] = 0 111. */
6250 if ( uimm (aarch64_get_instr (cpu), 15, 10) == 0x07
6251 && (uimm (aarch64_get_instr (cpu), 9, 5) ==
6252 uimm (aarch64_get_instr (cpu), 20, 16)))
6253 {
6254 if (uimm (aarch64_get_instr (cpu), 31, 21) == 0x075
6255 || uimm (aarch64_get_instr (cpu), 31, 21) == 0x275)
6256 {
6257 do_vec_MOV_whole_vector (cpu);
6258 return;
6259 }
6260 }
6261
6262 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x1E0)
6263 {
6264 do_vec_MOV_immediate (cpu);
6265 return;
6266 }
6267
6268 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x5E0)
6269 {
6270 do_vec_MVNI (cpu);
6271 return;
6272 }
6273
6274 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x1C0
6275 || uimm (aarch64_get_instr (cpu), 29, 19) == 0x1C1)
6276 {
6277 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x03)
6278 {
6279 do_vec_DUP_scalar_into_vector (cpu);
6280 return;
6281 }
6282 }
6283
6284 switch (uimm (aarch64_get_instr (cpu), 29, 24))
6285 {
6286 case 0x0E: do_vec_op1 (cpu); return;
6287 case 0x0F: do_vec_op2 (cpu); return;
6288
6289 case 0x2f:
6290 switch (uimm (aarch64_get_instr (cpu), 15, 10))
6291 {
6292 case 0x01: do_vec_SSHR_USHR (cpu); return;
6293 case 0x10:
6294 case 0x12: do_vec_mls_indexed (cpu); return;
6295 case 0x29: do_vec_xtl (cpu); return;
6296 default:
6297 HALT_NYI;
6298 }
6299
6300 case 0x2E:
6301 if (uimm (aarch64_get_instr (cpu), 21, 21) == 1)
6302 {
6303 switch (uimm (aarch64_get_instr (cpu), 15, 10))
6304 {
6305 case 0x07:
6306 switch (uimm (aarch64_get_instr (cpu), 23, 22))
6307 {
6308 case 0: do_vec_EOR (cpu); return;
6309 case 1: do_vec_BSL (cpu); return;
6310 case 2:
6311 case 3: do_vec_bit (cpu); return;
6312 }
6313 break;
6314
6315 case 0x08: do_vec_sub_long (cpu); return;
6316 case 0x11: do_vec_USHL (cpu); return;
6317 case 0x16: do_vec_NOT (cpu); return;
6318 case 0x19: do_vec_max (cpu); return;
6319 case 0x1B: do_vec_min (cpu); return;
6320 case 0x21: do_vec_SUB (cpu); return;
6321 case 0x25: do_vec_MLS (cpu); return;
6322 case 0x31: do_vec_FminmaxNMP (cpu); return;
6323 case 0x35: do_vec_FADDP (cpu); return;
6324 case 0x37: do_vec_FMUL (cpu); return;
6325 case 0x3F: do_vec_FDIV (cpu); return;
6326
6327 case 0x3E:
6328 switch (uimm (aarch64_get_instr (cpu), 20, 16))
6329 {
6330 case 0x00: do_vec_FNEG (cpu); return;
6331 case 0x01: do_vec_FSQRT (cpu); return;
6332 default: HALT_NYI;
6333 }
6334
6335 case 0x0D:
6336 case 0x0F:
6337 case 0x22:
6338 case 0x23:
6339 case 0x26:
6340 case 0x2A:
6341 case 0x32:
6342 case 0x36:
6343 case 0x39:
6344 case 0x3A:
6345 do_vec_compare (cpu); return;
6346
6347 default: break;
6348 }
6349 }
6350
6351 if (uimm (aarch64_get_instr (cpu), 31, 21) == 0x370)
6352 {
6353 do_vec_MOV_element (cpu);
6354 return;
6355 }
6356
6357 switch (uimm (aarch64_get_instr (cpu), 21, 10))
6358 {
6359 case 0x82E: do_vec_neg (cpu); return;
6360 case 0x87E: do_vec_sqrt (cpu); return;
6361 default:
6362 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x30)
6363 {
6364 do_vec_mull (cpu);
6365 return;
6366 }
6367 break;
6368 }
6369 break;
6370
6371 default:
6372 break;
6373 }
6374
6375 HALT_NYI;
6376 }
6377
6378 /* 3 sources. */
6379
6380 /* Float multiply add. */
6381 static void
6382 fmadds (sim_cpu *cpu)
6383 {
6384 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6385 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6386 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6387 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6388
6389 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6390 + aarch64_get_FP_float (cpu, sn)
6391 * aarch64_get_FP_float (cpu, sm));
6392 }
6393
6394 /* Double multiply add. */
6395 static void
6396 fmaddd (sim_cpu *cpu)
6397 {
6398 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6399 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6400 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6401 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6402
6403 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6404 + aarch64_get_FP_double (cpu, sn)
6405 * aarch64_get_FP_double (cpu, sm));
6406 }
6407
6408 /* Float multiply subtract. */
6409 static void
6410 fmsubs (sim_cpu *cpu)
6411 {
6412 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6413 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6414 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6415 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6416
6417 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6418 - aarch64_get_FP_float (cpu, sn)
6419 * aarch64_get_FP_float (cpu, sm));
6420 }
6421
6422 /* Double multiply subtract. */
6423 static void
6424 fmsubd (sim_cpu *cpu)
6425 {
6426 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6427 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6428 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6429 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6430
6431 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6432 - aarch64_get_FP_double (cpu, sn)
6433 * aarch64_get_FP_double (cpu, sm));
6434 }
6435
6436 /* Float negative multiply add. */
6437 static void
6438 fnmadds (sim_cpu *cpu)
6439 {
6440 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6441 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6442 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6443 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6444
6445 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6446 + (- aarch64_get_FP_float (cpu, sn))
6447 * aarch64_get_FP_float (cpu, sm));
6448 }
6449
6450 /* Double negative multiply add. */
6451 static void
6452 fnmaddd (sim_cpu *cpu)
6453 {
6454 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6455 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6456 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6457 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6458
6459 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6460 + (- aarch64_get_FP_double (cpu, sn))
6461 * aarch64_get_FP_double (cpu, sm));
6462 }
6463
6464 /* Float negative multiply subtract. */
6465 static void
6466 fnmsubs (sim_cpu *cpu)
6467 {
6468 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6469 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6470 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6471 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6472
6473 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6474 + aarch64_get_FP_float (cpu, sn)
6475 * aarch64_get_FP_float (cpu, sm));
6476 }
6477
6478 /* Double negative multiply subtract. */
6479 static void
6480 fnmsubd (sim_cpu *cpu)
6481 {
6482 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6483 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6484 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6485 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6486
6487 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6488 + aarch64_get_FP_double (cpu, sn)
6489 * aarch64_get_FP_double (cpu, sm));
6490 }
6491
6492 static void
6493 dexSimpleFPDataProc3Source (sim_cpu *cpu)
6494 {
6495 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
6496 instr[30] = 0
6497 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
6498 instr[28,25] = 1111
6499 instr[24] = 1
6500 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
6501 instr[21] ==> o1 : 0 ==> unnegated, 1 ==> negated
6502 instr[15] ==> o2 : 0 ==> ADD, 1 ==> SUB */
6503
6504 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
6505 | uimm (aarch64_get_instr (cpu), 29, 29);
6506 /* dispatch on combined type:o1:o2. */
6507 uint32_t dispatch = (uimm (aarch64_get_instr (cpu), 23, 21) << 1)
6508 | uimm (aarch64_get_instr (cpu), 15, 15);
6509
6510 if (M_S != 0)
6511 HALT_UNALLOC;
6512
6513 switch (dispatch)
6514 {
6515 case 0: fmadds (cpu); return;
6516 case 1: fmsubs (cpu); return;
6517 case 2: fnmadds (cpu); return;
6518 case 3: fnmsubs (cpu); return;
6519 case 4: fmaddd (cpu); return;
6520 case 5: fmsubd (cpu); return;
6521 case 6: fnmaddd (cpu); return;
6522 case 7: fnmsubd (cpu); return;
6523 default:
6524 /* type > 1 is currently unallocated. */
6525 HALT_UNALLOC;
6526 }
6527 }
6528
6529 static void
6530 dexSimpleFPFixedConvert (sim_cpu *cpu)
6531 {
6532 HALT_NYI;
6533 }
6534
6535 static void
6536 dexSimpleFPCondCompare (sim_cpu *cpu)
6537 {
6538 HALT_NYI;
6539 }
6540
6541 /* 2 sources. */
6542
6543 /* Float add. */
6544 static void
6545 fadds (sim_cpu *cpu)
6546 {
6547 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6548 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6549 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6550
6551 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6552 + aarch64_get_FP_float (cpu, sm));
6553 }
6554
6555 /* Double add. */
6556 static void
6557 faddd (sim_cpu *cpu)
6558 {
6559 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6560 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6561 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6562
6563 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6564 + aarch64_get_FP_double (cpu, sm));
6565 }
6566
6567 /* Float divide. */
6568 static void
6569 fdivs (sim_cpu *cpu)
6570 {
6571 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6572 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6573 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6574
6575 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6576 / aarch64_get_FP_float (cpu, sm));
6577 }
6578
6579 /* Double divide. */
6580 static void
6581 fdivd (sim_cpu *cpu)
6582 {
6583 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6584 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6585 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6586
6587 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6588 / aarch64_get_FP_double (cpu, sm));
6589 }
6590
6591 /* Float multiply. */
6592 static void
6593 fmuls (sim_cpu *cpu)
6594 {
6595 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6596 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6597 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6598
6599 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6600 * aarch64_get_FP_float (cpu, sm));
6601 }
6602
6603 /* Double multiply. */
6604 static void
6605 fmuld (sim_cpu *cpu)
6606 {
6607 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6608 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6609 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6610
6611 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6612 * aarch64_get_FP_double (cpu, sm));
6613 }
6614
6615 /* Float negate and multiply. */
6616 static void
6617 fnmuls (sim_cpu *cpu)
6618 {
6619 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6620 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6621 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6622
6623 aarch64_set_FP_float (cpu, sd, - (aarch64_get_FP_float (cpu, sn)
6624 * aarch64_get_FP_float (cpu, sm)));
6625 }
6626
6627 /* Double negate and multiply. */
6628 static void
6629 fnmuld (sim_cpu *cpu)
6630 {
6631 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6632 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6633 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6634
6635 aarch64_set_FP_double (cpu, sd, - (aarch64_get_FP_double (cpu, sn)
6636 * aarch64_get_FP_double (cpu, sm)));
6637 }
6638
6639 /* Float subtract. */
6640 static void
6641 fsubs (sim_cpu *cpu)
6642 {
6643 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6644 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6645 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6646
6647 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6648 - aarch64_get_FP_float (cpu, sm));
6649 }
6650
6651 /* Double subtract. */
6652 static void
6653 fsubd (sim_cpu *cpu)
6654 {
6655 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6656 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6657 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6658
6659 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6660 - aarch64_get_FP_double (cpu, sm));
6661 }
6662
6663 static void
6664 do_FMINNM (sim_cpu *cpu)
6665 {
6666 /* instr[31,23] = 0 0011 1100
6667 instr[22] = float(0)/double(1)
6668 instr[21] = 1
6669 instr[20,16] = Sm
6670 instr[15,10] = 01 1110
6671 instr[9,5] = Sn
6672 instr[4,0] = Cpu */
6673
6674 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6675 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6676 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6677
6678 NYI_assert (31, 23, 0x03C);
6679 NYI_assert (15, 10, 0x1E);
6680
6681 if (uimm (aarch64_get_instr (cpu), 22, 22))
6682 aarch64_set_FP_double (cpu, sd,
6683 dminnm (aarch64_get_FP_double (cpu, sn),
6684 aarch64_get_FP_double (cpu, sm)));
6685 else
6686 aarch64_set_FP_float (cpu, sd,
6687 fminnm (aarch64_get_FP_float (cpu, sn),
6688 aarch64_get_FP_float (cpu, sm)));
6689 }
6690
6691 static void
6692 do_FMAXNM (sim_cpu *cpu)
6693 {
6694 /* instr[31,23] = 0 0011 1100
6695 instr[22] = float(0)/double(1)
6696 instr[21] = 1
6697 instr[20,16] = Sm
6698 instr[15,10] = 01 1010
6699 instr[9,5] = Sn
6700 instr[4,0] = Cpu */
6701
6702 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6703 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6704 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6705
6706 NYI_assert (31, 23, 0x03C);
6707 NYI_assert (15, 10, 0x1A);
6708
6709 if (uimm (aarch64_get_instr (cpu), 22, 22))
6710 aarch64_set_FP_double (cpu, sd,
6711 dmaxnm (aarch64_get_FP_double (cpu, sn),
6712 aarch64_get_FP_double (cpu, sm)));
6713 else
6714 aarch64_set_FP_float (cpu, sd,
6715 fmaxnm (aarch64_get_FP_float (cpu, sn),
6716 aarch64_get_FP_float (cpu, sm)));
6717 }
6718
6719 static void
6720 dexSimpleFPDataProc2Source (sim_cpu *cpu)
6721 {
6722 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
6723 instr[30] = 0
6724 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
6725 instr[28,25] = 1111
6726 instr[24] = 0
6727 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
6728 instr[21] = 1
6729 instr[20,16] = Vm
6730 instr[15,12] ==> opcode : 0000 ==> FMUL, 0001 ==> FDIV
6731 0010 ==> FADD, 0011 ==> FSUB,
6732 0100 ==> FMAX, 0101 ==> FMIN
6733 0110 ==> FMAXNM, 0111 ==> FMINNM
6734 1000 ==> FNMUL, ow ==> UNALLOC
6735 instr[11,10] = 10
6736 instr[9,5] = Vn
6737 instr[4,0] = Vd */
6738
6739 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
6740 | uimm (aarch64_get_instr (cpu), 29, 29);
6741 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
6742 /* Dispatch on opcode. */
6743 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 15, 12);
6744
6745 if (type > 1)
6746 HALT_UNALLOC;
6747
6748 if (M_S != 0)
6749 HALT_UNALLOC;
6750
6751 if (type)
6752 switch (dispatch)
6753 {
6754 case 0: fmuld (cpu); return;
6755 case 1: fdivd (cpu); return;
6756 case 2: faddd (cpu); return;
6757 case 3: fsubd (cpu); return;
6758 case 6: do_FMAXNM (cpu); return;
6759 case 7: do_FMINNM (cpu); return;
6760 case 8: fnmuld (cpu); return;
6761
6762 /* Have not yet implemented fmax and fmin. */
6763 case 4:
6764 case 5:
6765 HALT_NYI;
6766
6767 default:
6768 HALT_UNALLOC;
6769 }
6770 else /* type == 0 => floats. */
6771 switch (dispatch)
6772 {
6773 case 0: fmuls (cpu); return;
6774 case 1: fdivs (cpu); return;
6775 case 2: fadds (cpu); return;
6776 case 3: fsubs (cpu); return;
6777 case 6: do_FMAXNM (cpu); return;
6778 case 7: do_FMINNM (cpu); return;
6779 case 8: fnmuls (cpu); return;
6780
6781 case 4:
6782 case 5:
6783 HALT_NYI;
6784
6785 default:
6786 HALT_UNALLOC;
6787 }
6788 }
6789
6790 static void
6791 dexSimpleFPCondSelect (sim_cpu *cpu)
6792 {
6793 /* FCSEL
6794 instr[31,23] = 0 0011 1100
6795 instr[22] = 0=>single 1=>double
6796 instr[21] = 1
6797 instr[20,16] = Sm
6798 instr[15,12] = cond
6799 instr[11,10] = 11
6800 instr[9,5] = Sn
6801 instr[4,0] = Cpu */
6802 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6803 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6804 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6805 uint32_t set = testConditionCode (cpu, uimm (aarch64_get_instr (cpu), 15, 12));
6806
6807 NYI_assert (31, 23, 0x03C);
6808 NYI_assert (11, 10, 0x3);
6809
6810 if (uimm (aarch64_get_instr (cpu), 22, 22))
6811 aarch64_set_FP_double (cpu, sd, set ? sn : sm);
6812 else
6813 aarch64_set_FP_float (cpu, sd, set ? sn : sm);
6814 }
6815
6816 /* Store 32 bit unscaled signed 9 bit. */
6817 static void
6818 fsturs (sim_cpu *cpu, int32_t offset)
6819 {
6820 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6821 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6822
6823 aarch64_set_mem_float (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
6824 aarch64_get_FP_float (cpu, rn));
6825 }
6826
6827 /* Store 64 bit unscaled signed 9 bit. */
6828 static void
6829 fsturd (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_double (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
6835 aarch64_get_FP_double (cpu, rn));
6836 }
6837
6838 /* Store 128 bit unscaled signed 9 bit. */
6839 static void
6840 fsturq (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 FRegister a;
6845
6846 aarch64_get_FP_long_double (cpu, rn, & a);
6847 aarch64_set_mem_long_double (cpu,
6848 aarch64_get_reg_u64 (cpu, st, 1)
6849 + offset, a);
6850 }
6851
6852 /* TODO FP move register. */
6853
6854 /* 32 bit fp to fp move register. */
6855 static void
6856 ffmovs (sim_cpu *cpu)
6857 {
6858 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6859 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6860
6861 aarch64_set_FP_float (cpu, st, aarch64_get_FP_float (cpu, rn));
6862 }
6863
6864 /* 64 bit fp to fp move register. */
6865 static void
6866 ffmovd (sim_cpu *cpu)
6867 {
6868 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6869 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6870
6871 aarch64_set_FP_double (cpu, st, aarch64_get_FP_double (cpu, rn));
6872 }
6873
6874 /* 32 bit GReg to Vec move register. */
6875 static void
6876 fgmovs (sim_cpu *cpu)
6877 {
6878 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6879 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6880
6881 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_reg_u32 (cpu, rn, NO_SP));
6882 }
6883
6884 /* 64 bit g to fp move register. */
6885 static void
6886 fgmovd (sim_cpu *cpu)
6887 {
6888 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6889 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6890
6891 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_reg_u64 (cpu, rn, NO_SP));
6892 }
6893
6894 /* 32 bit fp to g move register. */
6895 static void
6896 gfmovs (sim_cpu *cpu)
6897 {
6898 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6899 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6900
6901 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u32 (cpu, rn, 0));
6902 }
6903
6904 /* 64 bit fp to g move register. */
6905 static void
6906 gfmovd (sim_cpu *cpu)
6907 {
6908 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6909 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6910
6911 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u64 (cpu, rn, 0));
6912 }
6913
6914 /* FP move immediate
6915
6916 These install an immediate 8 bit value in the target register
6917 where the 8 bits comprise 1 sign bit, 4 bits of fraction and a 3
6918 bit exponent. */
6919
6920 static void
6921 fmovs (sim_cpu *cpu)
6922 {
6923 unsigned int sd = uimm (aarch64_get_instr (cpu), 4, 0);
6924 uint32_t imm = uimm (aarch64_get_instr (cpu), 20, 13);
6925 float f = fp_immediate_for_encoding_32 (imm);
6926
6927 aarch64_set_FP_float (cpu, sd, f);
6928 }
6929
6930 static void
6931 fmovd (sim_cpu *cpu)
6932 {
6933 unsigned int sd = uimm (aarch64_get_instr (cpu), 4, 0);
6934 uint32_t imm = uimm (aarch64_get_instr (cpu), 20, 13);
6935 double d = fp_immediate_for_encoding_64 (imm);
6936
6937 aarch64_set_FP_double (cpu, sd, d);
6938 }
6939
6940 static void
6941 dexSimpleFPImmediate (sim_cpu *cpu)
6942 {
6943 /* instr[31,23] == 00111100
6944 instr[22] == type : single(0)/double(1)
6945 instr[21] == 1
6946 instr[20,13] == imm8
6947 instr[12,10] == 100
6948 instr[9,5] == imm5 : 00000 ==> PK, ow ==> UNALLOC
6949 instr[4,0] == Rd */
6950 uint32_t imm5 = uimm (aarch64_get_instr (cpu), 9, 5);
6951
6952 NYI_assert (31, 23, 0x3C);
6953
6954 if (imm5 != 0)
6955 HALT_UNALLOC;
6956
6957 if (uimm (aarch64_get_instr (cpu), 22, 22))
6958 fmovd (cpu);
6959 else
6960 fmovs (cpu);
6961 }
6962
6963 /* TODO specific decode and execute for group Load Store. */
6964
6965 /* TODO FP load/store single register (unscaled offset). */
6966
6967 /* TODO load 8 bit unscaled signed 9 bit. */
6968 /* TODO load 16 bit unscaled signed 9 bit. */
6969
6970 /* Load 32 bit unscaled signed 9 bit. */
6971 static void
6972 fldurs (sim_cpu *cpu, int32_t offset)
6973 {
6974 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6975 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6976
6977 aarch64_set_FP_float (cpu, st, aarch64_get_mem_float
6978 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
6979 }
6980
6981 /* Load 64 bit unscaled signed 9 bit. */
6982 static void
6983 fldurd (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_double (cpu, st, aarch64_get_mem_double
6989 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
6990 }
6991
6992 /* Load 128 bit unscaled signed 9 bit. */
6993 static void
6994 fldurq (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 FRegister a;
6999 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
7000
7001 aarch64_get_mem_long_double (cpu, addr, & a);
7002 aarch64_set_FP_long_double (cpu, st, a);
7003 }
7004
7005 /* TODO store 8 bit unscaled signed 9 bit. */
7006 /* TODO store 16 bit unscaled signed 9 bit. */
7007
7008
7009 /* 1 source. */
7010
7011 /* Float absolute value. */
7012 static void
7013 fabss (sim_cpu *cpu)
7014 {
7015 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7016 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7017 float value = aarch64_get_FP_float (cpu, sn);
7018
7019 aarch64_set_FP_float (cpu, sd, fabsf (value));
7020 }
7021
7022 /* Double absolute value. */
7023 static void
7024 fabcpu (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 double value = aarch64_get_FP_double (cpu, sn);
7029
7030 aarch64_set_FP_double (cpu, sd, fabs (value));
7031 }
7032
7033 /* Float negative value. */
7034 static void
7035 fnegs (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
7040 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sn));
7041 }
7042
7043 /* Double negative value. */
7044 static void
7045 fnegd (sim_cpu *cpu)
7046 {
7047 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7048 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7049
7050 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sn));
7051 }
7052
7053 /* Float square root. */
7054 static void
7055 fsqrts (sim_cpu *cpu)
7056 {
7057 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7058 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7059
7060 aarch64_set_FP_float (cpu, sd, sqrt (aarch64_get_FP_float (cpu, sn)));
7061 }
7062
7063 /* Double square root. */
7064 static void
7065 fsqrtd (sim_cpu *cpu)
7066 {
7067 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7068 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7069
7070 aarch64_set_FP_double (cpu, sd,
7071 sqrt (aarch64_get_FP_double (cpu, sn)));
7072 }
7073
7074 /* Convert double to float. */
7075 static void
7076 fcvtds (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_float (cpu, sd, (float) aarch64_get_FP_double (cpu, sn));
7082 }
7083
7084 /* Convert float to double. */
7085 static void
7086 fcvtcpu (sim_cpu *cpu)
7087 {
7088 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7089 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7090
7091 aarch64_set_FP_double (cpu, sd, (double) aarch64_get_FP_float (cpu, sn));
7092 }
7093
7094 static void
7095 do_FRINT (sim_cpu *cpu)
7096 {
7097 /* instr[31,23] = 0001 1110 0
7098 instr[22] = single(0)/double(1)
7099 instr[21,18] = 1001
7100 instr[17,15] = rounding mode
7101 instr[14,10] = 10000
7102 instr[9,5] = source
7103 instr[4,0] = dest */
7104
7105 float val;
7106 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7107 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7108 unsigned int rmode = uimm (aarch64_get_instr (cpu), 17, 15);
7109
7110 NYI_assert (31, 23, 0x03C);
7111 NYI_assert (21, 18, 0x9);
7112 NYI_assert (14, 10, 0x10);
7113
7114 if (rmode == 6 || rmode == 7)
7115 /* FIXME: Add support for rmode == 6 exactness check. */
7116 rmode = uimm (aarch64_get_FPSR (cpu), 23, 22);
7117
7118 if (uimm (aarch64_get_instr (cpu), 22, 22))
7119 {
7120 double val = aarch64_get_FP_double (cpu, rs);
7121
7122 switch (rmode)
7123 {
7124 case 0: /* mode N: nearest or even. */
7125 {
7126 double rval = round (val);
7127
7128 if (val - rval == 0.5)
7129 {
7130 if (((rval / 2.0) * 2.0) != rval)
7131 rval += 1.0;
7132 }
7133
7134 aarch64_set_FP_double (cpu, rd, round (val));
7135 return;
7136 }
7137
7138 case 1: /* mode P: towards +inf. */
7139 if (val < 0.0)
7140 aarch64_set_FP_double (cpu, rd, trunc (val));
7141 else
7142 aarch64_set_FP_double (cpu, rd, round (val));
7143 return;
7144
7145 case 2: /* mode M: towards -inf. */
7146 if (val < 0.0)
7147 aarch64_set_FP_double (cpu, rd, round (val));
7148 else
7149 aarch64_set_FP_double (cpu, rd, trunc (val));
7150 return;
7151
7152 case 3: /* mode Z: towards 0. */
7153 aarch64_set_FP_double (cpu, rd, trunc (val));
7154 return;
7155
7156 case 4: /* mode A: away from 0. */
7157 aarch64_set_FP_double (cpu, rd, round (val));
7158 return;
7159
7160 case 6: /* mode X: use FPCR with exactness check. */
7161 case 7: /* mode I: use FPCR mode. */
7162 HALT_NYI;
7163
7164 default:
7165 HALT_UNALLOC;
7166 }
7167 }
7168
7169 val = aarch64_get_FP_float (cpu, rs);
7170
7171 switch (rmode)
7172 {
7173 case 0: /* mode N: nearest or even. */
7174 {
7175 float rval = roundf (val);
7176
7177 if (val - rval == 0.5)
7178 {
7179 if (((rval / 2.0) * 2.0) != rval)
7180 rval += 1.0;
7181 }
7182
7183 aarch64_set_FP_float (cpu, rd, rval);
7184 return;
7185 }
7186
7187 case 1: /* mode P: towards +inf. */
7188 if (val < 0.0)
7189 aarch64_set_FP_float (cpu, rd, truncf (val));
7190 else
7191 aarch64_set_FP_float (cpu, rd, roundf (val));
7192 return;
7193
7194 case 2: /* mode M: towards -inf. */
7195 if (val < 0.0)
7196 aarch64_set_FP_float (cpu, rd, truncf (val));
7197 else
7198 aarch64_set_FP_float (cpu, rd, roundf (val));
7199 return;
7200
7201 case 3: /* mode Z: towards 0. */
7202 aarch64_set_FP_float (cpu, rd, truncf (val));
7203 return;
7204
7205 case 4: /* mode A: away from 0. */
7206 aarch64_set_FP_float (cpu, rd, roundf (val));
7207 return;
7208
7209 case 6: /* mode X: use FPCR with exactness check. */
7210 case 7: /* mode I: use FPCR mode. */
7211 HALT_NYI;
7212
7213 default:
7214 HALT_UNALLOC;
7215 }
7216 }
7217
7218 static void
7219 dexSimpleFPDataProc1Source (sim_cpu *cpu)
7220 {
7221 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7222 instr[30] = 0
7223 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7224 instr[28,25] = 1111
7225 instr[24] = 0
7226 instr[23,22] ==> type : 00 ==> source is single,
7227 01 ==> source is double
7228 10 ==> UNALLOC
7229 11 ==> UNALLOC or source is half
7230 instr[21] = 1
7231 instr[20,15] ==> opcode : with type 00 or 01
7232 000000 ==> FMOV, 000001 ==> FABS,
7233 000010 ==> FNEG, 000011 ==> FSQRT,
7234 000100 ==> UNALLOC, 000101 ==> FCVT,(to single/double)
7235 000110 ==> UNALLOC, 000111 ==> FCVT (to half)
7236 001000 ==> FRINTN, 001001 ==> FRINTP,
7237 001010 ==> FRINTM, 001011 ==> FRINTZ,
7238 001100 ==> FRINTA, 001101 ==> UNALLOC
7239 001110 ==> FRINTX, 001111 ==> FRINTI
7240 with type 11
7241 000100 ==> FCVT (half-to-single)
7242 000101 ==> FCVT (half-to-double)
7243 instr[14,10] = 10000. */
7244
7245 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
7246 | uimm (aarch64_get_instr (cpu), 29, 29);
7247 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
7248 uint32_t opcode = uimm (aarch64_get_instr (cpu), 20, 15);
7249
7250 if (M_S != 0)
7251 HALT_UNALLOC;
7252
7253 if (type == 3)
7254 {
7255 if (opcode == 4 || opcode == 5)
7256 HALT_NYI;
7257 else
7258 HALT_UNALLOC;
7259 }
7260
7261 if (type == 2)
7262 HALT_UNALLOC;
7263
7264 switch (opcode)
7265 {
7266 case 0:
7267 if (type)
7268 ffmovd (cpu);
7269 else
7270 ffmovs (cpu);
7271 return;
7272
7273 case 1:
7274 if (type)
7275 fabcpu (cpu);
7276 else
7277 fabss (cpu);
7278 return;
7279
7280 case 2:
7281 if (type)
7282 fnegd (cpu);
7283 else
7284 fnegs (cpu);
7285 return;
7286
7287 case 3:
7288 if (type)
7289 fsqrtd (cpu);
7290 else
7291 fsqrts (cpu);
7292 return;
7293
7294 case 4:
7295 if (type)
7296 fcvtds (cpu);
7297 else
7298 HALT_UNALLOC;
7299 return;
7300
7301 case 5:
7302 if (type)
7303 HALT_UNALLOC;
7304 fcvtcpu (cpu);
7305 return;
7306
7307 case 8: /* FRINTN etc. */
7308 case 9:
7309 case 10:
7310 case 11:
7311 case 12:
7312 case 14:
7313 case 15:
7314 do_FRINT (cpu);
7315 return;
7316
7317 case 7: /* FCVT double/single to half precision. */
7318 case 13:
7319 HALT_NYI;
7320
7321 default:
7322 HALT_UNALLOC;
7323 }
7324 }
7325
7326 /* 32 bit signed int to float. */
7327 static void
7328 scvtf32 (sim_cpu *cpu)
7329 {
7330 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7331 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7332
7333 aarch64_set_FP_float
7334 (cpu, sd, (float) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7335 }
7336
7337 /* signed int to float. */
7338 static void
7339 scvtf (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_s64 (cpu, rn, NO_SP));
7346 }
7347
7348 /* 32 bit signed int to double. */
7349 static void
7350 scvtd32 (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_double
7356 (cpu, sd, (double) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7357 }
7358
7359 /* signed int to double. */
7360 static void
7361 scvtd (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_s64 (cpu, rn, NO_SP));
7368 }
7369
7370 static const float FLOAT_INT_MAX = (float) INT_MAX;
7371 static const float FLOAT_INT_MIN = (float) INT_MIN;
7372 static const double DOUBLE_INT_MAX = (double) INT_MAX;
7373 static const double DOUBLE_INT_MIN = (double) INT_MIN;
7374 static const float FLOAT_LONG_MAX = (float) LONG_MAX;
7375 static const float FLOAT_LONG_MIN = (float) LONG_MIN;
7376 static const double DOUBLE_LONG_MAX = (double) LONG_MAX;
7377 static const double DOUBLE_LONG_MIN = (double) LONG_MIN;
7378
7379 /* Check for FP exception conditions:
7380 NaN raises IO
7381 Infinity raises IO
7382 Out of Range raises IO and IX and saturates value
7383 Denormal raises ID and IX and sets to zero. */
7384 #define RAISE_EXCEPTIONS(F, VALUE, FTYPE, ITYPE) \
7385 do \
7386 { \
7387 switch (fpclassify (F)) \
7388 { \
7389 case FP_INFINITE: \
7390 case FP_NAN: \
7391 aarch64_set_FPSR (cpu, IO); \
7392 if (signbit (F)) \
7393 VALUE = ITYPE##_MAX; \
7394 else \
7395 VALUE = ITYPE##_MIN; \
7396 break; \
7397 \
7398 case FP_NORMAL: \
7399 if (F >= FTYPE##_##ITYPE##_MAX) \
7400 { \
7401 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7402 VALUE = ITYPE##_MAX; \
7403 } \
7404 else if (F <= FTYPE##_##ITYPE##_MIN) \
7405 { \
7406 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7407 VALUE = ITYPE##_MIN; \
7408 } \
7409 break; \
7410 \
7411 case FP_SUBNORMAL: \
7412 aarch64_set_FPSR_bits (cpu, IO | IX | ID, IX | ID); \
7413 VALUE = 0; \
7414 break; \
7415 \
7416 default: \
7417 case FP_ZERO: \
7418 VALUE = 0; \
7419 break; \
7420 } \
7421 } \
7422 while (0)
7423
7424 /* 32 bit convert float to signed int truncate towards zero. */
7425 static void
7426 fcvtszs32 (sim_cpu *cpu)
7427 {
7428 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7429 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7430 /* TODO : check that this rounds toward zero. */
7431 float f = aarch64_get_FP_float (cpu, sn);
7432 int32_t value = (int32_t) f;
7433
7434 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
7435
7436 /* Avoid sign extension to 64 bit. */
7437 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7438 }
7439
7440 /* 64 bit convert float to signed int truncate towards zero. */
7441 static void
7442 fcvtszs (sim_cpu *cpu)
7443 {
7444 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7445 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7446 float f = aarch64_get_FP_float (cpu, sn);
7447 int64_t value = (int64_t) f;
7448
7449 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
7450
7451 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7452 }
7453
7454 /* 32 bit convert double to signed int truncate towards zero. */
7455 static void
7456 fcvtszd32 (sim_cpu *cpu)
7457 {
7458 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7459 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7460 /* TODO : check that this rounds toward zero. */
7461 double d = aarch64_get_FP_double (cpu, sn);
7462 int32_t value = (int32_t) d;
7463
7464 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
7465
7466 /* Avoid sign extension to 64 bit. */
7467 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7468 }
7469
7470 /* 64 bit convert double to signed int truncate towards zero. */
7471 static void
7472 fcvtszd (sim_cpu *cpu)
7473 {
7474 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7475 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7476 /* TODO : check that this rounds toward zero. */
7477 double d = aarch64_get_FP_double (cpu, sn);
7478 int64_t value;
7479
7480 value = (int64_t) d;
7481
7482 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7483
7484 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7485 }
7486
7487 static void
7488 do_fcvtzu (sim_cpu *cpu)
7489 {
7490 /* instr[31] = size: 32-bit (0), 64-bit (1)
7491 instr[30,23] = 00111100
7492 instr[22] = type: single (0)/ double (1)
7493 instr[21] = enable (0)/disable(1) precision
7494 instr[20,16] = 11001
7495 instr[15,10] = precision
7496 instr[9,5] = Rs
7497 instr[4,0] = Rd. */
7498
7499 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7500 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7501
7502 NYI_assert (30, 23, 0x3C);
7503 NYI_assert (20, 16, 0x19);
7504
7505 if (uimm (aarch64_get_instr (cpu), 21, 21) != 1)
7506 /* Convert to fixed point. */
7507 HALT_NYI;
7508
7509 if (uimm (aarch64_get_instr (cpu), 31, 31))
7510 {
7511 /* Convert to unsigned 64-bit integer. */
7512 if (uimm (aarch64_get_instr (cpu), 22, 22))
7513 {
7514 double d = aarch64_get_FP_double (cpu, rs);
7515 uint64_t value = (uint64_t) d;
7516
7517 /* Do not raise an exception if we have reached ULONG_MAX. */
7518 if (value != (1UL << 63))
7519 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7520
7521 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7522 }
7523 else
7524 {
7525 float f = aarch64_get_FP_float (cpu, rs);
7526 uint64_t value = (uint64_t) f;
7527
7528 /* Do not raise an exception if we have reached ULONG_MAX. */
7529 if (value != (1UL << 63))
7530 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
7531
7532 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7533 }
7534 }
7535 else
7536 {
7537 uint32_t value;
7538
7539 /* Convert to unsigned 32-bit integer. */
7540 if (uimm (aarch64_get_instr (cpu), 22, 22))
7541 {
7542 double d = aarch64_get_FP_double (cpu, rs);
7543
7544 value = (uint32_t) d;
7545 /* Do not raise an exception if we have reached UINT_MAX. */
7546 if (value != (1UL << 31))
7547 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
7548 }
7549 else
7550 {
7551 float f = aarch64_get_FP_float (cpu, rs);
7552
7553 value = (uint32_t) f;
7554 /* Do not raise an exception if we have reached UINT_MAX. */
7555 if (value != (1UL << 31))
7556 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
7557 }
7558
7559 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7560 }
7561 }
7562
7563 static void
7564 do_UCVTF (sim_cpu *cpu)
7565 {
7566 /* instr[31] = size: 32-bit (0), 64-bit (1)
7567 instr[30,23] = 001 1110 0
7568 instr[22] = type: single (0)/ double (1)
7569 instr[21] = enable (0)/disable(1) precision
7570 instr[20,16] = 0 0011
7571 instr[15,10] = precision
7572 instr[9,5] = Rs
7573 instr[4,0] = Rd. */
7574
7575 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7576 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7577
7578 NYI_assert (30, 23, 0x3C);
7579 NYI_assert (20, 16, 0x03);
7580
7581 if (uimm (aarch64_get_instr (cpu), 21, 21) != 1)
7582 HALT_NYI;
7583
7584 /* FIXME: Add exception raising. */
7585 if (uimm (aarch64_get_instr (cpu), 31, 31))
7586 {
7587 uint64_t value = aarch64_get_reg_u64 (cpu, rs, NO_SP);
7588
7589 if (uimm (aarch64_get_instr (cpu), 22, 22))
7590 aarch64_set_FP_double (cpu, rd, (double) value);
7591 else
7592 aarch64_set_FP_float (cpu, rd, (float) value);
7593 }
7594 else
7595 {
7596 uint32_t value = aarch64_get_reg_u32 (cpu, rs, NO_SP);
7597
7598 if (uimm (aarch64_get_instr (cpu), 22, 22))
7599 aarch64_set_FP_double (cpu, rd, (double) value);
7600 else
7601 aarch64_set_FP_float (cpu, rd, (float) value);
7602 }
7603 }
7604
7605 static void
7606 float_vector_move (sim_cpu *cpu)
7607 {
7608 /* instr[31,17] == 100 1111 0101 0111
7609 instr[16] ==> direction 0=> to GR, 1=> from GR
7610 instr[15,10] => ???
7611 instr[9,5] ==> source
7612 instr[4,0] ==> dest. */
7613
7614 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7615 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7616
7617 NYI_assert (31, 17, 0x4F57);
7618
7619 if (uimm (aarch64_get_instr (cpu), 15, 10) != 0)
7620 HALT_UNALLOC;
7621
7622 if (uimm (aarch64_get_instr (cpu), 16, 16))
7623 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_reg_u64 (cpu, rn, NO_SP));
7624 else
7625 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, rn, 1));
7626 }
7627
7628 static void
7629 dexSimpleFPIntegerConvert (sim_cpu *cpu)
7630 {
7631 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
7632 instr[30 = 0
7633 instr[29] = S : 0 ==> OK, 1 ==> UNALLOC
7634 instr[28,25] = 1111
7635 instr[24] = 0
7636 instr[23,22] = type : 00 ==> single, 01 ==> double, 1x ==> UNALLOC
7637 instr[21] = 1
7638 instr[20,19] = rmode
7639 instr[18,16] = opcode
7640 instr[15,10] = 10 0000 */
7641
7642 uint32_t rmode_opcode;
7643 uint32_t size_type;
7644 uint32_t type;
7645 uint32_t size;
7646 uint32_t S;
7647
7648 if (uimm (aarch64_get_instr (cpu), 31, 17) == 0x4F57)
7649 {
7650 float_vector_move (cpu);
7651 return;
7652 }
7653
7654 size = uimm (aarch64_get_instr (cpu), 31, 31);
7655 S = uimm (aarch64_get_instr (cpu), 29, 29);
7656 if (S != 0)
7657 HALT_UNALLOC;
7658
7659 type = uimm (aarch64_get_instr (cpu), 23, 22);
7660 if (type > 1)
7661 HALT_UNALLOC;
7662
7663 rmode_opcode = uimm (aarch64_get_instr (cpu), 20, 16);
7664 size_type = (size << 1) | type; /* 0==32f, 1==32d, 2==64f, 3==64d. */
7665
7666 switch (rmode_opcode)
7667 {
7668 case 2: /* SCVTF. */
7669 switch (size_type)
7670 {
7671 case 0: scvtf32 (cpu); return;
7672 case 1: scvtd32 (cpu); return;
7673 case 2: scvtf (cpu); return;
7674 case 3: scvtd (cpu); return;
7675 default:
7676 HALT_UNREACHABLE;
7677 }
7678
7679 case 6: /* FMOV GR, Vec. */
7680 switch (size_type)
7681 {
7682 case 0: gfmovs (cpu); return;
7683 case 3: gfmovd (cpu); return;
7684 default: HALT_UNALLOC;
7685 }
7686
7687 case 7: /* FMOV vec, GR. */
7688 switch (size_type)
7689 {
7690 case 0: fgmovs (cpu); return;
7691 case 3: fgmovd (cpu); return;
7692 default: HALT_UNALLOC;
7693 }
7694
7695 case 24: /* FCVTZS. */
7696 switch (size_type)
7697 {
7698 case 0: fcvtszs32 (cpu); return;
7699 case 1: fcvtszd32 (cpu); return;
7700 case 2: fcvtszs (cpu); return;
7701 case 3: fcvtszd (cpu); return;
7702 default: HALT_UNREACHABLE;
7703 }
7704
7705 case 25: do_fcvtzu (cpu); return;
7706 case 3: do_UCVTF (cpu); return;
7707
7708 case 0: /* FCVTNS. */
7709 case 1: /* FCVTNU. */
7710 case 4: /* FCVTAS. */
7711 case 5: /* FCVTAU. */
7712 case 8: /* FCVPTS. */
7713 case 9: /* FCVTPU. */
7714 case 16: /* FCVTMS. */
7715 case 17: /* FCVTMU. */
7716 default:
7717 HALT_NYI;
7718 }
7719 }
7720
7721 static void
7722 set_flags_for_float_compare (sim_cpu *cpu, float fvalue1, float fvalue2)
7723 {
7724 uint32_t flags;
7725
7726 if (isnan (fvalue1) || isnan (fvalue2))
7727 flags = C|V;
7728 else
7729 {
7730 float result = fvalue1 - fvalue2;
7731
7732 if (result == 0.0)
7733 flags = Z|C;
7734 else if (result < 0)
7735 flags = N;
7736 else /* (result > 0). */
7737 flags = C;
7738 }
7739
7740 aarch64_set_CPSR (cpu, flags);
7741 }
7742
7743 static void
7744 fcmps (sim_cpu *cpu)
7745 {
7746 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7747 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7748
7749 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7750 float fvalue2 = aarch64_get_FP_float (cpu, sm);
7751
7752 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
7753 }
7754
7755 /* Float compare to zero -- Invalid Operation exception
7756 only on signaling NaNs. */
7757 static void
7758 fcmpzs (sim_cpu *cpu)
7759 {
7760 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7761 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7762
7763 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
7764 }
7765
7766 /* Float compare -- Invalid Operation exception on all NaNs. */
7767 static void
7768 fcmpes (sim_cpu *cpu)
7769 {
7770 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7771 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7772
7773 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7774 float fvalue2 = aarch64_get_FP_float (cpu, sm);
7775
7776 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
7777 }
7778
7779 /* Float compare to zero -- Invalid Operation exception on all NaNs. */
7780 static void
7781 fcmpzes (sim_cpu *cpu)
7782 {
7783 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7784 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7785
7786 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
7787 }
7788
7789 static void
7790 set_flags_for_double_compare (sim_cpu *cpu, double dval1, double dval2)
7791 {
7792 uint32_t flags;
7793
7794 if (isnan (dval1) || isnan (dval2))
7795 flags = C|V;
7796 else
7797 {
7798 double result = dval1 - dval2;
7799
7800 if (result == 0.0)
7801 flags = Z|C;
7802 else if (result < 0)
7803 flags = N;
7804 else /* (result > 0). */
7805 flags = C;
7806 }
7807
7808 aarch64_set_CPSR (cpu, flags);
7809 }
7810
7811 /* Double compare -- Invalid Operation exception only on signaling NaNs. */
7812 static void
7813 fcmpd (sim_cpu *cpu)
7814 {
7815 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7816 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7817
7818 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7819 double dvalue2 = aarch64_get_FP_double (cpu, sm);
7820
7821 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
7822 }
7823
7824 /* Double compare to zero -- Invalid Operation exception
7825 only on signaling NaNs. */
7826 static void
7827 fcmpzd (sim_cpu *cpu)
7828 {
7829 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7830 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7831
7832 set_flags_for_double_compare (cpu, dvalue1, 0.0);
7833 }
7834
7835 /* Double compare -- Invalid Operation exception on all NaNs. */
7836 static void
7837 fcmped (sim_cpu *cpu)
7838 {
7839 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7840 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7841
7842 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7843 double dvalue2 = aarch64_get_FP_double (cpu, sm);
7844
7845 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
7846 }
7847
7848 /* Double compare to zero -- Invalid Operation exception on all NaNs. */
7849 static void
7850 fcmpzed (sim_cpu *cpu)
7851 {
7852 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7853 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7854
7855 set_flags_for_double_compare (cpu, dvalue1, 0.0);
7856 }
7857
7858 static void
7859 dexSimpleFPCompare (sim_cpu *cpu)
7860 {
7861 /* assert instr[28,25] == 1111
7862 instr[30:24:21:13,10] = 0011000
7863 instr[31] = M : 0 ==> OK, 1 ==> UNALLOC
7864 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7865 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7866 instr[15,14] ==> op : 00 ==> OK, ow ==> UNALLOC
7867 instr[4,0] ==> opcode2 : 00000 ==> FCMP, 10000 ==> FCMPE,
7868 01000 ==> FCMPZ, 11000 ==> FCMPEZ,
7869 ow ==> UNALLOC */
7870 uint32_t dispatch;
7871 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
7872 | uimm (aarch64_get_instr (cpu), 29, 29);
7873 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
7874 uint32_t op = uimm (aarch64_get_instr (cpu), 15, 14);
7875 uint32_t op2_2_0 = uimm (aarch64_get_instr (cpu), 2, 0);
7876
7877 if (op2_2_0 != 0)
7878 HALT_UNALLOC;
7879
7880 if (M_S != 0)
7881 HALT_UNALLOC;
7882
7883 if (type > 1)
7884 HALT_UNALLOC;
7885
7886 if (op != 0)
7887 HALT_UNALLOC;
7888
7889 /* dispatch on type and top 2 bits of opcode. */
7890 dispatch = (type << 2) | uimm (aarch64_get_instr (cpu), 4, 3);
7891
7892 switch (dispatch)
7893 {
7894 case 0: fcmps (cpu); return;
7895 case 1: fcmpzs (cpu); return;
7896 case 2: fcmpes (cpu); return;
7897 case 3: fcmpzes (cpu); return;
7898 case 4: fcmpd (cpu); return;
7899 case 5: fcmpzd (cpu); return;
7900 case 6: fcmped (cpu); return;
7901 case 7: fcmpzed (cpu); return;
7902 default: HALT_UNREACHABLE;
7903 }
7904 }
7905
7906 static void
7907 do_scalar_FADDP (sim_cpu *cpu)
7908 {
7909 /* instr [31,23] = 011111100
7910 instr [22] = single(0)/double(1)
7911 instr [21,10] = 1100 0011 0110
7912 instr [9,5] = Fn
7913 instr [4,0] = Fd. */
7914
7915 unsigned Fn = uimm (aarch64_get_instr (cpu), 9, 5);
7916 unsigned Fd = uimm (aarch64_get_instr (cpu), 4, 0);
7917
7918 NYI_assert (31, 23, 0x0FC);
7919 NYI_assert (21, 10, 0xC36);
7920
7921 if (uimm (aarch64_get_instr (cpu), 22, 22))
7922 {
7923 double val1 = aarch64_get_vec_double (cpu, Fn, 0);
7924 double val2 = aarch64_get_vec_double (cpu, Fn, 1);
7925
7926 aarch64_set_FP_double (cpu, Fd, val1 + val2);
7927 }
7928 else
7929 {
7930 float val1 = aarch64_get_vec_float (cpu, Fn, 0);
7931 float val2 = aarch64_get_vec_float (cpu, Fn, 1);
7932
7933 aarch64_set_FP_float (cpu, Fd, val1 + val2);
7934 }
7935 }
7936
7937 /* Floating point absolute difference. */
7938
7939 static void
7940 do_scalar_FABD (sim_cpu *cpu)
7941 {
7942 /* instr [31,23] = 0111 1110 1
7943 instr [22] = float(0)/double(1)
7944 instr [21] = 1
7945 instr [20,16] = Rm
7946 instr [15,10] = 1101 01
7947 instr [9, 5] = Rn
7948 instr [4, 0] = Rd. */
7949
7950 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
7951 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7952 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7953
7954 NYI_assert (31, 23, 0x0FD);
7955 NYI_assert (21, 21, 1);
7956 NYI_assert (15, 10, 0x35);
7957
7958 if (uimm (aarch64_get_instr (cpu), 22, 22))
7959 aarch64_set_FP_double (cpu, rd,
7960 fabs (aarch64_get_FP_double (cpu, rn)
7961 - aarch64_get_FP_double (cpu, rm)));
7962 else
7963 aarch64_set_FP_float (cpu, rd,
7964 fabsf (aarch64_get_FP_float (cpu, rn)
7965 - aarch64_get_FP_float (cpu, rm)));
7966 }
7967
7968 static void
7969 do_scalar_CMGT (sim_cpu *cpu)
7970 {
7971 /* instr [31,21] = 0101 1110 111
7972 instr [20,16] = Rm
7973 instr [15,10] = 00 1101
7974 instr [9, 5] = Rn
7975 instr [4, 0] = Rd. */
7976
7977 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
7978 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7979 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7980
7981 NYI_assert (31, 21, 0x2F7);
7982 NYI_assert (15, 10, 0x0D);
7983
7984 aarch64_set_vec_u64 (cpu, rd, 0,
7985 aarch64_get_vec_u64 (cpu, rn, 0) >
7986 aarch64_get_vec_u64 (cpu, rm, 0) ? -1L : 0L);
7987 }
7988
7989 static void
7990 do_scalar_USHR (sim_cpu *cpu)
7991 {
7992 /* instr [31,23] = 0111 1111 0
7993 instr [22,16] = shift amount
7994 instr [15,10] = 0000 01
7995 instr [9, 5] = Rn
7996 instr [4, 0] = Rd. */
7997
7998 unsigned amount = 128 - uimm (aarch64_get_instr (cpu), 22, 16);
7999 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8000 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8001
8002 NYI_assert (31, 23, 0x0FE);
8003 NYI_assert (15, 10, 0x01);
8004
8005 aarch64_set_vec_u64 (cpu, rd, 0,
8006 aarch64_get_vec_u64 (cpu, rn, 0) >> amount);
8007 }
8008
8009 static void
8010 do_scalar_SHL (sim_cpu *cpu)
8011 {
8012 /* instr [31,23] = 0111 1101 0
8013 instr [22,16] = shift amount
8014 instr [15,10] = 0101 01
8015 instr [9, 5] = Rn
8016 instr [4, 0] = Rd. */
8017
8018 unsigned amount = uimm (aarch64_get_instr (cpu), 22, 16) - 64;
8019 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8020 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8021
8022 NYI_assert (31, 23, 0x0BE);
8023 NYI_assert (15, 10, 0x15);
8024
8025 if (uimm (aarch64_get_instr (cpu), 22, 22) == 0)
8026 HALT_UNALLOC;
8027
8028 aarch64_set_vec_u64 (cpu, rd, 0,
8029 aarch64_get_vec_u64 (cpu, rn, 0) << amount);
8030 }
8031
8032 /* FCMEQ FCMGT FCMGE. */
8033 static void
8034 do_scalar_FCM (sim_cpu *cpu)
8035 {
8036 /* instr [31,30] = 01
8037 instr [29] = U
8038 instr [28,24] = 1 1110
8039 instr [23] = E
8040 instr [22] = size
8041 instr [21] = 1
8042 instr [20,16] = Rm
8043 instr [15,12] = 1110
8044 instr [11] = AC
8045 instr [10] = 1
8046 instr [9, 5] = Rn
8047 instr [4, 0] = Rd. */
8048
8049 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8050 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8051 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8052 unsigned EUac = (uimm (aarch64_get_instr (cpu), 23, 23) << 2)
8053 | (uimm (aarch64_get_instr (cpu), 29, 29) << 1)
8054 | uimm (aarch64_get_instr (cpu), 11, 11);
8055 unsigned result;
8056 float val1;
8057 float val2;
8058
8059 NYI_assert (31, 30, 1);
8060 NYI_assert (28, 24, 0x1E);
8061 NYI_assert (21, 21, 1);
8062 NYI_assert (15, 12, 0xE);
8063 NYI_assert (10, 10, 1);
8064
8065 if (uimm (aarch64_get_instr (cpu), 22, 22))
8066 {
8067 double val1 = aarch64_get_FP_double (cpu, rn);
8068 double val2 = aarch64_get_FP_double (cpu, rm);
8069
8070 switch (EUac)
8071 {
8072 case 0: /* 000 */
8073 result = val1 == val2;
8074 break;
8075
8076 case 3: /* 011 */
8077 val1 = fabs (val1);
8078 val2 = fabs (val2);
8079 /* Fall through. */
8080 case 2: /* 010 */
8081 result = val1 >= val2;
8082 break;
8083
8084 case 7: /* 111 */
8085 val1 = fabs (val1);
8086 val2 = fabs (val2);
8087 /* Fall through. */
8088 case 6: /* 110 */
8089 result = val1 > val2;
8090 break;
8091
8092 default:
8093 HALT_UNALLOC;
8094 }
8095
8096 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8097 return;
8098 }
8099
8100 val1 = aarch64_get_FP_float (cpu, rn);
8101 val2 = aarch64_get_FP_float (cpu, rm);
8102
8103 switch (EUac)
8104 {
8105 case 0: /* 000 */
8106 result = val1 == val2;
8107 break;
8108
8109 case 3: /* 011 */
8110 val1 = fabsf (val1);
8111 val2 = fabsf (val2);
8112 /* Fall through. */
8113 case 2: /* 010 */
8114 result = val1 >= val2;
8115 break;
8116
8117 case 7: /* 111 */
8118 val1 = fabsf (val1);
8119 val2 = fabsf (val2);
8120 /* Fall through. */
8121 case 6: /* 110 */
8122 result = val1 > val2;
8123 break;
8124
8125 default:
8126 HALT_UNALLOC;
8127 }
8128
8129 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8130 }
8131
8132 /* An alias of DUP. */
8133 static void
8134 do_scalar_MOV (sim_cpu *cpu)
8135 {
8136 /* instr [31,21] = 0101 1110 000
8137 instr [20,16] = imm5
8138 instr [15,10] = 0000 01
8139 instr [9, 5] = Rn
8140 instr [4, 0] = Rd. */
8141
8142 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8143 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8144 unsigned index;
8145
8146 NYI_assert (31, 21, 0x2F0);
8147 NYI_assert (15, 10, 0x01);
8148
8149 if (uimm (aarch64_get_instr (cpu), 16, 16))
8150 {
8151 /* 8-bit. */
8152 index = uimm (aarch64_get_instr (cpu), 20, 17);
8153 aarch64_set_vec_u8
8154 (cpu, rd, 0, aarch64_get_vec_u8 (cpu, rn, index));
8155 }
8156 else if (uimm (aarch64_get_instr (cpu), 17, 17))
8157 {
8158 /* 16-bit. */
8159 index = uimm (aarch64_get_instr (cpu), 20, 18);
8160 aarch64_set_vec_u16
8161 (cpu, rd, 0, aarch64_get_vec_u16 (cpu, rn, index));
8162 }
8163 else if (uimm (aarch64_get_instr (cpu), 18, 18))
8164 {
8165 /* 32-bit. */
8166 index = uimm (aarch64_get_instr (cpu), 20, 19);
8167 aarch64_set_vec_u32
8168 (cpu, rd, 0, aarch64_get_vec_u32 (cpu, rn, index));
8169 }
8170 else if (uimm (aarch64_get_instr (cpu), 19, 19))
8171 {
8172 /* 64-bit. */
8173 index = uimm (aarch64_get_instr (cpu), 20, 20);
8174 aarch64_set_vec_u64
8175 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, index));
8176 }
8177 else
8178 HALT_UNALLOC;
8179 }
8180
8181 static void
8182 do_double_add (sim_cpu *cpu)
8183 {
8184 /* instr [28,25] = 1111. */
8185 unsigned Fd;
8186 unsigned Fm;
8187 unsigned Fn;
8188 double val1;
8189 double val2;
8190
8191 switch (uimm (aarch64_get_instr (cpu), 31, 23))
8192 {
8193 case 0xBC:
8194 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8195 {
8196 case 0x01: do_scalar_MOV (cpu); return;
8197 case 0x39: do_scalar_FCM (cpu); return;
8198 case 0x3B: do_scalar_FCM (cpu); return;
8199 }
8200 break;
8201
8202 case 0xBE: do_scalar_SHL (cpu); return;
8203
8204 case 0xFC:
8205 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8206 {
8207 case 0x36: do_scalar_FADDP (cpu); return;
8208 case 0x39: do_scalar_FCM (cpu); return;
8209 case 0x3B: do_scalar_FCM (cpu); return;
8210 }
8211 break;
8212
8213 case 0xFD:
8214 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8215 {
8216 case 0x0D: do_scalar_CMGT (cpu); return;
8217 case 0x35: do_scalar_FABD (cpu); return;
8218 case 0x39: do_scalar_FCM (cpu); return;
8219 case 0x3B: do_scalar_FCM (cpu); return;
8220 default:
8221 HALT_NYI;
8222 }
8223
8224 case 0xFE: do_scalar_USHR (cpu); return;
8225 default:
8226 break;
8227 }
8228
8229 /* instr [31,21] = 0101 1110 111
8230 instr [20,16] = Fn
8231 instr [15,10] = 1000 01
8232 instr [9,5] = Fm
8233 instr [4,0] = Fd. */
8234 if (uimm (aarch64_get_instr (cpu), 31, 21) != 0x2F7
8235 || uimm (aarch64_get_instr (cpu), 15, 10) != 0x21)
8236 HALT_NYI;
8237
8238 Fd = uimm (aarch64_get_instr (cpu), 4, 0);
8239 Fm = uimm (aarch64_get_instr (cpu), 9, 5);
8240 Fn = uimm (aarch64_get_instr (cpu), 20, 16);
8241
8242 val1 = aarch64_get_FP_double (cpu, Fm);
8243 val2 = aarch64_get_FP_double (cpu, Fn);
8244
8245 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8246 }
8247
8248 static void
8249 dexAdvSIMD1 (sim_cpu *cpu)
8250 {
8251 /* instr [28,25] = 1 111. */
8252
8253 /* we are currently only interested in the basic
8254 scalar fp routines which all have bit 30 = 0. */
8255 if (uimm (aarch64_get_instr (cpu), 30, 30))
8256 do_double_add (cpu);
8257
8258 /* instr[24] is set for FP data processing 3-source and clear for
8259 all other basic scalar fp instruction groups. */
8260 else if (uimm (aarch64_get_instr (cpu), 24, 24))
8261 dexSimpleFPDataProc3Source (cpu);
8262
8263 /* instr[21] is clear for floating <-> fixed conversions and set for
8264 all other basic scalar fp instruction groups. */
8265 else if (!uimm (aarch64_get_instr (cpu), 21, 21))
8266 dexSimpleFPFixedConvert (cpu);
8267
8268 /* instr[11,10] : 01 ==> cond compare, 10 ==> Data Proc 2 Source
8269 11 ==> cond select, 00 ==> other. */
8270 else
8271 switch (uimm (aarch64_get_instr (cpu), 11, 10))
8272 {
8273 case 1: dexSimpleFPCondCompare (cpu); return;
8274 case 2: dexSimpleFPDataProc2Source (cpu); return;
8275 case 3: dexSimpleFPCondSelect (cpu); return;
8276
8277 default:
8278 /* Now an ordered cascade of tests.
8279 FP immediate has aarch64_get_instr (cpu)[12] == 1.
8280 FP compare has aarch64_get_instr (cpu)[13] == 1.
8281 FP Data Proc 1 Source has aarch64_get_instr (cpu)[14] == 1.
8282 FP floating <--> integer conversions has aarch64_get_instr (cpu)[15] == 0. */
8283 if (uimm (aarch64_get_instr (cpu), 12, 12))
8284 dexSimpleFPImmediate (cpu);
8285
8286 else if (uimm (aarch64_get_instr (cpu), 13, 13))
8287 dexSimpleFPCompare (cpu);
8288
8289 else if (uimm (aarch64_get_instr (cpu), 14, 14))
8290 dexSimpleFPDataProc1Source (cpu);
8291
8292 else if (!uimm (aarch64_get_instr (cpu), 15, 15))
8293 dexSimpleFPIntegerConvert (cpu);
8294
8295 else
8296 /* If we get here then instr[15] == 1 which means UNALLOC. */
8297 HALT_UNALLOC;
8298 }
8299 }
8300
8301 /* PC relative addressing. */
8302
8303 static void
8304 pcadr (sim_cpu *cpu)
8305 {
8306 /* instr[31] = op : 0 ==> ADR, 1 ==> ADRP
8307 instr[30,29] = immlo
8308 instr[23,5] = immhi. */
8309 uint64_t address;
8310 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8311 uint32_t isPage = uimm (aarch64_get_instr (cpu), 31, 31);
8312 union { int64_t u64; uint64_t s64; } imm;
8313 uint64_t offset;
8314
8315 imm.s64 = simm64 (aarch64_get_instr (cpu), 23, 5);
8316 offset = imm.u64;
8317 offset = (offset << 2) | uimm (aarch64_get_instr (cpu), 30, 29);
8318
8319 address = aarch64_get_PC (cpu);
8320
8321 if (isPage)
8322 {
8323 offset <<= 12;
8324 address &= ~0xfff;
8325 }
8326
8327 aarch64_set_reg_u64 (cpu, rd, NO_SP, address + offset);
8328 }
8329
8330 /* Specific decode and execute for group Data Processing Immediate. */
8331
8332 static void
8333 dexPCRelAddressing (sim_cpu *cpu)
8334 {
8335 /* assert instr[28,24] = 10000. */
8336 pcadr (cpu);
8337 }
8338
8339 /* Immediate logical.
8340 The bimm32/64 argument is constructed by replicating a 2, 4, 8,
8341 16, 32 or 64 bit sequence pulled out at decode and possibly
8342 inverting it..
8343
8344 N.B. the output register (dest) can normally be Xn or SP
8345 the exception occurs for flag setting instructions which may
8346 only use Xn for the output (dest). The input register can
8347 never be SP. */
8348
8349 /* 32 bit and immediate. */
8350 static void
8351 and32 (sim_cpu *cpu, uint32_t bimm)
8352 {
8353 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8354 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8355
8356 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8357 aarch64_get_reg_u32 (cpu, rn, NO_SP) & bimm);
8358 }
8359
8360 /* 64 bit and immediate. */
8361 static void
8362 and64 (sim_cpu *cpu, uint64_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_u64 (cpu, rn, NO_SP) & bimm);
8369 }
8370
8371 /* 32 bit and immediate set flags. */
8372 static void
8373 ands32 (sim_cpu *cpu, uint32_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 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8379 uint32_t value2 = bimm;
8380
8381 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8382 set_flags_for_binop32 (cpu, value1 & value2);
8383 }
8384
8385 /* 64 bit and immediate set flags. */
8386 static void
8387 ands64 (sim_cpu *cpu, uint64_t bimm)
8388 {
8389 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8390 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8391
8392 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8393 uint64_t value2 = bimm;
8394
8395 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8396 set_flags_for_binop64 (cpu, value1 & value2);
8397 }
8398
8399 /* 32 bit exclusive or immediate. */
8400 static void
8401 eor32 (sim_cpu *cpu, uint32_t bimm)
8402 {
8403 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8404 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8405
8406 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8407 aarch64_get_reg_u32 (cpu, rn, NO_SP) ^ bimm);
8408 }
8409
8410 /* 64 bit exclusive or immediate. */
8411 static void
8412 eor64 (sim_cpu *cpu, uint64_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_u64 (cpu, rn, NO_SP) ^ bimm);
8419 }
8420
8421 /* 32 bit or immediate. */
8422 static void
8423 orr32 (sim_cpu *cpu, uint32_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_u32 (cpu, rn, NO_SP) | bimm);
8430 }
8431
8432 /* 64 bit or immediate. */
8433 static void
8434 orr64 (sim_cpu *cpu, uint64_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_u64 (cpu, rn, NO_SP) | bimm);
8441 }
8442
8443 /* Logical shifted register.
8444 These allow an optional LSL, ASR, LSR or ROR to the second source
8445 register with a count up to the register bit count.
8446 N.B register args may not be SP. */
8447
8448 /* 32 bit AND shifted register. */
8449 static void
8450 and32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8451 {
8452 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8453 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8454 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8455
8456 aarch64_set_reg_u64
8457 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8458 & shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8459 }
8460
8461 /* 64 bit AND shifted register. */
8462 static void
8463 and64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8464 {
8465 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8466 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8467 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8468
8469 aarch64_set_reg_u64
8470 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8471 & shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8472 }
8473
8474 /* 32 bit AND shifted register setting flags. */
8475 static void
8476 ands32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8477 {
8478 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8479 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8480 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8481
8482 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8483 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
8484 shift, count);
8485
8486 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8487 set_flags_for_binop32 (cpu, value1 & value2);
8488 }
8489
8490 /* 64 bit AND shifted register setting flags. */
8491 static void
8492 ands64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8493 {
8494 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8495 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8496 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8497
8498 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8499 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
8500 shift, count);
8501
8502 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8503 set_flags_for_binop64 (cpu, value1 & value2);
8504 }
8505
8506 /* 32 bit BIC shifted register. */
8507 static void
8508 bic32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8509 {
8510 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8511 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8512 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8513
8514 aarch64_set_reg_u64
8515 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8516 & ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8517 }
8518
8519 /* 64 bit BIC shifted register. */
8520 static void
8521 bic64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8522 {
8523 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8524 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8525 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8526
8527 aarch64_set_reg_u64
8528 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8529 & ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8530 }
8531
8532 /* 32 bit BIC shifted register setting flags. */
8533 static void
8534 bics32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8535 {
8536 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8537 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8538 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8539
8540 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8541 uint32_t value2 = ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
8542 shift, count);
8543
8544 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8545 set_flags_for_binop32 (cpu, value1 & value2);
8546 }
8547
8548 /* 64 bit BIC shifted register setting flags. */
8549 static void
8550 bics64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8551 {
8552 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8553 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8554 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8555
8556 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8557 uint64_t value2 = ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
8558 shift, count);
8559
8560 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8561 set_flags_for_binop64 (cpu, value1 & value2);
8562 }
8563
8564 /* 32 bit EON shifted register. */
8565 static void
8566 eon32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8567 {
8568 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8569 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8570 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8571
8572 aarch64_set_reg_u64
8573 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8574 ^ ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8575 }
8576
8577 /* 64 bit EON shifted register. */
8578 static void
8579 eon64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8580 {
8581 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8582 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8583 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8584
8585 aarch64_set_reg_u64
8586 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8587 ^ ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8588 }
8589
8590 /* 32 bit EOR shifted register. */
8591 static void
8592 eor32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8593 {
8594 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8595 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8596 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8597
8598 aarch64_set_reg_u64
8599 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8600 ^ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8601 }
8602
8603 /* 64 bit EOR shifted register. */
8604 static void
8605 eor64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8606 {
8607 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8608 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8609 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8610
8611 aarch64_set_reg_u64
8612 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8613 ^ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8614 }
8615
8616 /* 32 bit ORR shifted register. */
8617 static void
8618 orr32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8619 {
8620 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8621 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8622 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8623
8624 aarch64_set_reg_u64
8625 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8626 | shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8627 }
8628
8629 /* 64 bit ORR shifted register. */
8630 static void
8631 orr64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8632 {
8633 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8634 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8635 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8636
8637 aarch64_set_reg_u64
8638 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8639 | shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8640 }
8641
8642 /* 32 bit ORN shifted register. */
8643 static void
8644 orn32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8645 {
8646 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8647 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8648 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8649
8650 aarch64_set_reg_u64
8651 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8652 | ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8653 }
8654
8655 /* 64 bit ORN shifted register. */
8656 static void
8657 orn64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8658 {
8659 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8660 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8661 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8662
8663 aarch64_set_reg_u64
8664 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8665 | ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8666 }
8667
8668 static void
8669 dexLogicalImmediate (sim_cpu *cpu)
8670 {
8671 /* assert instr[28,23] = 1001000
8672 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8673 instr[30,29] = op : 0 ==> AND, 1 ==> ORR, 2 ==> EOR, 3 ==> ANDS
8674 instr[22] = N : used to construct immediate mask
8675 instr[21,16] = immr
8676 instr[15,10] = imms
8677 instr[9,5] = Rn
8678 instr[4,0] = Rd */
8679
8680 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
8681 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
8682 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
8683 /* uint32_t immr = uimm (aarch64_get_instr (cpu), 21, 16);. */
8684 /* uint32_t imms = uimm (aarch64_get_instr (cpu), 15, 10);. */
8685 uint32_t index = uimm (aarch64_get_instr (cpu), 22, 10);
8686 uint64_t bimm64 = LITable [index];
8687 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 30, 29);
8688
8689 if (~size & N)
8690 HALT_UNALLOC;
8691
8692 if (!bimm64)
8693 HALT_UNALLOC;
8694
8695 if (size == 0)
8696 {
8697 uint32_t bimm = (uint32_t) bimm64;
8698
8699 switch (dispatch)
8700 {
8701 case 0: and32 (cpu, bimm); return;
8702 case 1: orr32 (cpu, bimm); return;
8703 case 2: eor32 (cpu, bimm); return;
8704 case 3: ands32 (cpu, bimm); return;
8705 }
8706 }
8707 else
8708 {
8709 switch (dispatch)
8710 {
8711 case 0: and64 (cpu, bimm64); return;
8712 case 1: orr64 (cpu, bimm64); return;
8713 case 2: eor64 (cpu, bimm64); return;
8714 case 3: ands64 (cpu, bimm64); return;
8715 }
8716 }
8717 HALT_UNALLOC;
8718 }
8719
8720 /* Immediate move.
8721 The uimm argument is a 16 bit value to be inserted into the
8722 target register the pos argument locates the 16 bit word in the
8723 dest register i.e. it is in {0, 1} for 32 bit and {0, 1, 2,
8724 3} for 64 bit.
8725 N.B register arg may not be SP so it should be.
8726 accessed using the setGZRegisterXXX accessors. */
8727
8728 /* 32 bit move 16 bit immediate zero remaining shorts. */
8729 static void
8730 movz32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8731 {
8732 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8733
8734 aarch64_set_reg_u64 (cpu, rd, NO_SP, val << (pos * 16));
8735 }
8736
8737 /* 64 bit move 16 bit immediate zero remaining shorts. */
8738 static void
8739 movz64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8740 {
8741 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8742
8743 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((uint64_t) val) << (pos * 16));
8744 }
8745
8746 /* 32 bit move 16 bit immediate negated. */
8747 static void
8748 movn32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8749 {
8750 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8751
8752 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((val << (pos * 16)) ^ 0xffffffffU));
8753 }
8754
8755 /* 64 bit move 16 bit immediate negated. */
8756 static void
8757 movn64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8758 {
8759 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8760
8761 aarch64_set_reg_u64
8762 (cpu, rd, NO_SP, ((((uint64_t) val) << (pos * 16))
8763 ^ 0xffffffffffffffffULL));
8764 }
8765
8766 /* 32 bit move 16 bit immediate keep remaining shorts. */
8767 static void
8768 movk32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8769 {
8770 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8771 uint32_t current = aarch64_get_reg_u32 (cpu, rd, NO_SP);
8772 uint32_t value = val << (pos * 16);
8773 uint32_t mask = ~(0xffffU << (pos * 16));
8774
8775 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
8776 }
8777
8778 /* 64 bit move 16 it immediate keep remaining shorts. */
8779 static void
8780 movk64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8781 {
8782 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8783 uint64_t current = aarch64_get_reg_u64 (cpu, rd, NO_SP);
8784 uint64_t value = (uint64_t) val << (pos * 16);
8785 uint64_t mask = ~(0xffffULL << (pos * 16));
8786
8787 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
8788 }
8789
8790 static void
8791 dexMoveWideImmediate (sim_cpu *cpu)
8792 {
8793 /* assert instr[28:23] = 100101
8794 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8795 instr[30,29] = op : 0 ==> MOVN, 1 ==> UNALLOC, 2 ==> MOVZ, 3 ==> MOVK
8796 instr[22,21] = shift : 00 == LSL#0, 01 = LSL#16, 10 = LSL#32, 11 = LSL#48
8797 instr[20,5] = uimm16
8798 instr[4,0] = Rd */
8799
8800 /* N.B. the (multiple of 16) shift is applied by the called routine,
8801 we just pass the multiplier. */
8802
8803 uint32_t imm;
8804 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
8805 uint32_t op = uimm (aarch64_get_instr (cpu), 30, 29);
8806 uint32_t shift = uimm (aarch64_get_instr (cpu), 22, 21);
8807
8808 /* 32 bit can only shift 0 or 1 lot of 16.
8809 anything else is an unallocated instruction. */
8810 if (size == 0 && (shift > 1))
8811 HALT_UNALLOC;
8812
8813 if (op == 1)
8814 HALT_UNALLOC;
8815
8816 imm = uimm (aarch64_get_instr (cpu), 20, 5);
8817
8818 if (size == 0)
8819 {
8820 if (op == 0)
8821 movn32 (cpu, imm, shift);
8822 else if (op == 2)
8823 movz32 (cpu, imm, shift);
8824 else
8825 movk32 (cpu, imm, shift);
8826 }
8827 else
8828 {
8829 if (op == 0)
8830 movn64 (cpu, imm, shift);
8831 else if (op == 2)
8832 movz64 (cpu, imm, shift);
8833 else
8834 movk64 (cpu, imm, shift);
8835 }
8836 }
8837
8838 /* Bitfield operations.
8839 These take a pair of bit positions r and s which are in {0..31}
8840 or {0..63} depending on the instruction word size.
8841 N.B register args may not be SP. */
8842
8843 /* OK, we start with ubfm which just needs to pick
8844 some bits out of source zero the rest and write
8845 the result to dest. Just need two logical shifts. */
8846
8847 /* 32 bit bitfield move, left and right of affected zeroed
8848 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8849 static void
8850 ubfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8851 {
8852 unsigned rd;
8853 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8854 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8855
8856 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
8857 if (r <= s)
8858 {
8859 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
8860 We want only bits s:xxx:r at the bottom of the word
8861 so we LSL bit s up to bit 31 i.e. by 31 - s
8862 and then we LSR to bring bit 31 down to bit s - r
8863 i.e. by 31 + r - s. */
8864 value <<= 31 - s;
8865 value >>= 31 + r - s;
8866 }
8867 else
8868 {
8869 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0
8870 We want only bits s:xxx:0 starting at it 31-(r-1)
8871 so we LSL bit s up to bit 31 i.e. by 31 - s
8872 and then we LSL to bring bit 31 down to 31-(r-1)+s
8873 i.e. by r - (s + 1). */
8874 value <<= 31 - s;
8875 value >>= r - (s + 1);
8876 }
8877
8878 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8879 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8880 }
8881
8882 /* 64 bit bitfield move, left and right of affected zeroed
8883 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
8884 static void
8885 ubfm (sim_cpu *cpu, uint32_t r, uint32_t s)
8886 {
8887 unsigned rd;
8888 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8889 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8890
8891 if (r <= s)
8892 {
8893 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
8894 We want only bits s:xxx:r at the bottom of the word.
8895 So we LSL bit s up to bit 63 i.e. by 63 - s
8896 and then we LSR to bring bit 63 down to bit s - r
8897 i.e. by 63 + r - s. */
8898 value <<= 63 - s;
8899 value >>= 63 + r - s;
8900 }
8901 else
8902 {
8903 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0.
8904 We want only bits s:xxx:0 starting at it 63-(r-1).
8905 So we LSL bit s up to bit 63 i.e. by 63 - s
8906 and then we LSL to bring bit 63 down to 63-(r-1)+s
8907 i.e. by r - (s + 1). */
8908 value <<= 63 - s;
8909 value >>= r - (s + 1);
8910 }
8911
8912 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8913 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8914 }
8915
8916 /* The signed versions need to insert sign bits
8917 on the left of the inserted bit field. so we do
8918 much the same as the unsigned version except we
8919 use an arithmetic shift right -- this just means
8920 we need to operate on signed values. */
8921
8922 /* 32 bit bitfield move, left of affected sign-extended, right zeroed. */
8923 /* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8924 static void
8925 sbfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8926 {
8927 unsigned rd;
8928 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8929 /* as per ubfm32 but use an ASR instead of an LSR. */
8930 int32_t value = aarch64_get_reg_s32 (cpu, rn, NO_SP);
8931
8932 if (r <= s)
8933 {
8934 value <<= 31 - s;
8935 value >>= 31 + r - s;
8936 }
8937 else
8938 {
8939 value <<= 31 - s;
8940 value >>= r - (s + 1);
8941 }
8942
8943 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8944 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8945 }
8946
8947 /* 64 bit bitfield move, left of affected sign-extended, right zeroed. */
8948 /* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
8949 static void
8950 sbfm (sim_cpu *cpu, uint32_t r, uint32_t s)
8951 {
8952 unsigned rd;
8953 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8954 /* acpu per ubfm but use an ASR instead of an LSR. */
8955 int64_t value = aarch64_get_reg_s64 (cpu, rn, NO_SP);
8956
8957 if (r <= s)
8958 {
8959 value <<= 63 - s;
8960 value >>= 63 + r - s;
8961 }
8962 else
8963 {
8964 value <<= 63 - s;
8965 value >>= r - (s + 1);
8966 }
8967
8968 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8969 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8970 }
8971
8972 /* Finally, these versions leave non-affected bits
8973 as is. so we need to generate the bits as per
8974 ubfm and also generate a mask to pick the
8975 bits from the original and computed values. */
8976
8977 /* 32 bit bitfield move, non-affected bits left as is.
8978 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8979 static void
8980 bfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8981 {
8982 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8983 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8984 uint32_t mask = -1;
8985 unsigned rd;
8986 uint32_t value2;
8987
8988 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
8989 if (r <= s)
8990 {
8991 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
8992 We want only bits s:xxx:r at the bottom of the word
8993 so we LSL bit s up to bit 31 i.e. by 31 - s
8994 and then we LSR to bring bit 31 down to bit s - r
8995 i.e. by 31 + r - s. */
8996 value <<= 31 - s;
8997 value >>= 31 + r - s;
8998 /* the mask must include the same bits. */
8999 mask <<= 31 - s;
9000 mask >>= 31 + r - s;
9001 }
9002 else
9003 {
9004 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0.
9005 We want only bits s:xxx:0 starting at it 31-(r-1)
9006 so we LSL bit s up to bit 31 i.e. by 31 - s
9007 and then we LSL to bring bit 31 down to 31-(r-1)+s
9008 i.e. by r - (s + 1). */
9009 value <<= 31 - s;
9010 value >>= r - (s + 1);
9011 /* The mask must include the same bits. */
9012 mask <<= 31 - s;
9013 mask >>= r - (s + 1);
9014 }
9015
9016 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9017 value2 = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9018
9019 value2 &= ~mask;
9020 value2 |= value;
9021
9022 aarch64_set_reg_u64
9023 (cpu, rd, NO_SP, (aarch64_get_reg_u32 (cpu, rd, NO_SP) & ~mask) | value);
9024 }
9025
9026 /* 64 bit bitfield move, non-affected bits left as is.
9027 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9028 static void
9029 bfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9030 {
9031 unsigned rd;
9032 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9033 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9034 uint64_t mask = 0xffffffffffffffffULL;
9035
9036 if (r <= s)
9037 {
9038 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9039 We want only bits s:xxx:r at the bottom of the word
9040 so we LSL bit s up to bit 63 i.e. by 63 - s
9041 and then we LSR to bring bit 63 down to bit s - r
9042 i.e. by 63 + r - s. */
9043 value <<= 63 - s;
9044 value >>= 63 + r - s;
9045 /* The mask must include the same bits. */
9046 mask <<= 63 - s;
9047 mask >>= 63 + r - s;
9048 }
9049 else
9050 {
9051 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0
9052 We want only bits s:xxx:0 starting at it 63-(r-1)
9053 so we LSL bit s up to bit 63 i.e. by 63 - s
9054 and then we LSL to bring bit 63 down to 63-(r-1)+s
9055 i.e. by r - (s + 1). */
9056 value <<= 63 - s;
9057 value >>= r - (s + 1);
9058 /* The mask must include the same bits. */
9059 mask <<= 63 - s;
9060 mask >>= r - (s + 1);
9061 }
9062
9063 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9064 aarch64_set_reg_u64
9065 (cpu, rd, NO_SP, (aarch64_get_reg_u64 (cpu, rd, NO_SP) & ~mask) | value);
9066 }
9067
9068 static void
9069 dexBitfieldImmediate (sim_cpu *cpu)
9070 {
9071 /* assert instr[28:23] = 100110
9072 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9073 instr[30,29] = op : 0 ==> SBFM, 1 ==> BFM, 2 ==> UBFM, 3 ==> UNALLOC
9074 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit ow UNALLOC
9075 instr[21,16] = immr : 0xxxxx for 32 bit, xxxxxx for 64 bit
9076 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9077 instr[9,5] = Rn
9078 instr[4,0] = Rd */
9079
9080 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9081 uint32_t dispatch;
9082 uint32_t imms;
9083 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
9084 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
9085 /* 32 bit operations must have immr[5] = 0 and imms[5] = 0. */
9086 /* or else we have an UNALLOC. */
9087 uint32_t immr = uimm (aarch64_get_instr (cpu), 21, 16);
9088
9089 if (~size & N)
9090 HALT_UNALLOC;
9091
9092 if (!size && uimm (immr, 5, 5))
9093 HALT_UNALLOC;
9094
9095 imms = uimm (aarch64_get_instr (cpu), 15, 10);
9096 if (!size && uimm (imms, 5, 5))
9097 HALT_UNALLOC;
9098
9099 /* Switch on combined size and op. */
9100 dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
9101 switch (dispatch)
9102 {
9103 case 0: sbfm32 (cpu, immr, imms); return;
9104 case 1: bfm32 (cpu, immr, imms); return;
9105 case 2: ubfm32 (cpu, immr, imms); return;
9106 case 4: sbfm (cpu, immr, imms); return;
9107 case 5: bfm (cpu, immr, imms); return;
9108 case 6: ubfm (cpu, immr, imms); return;
9109 default: HALT_UNALLOC;
9110 }
9111 }
9112
9113 static void
9114 do_EXTR_32 (sim_cpu *cpu)
9115 {
9116 /* instr[31:21] = 00010011100
9117 instr[20,16] = Rm
9118 instr[15,10] = imms : 0xxxxx for 32 bit
9119 instr[9,5] = Rn
9120 instr[4,0] = Rd */
9121 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9122 unsigned imms = uimm (aarch64_get_instr (cpu), 15, 10) & 31;
9123 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9124 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
9125 uint64_t val1;
9126 uint64_t val2;
9127
9128 val1 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
9129 val1 >>= imms;
9130 val2 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9131 val2 <<= (32 - imms);
9132
9133 aarch64_set_reg_u64 (cpu, rd, NO_SP, val1 | val2);
9134 }
9135
9136 static void
9137 do_EXTR_64 (sim_cpu *cpu)
9138 {
9139 /* instr[31:21] = 10010011100
9140 instr[20,16] = Rm
9141 instr[15,10] = imms
9142 instr[9,5] = Rn
9143 instr[4,0] = Rd */
9144 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9145 unsigned imms = uimm (aarch64_get_instr (cpu), 15, 10) & 63;
9146 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9147 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
9148 uint64_t val;
9149
9150 val = aarch64_get_reg_u64 (cpu, rm, NO_SP);
9151 val >>= imms;
9152 val |= (aarch64_get_reg_u64 (cpu, rn, NO_SP) << (64 - imms));
9153
9154 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
9155 }
9156
9157 static void
9158 dexExtractImmediate (sim_cpu *cpu)
9159 {
9160 /* assert instr[28:23] = 100111
9161 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9162 instr[30,29] = op21 : 0 ==> EXTR, 1,2,3 ==> UNALLOC
9163 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit or UNALLOC
9164 instr[21] = op0 : must be 0 or UNALLOC
9165 instr[20,16] = Rm
9166 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9167 instr[9,5] = Rn
9168 instr[4,0] = Rd */
9169
9170 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9171 /* 64 bit operations must have N = 1 or else we have an UNALLOC. */
9172 uint32_t dispatch;
9173 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
9174 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
9175 /* 32 bit operations must have imms[5] = 0
9176 or else we have an UNALLOC. */
9177 uint32_t imms = uimm (aarch64_get_instr (cpu), 15, 10);
9178
9179 if (size ^ N)
9180 HALT_UNALLOC;
9181
9182 if (!size && uimm (imms, 5, 5))
9183 HALT_UNALLOC;
9184
9185 /* Switch on combined size and op. */
9186 dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
9187
9188 if (dispatch == 0)
9189 do_EXTR_32 (cpu);
9190
9191 else if (dispatch == 4)
9192 do_EXTR_64 (cpu);
9193
9194 else if (dispatch == 1)
9195 HALT_NYI;
9196 else
9197 HALT_UNALLOC;
9198 }
9199
9200 static void
9201 dexDPImm (sim_cpu *cpu)
9202 {
9203 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
9204 assert group == GROUP_DPIMM_1000 || grpoup == GROUP_DPIMM_1001
9205 bits [25,23] of a DPImm are the secondary dispatch vector. */
9206 uint32_t group2 = dispatchDPImm (aarch64_get_instr (cpu));
9207
9208 switch (group2)
9209 {
9210 case DPIMM_PCADR_000:
9211 case DPIMM_PCADR_001:
9212 dexPCRelAddressing (cpu);
9213 return;
9214
9215 case DPIMM_ADDSUB_010:
9216 case DPIMM_ADDSUB_011:
9217 dexAddSubtractImmediate (cpu);
9218 return;
9219
9220 case DPIMM_LOG_100:
9221 dexLogicalImmediate (cpu);
9222 return;
9223
9224 case DPIMM_MOV_101:
9225 dexMoveWideImmediate (cpu);
9226 return;
9227
9228 case DPIMM_BITF_110:
9229 dexBitfieldImmediate (cpu);
9230 return;
9231
9232 case DPIMM_EXTR_111:
9233 dexExtractImmediate (cpu);
9234 return;
9235
9236 default:
9237 /* Should never reach here. */
9238 HALT_NYI;
9239 }
9240 }
9241
9242 static void
9243 dexLoadUnscaledImmediate (sim_cpu *cpu)
9244 {
9245 /* instr[29,24] == 111_00
9246 instr[21] == 0
9247 instr[11,10] == 00
9248 instr[31,30] = size
9249 instr[26] = V
9250 instr[23,22] = opc
9251 instr[20,12] = simm9
9252 instr[9,5] = rn may be SP. */
9253 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9254 uint32_t V = uimm (aarch64_get_instr (cpu), 26, 26);
9255 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9256 | uimm (aarch64_get_instr (cpu), 23, 22));
9257 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
9258
9259 if (!V)
9260 {
9261 /* GReg operations. */
9262 switch (dispatch)
9263 {
9264 case 0: sturb (cpu, imm); return;
9265 case 1: ldurb32 (cpu, imm); return;
9266 case 2: ldursb64 (cpu, imm); return;
9267 case 3: ldursb32 (cpu, imm); return;
9268 case 4: sturh (cpu, imm); return;
9269 case 5: ldurh32 (cpu, imm); return;
9270 case 6: ldursh64 (cpu, imm); return;
9271 case 7: ldursh32 (cpu, imm); return;
9272 case 8: stur32 (cpu, imm); return;
9273 case 9: ldur32 (cpu, imm); return;
9274 case 10: ldursw (cpu, imm); return;
9275 case 12: stur64 (cpu, imm); return;
9276 case 13: ldur64 (cpu, imm); return;
9277
9278 case 14:
9279 /* PRFUM NYI. */
9280 HALT_NYI;
9281
9282 default:
9283 case 11:
9284 case 15:
9285 HALT_UNALLOC;
9286 }
9287 }
9288
9289 /* FReg operations. */
9290 switch (dispatch)
9291 {
9292 case 2: fsturq (cpu, imm); return;
9293 case 3: fldurq (cpu, imm); return;
9294 case 8: fsturs (cpu, imm); return;
9295 case 9: fldurs (cpu, imm); return;
9296 case 12: fsturd (cpu, imm); return;
9297 case 13: fldurd (cpu, imm); return;
9298
9299 case 0: /* STUR 8 bit FP. */
9300 case 1: /* LDUR 8 bit FP. */
9301 case 4: /* STUR 16 bit FP. */
9302 case 5: /* LDUR 8 bit FP. */
9303 HALT_NYI;
9304
9305 default:
9306 case 6:
9307 case 7:
9308 case 10:
9309 case 11:
9310 case 14:
9311 case 15:
9312 HALT_UNALLOC;
9313 }
9314 }
9315
9316 /* N.B. A preliminary note regarding all the ldrs<x>32
9317 instructions
9318
9319 The signed value loaded by these instructions is cast to unsigned
9320 before being assigned to aarch64_get_reg_u64 (cpu, N) i.e. to the
9321 64 bit element of the GReg union. this performs a 32 bit sign extension
9322 (as required) but avoids 64 bit sign extension, thus ensuring that the
9323 top half of the register word is zero. this is what the spec demands
9324 when a 32 bit load occurs. */
9325
9326 /* 32 bit load sign-extended byte scaled unsigned 12 bit. */
9327 static void
9328 ldrsb32_abs (sim_cpu *cpu, uint32_t offset)
9329 {
9330 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9331 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9332
9333 /* The target register may not be SP but the source may be
9334 there is no scaling required for a byte load. */
9335 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
9336 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9337 (int64_t) aarch64_get_mem_s8 (cpu, address));
9338 }
9339
9340 /* 32 bit load sign-extended byte scaled or unscaled zero-
9341 or sign-extended 32-bit register offset. */
9342 static void
9343 ldrsb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9344 {
9345 unsigned int rm = uimm (aarch64_get_instr (cpu), 20, 16);
9346 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9347 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9348
9349 /* rn may reference SP, rm and rt must reference ZR. */
9350
9351 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9352 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9353 extension);
9354
9355 /* There is no scaling required for a byte load. */
9356 aarch64_set_reg_u64
9357 (cpu, rt, NO_SP, (int64_t) aarch64_get_mem_s8 (cpu, address
9358 + displacement));
9359 }
9360
9361 /* 32 bit load sign-extended byte unscaled signed 9 bit with
9362 pre- or post-writeback. */
9363 static void
9364 ldrsb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9365 {
9366 uint64_t address;
9367 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9368 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9369
9370 if (rn == rt && wb != NoWriteBack)
9371 HALT_UNALLOC;
9372
9373 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9374
9375 if (wb == Pre)
9376 address += offset;
9377
9378 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9379 (int64_t) aarch64_get_mem_s8 (cpu, address));
9380
9381 if (wb == Post)
9382 address += offset;
9383
9384 if (wb != NoWriteBack)
9385 aarch64_set_reg_u64 (cpu, rn, NO_SP, address);
9386 }
9387
9388 /* 8 bit store scaled. */
9389 static void
9390 fstrb_abs (sim_cpu *cpu, uint32_t offset)
9391 {
9392 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9393 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9394
9395 aarch64_set_mem_u8 (cpu,
9396 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
9397 aarch64_get_vec_u8 (cpu, st, 0));
9398 }
9399
9400 /* 8 bit store scaled or unscaled zero- or
9401 sign-extended 8-bit register offset. */
9402 static void
9403 fstrb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9404 {
9405 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9406 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9407 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9408
9409 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9410 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9411 extension);
9412 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9413
9414 aarch64_set_mem_u8
9415 (cpu, address + displacement, aarch64_get_vec_u8 (cpu, st, 0));
9416 }
9417
9418 /* 16 bit store scaled. */
9419 static void
9420 fstrh_abs (sim_cpu *cpu, uint32_t offset)
9421 {
9422 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9423 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9424
9425 aarch64_set_mem_u16
9426 (cpu,
9427 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16),
9428 aarch64_get_vec_u16 (cpu, st, 0));
9429 }
9430
9431 /* 16 bit store scaled or unscaled zero-
9432 or sign-extended 16-bit register offset. */
9433 static void
9434 fstrh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9435 {
9436 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9437 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9438 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9439
9440 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9441 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9442 extension);
9443 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9444
9445 aarch64_set_mem_u16
9446 (cpu, address + displacement, aarch64_get_vec_u16 (cpu, st, 0));
9447 }
9448
9449 /* 32 bit store scaled unsigned 12 bit. */
9450 static void
9451 fstrs_abs (sim_cpu *cpu, uint32_t offset)
9452 {
9453 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9454 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9455
9456 aarch64_set_mem_float
9457 (cpu,
9458 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
9459 aarch64_get_FP_float (cpu, st));
9460 }
9461
9462 /* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
9463 static void
9464 fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9465 {
9466 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9467 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9468
9469 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9470
9471 if (wb != Post)
9472 address += offset;
9473
9474 aarch64_set_mem_float (cpu, address, aarch64_get_FP_float (cpu, st));
9475
9476 if (wb == Post)
9477 address += offset;
9478
9479 if (wb != NoWriteBack)
9480 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9481 }
9482
9483 /* 32 bit store scaled or unscaled zero-
9484 or sign-extended 32-bit register offset. */
9485 static void
9486 fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9487 {
9488 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9489 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9490 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9491
9492 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9493 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9494 extension);
9495 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9496
9497 aarch64_set_mem_float
9498 (cpu, address + displacement, aarch64_get_FP_float (cpu, st));
9499 }
9500
9501 /* 64 bit store scaled unsigned 12 bit. */
9502 static void
9503 fstrd_abs (sim_cpu *cpu, uint32_t offset)
9504 {
9505 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9506 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9507
9508 aarch64_set_mem_double
9509 (cpu,
9510 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
9511 aarch64_get_FP_double (cpu, st));
9512 }
9513
9514 /* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
9515 static void
9516 fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9517 {
9518 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9519 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9520
9521 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9522
9523 if (wb != Post)
9524 address += offset;
9525
9526 aarch64_set_mem_double (cpu, address, aarch64_get_FP_double (cpu, st));
9527
9528 if (wb == Post)
9529 address += offset;
9530
9531 if (wb != NoWriteBack)
9532 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9533 }
9534
9535 /* 64 bit store scaled or unscaled zero-
9536 or sign-extended 32-bit register offset. */
9537 static void
9538 fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9539 {
9540 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9541 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9542 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9543
9544 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9545 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9546 extension);
9547 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
9548
9549 aarch64_set_mem_double
9550 (cpu, address + displacement, aarch64_get_FP_double (cpu, st));
9551 }
9552
9553 /* 128 bit store scaled unsigned 12 bit. */
9554 static void
9555 fstrq_abs (sim_cpu *cpu, uint32_t offset)
9556 {
9557 FRegister a;
9558 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9559 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9560 uint64_t addr;
9561
9562 aarch64_get_FP_long_double (cpu, st, & a);
9563
9564 addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
9565 aarch64_set_mem_long_double (cpu, addr, a);
9566 }
9567
9568 /* 128 bit store unscaled signed 9 bit with pre- or post-writeback. */
9569 static void
9570 fstrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9571 {
9572 FRegister a;
9573 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9574 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9575 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9576
9577 if (wb != Post)
9578 address += offset;
9579
9580 aarch64_get_FP_long_double (cpu, st, & a);
9581 aarch64_set_mem_long_double (cpu, address, a);
9582
9583 if (wb == Post)
9584 address += offset;
9585
9586 if (wb != NoWriteBack)
9587 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9588 }
9589
9590 /* 128 bit store scaled or unscaled zero-
9591 or sign-extended 32-bit register offset. */
9592 static void
9593 fstrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9594 {
9595 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9596 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9597 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9598
9599 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9600 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9601 extension);
9602 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
9603
9604 FRegister a;
9605
9606 aarch64_get_FP_long_double (cpu, st, & a);
9607 aarch64_set_mem_long_double (cpu, address + displacement, a);
9608 }
9609
9610 static void
9611 dexLoadImmediatePrePost (sim_cpu *cpu)
9612 {
9613 /* instr[29,24] == 111_00
9614 instr[21] == 0
9615 instr[11,10] == 00
9616 instr[31,30] = size
9617 instr[26] = V
9618 instr[23,22] = opc
9619 instr[20,12] = simm9
9620 instr[11] = wb : 0 ==> Post, 1 ==> Pre
9621 instr[9,5] = rn may be SP. */
9622 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9623 uint32_t V = uimm (aarch64_get_instr (cpu), 26, 26);
9624 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9625 | uimm (aarch64_get_instr (cpu), 23, 22));
9626 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
9627 WriteBack wb = writeback (aarch64_get_instr (cpu), 11);
9628
9629 if (!V)
9630 {
9631 /* GReg operations. */
9632 switch (dispatch)
9633 {
9634 case 0: strb_wb (cpu, imm, wb); return;
9635 case 1: ldrb32_wb (cpu, imm, wb); return;
9636 case 2: ldrsb_wb (cpu, imm, wb); return;
9637 case 3: ldrsb32_wb (cpu, imm, wb); return;
9638 case 4: strh_wb (cpu, imm, wb); return;
9639 case 5: ldrh32_wb (cpu, imm, wb); return;
9640 case 6: ldrsh64_wb (cpu, imm, wb); return;
9641 case 7: ldrsh32_wb (cpu, imm, wb); return;
9642 case 8: str32_wb (cpu, imm, wb); return;
9643 case 9: ldr32_wb (cpu, imm, wb); return;
9644 case 10: ldrsw_wb (cpu, imm, wb); return;
9645 case 12: str_wb (cpu, imm, wb); return;
9646 case 13: ldr_wb (cpu, imm, wb); return;
9647
9648 default:
9649 case 11:
9650 case 14:
9651 case 15:
9652 HALT_UNALLOC;
9653 }
9654 }
9655
9656 /* FReg operations. */
9657 switch (dispatch)
9658 {
9659 case 2: fstrq_wb (cpu, imm, wb); return;
9660 case 3: fldrq_wb (cpu, imm, wb); return;
9661 case 8: fstrs_wb (cpu, imm, wb); return;
9662 case 9: fldrs_wb (cpu, imm, wb); return;
9663 case 12: fstrd_wb (cpu, imm, wb); return;
9664 case 13: fldrd_wb (cpu, imm, wb); return;
9665
9666 case 0: /* STUR 8 bit FP. */
9667 case 1: /* LDUR 8 bit FP. */
9668 case 4: /* STUR 16 bit FP. */
9669 case 5: /* LDUR 8 bit FP. */
9670 HALT_NYI;
9671
9672 default:
9673 case 6:
9674 case 7:
9675 case 10:
9676 case 11:
9677 case 14:
9678 case 15:
9679 HALT_UNALLOC;
9680 }
9681 }
9682
9683 static void
9684 dexLoadRegisterOffset (sim_cpu *cpu)
9685 {
9686 /* instr[31,30] = size
9687 instr[29,27] = 111
9688 instr[26] = V
9689 instr[25,24] = 00
9690 instr[23,22] = opc
9691 instr[21] = 1
9692 instr[20,16] = rm
9693 instr[15,13] = option : 010 ==> UXTW, 011 ==> UXTX/LSL,
9694 110 ==> SXTW, 111 ==> SXTX,
9695 ow ==> RESERVED
9696 instr[12] = scaled
9697 instr[11,10] = 10
9698 instr[9,5] = rn
9699 instr[4,0] = rt. */
9700
9701 uint32_t V = uimm (aarch64_get_instr (cpu), 26,26);
9702 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9703 | uimm (aarch64_get_instr (cpu), 23, 22));
9704 Scaling scale = scaling (aarch64_get_instr (cpu), 12);
9705 Extension extensionType = extension (aarch64_get_instr (cpu), 13);
9706
9707 /* Check for illegal extension types. */
9708 if (uimm (extensionType, 1, 1) == 0)
9709 HALT_UNALLOC;
9710
9711 if (extensionType == UXTX || extensionType == SXTX)
9712 extensionType = NoExtension;
9713
9714 if (!V)
9715 {
9716 /* GReg operations. */
9717 switch (dispatch)
9718 {
9719 case 0: strb_scale_ext (cpu, scale, extensionType); return;
9720 case 1: ldrb32_scale_ext (cpu, scale, extensionType); return;
9721 case 2: ldrsb_scale_ext (cpu, scale, extensionType); return;
9722 case 3: ldrsb32_scale_ext (cpu, scale, extensionType); return;
9723 case 4: strh_scale_ext (cpu, scale, extensionType); return;
9724 case 5: ldrh32_scale_ext (cpu, scale, extensionType); return;
9725 case 6: ldrsh_scale_ext (cpu, scale, extensionType); return;
9726 case 7: ldrsh32_scale_ext (cpu, scale, extensionType); return;
9727 case 8: str32_scale_ext (cpu, scale, extensionType); return;
9728 case 9: ldr32_scale_ext (cpu, scale, extensionType); return;
9729 case 10: ldrsw_scale_ext (cpu, scale, extensionType); return;
9730 case 12: str_scale_ext (cpu, scale, extensionType); return;
9731 case 13: ldr_scale_ext (cpu, scale, extensionType); return;
9732 case 14: prfm_scale_ext (cpu, scale, extensionType); return;
9733
9734 default:
9735 case 11:
9736 case 15:
9737 HALT_UNALLOC;
9738 }
9739 }
9740
9741 /* FReg operations. */
9742 switch (dispatch)
9743 {
9744 case 1: /* LDUR 8 bit FP. */
9745 HALT_NYI;
9746 case 3: fldrq_scale_ext (cpu, scale, extensionType); return;
9747 case 5: /* LDUR 8 bit FP. */
9748 HALT_NYI;
9749 case 9: fldrs_scale_ext (cpu, scale, extensionType); return;
9750 case 13: fldrd_scale_ext (cpu, scale, extensionType); return;
9751
9752 case 0: fstrb_scale_ext (cpu, scale, extensionType); return;
9753 case 2: fstrq_scale_ext (cpu, scale, extensionType); return;
9754 case 4: fstrh_scale_ext (cpu, scale, extensionType); return;
9755 case 8: fstrs_scale_ext (cpu, scale, extensionType); return;
9756 case 12: fstrd_scale_ext (cpu, scale, extensionType); return;
9757
9758 default:
9759 case 6:
9760 case 7:
9761 case 10:
9762 case 11:
9763 case 14:
9764 case 15:
9765 HALT_UNALLOC;
9766 }
9767 }
9768
9769 static void
9770 dexLoadUnsignedImmediate (sim_cpu *cpu)
9771 {
9772 /* assert instr[29,24] == 111_01
9773 instr[31,30] = size
9774 instr[26] = V
9775 instr[23,22] = opc
9776 instr[21,10] = uimm12 : unsigned immediate offset
9777 instr[9,5] = rn may be SP. */
9778 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9779 uint32_t V = uimm (aarch64_get_instr (cpu), 26,26);
9780 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9781 | uimm (aarch64_get_instr (cpu), 23, 22));
9782 uint32_t imm = uimm (aarch64_get_instr (cpu), 21, 10);
9783
9784 if (!V)
9785 {
9786 /* GReg operations. */
9787 switch (dispatch)
9788 {
9789 case 0: strb_abs (cpu, imm); return;
9790 case 1: ldrb32_abs (cpu, imm); return;
9791 case 2: ldrsb_abs (cpu, imm); return;
9792 case 3: ldrsb32_abs (cpu, imm); return;
9793 case 4: strh_abs (cpu, imm); return;
9794 case 5: ldrh32_abs (cpu, imm); return;
9795 case 6: ldrsh_abs (cpu, imm); return;
9796 case 7: ldrsh32_abs (cpu, imm); return;
9797 case 8: str32_abs (cpu, imm); return;
9798 case 9: ldr32_abs (cpu, imm); return;
9799 case 10: ldrsw_abs (cpu, imm); return;
9800 case 12: str_abs (cpu, imm); return;
9801 case 13: ldr_abs (cpu, imm); return;
9802 case 14: prfm_abs (cpu, imm); return;
9803
9804 default:
9805 case 11:
9806 case 15:
9807 HALT_UNALLOC;
9808 }
9809 }
9810
9811 /* FReg operations. */
9812 switch (dispatch)
9813 {
9814 case 3: fldrq_abs (cpu, imm); return;
9815 case 9: fldrs_abs (cpu, imm); return;
9816 case 13: fldrd_abs (cpu, imm); return;
9817
9818 case 0: fstrb_abs (cpu, imm); return;
9819 case 2: fstrq_abs (cpu, imm); return;
9820 case 4: fstrh_abs (cpu, imm); return;
9821 case 8: fstrs_abs (cpu, imm); return;
9822 case 12: fstrd_abs (cpu, imm); return;
9823
9824 case 1: /* LDR 8 bit FP. */
9825 case 5: /* LDR 8 bit FP. */
9826 HALT_NYI;
9827
9828 default:
9829 case 6:
9830 case 7:
9831 case 10:
9832 case 11:
9833 case 14:
9834 case 15:
9835 HALT_UNALLOC;
9836 }
9837 }
9838
9839 static void
9840 dexLoadExclusive (sim_cpu *cpu)
9841 {
9842 /* assert instr[29:24] = 001000;
9843 instr[31,30] = size
9844 instr[23] = 0 if exclusive
9845 instr[22] = L : 1 if load, 0 if store
9846 instr[21] = 1 if pair
9847 instr[20,16] = Rs
9848 instr[15] = o0 : 1 if ordered
9849 instr[14,10] = Rt2
9850 instr[9,5] = Rn
9851 instr[4.0] = Rt. */
9852
9853 switch (uimm (aarch64_get_instr (cpu), 22, 21))
9854 {
9855 case 2: ldxr (cpu); return;
9856 case 0: stxr (cpu); return;
9857 default: HALT_NYI;
9858 }
9859 }
9860
9861 static void
9862 dexLoadOther (sim_cpu *cpu)
9863 {
9864 uint32_t dispatch;
9865
9866 /* instr[29,25] = 111_0
9867 instr[24] == 0 ==> dispatch, 1 ==> ldst reg unsigned immediate
9868 instr[21:11,10] is the secondary dispatch. */
9869 if (uimm (aarch64_get_instr (cpu), 24, 24))
9870 {
9871 dexLoadUnsignedImmediate (cpu);
9872 return;
9873 }
9874
9875 dispatch = ( (uimm (aarch64_get_instr (cpu), 21, 21) << 2)
9876 | uimm (aarch64_get_instr (cpu), 11, 10));
9877 switch (dispatch)
9878 {
9879 case 0: dexLoadUnscaledImmediate (cpu); return;
9880 case 1: dexLoadImmediatePrePost (cpu); return;
9881 case 3: dexLoadImmediatePrePost (cpu); return;
9882 case 6: dexLoadRegisterOffset (cpu); return;
9883
9884 default:
9885 case 2:
9886 case 4:
9887 case 5:
9888 case 7:
9889 HALT_NYI;
9890 }
9891 }
9892
9893 static void
9894 store_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9895 {
9896 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9897 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9898 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9899 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9900
9901 if ((rn == rd || rm == rd) && wb != NoWriteBack)
9902 HALT_UNALLOC; /* ??? */
9903
9904 offset <<= 2;
9905
9906 if (wb != Post)
9907 address += offset;
9908
9909 aarch64_set_mem_u32 (cpu, address,
9910 aarch64_get_reg_u32 (cpu, rm, NO_SP));
9911 aarch64_set_mem_u32 (cpu, address + 4,
9912 aarch64_get_reg_u32 (cpu, rn, NO_SP));
9913
9914 if (wb == Post)
9915 address += offset;
9916
9917 if (wb != NoWriteBack)
9918 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9919 }
9920
9921 static void
9922 store_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9923 {
9924 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9925 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9926 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9927 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9928
9929 if ((rn == rd || rm == rd) && wb != NoWriteBack)
9930 HALT_UNALLOC; /* ??? */
9931
9932 offset <<= 3;
9933
9934 if (wb != Post)
9935 address += offset;
9936
9937 aarch64_set_mem_u64 (cpu, address,
9938 aarch64_get_reg_u64 (cpu, rm, SP_OK));
9939 aarch64_set_mem_u64 (cpu, address + 8,
9940 aarch64_get_reg_u64 (cpu, rn, SP_OK));
9941
9942 if (wb == Post)
9943 address += offset;
9944
9945 if (wb != NoWriteBack)
9946 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9947 }
9948
9949 static void
9950 load_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9951 {
9952 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9953 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9954 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9955 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9956
9957 /* treat this as unalloc to make sure we don't do it. */
9958 if (rn == rm)
9959 HALT_UNALLOC;
9960
9961 offset <<= 2;
9962
9963 if (wb != Post)
9964 address += offset;
9965
9966 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u32 (cpu, address));
9967 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u32 (cpu, address + 4));
9968
9969 if (wb == Post)
9970 address += offset;
9971
9972 if (wb != NoWriteBack)
9973 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9974 }
9975
9976 static void
9977 load_pair_s32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9978 {
9979 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9980 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9981 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9982 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9983
9984 /* Treat this as unalloc to make sure we don't do it. */
9985 if (rn == rm)
9986 HALT_UNALLOC;
9987
9988 offset <<= 2;
9989
9990 if (wb != Post)
9991 address += offset;
9992
9993 aarch64_set_reg_s64 (cpu, rm, SP_OK, aarch64_get_mem_s32 (cpu, address));
9994 aarch64_set_reg_s64 (cpu, rn, SP_OK, aarch64_get_mem_s32 (cpu, address + 4));
9995
9996 if (wb == Post)
9997 address += offset;
9998
9999 if (wb != NoWriteBack)
10000 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10001 }
10002
10003 static void
10004 load_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10005 {
10006 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10007 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10008 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10009 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10010
10011 /* Treat this as unalloc to make sure we don't do it. */
10012 if (rn == rm)
10013 HALT_UNALLOC;
10014
10015 offset <<= 3;
10016
10017 if (wb != Post)
10018 address += offset;
10019
10020 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u64 (cpu, address));
10021 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u64 (cpu, address + 8));
10022
10023 if (wb == Post)
10024 address += offset;
10025
10026 if (wb != NoWriteBack)
10027 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10028 }
10029
10030 static void
10031 dex_load_store_pair_gr (sim_cpu *cpu)
10032 {
10033 /* instr[31,30] = size (10=> 64-bit, 01=> signed 32-bit, 00=> 32-bit)
10034 instr[29,25] = instruction encoding: 101_0
10035 instr[26] = V : 1 if fp 0 if gp
10036 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10037 instr[22] = load/store (1=> load)
10038 instr[21,15] = signed, scaled, offset
10039 instr[14,10] = Rn
10040 instr[ 9, 5] = Rd
10041 instr[ 4, 0] = Rm. */
10042
10043 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 3)
10044 | uimm (aarch64_get_instr (cpu), 24, 22));
10045 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10046
10047 switch (dispatch)
10048 {
10049 case 2: store_pair_u32 (cpu, offset, Post); return;
10050 case 3: load_pair_u32 (cpu, offset, Post); return;
10051 case 4: store_pair_u32 (cpu, offset, NoWriteBack); return;
10052 case 5: load_pair_u32 (cpu, offset, NoWriteBack); return;
10053 case 6: store_pair_u32 (cpu, offset, Pre); return;
10054 case 7: load_pair_u32 (cpu, offset, Pre); return;
10055
10056 case 11: load_pair_s32 (cpu, offset, Post); return;
10057 case 13: load_pair_s32 (cpu, offset, NoWriteBack); return;
10058 case 15: load_pair_s32 (cpu, offset, Pre); return;
10059
10060 case 18: store_pair_u64 (cpu, offset, Post); return;
10061 case 19: load_pair_u64 (cpu, offset, Post); return;
10062 case 20: store_pair_u64 (cpu, offset, NoWriteBack); return;
10063 case 21: load_pair_u64 (cpu, offset, NoWriteBack); return;
10064 case 22: store_pair_u64 (cpu, offset, Pre); return;
10065 case 23: load_pair_u64 (cpu, offset, Pre); return;
10066
10067 default:
10068 HALT_UNALLOC;
10069 }
10070 }
10071
10072 static void
10073 store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10074 {
10075 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10076 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10077 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10078 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10079
10080 offset <<= 2;
10081
10082 if (wb != Post)
10083 address += offset;
10084
10085 aarch64_set_mem_float (cpu, address, aarch64_get_FP_float (cpu, rm));
10086 aarch64_set_mem_float (cpu, address + 4, aarch64_get_FP_float (cpu, rn));
10087
10088 if (wb == Post)
10089 address += offset;
10090
10091 if (wb != NoWriteBack)
10092 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10093 }
10094
10095 static void
10096 store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10097 {
10098 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10099 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10100 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10101 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10102
10103 offset <<= 3;
10104
10105 if (wb != Post)
10106 address += offset;
10107
10108 aarch64_set_mem_double (cpu, address, aarch64_get_FP_double (cpu, rm));
10109 aarch64_set_mem_double (cpu, address + 8, aarch64_get_FP_double (cpu, rn));
10110
10111 if (wb == Post)
10112 address += offset;
10113
10114 if (wb != NoWriteBack)
10115 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10116 }
10117
10118 static void
10119 store_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10120 {
10121 FRegister a;
10122 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10123 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10124 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10125 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10126
10127 offset <<= 4;
10128
10129 if (wb != Post)
10130 address += offset;
10131
10132 aarch64_get_FP_long_double (cpu, rm, & a);
10133 aarch64_set_mem_long_double (cpu, address, a);
10134 aarch64_get_FP_long_double (cpu, rn, & a);
10135 aarch64_set_mem_long_double (cpu, address + 16, a);
10136
10137 if (wb == Post)
10138 address += offset;
10139
10140 if (wb != NoWriteBack)
10141 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10142 }
10143
10144 static void
10145 load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10146 {
10147 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10148 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10149 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10150 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10151
10152 if (rm == rn)
10153 HALT_UNALLOC;
10154
10155 offset <<= 2;
10156
10157 if (wb != Post)
10158 address += offset;
10159
10160 aarch64_set_FP_float (cpu, rm, aarch64_get_mem_float (cpu, address));
10161 aarch64_set_FP_float (cpu, rn, aarch64_get_mem_float (cpu, address + 4));
10162
10163 if (wb == Post)
10164 address += offset;
10165
10166 if (wb != NoWriteBack)
10167 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10168 }
10169
10170 static void
10171 load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10172 {
10173 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10174 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10175 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10176 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10177
10178 if (rm == rn)
10179 HALT_UNALLOC;
10180
10181 offset <<= 3;
10182
10183 if (wb != Post)
10184 address += offset;
10185
10186 aarch64_set_FP_double (cpu, rm, aarch64_get_mem_double (cpu, address));
10187 aarch64_set_FP_double (cpu, rn, aarch64_get_mem_double (cpu, address + 8));
10188
10189 if (wb == Post)
10190 address += offset;
10191
10192 if (wb != NoWriteBack)
10193 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10194 }
10195
10196 static void
10197 load_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10198 {
10199 FRegister a;
10200 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10201 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10202 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10203 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10204
10205 if (rm == rn)
10206 HALT_UNALLOC;
10207
10208 offset <<= 4;
10209
10210 if (wb != Post)
10211 address += offset;
10212
10213 aarch64_get_mem_long_double (cpu, address, & a);
10214 aarch64_set_FP_long_double (cpu, rm, a);
10215 aarch64_get_mem_long_double (cpu, address + 16, & a);
10216 aarch64_set_FP_long_double (cpu, rn, a);
10217
10218 if (wb == Post)
10219 address += offset;
10220
10221 if (wb != NoWriteBack)
10222 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10223 }
10224
10225 static void
10226 dex_load_store_pair_fp (sim_cpu *cpu)
10227 {
10228 /* instr[31,30] = size (10=> 128-bit, 01=> 64-bit, 00=> 32-bit)
10229 instr[29,25] = instruction encoding
10230 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10231 instr[22] = load/store (1=> load)
10232 instr[21,15] = signed, scaled, offset
10233 instr[14,10] = Rn
10234 instr[ 9, 5] = Rd
10235 instr[ 4, 0] = Rm */
10236
10237 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 3)
10238 | uimm (aarch64_get_instr (cpu), 24, 22));
10239 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10240
10241 switch (dispatch)
10242 {
10243 case 2: store_pair_float (cpu, offset, Post); return;
10244 case 3: load_pair_float (cpu, offset, Post); return;
10245 case 4: store_pair_float (cpu, offset, NoWriteBack); return;
10246 case 5: load_pair_float (cpu, offset, NoWriteBack); return;
10247 case 6: store_pair_float (cpu, offset, Pre); return;
10248 case 7: load_pair_float (cpu, offset, Pre); return;
10249
10250 case 10: store_pair_double (cpu, offset, Post); return;
10251 case 11: load_pair_double (cpu, offset, Post); return;
10252 case 12: store_pair_double (cpu, offset, NoWriteBack); return;
10253 case 13: load_pair_double (cpu, offset, NoWriteBack); return;
10254 case 14: store_pair_double (cpu, offset, Pre); return;
10255 case 15: load_pair_double (cpu, offset, Pre); return;
10256
10257 case 18: store_pair_long_double (cpu, offset, Post); return;
10258 case 19: load_pair_long_double (cpu, offset, Post); return;
10259 case 20: store_pair_long_double (cpu, offset, NoWriteBack); return;
10260 case 21: load_pair_long_double (cpu, offset, NoWriteBack); return;
10261 case 22: store_pair_long_double (cpu, offset, Pre); return;
10262 case 23: load_pair_long_double (cpu, offset, Pre); return;
10263
10264 default:
10265 HALT_UNALLOC;
10266 }
10267 }
10268
10269 static inline unsigned
10270 vec_reg (unsigned v, unsigned o)
10271 {
10272 return (v + o) & 0x3F;
10273 }
10274
10275 /* Load multiple N-element structures to N consecutive registers. */
10276 static void
10277 vec_load (sim_cpu *cpu, uint64_t address, unsigned N)
10278 {
10279 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10280 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10281 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10282 unsigned i;
10283
10284 switch (size)
10285 {
10286 case 0: /* 8-bit operations. */
10287 if (all)
10288 for (i = 0; i < (16 * N); i++)
10289 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15,
10290 aarch64_get_mem_u8 (cpu, address + i));
10291 else
10292 for (i = 0; i < (8 * N); i++)
10293 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7,
10294 aarch64_get_mem_u8 (cpu, address + i));
10295 return;
10296
10297 case 1: /* 16-bit operations. */
10298 if (all)
10299 for (i = 0; i < (8 * N); i++)
10300 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7,
10301 aarch64_get_mem_u16 (cpu, address + i * 2));
10302 else
10303 for (i = 0; i < (4 * N); i++)
10304 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3,
10305 aarch64_get_mem_u16 (cpu, address + i * 2));
10306 return;
10307
10308 case 2: /* 32-bit operations. */
10309 if (all)
10310 for (i = 0; i < (4 * N); i++)
10311 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3,
10312 aarch64_get_mem_u32 (cpu, address + i * 4));
10313 else
10314 for (i = 0; i < (2 * N); i++)
10315 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1,
10316 aarch64_get_mem_u32 (cpu, address + i * 4));
10317 return;
10318
10319 case 3: /* 64-bit operations. */
10320 if (all)
10321 for (i = 0; i < (2 * N); i++)
10322 aarch64_set_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1,
10323 aarch64_get_mem_u64 (cpu, address + i * 8));
10324 else
10325 for (i = 0; i < N; i++)
10326 aarch64_set_vec_u64 (cpu, vec_reg (vd, i), 0,
10327 aarch64_get_mem_u64 (cpu, address + i * 8));
10328 return;
10329
10330 default:
10331 HALT_UNREACHABLE;
10332 }
10333 }
10334
10335 /* LD4: load multiple 4-element to four consecutive registers. */
10336 static void
10337 LD4 (sim_cpu *cpu, uint64_t address)
10338 {
10339 vec_load (cpu, address, 4);
10340 }
10341
10342 /* LD3: load multiple 3-element structures to three consecutive registers. */
10343 static void
10344 LD3 (sim_cpu *cpu, uint64_t address)
10345 {
10346 vec_load (cpu, address, 3);
10347 }
10348
10349 /* LD2: load multiple 2-element structures to two consecutive registers. */
10350 static void
10351 LD2 (sim_cpu *cpu, uint64_t address)
10352 {
10353 vec_load (cpu, address, 2);
10354 }
10355
10356 /* Load multiple 1-element structures into one register. */
10357 static void
10358 LD1_1 (sim_cpu *cpu, uint64_t address)
10359 {
10360 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10361 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10362 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10363 unsigned i;
10364
10365 switch (size)
10366 {
10367 case 0:
10368 /* LD1 {Vd.16b}, addr, #16 */
10369 /* LD1 {Vd.8b}, addr, #8 */
10370 for (i = 0; i < (all ? 16 : 8); i++)
10371 aarch64_set_vec_u8 (cpu, vd, i,
10372 aarch64_get_mem_u8 (cpu, address + i));
10373 return;
10374
10375 case 1:
10376 /* LD1 {Vd.8h}, addr, #16 */
10377 /* LD1 {Vd.4h}, addr, #8 */
10378 for (i = 0; i < (all ? 8 : 4); i++)
10379 aarch64_set_vec_u16 (cpu, vd, i,
10380 aarch64_get_mem_u16 (cpu, address + i * 2));
10381 return;
10382
10383 case 2:
10384 /* LD1 {Vd.4s}, addr, #16 */
10385 /* LD1 {Vd.2s}, addr, #8 */
10386 for (i = 0; i < (all ? 4 : 2); i++)
10387 aarch64_set_vec_u32 (cpu, vd, i,
10388 aarch64_get_mem_u32 (cpu, address + i * 4));
10389 return;
10390
10391 case 3:
10392 /* LD1 {Vd.2d}, addr, #16 */
10393 /* LD1 {Vd.1d}, addr, #8 */
10394 for (i = 0; i < (all ? 2 : 1); i++)
10395 aarch64_set_vec_u64 (cpu, vd, i,
10396 aarch64_get_mem_u64 (cpu, address + i * 8));
10397 return;
10398
10399 default:
10400 HALT_UNREACHABLE;
10401 }
10402 }
10403
10404 /* Load multiple 1-element structures into two registers. */
10405 static void
10406 LD1_2 (sim_cpu *cpu, uint64_t address)
10407 {
10408 /* FIXME: This algorithm is *exactly* the same as the LD2 version.
10409 So why have two different instructions ? There must be something
10410 wrong somewhere. */
10411 vec_load (cpu, address, 2);
10412 }
10413
10414 /* Load multiple 1-element structures into three registers. */
10415 static void
10416 LD1_3 (sim_cpu *cpu, uint64_t address)
10417 {
10418 /* FIXME: This algorithm is *exactly* the same as the LD3 version.
10419 So why have two different instructions ? There must be something
10420 wrong somewhere. */
10421 vec_load (cpu, address, 3);
10422 }
10423
10424 /* Load multiple 1-element structures into four registers. */
10425 static void
10426 LD1_4 (sim_cpu *cpu, uint64_t address)
10427 {
10428 /* FIXME: This algorithm is *exactly* the same as the LD4 version.
10429 So why have two different instructions ? There must be something
10430 wrong somewhere. */
10431 vec_load (cpu, address, 4);
10432 }
10433
10434 /* Store multiple N-element structures to N consecutive registers. */
10435 static void
10436 vec_store (sim_cpu *cpu, uint64_t address, unsigned N)
10437 {
10438 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10439 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10440 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10441 unsigned i;
10442
10443 switch (size)
10444 {
10445 case 0: /* 8-bit operations. */
10446 if (all)
10447 for (i = 0; i < (16 * N); i++)
10448 aarch64_set_mem_u8
10449 (cpu, address + i,
10450 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15));
10451 else
10452 for (i = 0; i < (8 * N); i++)
10453 aarch64_set_mem_u8
10454 (cpu, address + i,
10455 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7));
10456 return;
10457
10458 case 1: /* 16-bit operations. */
10459 if (all)
10460 for (i = 0; i < (8 * N); i++)
10461 aarch64_set_mem_u16
10462 (cpu, address + i * 2,
10463 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7));
10464 else
10465 for (i = 0; i < (4 * N); i++)
10466 aarch64_set_mem_u16
10467 (cpu, address + i * 2,
10468 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3));
10469 return;
10470
10471 case 2: /* 32-bit operations. */
10472 if (all)
10473 for (i = 0; i < (4 * N); i++)
10474 aarch64_set_mem_u32
10475 (cpu, address + i * 4,
10476 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3));
10477 else
10478 for (i = 0; i < (2 * N); i++)
10479 aarch64_set_mem_u32
10480 (cpu, address + i * 4,
10481 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1));
10482 return;
10483
10484 case 3: /* 64-bit operations. */
10485 if (all)
10486 for (i = 0; i < (2 * N); i++)
10487 aarch64_set_mem_u64
10488 (cpu, address + i * 8,
10489 aarch64_get_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1));
10490 else
10491 for (i = 0; i < N; i++)
10492 aarch64_set_mem_u64
10493 (cpu, address + i * 8,
10494 aarch64_get_vec_u64 (cpu, vec_reg (vd, i), 0));
10495 return;
10496
10497 default:
10498 HALT_UNREACHABLE;
10499 }
10500 }
10501
10502 /* Store multiple 4-element structure to four consecutive registers. */
10503 static void
10504 ST4 (sim_cpu *cpu, uint64_t address)
10505 {
10506 vec_store (cpu, address, 4);
10507 }
10508
10509 /* Store multiple 3-element structures to three consecutive registers. */
10510 static void
10511 ST3 (sim_cpu *cpu, uint64_t address)
10512 {
10513 vec_store (cpu, address, 3);
10514 }
10515
10516 /* Store multiple 2-element structures to two consecutive registers. */
10517 static void
10518 ST2 (sim_cpu *cpu, uint64_t address)
10519 {
10520 vec_store (cpu, address, 2);
10521 }
10522
10523 /* Store multiple 1-element structures into one register. */
10524 static void
10525 ST1_1 (sim_cpu *cpu, uint64_t address)
10526 {
10527 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10528 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10529 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10530 unsigned i;
10531
10532 switch (size)
10533 {
10534 case 0:
10535 for (i = 0; i < (all ? 16 : 8); i++)
10536 aarch64_set_mem_u8 (cpu, address + i,
10537 aarch64_get_vec_u8 (cpu, vd, i));
10538 return;
10539
10540 case 1:
10541 for (i = 0; i < (all ? 8 : 4); i++)
10542 aarch64_set_mem_u16 (cpu, address + i * 2,
10543 aarch64_get_vec_u16 (cpu, vd, i));
10544 return;
10545
10546 case 2:
10547 for (i = 0; i < (all ? 4 : 2); i++)
10548 aarch64_set_mem_u32 (cpu, address + i * 4,
10549 aarch64_get_vec_u32 (cpu, vd, i));
10550 return;
10551
10552 case 3:
10553 for (i = 0; i < (all ? 2 : 1); i++)
10554 aarch64_set_mem_u64 (cpu, address + i * 8,
10555 aarch64_get_vec_u64 (cpu, vd, i));
10556 return;
10557
10558 default:
10559 HALT_UNREACHABLE;
10560 }
10561 }
10562
10563 /* Store multiple 1-element structures into two registers. */
10564 static void
10565 ST1_2 (sim_cpu *cpu, uint64_t address)
10566 {
10567 /* FIXME: This algorithm is *exactly* the same as the ST2 version.
10568 So why have two different instructions ? There must be
10569 something wrong somewhere. */
10570 vec_store (cpu, address, 2);
10571 }
10572
10573 /* Store multiple 1-element structures into three registers. */
10574 static void
10575 ST1_3 (sim_cpu *cpu, uint64_t address)
10576 {
10577 /* FIXME: This algorithm is *exactly* the same as the ST3 version.
10578 So why have two different instructions ? There must be
10579 something wrong somewhere. */
10580 vec_store (cpu, address, 3);
10581 }
10582
10583 /* Store multiple 1-element structures into four registers. */
10584 static void
10585 ST1_4 (sim_cpu *cpu, uint64_t address)
10586 {
10587 /* FIXME: This algorithm is *exactly* the same as the ST4 version.
10588 So why have two different instructions ? There must be
10589 something wrong somewhere. */
10590 vec_store (cpu, address, 4);
10591 }
10592
10593 static void
10594 do_vec_LDnR (sim_cpu *cpu, uint64_t address)
10595 {
10596 /* instr[31] = 0
10597 instr[30] = element selector 0=>half, 1=>all elements
10598 instr[29,24] = 00 1101
10599 instr[23] = 0=>simple, 1=>post
10600 instr[22] = 1
10601 instr[21] = width: LD1R-or-LD3R (0) / LD2R-or-LD4R (1)
10602 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
10603 11111 (immediate post inc)
10604 instr[15,14] = 11
10605 instr[13] = width: LD1R-or-LD2R (0) / LD3R-or-LD4R (1)
10606 instr[12] = 0
10607 instr[11,10] = element size 00=> byte(b), 01=> half(h),
10608 10=> word(s), 11=> double(d)
10609 instr[9,5] = address
10610 instr[4,0] = Vd */
10611
10612 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
10613 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10614 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10615 int i;
10616
10617 NYI_assert (29, 24, 0x0D);
10618 NYI_assert (22, 22, 1);
10619 NYI_assert (15, 14, 3);
10620 NYI_assert (12, 12, 0);
10621
10622 switch ((uimm (aarch64_get_instr (cpu), 13, 13) << 1)
10623 | uimm (aarch64_get_instr (cpu), 21, 21))
10624 {
10625 case 0: /* LD1R. */
10626 switch (size)
10627 {
10628 case 0:
10629 {
10630 uint8_t val = aarch64_get_mem_u8 (cpu, address);
10631 for (i = 0; i < (full ? 16 : 8); i++)
10632 aarch64_set_vec_u8 (cpu, vd, i, val);
10633 break;
10634 }
10635
10636 case 1:
10637 {
10638 uint16_t val = aarch64_get_mem_u16 (cpu, address);
10639 for (i = 0; i < (full ? 8 : 4); i++)
10640 aarch64_set_vec_u16 (cpu, vd, i, val);
10641 break;
10642 }
10643
10644 case 2:
10645 {
10646 uint32_t val = aarch64_get_mem_u32 (cpu, address);
10647 for (i = 0; i < (full ? 4 : 2); i++)
10648 aarch64_set_vec_u32 (cpu, vd, i, val);
10649 break;
10650 }
10651
10652 case 3:
10653 {
10654 uint64_t val = aarch64_get_mem_u64 (cpu, address);
10655 for (i = 0; i < (full ? 2 : 1); i++)
10656 aarch64_set_vec_u64 (cpu, vd, i, val);
10657 break;
10658 }
10659
10660 default:
10661 HALT_UNALLOC;
10662 }
10663 break;
10664
10665 case 1: /* LD2R. */
10666 switch (size)
10667 {
10668 case 0:
10669 {
10670 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10671 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10672
10673 for (i = 0; i < (full ? 16 : 8); i++)
10674 {
10675 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10676 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10677 }
10678 break;
10679 }
10680
10681 case 1:
10682 {
10683 uint16_t val1 = aarch64_get_mem_u16 (cpu, address);
10684 uint16_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10685
10686 for (i = 0; i < (full ? 8 : 4); i++)
10687 {
10688 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10689 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10690 }
10691 break;
10692 }
10693
10694 case 2:
10695 {
10696 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10697 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10698
10699 for (i = 0; i < (full ? 4 : 2); i++)
10700 {
10701 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10702 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10703 }
10704 break;
10705 }
10706
10707 case 3:
10708 {
10709 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10710 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10711
10712 for (i = 0; i < (full ? 2 : 1); i++)
10713 {
10714 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10715 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10716 }
10717 break;
10718 }
10719
10720 default:
10721 HALT_UNALLOC;
10722 }
10723 break;
10724
10725 case 2: /* LD3R. */
10726 switch (size)
10727 {
10728 case 0:
10729 {
10730 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10731 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10732 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
10733
10734 for (i = 0; i < (full ? 16 : 8); i++)
10735 {
10736 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10737 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10738 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
10739 }
10740 }
10741 break;
10742
10743 case 1:
10744 {
10745 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
10746 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10747 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
10748
10749 for (i = 0; i < (full ? 8 : 4); i++)
10750 {
10751 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10752 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10753 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
10754 }
10755 }
10756 break;
10757
10758 case 2:
10759 {
10760 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10761 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10762 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
10763
10764 for (i = 0; i < (full ? 4 : 2); i++)
10765 {
10766 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10767 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10768 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
10769 }
10770 }
10771 break;
10772
10773 case 3:
10774 {
10775 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10776 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10777 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
10778
10779 for (i = 0; i < (full ? 2 : 1); i++)
10780 {
10781 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10782 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10783 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
10784 }
10785 }
10786 break;
10787
10788 default:
10789 HALT_UNALLOC;
10790 }
10791 break;
10792
10793 case 3: /* LD4R. */
10794 switch (size)
10795 {
10796 case 0:
10797 {
10798 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10799 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10800 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
10801 uint8_t val4 = aarch64_get_mem_u8 (cpu, address + 3);
10802
10803 for (i = 0; i < (full ? 16 : 8); i++)
10804 {
10805 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10806 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10807 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
10808 aarch64_set_vec_u8 (cpu, vd + 3, 0, val4);
10809 }
10810 }
10811 break;
10812
10813 case 1:
10814 {
10815 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
10816 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10817 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
10818 uint32_t val4 = aarch64_get_mem_u16 (cpu, address + 6);
10819
10820 for (i = 0; i < (full ? 8 : 4); i++)
10821 {
10822 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10823 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10824 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
10825 aarch64_set_vec_u16 (cpu, vd + 3, 0, val4);
10826 }
10827 }
10828 break;
10829
10830 case 2:
10831 {
10832 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10833 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10834 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
10835 uint32_t val4 = aarch64_get_mem_u32 (cpu, address + 12);
10836
10837 for (i = 0; i < (full ? 4 : 2); i++)
10838 {
10839 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10840 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10841 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
10842 aarch64_set_vec_u32 (cpu, vd + 3, 0, val4);
10843 }
10844 }
10845 break;
10846
10847 case 3:
10848 {
10849 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10850 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10851 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
10852 uint64_t val4 = aarch64_get_mem_u64 (cpu, address + 24);
10853
10854 for (i = 0; i < (full ? 2 : 1); i++)
10855 {
10856 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10857 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10858 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
10859 aarch64_set_vec_u64 (cpu, vd + 3, 0, val4);
10860 }
10861 }
10862 break;
10863
10864 default:
10865 HALT_UNALLOC;
10866 }
10867 break;
10868
10869 default:
10870 HALT_UNALLOC;
10871 }
10872 }
10873
10874 static void
10875 do_vec_load_store (sim_cpu *cpu)
10876 {
10877 /* {LD|ST}<N> {Vd..Vd+N}, vaddr
10878
10879 instr[31] = 0
10880 instr[30] = element selector 0=>half, 1=>all elements
10881 instr[29,25] = 00110
10882 instr[24] = ?
10883 instr[23] = 0=>simple, 1=>post
10884 instr[22] = 0=>store, 1=>load
10885 instr[21] = 0 (LDn) / small(0)-large(1) selector (LDnR)
10886 instr[20,16] = 00000 (simple), Vinc (reg-post-inc, no SP),
10887 11111 (immediate post inc)
10888 instr[15,12] = elements and destinations. eg for load:
10889 0000=>LD4 => load multiple 4-element to
10890 four consecutive registers
10891 0100=>LD3 => load multiple 3-element to
10892 three consecutive registers
10893 1000=>LD2 => load multiple 2-element to
10894 two consecutive registers
10895 0010=>LD1 => load multiple 1-element to
10896 four consecutive registers
10897 0110=>LD1 => load multiple 1-element to
10898 three consecutive registers
10899 1010=>LD1 => load multiple 1-element to
10900 two consecutive registers
10901 0111=>LD1 => load multiple 1-element to
10902 one register
10903 1100=>LDR1,LDR2
10904 1110=>LDR3,LDR4
10905 instr[11,10] = element size 00=> byte(b), 01=> half(h),
10906 10=> word(s), 11=> double(d)
10907 instr[9,5] = Vn, can be SP
10908 instr[4,0] = Vd */
10909
10910 int post;
10911 int load;
10912 unsigned vn;
10913 uint64_t address;
10914 int type;
10915
10916 if (uimm (aarch64_get_instr (cpu), 31, 31) != 0
10917 || uimm (aarch64_get_instr (cpu), 29, 25) != 0x06)
10918 HALT_NYI;
10919
10920 type = uimm (aarch64_get_instr (cpu), 15, 12);
10921 if (type != 0xE && type != 0xE && uimm (aarch64_get_instr (cpu), 21, 21) != 0)
10922 HALT_NYI;
10923
10924 post = uimm (aarch64_get_instr (cpu), 23, 23);
10925 load = uimm (aarch64_get_instr (cpu), 22, 22);
10926 vn = uimm (aarch64_get_instr (cpu), 9, 5);
10927 address = aarch64_get_reg_u64 (cpu, vn, SP_OK);
10928
10929 if (post)
10930 {
10931 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
10932
10933 if (vm == R31)
10934 {
10935 unsigned sizeof_operation;
10936
10937 switch (type)
10938 {
10939 case 0: sizeof_operation = 32; break;
10940 case 4: sizeof_operation = 24; break;
10941 case 8: sizeof_operation = 16; break;
10942
10943 case 0xC:
10944 sizeof_operation = uimm (aarch64_get_instr (cpu), 21, 21) ? 2 : 1;
10945 sizeof_operation <<= uimm (aarch64_get_instr (cpu), 11, 10);
10946 break;
10947
10948 case 0xE:
10949 sizeof_operation = uimm (aarch64_get_instr (cpu), 21, 21) ? 8 : 4;
10950 sizeof_operation <<= uimm (aarch64_get_instr (cpu), 11, 10);
10951 break;
10952
10953 case 2:
10954 case 6:
10955 case 10:
10956 case 7:
10957 sizeof_operation = 2 << uimm (aarch64_get_instr (cpu), 11, 10);
10958 break;
10959
10960 default:
10961 HALT_UNALLOC;
10962 }
10963
10964 if (uimm (aarch64_get_instr (cpu), 30, 30))
10965 sizeof_operation *= 2;
10966
10967 aarch64_set_reg_u64 (cpu, vn, SP_OK, address + sizeof_operation);
10968 }
10969 else
10970 aarch64_set_reg_u64 (cpu, vn, SP_OK,
10971 address + aarch64_get_reg_u64 (cpu, vm, NO_SP));
10972 }
10973 else
10974 {
10975 NYI_assert (20, 16, 0);
10976 }
10977
10978 if (load)
10979 {
10980 switch (type)
10981 {
10982 case 0: LD4 (cpu, address); return;
10983 case 4: LD3 (cpu, address); return;
10984 case 8: LD2 (cpu, address); return;
10985 case 2: LD1_4 (cpu, address); return;
10986 case 6: LD1_3 (cpu, address); return;
10987 case 10: LD1_2 (cpu, address); return;
10988 case 7: LD1_1 (cpu, address); return;
10989
10990 case 0xE:
10991 case 0xC: do_vec_LDnR (cpu, address); return;
10992
10993 default:
10994 HALT_NYI;
10995 }
10996 }
10997
10998 /* Stores. */
10999 switch (type)
11000 {
11001 case 0: ST4 (cpu, address); return;
11002 case 4: ST3 (cpu, address); return;
11003 case 8: ST2 (cpu, address); return;
11004 case 2: ST1_4 (cpu, address); return;
11005 case 6: ST1_3 (cpu, address); return;
11006 case 10: ST1_2 (cpu, address); return;
11007 case 7: ST1_1 (cpu, address); return;
11008 default:
11009 HALT_NYI;
11010 }
11011 }
11012
11013 static void
11014 dexLdSt (sim_cpu *cpu)
11015 {
11016 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
11017 assert group == GROUP_LDST_0100 || group == GROUP_LDST_0110 ||
11018 group == GROUP_LDST_1100 || group == GROUP_LDST_1110
11019 bits [29,28:26] of a LS are the secondary dispatch vector. */
11020 uint32_t group2 = dispatchLS (aarch64_get_instr (cpu));
11021
11022 switch (group2)
11023 {
11024 case LS_EXCL_000:
11025 dexLoadExclusive (cpu); return;
11026
11027 case LS_LIT_010:
11028 case LS_LIT_011:
11029 dexLoadLiteral (cpu); return;
11030
11031 case LS_OTHER_110:
11032 case LS_OTHER_111:
11033 dexLoadOther (cpu); return;
11034
11035 case LS_ADVSIMD_001:
11036 do_vec_load_store (cpu); return;
11037
11038 case LS_PAIR_100:
11039 dex_load_store_pair_gr (cpu); return;
11040
11041 case LS_PAIR_101:
11042 dex_load_store_pair_fp (cpu); return;
11043
11044 default:
11045 /* Should never reach here. */
11046 HALT_NYI;
11047 }
11048 }
11049
11050 /* Specific decode and execute for group Data Processing Register. */
11051
11052 static void
11053 dexLogicalShiftedRegister (sim_cpu *cpu)
11054 {
11055 /* assert instr[28:24] = 01010
11056 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11057 instr[30,29:21] = op,N : 000 ==> AND, 001 ==> BIC,
11058 010 ==> ORR, 011 ==> ORN
11059 100 ==> EOR, 101 ==> EON,
11060 110 ==> ANDS, 111 ==> BICS
11061 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> ROR
11062 instr[15,10] = count : must be 0xxxxx for 32 bit
11063 instr[9,5] = Rn
11064 instr[4,0] = Rd */
11065
11066 /* unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16); */
11067 uint32_t dispatch;
11068 Shift shiftType;
11069 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
11070
11071 /* 32 bit operations must have count[5] = 0. */
11072 /* or else we have an UNALLOC. */
11073 uint32_t count = uimm (aarch64_get_instr (cpu), 15, 10);
11074
11075 if (!size && uimm (count, 5, 5))
11076 HALT_UNALLOC;
11077
11078 shiftType = shift (aarch64_get_instr (cpu), 22);
11079
11080 /* dispatch on size:op:N i.e aarch64_get_instr (cpu)[31,29:21]. */
11081 dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 29) << 1)
11082 | uimm (aarch64_get_instr (cpu), 21, 21));
11083
11084 switch (dispatch)
11085 {
11086 case 0: and32_shift (cpu, shiftType, count); return;
11087 case 1: bic32_shift (cpu, shiftType, count); return;
11088 case 2: orr32_shift (cpu, shiftType, count); return;
11089 case 3: orn32_shift (cpu, shiftType, count); return;
11090 case 4: eor32_shift (cpu, shiftType, count); return;
11091 case 5: eon32_shift (cpu, shiftType, count); return;
11092 case 6: ands32_shift (cpu, shiftType, count); return;
11093 case 7: bics32_shift (cpu, shiftType, count); return;
11094 case 8: and64_shift (cpu, shiftType, count); return;
11095 case 9: bic64_shift (cpu, shiftType, count); return;
11096 case 10:orr64_shift (cpu, shiftType, count); return;
11097 case 11:orn64_shift (cpu, shiftType, count); return;
11098 case 12:eor64_shift (cpu, shiftType, count); return;
11099 case 13:eon64_shift (cpu, shiftType, count); return;
11100 case 14:ands64_shift (cpu, shiftType, count); return;
11101 case 15:bics64_shift (cpu, shiftType, count); return;
11102 default: HALT_UNALLOC;
11103 }
11104 }
11105
11106 /* 32 bit conditional select. */
11107 static void
11108 csel32 (sim_cpu *cpu, CondCode cc)
11109 {
11110 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11111 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11112 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11113
11114 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11115 testConditionCode (cpu, cc)
11116 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11117 : aarch64_get_reg_u32 (cpu, rm, NO_SP));
11118 }
11119
11120 /* 64 bit conditional select. */
11121 static void
11122 csel64 (sim_cpu *cpu, CondCode cc)
11123 {
11124 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11125 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11126 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11127
11128 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11129 testConditionCode (cpu, cc)
11130 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11131 : aarch64_get_reg_u64 (cpu, rm, NO_SP));
11132 }
11133
11134 /* 32 bit conditional increment. */
11135 static void
11136 csinc32 (sim_cpu *cpu, CondCode cc)
11137 {
11138 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11139 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11140 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11141
11142 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11143 testConditionCode (cpu, cc)
11144 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11145 : aarch64_get_reg_u32 (cpu, rm, NO_SP) + 1);
11146 }
11147
11148 /* 64 bit conditional increment. */
11149 static void
11150 csinc64 (sim_cpu *cpu, CondCode cc)
11151 {
11152 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11153 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11154 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11155
11156 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11157 testConditionCode (cpu, cc)
11158 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11159 : aarch64_get_reg_u64 (cpu, rm, NO_SP) + 1);
11160 }
11161
11162 /* 32 bit conditional invert. */
11163 static void
11164 csinv32 (sim_cpu *cpu, CondCode cc)
11165 {
11166 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11167 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11168 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11169
11170 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11171 testConditionCode (cpu, cc)
11172 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11173 : ~ aarch64_get_reg_u32 (cpu, rm, NO_SP));
11174 }
11175
11176 /* 64 bit conditional invert. */
11177 static void
11178 csinv64 (sim_cpu *cpu, CondCode cc)
11179 {
11180 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11181 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11182 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11183
11184 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11185 testConditionCode (cpu, cc)
11186 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11187 : ~ aarch64_get_reg_u64 (cpu, rm, NO_SP));
11188 }
11189
11190 /* 32 bit conditional negate. */
11191 static void
11192 csneg32 (sim_cpu *cpu, CondCode cc)
11193 {
11194 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11195 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11196 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11197
11198 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11199 testConditionCode (cpu, cc)
11200 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11201 : - aarch64_get_reg_u32 (cpu, rm, NO_SP));
11202 }
11203
11204 /* 64 bit conditional negate. */
11205 static void
11206 csneg64 (sim_cpu *cpu, CondCode cc)
11207 {
11208 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11209 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11210 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11211
11212 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11213 testConditionCode (cpu, cc)
11214 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11215 : - aarch64_get_reg_u64 (cpu, rm, NO_SP));
11216 }
11217
11218 static void
11219 dexCondSelect (sim_cpu *cpu)
11220 {
11221 /* assert instr[28,21] = 11011011
11222 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11223 instr[30:11,10] = op : 000 ==> CSEL, 001 ==> CSINC,
11224 100 ==> CSINV, 101 ==> CSNEG,
11225 _1_ ==> UNALLOC
11226 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11227 instr[15,12] = cond
11228 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC */
11229
11230 CondCode cc;
11231 uint32_t dispatch;
11232 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11233 uint32_t op2 = uimm (aarch64_get_instr (cpu), 11, 10);
11234
11235 if (S == 1)
11236 HALT_UNALLOC;
11237
11238 if (op2 & 0x2)
11239 HALT_UNALLOC;
11240
11241 cc = condcode (aarch64_get_instr (cpu), 12);
11242 dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 1) | op2);
11243
11244 switch (dispatch)
11245 {
11246 case 0: csel32 (cpu, cc); return;
11247 case 1: csinc32 (cpu, cc); return;
11248 case 2: csinv32 (cpu, cc); return;
11249 case 3: csneg32 (cpu, cc); return;
11250 case 4: csel64 (cpu, cc); return;
11251 case 5: csinc64 (cpu, cc); return;
11252 case 6: csinv64 (cpu, cc); return;
11253 case 7: csneg64 (cpu, cc); return;
11254 default: HALT_UNALLOC;
11255 }
11256 }
11257
11258 /* Some helpers for counting leading 1 or 0 bits. */
11259
11260 /* Counts the number of leading bits which are the same
11261 in a 32 bit value in the range 1 to 32. */
11262 static uint32_t
11263 leading32 (uint32_t value)
11264 {
11265 int32_t mask= 0xffff0000;
11266 uint32_t count= 16; /* Counts number of bits set in mask. */
11267 uint32_t lo = 1; /* Lower bound for number of sign bits. */
11268 uint32_t hi = 32; /* Upper bound for number of sign bits. */
11269
11270 while (lo + 1 < hi)
11271 {
11272 int32_t test = (value & mask);
11273
11274 if (test == 0 || test == mask)
11275 {
11276 lo = count;
11277 count = (lo + hi) / 2;
11278 mask >>= (count - lo);
11279 }
11280 else
11281 {
11282 hi = count;
11283 count = (lo + hi) / 2;
11284 mask <<= hi - count;
11285 }
11286 }
11287
11288 if (lo != hi)
11289 {
11290 int32_t test;
11291
11292 mask >>= 1;
11293 test = (value & mask);
11294
11295 if (test == 0 || test == mask)
11296 count = hi;
11297 else
11298 count = lo;
11299 }
11300
11301 return count;
11302 }
11303
11304 /* Counts the number of leading bits which are the same
11305 in a 64 bit value in the range 1 to 64. */
11306 static uint64_t
11307 leading64 (uint64_t value)
11308 {
11309 int64_t mask= 0xffffffff00000000LL;
11310 uint64_t count = 32; /* Counts number of bits set in mask. */
11311 uint64_t lo = 1; /* Lower bound for number of sign bits. */
11312 uint64_t hi = 64; /* Upper bound for number of sign bits. */
11313
11314 while (lo + 1 < hi)
11315 {
11316 int64_t test = (value & mask);
11317
11318 if (test == 0 || test == mask)
11319 {
11320 lo = count;
11321 count = (lo + hi) / 2;
11322 mask >>= (count - lo);
11323 }
11324 else
11325 {
11326 hi = count;
11327 count = (lo + hi) / 2;
11328 mask <<= hi - count;
11329 }
11330 }
11331
11332 if (lo != hi)
11333 {
11334 int64_t test;
11335
11336 mask >>= 1;
11337 test = (value & mask);
11338
11339 if (test == 0 || test == mask)
11340 count = hi;
11341 else
11342 count = lo;
11343 }
11344
11345 return count;
11346 }
11347
11348 /* Bit operations. */
11349 /* N.B register args may not be SP. */
11350
11351 /* 32 bit count leading sign bits. */
11352 static void
11353 cls32 (sim_cpu *cpu)
11354 {
11355 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11356 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11357
11358 /* N.B. the result needs to exclude the leading bit. */
11359 aarch64_set_reg_u64
11360 (cpu, rd, NO_SP, leading32 (aarch64_get_reg_u32 (cpu, rn, NO_SP)) - 1);
11361 }
11362
11363 /* 64 bit count leading sign bits. */
11364 static void
11365 cls64 (sim_cpu *cpu)
11366 {
11367 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11368 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11369
11370 /* N.B. the result needs to exclude the leading bit. */
11371 aarch64_set_reg_u64
11372 (cpu, rd, NO_SP, leading64 (aarch64_get_reg_u64 (cpu, rn, NO_SP)) - 1);
11373 }
11374
11375 /* 32 bit count leading zero bits. */
11376 static void
11377 clz32 (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 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11382
11383 /* if the sign (top) bit is set then the count is 0. */
11384 if (pick32 (value, 31, 31))
11385 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11386 else
11387 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading32 (value));
11388 }
11389
11390 /* 64 bit count leading zero bits. */
11391 static void
11392 clz64 (sim_cpu *cpu)
11393 {
11394 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11395 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11396 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11397
11398 /* if the sign (top) bit is set then the count is 0. */
11399 if (pick64 (value, 63, 63))
11400 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11401 else
11402 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading64 (value));
11403 }
11404
11405 /* 32 bit reverse bits. */
11406 static void
11407 rbit32 (sim_cpu *cpu)
11408 {
11409 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11410 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11411 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11412 uint32_t result = 0;
11413 int i;
11414
11415 for (i = 0; i < 32; i++)
11416 {
11417 result <<= 1;
11418 result |= (value & 1);
11419 value >>= 1;
11420 }
11421 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11422 }
11423
11424 /* 64 bit reverse bits. */
11425 static void
11426 rbit64 (sim_cpu *cpu)
11427 {
11428 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11429 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11430 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11431 uint64_t result = 0;
11432 int i;
11433
11434 for (i = 0; i < 64; i++)
11435 {
11436 result <<= 1;
11437 result |= (value & 1L);
11438 value >>= 1;
11439 }
11440 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11441 }
11442
11443 /* 32 bit reverse bytes. */
11444 static void
11445 rev32 (sim_cpu *cpu)
11446 {
11447 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11448 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11449 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11450 uint32_t result = 0;
11451 int i;
11452
11453 for (i = 0; i < 4; i++)
11454 {
11455 result <<= 8;
11456 result |= (value & 0xff);
11457 value >>= 8;
11458 }
11459 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11460 }
11461
11462 /* 64 bit reverse bytes. */
11463 static void
11464 rev64 (sim_cpu *cpu)
11465 {
11466 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11467 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11468 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11469 uint64_t result = 0;
11470 int i;
11471
11472 for (i = 0; i < 8; i++)
11473 {
11474 result <<= 8;
11475 result |= (value & 0xffULL);
11476 value >>= 8;
11477 }
11478 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11479 }
11480
11481 /* 32 bit reverse shorts. */
11482 /* N.B.this reverses the order of the bytes in each half word. */
11483 static void
11484 revh32 (sim_cpu *cpu)
11485 {
11486 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11487 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11488 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11489 uint32_t result = 0;
11490 int i;
11491
11492 for (i = 0; i < 2; i++)
11493 {
11494 result <<= 8;
11495 result |= (value & 0x00ff00ff);
11496 value >>= 8;
11497 }
11498 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11499 }
11500
11501 /* 64 bit reverse shorts. */
11502 /* N.B.this reverses the order of the bytes in each half word. */
11503 static void
11504 revh64 (sim_cpu *cpu)
11505 {
11506 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11507 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11508 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11509 uint64_t result = 0;
11510 int i;
11511
11512 for (i = 0; i < 2; i++)
11513 {
11514 result <<= 8;
11515 result |= (value & 0x00ff00ff00ff00ffULL);
11516 value >>= 8;
11517 }
11518 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11519 }
11520
11521 static void
11522 dexDataProc1Source (sim_cpu *cpu)
11523 {
11524 /* assert instr[30] == 1
11525 aarch64_get_instr (cpu)[28,21] == 111010110
11526 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11527 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11528 instr[20,16] = opcode2 : 00000 ==> ok, ow ==> UNALLOC
11529 instr[15,10] = opcode : 000000 ==> RBIT, 000001 ==> REV16,
11530 000010 ==> REV, 000011 ==> UNALLOC
11531 000100 ==> CLZ, 000101 ==> CLS
11532 ow ==> UNALLOC
11533 instr[9,5] = rn : may not be SP
11534 instr[4,0] = rd : may not be SP. */
11535
11536 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11537 uint32_t opcode2 = uimm (aarch64_get_instr (cpu), 20, 16);
11538 uint32_t opcode = uimm (aarch64_get_instr (cpu), 15, 10);
11539 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 31) << 3) | opcode);
11540
11541 if (S == 1)
11542 HALT_UNALLOC;
11543
11544 if (opcode2 != 0)
11545 HALT_UNALLOC;
11546
11547 if (opcode & 0x38)
11548 HALT_UNALLOC;
11549
11550 switch (dispatch)
11551 {
11552 case 0: rbit32 (cpu); return;
11553 case 1: revh32 (cpu); return;
11554 case 2: rev32 (cpu); return;
11555 case 4: clz32 (cpu); return;
11556 case 5: cls32 (cpu); return;
11557 case 8: rbit64 (cpu); return;
11558 case 9: revh64 (cpu); return;
11559 case 10:rev32 (cpu); return;
11560 case 11:rev64 (cpu); return;
11561 case 12:clz64 (cpu); return;
11562 case 13:cls64 (cpu); return;
11563 default: HALT_UNALLOC;
11564 }
11565 }
11566
11567 /* Variable shift.
11568 Shifts by count supplied in register.
11569 N.B register args may not be SP.
11570 These all use the shifted auxiliary function for
11571 simplicity and clarity. Writing the actual shift
11572 inline would avoid a branch and so be faster but
11573 would also necessitate getting signs right. */
11574
11575 /* 32 bit arithmetic shift right. */
11576 static void
11577 asrv32 (sim_cpu *cpu)
11578 {
11579 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11580 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11581 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11582
11583 aarch64_set_reg_u64
11584 (cpu, rd, NO_SP,
11585 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ASR,
11586 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11587 }
11588
11589 /* 64 bit arithmetic shift right. */
11590 static void
11591 asrv64 (sim_cpu *cpu)
11592 {
11593 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11594 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11595 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11596
11597 aarch64_set_reg_u64
11598 (cpu, rd, NO_SP,
11599 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ASR,
11600 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11601 }
11602
11603 /* 32 bit logical shift left. */
11604 static void
11605 lslv32 (sim_cpu *cpu)
11606 {
11607 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11608 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11609 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11610
11611 aarch64_set_reg_u64
11612 (cpu, rd, NO_SP,
11613 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSL,
11614 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11615 }
11616
11617 /* 64 bit arithmetic shift left. */
11618 static void
11619 lslv64 (sim_cpu *cpu)
11620 {
11621 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11622 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11623 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11624
11625 aarch64_set_reg_u64
11626 (cpu, rd, NO_SP,
11627 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSL,
11628 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11629 }
11630
11631 /* 32 bit logical shift right. */
11632 static void
11633 lsrv32 (sim_cpu *cpu)
11634 {
11635 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11636 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11637 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11638
11639 aarch64_set_reg_u64
11640 (cpu, rd, NO_SP,
11641 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSR,
11642 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11643 }
11644
11645 /* 64 bit logical shift right. */
11646 static void
11647 lsrv64 (sim_cpu *cpu)
11648 {
11649 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11650 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11651 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11652
11653 aarch64_set_reg_u64
11654 (cpu, rd, NO_SP,
11655 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSR,
11656 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11657 }
11658
11659 /* 32 bit rotate right. */
11660 static void
11661 rorv32 (sim_cpu *cpu)
11662 {
11663 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11664 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11665 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11666
11667 aarch64_set_reg_u64
11668 (cpu, rd, NO_SP,
11669 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ROR,
11670 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11671 }
11672
11673 /* 64 bit rotate right. */
11674 static void
11675 rorv64 (sim_cpu *cpu)
11676 {
11677 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11678 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11679 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11680
11681 aarch64_set_reg_u64
11682 (cpu, rd, NO_SP,
11683 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ROR,
11684 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11685 }
11686
11687
11688 /* divide. */
11689
11690 /* 32 bit signed divide. */
11691 static void
11692 cpuiv32 (sim_cpu *cpu)
11693 {
11694 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11695 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11696 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11697 /* N.B. the pseudo-code does the divide using 64 bit data. */
11698 /* TODO : check that this rounds towards zero as required. */
11699 int64_t dividend = aarch64_get_reg_s32 (cpu, rn, NO_SP);
11700 int64_t divisor = aarch64_get_reg_s32 (cpu, rm, NO_SP);
11701
11702 aarch64_set_reg_s64 (cpu, rd, NO_SP,
11703 divisor ? ((int32_t) (dividend / divisor)) : 0);
11704 }
11705
11706 /* 64 bit signed divide. */
11707 static void
11708 cpuiv64 (sim_cpu *cpu)
11709 {
11710 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11711 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11712 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11713
11714 /* TODO : check that this rounds towards zero as required. */
11715 int64_t divisor = aarch64_get_reg_s64 (cpu, rm, NO_SP);
11716
11717 aarch64_set_reg_s64
11718 (cpu, rd, NO_SP,
11719 divisor ? (aarch64_get_reg_s64 (cpu, rn, NO_SP) / divisor) : 0);
11720 }
11721
11722 /* 32 bit unsigned divide. */
11723 static void
11724 udiv32 (sim_cpu *cpu)
11725 {
11726 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11727 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11728 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11729
11730 /* N.B. the pseudo-code does the divide using 64 bit data. */
11731 uint64_t dividend = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11732 uint64_t divisor = aarch64_get_reg_u32 (cpu, rm, NO_SP);
11733
11734 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11735 divisor ? (uint32_t) (dividend / divisor) : 0);
11736 }
11737
11738 /* 64 bit unsigned divide. */
11739 static void
11740 udiv64 (sim_cpu *cpu)
11741 {
11742 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11743 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11744 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11745
11746 /* TODO : check that this rounds towards zero as required. */
11747 uint64_t divisor = aarch64_get_reg_u64 (cpu, rm, NO_SP);
11748
11749 aarch64_set_reg_u64
11750 (cpu, rd, NO_SP,
11751 divisor ? (aarch64_get_reg_u64 (cpu, rn, NO_SP) / divisor) : 0);
11752 }
11753
11754 static void
11755 dexDataProc2Source (sim_cpu *cpu)
11756 {
11757 /* assert instr[30] == 0
11758 instr[28,21] == 11010110
11759 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11760 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11761 instr[15,10] = opcode : 000010 ==> UDIV, 000011 ==> CPUIV,
11762 001000 ==> LSLV, 001001 ==> LSRV
11763 001010 ==> ASRV, 001011 ==> RORV
11764 ow ==> UNALLOC. */
11765
11766 uint32_t dispatch;
11767 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11768 uint32_t opcode = uimm (aarch64_get_instr (cpu), 15, 10);
11769
11770 if (S == 1)
11771 HALT_UNALLOC;
11772
11773 if (opcode & 0x34)
11774 HALT_UNALLOC;
11775
11776 dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 31) << 3)
11777 | (uimm (opcode, 3, 3) << 2)
11778 | uimm (opcode, 1, 0));
11779 switch (dispatch)
11780 {
11781 case 2: udiv32 (cpu); return;
11782 case 3: cpuiv32 (cpu); return;
11783 case 4: lslv32 (cpu); return;
11784 case 5: lsrv32 (cpu); return;
11785 case 6: asrv32 (cpu); return;
11786 case 7: rorv32 (cpu); return;
11787 case 10: udiv64 (cpu); return;
11788 case 11: cpuiv64 (cpu); return;
11789 case 12: lslv64 (cpu); return;
11790 case 13: lsrv64 (cpu); return;
11791 case 14: asrv64 (cpu); return;
11792 case 15: rorv64 (cpu); return;
11793 default: HALT_UNALLOC;
11794 }
11795 }
11796
11797
11798 /* Multiply. */
11799
11800 /* 32 bit multiply and add. */
11801 static void
11802 madd32 (sim_cpu *cpu)
11803 {
11804 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11805 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11806 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11807 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11808
11809 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11810 aarch64_get_reg_u32 (cpu, ra, NO_SP)
11811 + aarch64_get_reg_u32 (cpu, rn, NO_SP)
11812 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
11813 }
11814
11815 /* 64 bit multiply and add. */
11816 static void
11817 madd64 (sim_cpu *cpu)
11818 {
11819 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11820 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11821 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11822 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11823
11824 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11825 aarch64_get_reg_u64 (cpu, ra, NO_SP)
11826 + aarch64_get_reg_u64 (cpu, rn, NO_SP)
11827 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
11828 }
11829
11830 /* 32 bit multiply and sub. */
11831 static void
11832 msub32 (sim_cpu *cpu)
11833 {
11834 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11835 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11836 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11837 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11838
11839 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11840 aarch64_get_reg_u32 (cpu, ra, NO_SP)
11841 - aarch64_get_reg_u32 (cpu, rn, NO_SP)
11842 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
11843 }
11844
11845 /* 64 bit multiply and sub. */
11846 static void
11847 msub64 (sim_cpu *cpu)
11848 {
11849 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11850 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11851 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11852 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11853
11854 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11855 aarch64_get_reg_u64 (cpu, ra, NO_SP)
11856 - aarch64_get_reg_u64 (cpu, rn, NO_SP)
11857 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
11858 }
11859
11860 /* Signed multiply add long -- source, source2 : 32 bit, source3 : 64 bit. */
11861 static void
11862 smaddl (sim_cpu *cpu)
11863 {
11864 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11865 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11866 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11867 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11868
11869 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
11870 obtain a 64 bit product. */
11871 aarch64_set_reg_s64
11872 (cpu, rd, NO_SP,
11873 aarch64_get_reg_s64 (cpu, ra, NO_SP)
11874 + ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
11875 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
11876 }
11877
11878 /* Signed multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
11879 static void
11880 smsubl (sim_cpu *cpu)
11881 {
11882 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11883 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11884 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11885 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11886
11887 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
11888 obtain a 64 bit product. */
11889 aarch64_set_reg_s64
11890 (cpu, rd, NO_SP,
11891 aarch64_get_reg_s64 (cpu, ra, NO_SP)
11892 - ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
11893 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
11894 }
11895
11896 /* Integer Multiply/Divide. */
11897
11898 /* First some macros and a helper function. */
11899 /* Macros to test or access elements of 64 bit words. */
11900
11901 /* Mask used to access lo 32 bits of 64 bit unsigned int. */
11902 #define LOW_WORD_MASK ((1ULL << 32) - 1)
11903 /* Return the lo 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
11904 #define lowWordToU64(_value_u64) ((_value_u64) & LOW_WORD_MASK)
11905 /* Return the hi 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
11906 #define highWordToU64(_value_u64) ((_value_u64) >> 32)
11907
11908 /* Offset of sign bit in 64 bit signed integger. */
11909 #define SIGN_SHIFT_U64 63
11910 /* The sign bit itself -- also identifies the minimum negative int value. */
11911 #define SIGN_BIT_U64 (1UL << SIGN_SHIFT_U64)
11912 /* Return true if a 64 bit signed int presented as an unsigned int is the
11913 most negative value. */
11914 #define isMinimumU64(_value_u64) ((_value_u64) == SIGN_BIT_U64)
11915 /* Return true (non-zero) if a 64 bit signed int presented as an unsigned
11916 int has its sign bit set to false. */
11917 #define isSignSetU64(_value_u64) ((_value_u64) & SIGN_BIT_U64)
11918 /* Return 1L or -1L according to whether a 64 bit signed int presented as
11919 an unsigned int has its sign bit set or not. */
11920 #define signOfU64(_value_u64) (1L + (((value_u64) >> SIGN_SHIFT_U64) * -2L)
11921 /* Clear the sign bit of a 64 bit signed int presented as an unsigned int. */
11922 #define clearSignU64(_value_u64) ((_value_u64) &= ~SIGN_BIT_U64)
11923
11924 /* Multiply two 64 bit ints and return.
11925 the hi 64 bits of the 128 bit product. */
11926
11927 static uint64_t
11928 mul64hi (uint64_t value1, uint64_t value2)
11929 {
11930 uint64_t resultmid1;
11931 uint64_t result;
11932 uint64_t value1_lo = lowWordToU64 (value1);
11933 uint64_t value1_hi = highWordToU64 (value1) ;
11934 uint64_t value2_lo = lowWordToU64 (value2);
11935 uint64_t value2_hi = highWordToU64 (value2);
11936
11937 /* Cross-multiply and collect results. */
11938
11939 uint64_t xproductlo = value1_lo * value2_lo;
11940 uint64_t xproductmid1 = value1_lo * value2_hi;
11941 uint64_t xproductmid2 = value1_hi * value2_lo;
11942 uint64_t xproducthi = value1_hi * value2_hi;
11943 uint64_t carry = 0;
11944 /* Start accumulating 64 bit results. */
11945 /* Drop bottom half of lowest cross-product. */
11946 uint64_t resultmid = xproductlo >> 32;
11947 /* Add in middle products. */
11948 resultmid = resultmid + xproductmid1;
11949
11950 /* Check for overflow. */
11951 if (resultmid < xproductmid1)
11952 /* Carry over 1 into top cross-product. */
11953 carry++;
11954
11955 resultmid1 = resultmid + xproductmid2;
11956
11957 /* Check for overflow. */
11958 if (resultmid1 < xproductmid2)
11959 /* Carry over 1 into top cross-product. */
11960 carry++;
11961
11962 /* Drop lowest 32 bits of middle cross-product. */
11963 result = resultmid1 >> 32;
11964
11965 /* Add top cross-product plus and any carry. */
11966 result += xproducthi + carry;
11967
11968 return result;
11969 }
11970
11971 /* Signed multiply high, source, source2 :
11972 64 bit, dest <-- high 64-bit of result. */
11973 static void
11974 smulh (sim_cpu *cpu)
11975 {
11976 uint64_t uresult;
11977 int64_t result;
11978 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11979 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11980 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11981 GReg ra = greg (aarch64_get_instr (cpu), 10);
11982 int64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11983 int64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
11984 uint64_t uvalue1;
11985 uint64_t uvalue2;
11986 int64_t signum = 1;
11987
11988 if (ra != R31)
11989 HALT_UNALLOC;
11990
11991 /* Convert to unsigned and use the unsigned mul64hi routine
11992 the fix the sign up afterwards. */
11993 if (value1 < 0)
11994 {
11995 signum *= -1L;
11996 uvalue1 = -value1;
11997 }
11998 else
11999 {
12000 uvalue1 = value1;
12001 }
12002
12003 if (value2 < 0)
12004 {
12005 signum *= -1L;
12006 uvalue2 = -value2;
12007 }
12008 else
12009 {
12010 uvalue2 = value2;
12011 }
12012
12013 uresult = mul64hi (uvalue1, uvalue2);
12014 result = uresult;
12015 result *= signum;
12016
12017 aarch64_set_reg_s64 (cpu, rd, NO_SP, result);
12018 }
12019
12020 /* Unsigned multiply add long -- source, source2 :
12021 32 bit, source3 : 64 bit. */
12022 static void
12023 umaddl (sim_cpu *cpu)
12024 {
12025 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12026 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
12027 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12028 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12029
12030 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12031 obtain a 64 bit product. */
12032 aarch64_set_reg_u64
12033 (cpu, rd, NO_SP,
12034 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12035 + ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12036 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12037 }
12038
12039 /* Unsigned multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12040 static void
12041 umsubl (sim_cpu *cpu)
12042 {
12043 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12044 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
12045 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12046 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12047
12048 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12049 obtain a 64 bit product. */
12050 aarch64_set_reg_u64
12051 (cpu, rd, NO_SP,
12052 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12053 - ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12054 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12055 }
12056
12057 /* Unsigned multiply high, source, source2 :
12058 64 bit, dest <-- high 64-bit of result. */
12059 static void
12060 umulh (sim_cpu *cpu)
12061 {
12062 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12063 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12064 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12065 GReg ra = greg (aarch64_get_instr (cpu), 10);
12066
12067 if (ra != R31)
12068 HALT_UNALLOC;
12069
12070 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12071 mul64hi (aarch64_get_reg_u64 (cpu, rn, NO_SP),
12072 aarch64_get_reg_u64 (cpu, rm, NO_SP)));
12073 }
12074
12075 static void
12076 dexDataProc3Source (sim_cpu *cpu)
12077 {
12078 /* assert instr[28,24] == 11011. */
12079 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit (for rd at least)
12080 instr[30,29] = op54 : 00 ==> ok, ow ==> UNALLOC
12081 instr[23,21] = op31 : 111 ==> UNALLOC, o2 ==> ok
12082 instr[15] = o0 : 0/1 ==> ok
12083 instr[23,21:15] ==> op : 0000 ==> MADD, 0001 ==> MSUB, (32/64 bit)
12084 0010 ==> SMADDL, 0011 ==> SMSUBL, (64 bit only)
12085 0100 ==> SMULH, (64 bit only)
12086 1010 ==> UMADDL, 1011 ==> UNSUBL, (64 bit only)
12087 1100 ==> UMULH (64 bit only)
12088 ow ==> UNALLOC. */
12089
12090 uint32_t dispatch;
12091 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
12092 uint32_t op54 = uimm (aarch64_get_instr (cpu), 30, 29);
12093 uint32_t op31 = uimm (aarch64_get_instr (cpu), 23, 21);
12094 uint32_t o0 = uimm (aarch64_get_instr (cpu), 15, 15);
12095
12096 if (op54 != 0)
12097 HALT_UNALLOC;
12098
12099 if (size == 0)
12100 {
12101 if (op31 != 0)
12102 HALT_UNALLOC;
12103
12104 if (o0 == 0)
12105 madd32 (cpu);
12106 else
12107 msub32 (cpu);
12108 return;
12109 }
12110
12111 dispatch = (op31 << 1) | o0;
12112
12113 switch (dispatch)
12114 {
12115 case 0: madd64 (cpu); return;
12116 case 1: msub64 (cpu); return;
12117 case 2: smaddl (cpu); return;
12118 case 3: smsubl (cpu); return;
12119 case 4: smulh (cpu); return;
12120 case 10: umaddl (cpu); return;
12121 case 11: umsubl (cpu); return;
12122 case 12: umulh (cpu); return;
12123 default: HALT_UNALLOC;
12124 }
12125 }
12126
12127 static void
12128 dexDPReg (sim_cpu *cpu)
12129 {
12130 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12131 assert group == GROUP_DPREG_0101 || group == GROUP_DPREG_1101
12132 bits [28:24:21] of a DPReg are the secondary dispatch vector. */
12133 uint32_t group2 = dispatchDPReg (aarch64_get_instr (cpu));
12134
12135 switch (group2)
12136 {
12137 case DPREG_LOG_000:
12138 case DPREG_LOG_001:
12139 dexLogicalShiftedRegister (cpu); return;
12140
12141 case DPREG_ADDSHF_010:
12142 dexAddSubtractShiftedRegister (cpu); return;
12143
12144 case DPREG_ADDEXT_011:
12145 dexAddSubtractExtendedRegister (cpu); return;
12146
12147 case DPREG_ADDCOND_100:
12148 {
12149 /* This set bundles a variety of different operations. */
12150 /* Check for. */
12151 /* 1) add/sub w carry. */
12152 uint32_t mask1 = 0x1FE00000U;
12153 uint32_t val1 = 0x1A000000U;
12154 /* 2) cond compare register/immediate. */
12155 uint32_t mask2 = 0x1FE00000U;
12156 uint32_t val2 = 0x1A400000U;
12157 /* 3) cond select. */
12158 uint32_t mask3 = 0x1FE00000U;
12159 uint32_t val3 = 0x1A800000U;
12160 /* 4) data proc 1/2 source. */
12161 uint32_t mask4 = 0x1FE00000U;
12162 uint32_t val4 = 0x1AC00000U;
12163
12164 if ((aarch64_get_instr (cpu) & mask1) == val1)
12165 dexAddSubtractWithCarry (cpu);
12166
12167 else if ((aarch64_get_instr (cpu) & mask2) == val2)
12168 CondCompare (cpu);
12169
12170 else if ((aarch64_get_instr (cpu) & mask3) == val3)
12171 dexCondSelect (cpu);
12172
12173 else if ((aarch64_get_instr (cpu) & mask4) == val4)
12174 {
12175 /* Bit 30 is clear for data proc 2 source
12176 and set for data proc 1 source. */
12177 if (aarch64_get_instr (cpu) & (1U << 30))
12178 dexDataProc1Source (cpu);
12179 else
12180 dexDataProc2Source (cpu);
12181 }
12182
12183 else
12184 /* Should not reach here. */
12185 HALT_NYI;
12186
12187 return;
12188 }
12189
12190 case DPREG_3SRC_110:
12191 dexDataProc3Source (cpu); return;
12192
12193 case DPREG_UNALLOC_101:
12194 HALT_UNALLOC;
12195
12196 case DPREG_3SRC_111:
12197 dexDataProc3Source (cpu); return;
12198
12199 default:
12200 /* Should never reach here. */
12201 HALT_NYI;
12202 }
12203 }
12204
12205 /* Unconditional Branch immediate.
12206 Offset is a PC-relative byte offset in the range +/- 128MiB.
12207 The offset is assumed to be raw from the decode i.e. the
12208 simulator is expected to scale them from word offsets to byte. */
12209
12210 /* Unconditional branch. */
12211 static void
12212 buc (sim_cpu *cpu, int32_t offset)
12213 {
12214 aarch64_set_next_PC_by_offset (cpu, offset);
12215 }
12216
12217 static unsigned stack_depth = 0;
12218
12219 /* Unconditional branch and link -- writes return PC to LR. */
12220 static void
12221 bl (sim_cpu *cpu, int32_t offset)
12222 {
12223 aarch64_save_LR (cpu);
12224 aarch64_set_next_PC_by_offset (cpu, offset);
12225
12226 if (TRACE_BRANCH_P (cpu))
12227 {
12228 ++ stack_depth;
12229 TRACE_BRANCH (cpu,
12230 " %*scall %" PRIx64 " [%s]"
12231 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12232 stack_depth, " ", aarch64_get_next_PC (cpu),
12233 aarch64_get_func (aarch64_get_next_PC (cpu)),
12234 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12235 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12236 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12237 );
12238 }
12239 }
12240
12241 /* Unconditional Branch register.
12242 Branch/return address is in source register. */
12243
12244 /* Unconditional branch. */
12245 static void
12246 br (sim_cpu *cpu)
12247 {
12248 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12249 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12250 }
12251
12252 /* Unconditional branch and link -- writes return PC to LR. */
12253 static void
12254 blr (sim_cpu *cpu)
12255 {
12256 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12257
12258 /* The pseudo code in the spec says we update LR before fetching.
12259 the value from the rn. */
12260 aarch64_save_LR (cpu);
12261 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12262
12263 if (TRACE_BRANCH_P (cpu))
12264 {
12265 ++ stack_depth;
12266 TRACE_BRANCH (cpu,
12267 " %*scall %" PRIx64 " [%s]"
12268 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12269 stack_depth, " ", aarch64_get_next_PC (cpu),
12270 aarch64_get_func (aarch64_get_next_PC (cpu)),
12271 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12272 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12273 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12274 );
12275 }
12276 }
12277
12278 /* Return -- assembler will default source to LR this is functionally
12279 equivalent to br but, presumably, unlike br it side effects the
12280 branch predictor. */
12281 static void
12282 ret (sim_cpu *cpu)
12283 {
12284 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12285 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12286
12287 if (TRACE_BRANCH_P (cpu))
12288 {
12289 TRACE_BRANCH (cpu,
12290 " %*sreturn [result: %" PRIx64 "]",
12291 stack_depth, " ", aarch64_get_reg_u64 (cpu, 0, NO_SP));
12292 -- stack_depth;
12293 }
12294 }
12295
12296 /* NOP -- we implement this and call it from the decode in case we
12297 want to intercept it later. */
12298
12299 static void
12300 nop (sim_cpu *cpu)
12301 {
12302 }
12303
12304 /* Data synchronization barrier. */
12305
12306 static void
12307 dsb (sim_cpu *cpu)
12308 {
12309 }
12310
12311 /* Data memory barrier. */
12312
12313 static void
12314 dmb (sim_cpu *cpu)
12315 {
12316 }
12317
12318 /* Instruction synchronization barrier. */
12319
12320 static void
12321 isb (sim_cpu *cpu)
12322 {
12323 }
12324
12325 static void
12326 dexBranchImmediate (sim_cpu *cpu)
12327 {
12328 /* assert instr[30,26] == 00101
12329 instr[31] ==> 0 == B, 1 == BL
12330 instr[25,0] == imm26 branch offset counted in words. */
12331
12332 uint32_t top = uimm (aarch64_get_instr (cpu), 31, 31);
12333 /* We have a 26 byte signed word offset which we need to pass to the
12334 execute routine as a signed byte offset. */
12335 int32_t offset = simm32 (aarch64_get_instr (cpu), 25, 0) << 2;
12336
12337 if (top)
12338 bl (cpu, offset);
12339 else
12340 buc (cpu, offset);
12341 }
12342
12343 /* Control Flow. */
12344
12345 /* Conditional branch
12346
12347 Offset is a PC-relative byte offset in the range +/- 1MiB pos is
12348 a bit position in the range 0 .. 63
12349
12350 cc is a CondCode enum value as pulled out of the decode
12351
12352 N.B. any offset register (source) can only be Xn or Wn. */
12353
12354 static void
12355 bcc (sim_cpu *cpu, int32_t offset, CondCode cc)
12356 {
12357 /* the test returns TRUE if CC is met. */
12358 if (testConditionCode (cpu, cc))
12359 aarch64_set_next_PC_by_offset (cpu, offset);
12360 }
12361
12362 /* 32 bit branch on register non-zero. */
12363 static void
12364 cbnz32 (sim_cpu *cpu, int32_t offset)
12365 {
12366 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12367
12368 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) != 0)
12369 aarch64_set_next_PC_by_offset (cpu, offset);
12370 }
12371
12372 /* 64 bit branch on register zero. */
12373 static void
12374 cbnz (sim_cpu *cpu, int32_t offset)
12375 {
12376 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12377
12378 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) != 0)
12379 aarch64_set_next_PC_by_offset (cpu, offset);
12380 }
12381
12382 /* 32 bit branch on register non-zero. */
12383 static void
12384 cbz32 (sim_cpu *cpu, int32_t offset)
12385 {
12386 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12387
12388 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) == 0)
12389 aarch64_set_next_PC_by_offset (cpu, offset);
12390 }
12391
12392 /* 64 bit branch on register zero. */
12393 static void
12394 cbz (sim_cpu *cpu, int32_t offset)
12395 {
12396 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12397
12398 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) == 0)
12399 aarch64_set_next_PC_by_offset (cpu, offset);
12400 }
12401
12402 /* Branch on register bit test non-zero -- one size fits all. */
12403 static void
12404 tbnz (sim_cpu *cpu, uint32_t pos, int32_t offset)
12405 {
12406 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12407
12408 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) & (1 << pos))
12409 aarch64_set_next_PC_by_offset (cpu, offset);
12410 }
12411
12412 /* branch on register bit test zero -- one size fits all. */
12413 static void
12414 tbz (sim_cpu *cpu, uint32_t pos, int32_t offset)
12415 {
12416 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12417
12418 if (!(aarch64_get_reg_u64 (cpu, rt, NO_SP) & (1 << pos)))
12419 aarch64_set_next_PC_by_offset (cpu, offset);
12420 }
12421
12422 static void
12423 dexCompareBranchImmediate (sim_cpu *cpu)
12424 {
12425 /* instr[30,25] = 01 1010
12426 instr[31] = size : 0 ==> 32, 1 ==> 64
12427 instr[24] = op : 0 ==> CBZ, 1 ==> CBNZ
12428 instr[23,5] = simm19 branch offset counted in words
12429 instr[4,0] = rt */
12430
12431 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
12432 uint32_t op = uimm (aarch64_get_instr (cpu), 24, 24);
12433 int32_t offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
12434
12435 if (size == 0)
12436 {
12437 if (op == 0)
12438 cbz32 (cpu, offset);
12439 else
12440 cbnz32 (cpu, offset);
12441 }
12442 else
12443 {
12444 if (op == 0)
12445 cbz (cpu, offset);
12446 else
12447 cbnz (cpu, offset);
12448 }
12449 }
12450
12451 static void
12452 dexTestBranchImmediate (sim_cpu *cpu)
12453 {
12454 /* instr[31] = b5 : bit 5 of test bit idx
12455 instr[30,25] = 01 1011
12456 instr[24] = op : 0 ==> TBZ, 1 == TBNZ
12457 instr[23,19] = b40 : bits 4 to 0 of test bit idx
12458 instr[18,5] = simm14 : signed offset counted in words
12459 instr[4,0] = uimm5 */
12460
12461 uint32_t pos = ((uimm (aarch64_get_instr (cpu), 31, 31) << 4)
12462 | uimm (aarch64_get_instr (cpu), 23,19));
12463 int32_t offset = simm32 (aarch64_get_instr (cpu), 18, 5) << 2;
12464
12465 NYI_assert (30, 25, 0x1b);
12466
12467 if (uimm (aarch64_get_instr (cpu), 24, 24) == 0)
12468 tbz (cpu, pos, offset);
12469 else
12470 tbnz (cpu, pos, offset);
12471 }
12472
12473 static void
12474 dexCondBranchImmediate (sim_cpu *cpu)
12475 {
12476 /* instr[31,25] = 010 1010
12477 instr[24] = op1; op => 00 ==> B.cond
12478 instr[23,5] = simm19 : signed offset counted in words
12479 instr[4] = op0
12480 instr[3,0] = cond */
12481
12482 int32_t offset;
12483 CondCode cc;
12484 uint32_t op = ((uimm (aarch64_get_instr (cpu), 24, 24) << 1)
12485 | uimm (aarch64_get_instr (cpu), 4, 4));
12486
12487 NYI_assert (31, 25, 0x2a);
12488
12489 if (op != 0)
12490 HALT_UNALLOC;
12491
12492 offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
12493 cc = condcode (aarch64_get_instr (cpu), 0);
12494
12495 bcc (cpu, offset, cc);
12496 }
12497
12498 static void
12499 dexBranchRegister (sim_cpu *cpu)
12500 {
12501 /* instr[31,25] = 110 1011
12502 instr[24,21] = op : 0 ==> BR, 1 => BLR, 2 => RET, 3 => ERET, 4 => DRPS
12503 instr[20,16] = op2 : must be 11111
12504 instr[15,10] = op3 : must be 000000
12505 instr[4,0] = op2 : must be 11111. */
12506
12507 uint32_t op = uimm (aarch64_get_instr (cpu), 24, 21);
12508 uint32_t op2 = uimm (aarch64_get_instr (cpu), 20, 16);
12509 uint32_t op3 = uimm (aarch64_get_instr (cpu), 15, 10);
12510 uint32_t op4 = uimm (aarch64_get_instr (cpu), 4, 0);
12511
12512 NYI_assert (31, 25, 0x6b);
12513
12514 if (op2 != 0x1F || op3 != 0 || op4 != 0)
12515 HALT_UNALLOC;
12516
12517 if (op == 0)
12518 br (cpu);
12519
12520 else if (op == 1)
12521 blr (cpu);
12522
12523 else if (op == 2)
12524 ret (cpu);
12525
12526 else
12527 {
12528 /* ERET and DRPS accept 0b11111 for rn = aarch64_get_instr (cpu)[4,0]. */
12529 /* anything else is unallocated. */
12530 uint32_t rn = greg (aarch64_get_instr (cpu), 0);
12531
12532 if (rn != 0x1f)
12533 HALT_UNALLOC;
12534
12535 if (op == 4 || op == 5)
12536 HALT_NYI;
12537
12538 HALT_UNALLOC;
12539 }
12540 }
12541
12542 /* FIXME: We should get the Angel SWI values from ../../libgloss/aarch64/svc.h
12543 but this may not be available. So instead we define the values we need
12544 here. */
12545 #define AngelSVC_Reason_Open 0x01
12546 #define AngelSVC_Reason_Close 0x02
12547 #define AngelSVC_Reason_Write 0x05
12548 #define AngelSVC_Reason_Read 0x06
12549 #define AngelSVC_Reason_IsTTY 0x09
12550 #define AngelSVC_Reason_Seek 0x0A
12551 #define AngelSVC_Reason_FLen 0x0C
12552 #define AngelSVC_Reason_Remove 0x0E
12553 #define AngelSVC_Reason_Rename 0x0F
12554 #define AngelSVC_Reason_Clock 0x10
12555 #define AngelSVC_Reason_Time 0x11
12556 #define AngelSVC_Reason_System 0x12
12557 #define AngelSVC_Reason_Errno 0x13
12558 #define AngelSVC_Reason_GetCmdLine 0x15
12559 #define AngelSVC_Reason_HeapInfo 0x16
12560 #define AngelSVC_Reason_ReportException 0x18
12561 #define AngelSVC_Reason_Elapsed 0x30
12562
12563
12564 static void
12565 handle_halt (sim_cpu *cpu, uint32_t val)
12566 {
12567 uint64_t result = 0;
12568
12569 if (val != 0xf000)
12570 {
12571 TRACE_SYSCALL (cpu, " HLT [0x%x]", val);
12572 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12573 sim_stopped, SIM_SIGTRAP);
12574 }
12575
12576 /* We have encountered an Angel SVC call. See if we can process it. */
12577 switch (aarch64_get_reg_u32 (cpu, 0, NO_SP))
12578 {
12579 case AngelSVC_Reason_HeapInfo:
12580 {
12581 /* Get the values. */
12582 uint64_t stack_top = aarch64_get_stack_start (cpu);
12583 uint64_t heap_base = aarch64_get_heap_start (cpu);
12584
12585 /* Get the pointer */
12586 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12587 ptr = aarch64_get_mem_u64 (cpu, ptr);
12588
12589 /* Fill in the memory block. */
12590 /* Start addr of heap. */
12591 aarch64_set_mem_u64 (cpu, ptr + 0, heap_base);
12592 /* End addr of heap. */
12593 aarch64_set_mem_u64 (cpu, ptr + 8, stack_top);
12594 /* Lowest stack addr. */
12595 aarch64_set_mem_u64 (cpu, ptr + 16, heap_base);
12596 /* Initial stack addr. */
12597 aarch64_set_mem_u64 (cpu, ptr + 24, stack_top);
12598
12599 TRACE_SYSCALL (cpu, " AngelSVC: Get Heap Info");
12600 }
12601 break;
12602
12603 case AngelSVC_Reason_Open:
12604 {
12605 /* Get the pointer */
12606 /* uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);. */
12607 /* FIXME: For now we just assume that we will only be asked
12608 to open the standard file descriptors. */
12609 static int fd = 0;
12610 result = fd ++;
12611
12612 TRACE_SYSCALL (cpu, " AngelSVC: Open file %d", fd - 1);
12613 }
12614 break;
12615
12616 case AngelSVC_Reason_Close:
12617 {
12618 uint64_t fh = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12619 TRACE_SYSCALL (cpu, " AngelSVC: Close file %d", (int) fh);
12620 result = 0;
12621 }
12622 break;
12623
12624 case AngelSVC_Reason_Errno:
12625 result = 0;
12626 TRACE_SYSCALL (cpu, " AngelSVC: Get Errno");
12627 break;
12628
12629 case AngelSVC_Reason_Clock:
12630 result =
12631 #ifdef CLOCKS_PER_SEC
12632 (CLOCKS_PER_SEC >= 100)
12633 ? (clock () / (CLOCKS_PER_SEC / 100))
12634 : ((clock () * 100) / CLOCKS_PER_SEC)
12635 #else
12636 /* Presume unix... clock() returns microseconds. */
12637 (clock () / 10000)
12638 #endif
12639 ;
12640 TRACE_SYSCALL (cpu, " AngelSVC: Get Clock");
12641 break;
12642
12643 case AngelSVC_Reason_GetCmdLine:
12644 {
12645 /* Get the pointer */
12646 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12647 ptr = aarch64_get_mem_u64 (cpu, ptr);
12648
12649 /* FIXME: No command line for now. */
12650 aarch64_set_mem_u64 (cpu, ptr, 0);
12651 TRACE_SYSCALL (cpu, " AngelSVC: Get Command Line");
12652 }
12653 break;
12654
12655 case AngelSVC_Reason_IsTTY:
12656 result = 1;
12657 TRACE_SYSCALL (cpu, " AngelSVC: IsTTY ?");
12658 break;
12659
12660 case AngelSVC_Reason_Write:
12661 {
12662 /* Get the pointer */
12663 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12664 /* Get the write control block. */
12665 uint64_t fd = aarch64_get_mem_u64 (cpu, ptr);
12666 uint64_t buf = aarch64_get_mem_u64 (cpu, ptr + 8);
12667 uint64_t len = aarch64_get_mem_u64 (cpu, ptr + 16);
12668
12669 TRACE_SYSCALL (cpu, "write of %" PRIx64 " bytes from %"
12670 PRIx64 " on descriptor %" PRIx64,
12671 len, buf, fd);
12672
12673 if (len > 1280)
12674 {
12675 TRACE_SYSCALL (cpu,
12676 " AngelSVC: Write: Suspiciously long write: %ld",
12677 (long) len);
12678 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12679 sim_stopped, SIM_SIGBUS);
12680 }
12681 else if (fd == 1)
12682 {
12683 printf ("%.*s", (int) len, aarch64_get_mem_ptr (cpu, buf));
12684 if (disas)
12685 /* So that the output stays in sync with trace output. */
12686 fflush (stdout);
12687 }
12688 else if (fd == 2)
12689 {
12690 TRACE (cpu, 0, "\n");
12691 sim_io_eprintf (CPU_STATE (cpu), "%.*s",
12692 (int) len, aarch64_get_mem_ptr (cpu, buf));
12693 TRACE (cpu, 0, "\n");
12694 }
12695 else
12696 {
12697 TRACE_SYSCALL (cpu,
12698 " AngelSVC: Write: Unexpected file handle: %d",
12699 (int) fd);
12700 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12701 sim_stopped, SIM_SIGABRT);
12702 }
12703 }
12704 break;
12705
12706 case AngelSVC_Reason_ReportException:
12707 {
12708 /* Get the pointer */
12709 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12710 /*ptr = aarch64_get_mem_u64 (cpu, ptr);. */
12711 uint64_t type = aarch64_get_mem_u64 (cpu, ptr);
12712 uint64_t state = aarch64_get_mem_u64 (cpu, ptr + 8);
12713
12714 TRACE_SYSCALL (cpu,
12715 "Angel Exception: type 0x%" PRIx64 " state %" PRIx64,
12716 type, state);
12717
12718 if (type == 0x20026)
12719 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12720 sim_exited, state);
12721 else
12722 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12723 sim_stopped, SIM_SIGINT);
12724 }
12725 break;
12726
12727 case AngelSVC_Reason_Read:
12728 case AngelSVC_Reason_FLen:
12729 case AngelSVC_Reason_Seek:
12730 case AngelSVC_Reason_Remove:
12731 case AngelSVC_Reason_Time:
12732 case AngelSVC_Reason_System:
12733 case AngelSVC_Reason_Rename:
12734 case AngelSVC_Reason_Elapsed:
12735 default:
12736 TRACE_SYSCALL (cpu, " HLT [Unknown angel %x]",
12737 aarch64_get_reg_u32 (cpu, 0, NO_SP));
12738 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12739 sim_stopped, SIM_SIGTRAP);
12740 }
12741
12742 aarch64_set_reg_u64 (cpu, 0, NO_SP, result);
12743 }
12744
12745 static void
12746 dexExcpnGen (sim_cpu *cpu)
12747 {
12748 /* instr[31:24] = 11010100
12749 instr[23,21] = opc : 000 ==> GEN EXCPN, 001 ==> BRK
12750 010 ==> HLT, 101 ==> DBG GEN EXCPN
12751 instr[20,5] = imm16
12752 instr[4,2] = opc2 000 ==> OK, ow ==> UNALLOC
12753 instr[1,0] = LL : discriminates opc */
12754
12755 uint32_t opc = uimm (aarch64_get_instr (cpu), 23, 21);
12756 uint32_t imm16 = uimm (aarch64_get_instr (cpu), 20, 5);
12757 uint32_t opc2 = uimm (aarch64_get_instr (cpu), 4, 2);
12758 uint32_t LL;
12759
12760 NYI_assert (31, 24, 0xd4);
12761
12762 if (opc2 != 0)
12763 HALT_UNALLOC;
12764
12765 LL = uimm (aarch64_get_instr (cpu), 1, 0);
12766
12767 /* We only implement HLT and BRK for now. */
12768 if (opc == 1 && LL == 0)
12769 {
12770 TRACE_EVENTS (cpu, " BRK [0x%x]", imm16);
12771 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12772 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
12773 }
12774
12775 if (opc == 2 && LL == 0)
12776 handle_halt (cpu, imm16);
12777
12778 else if (opc == 0 || opc == 5)
12779 HALT_NYI;
12780
12781 else
12782 HALT_UNALLOC;
12783 }
12784
12785 /* Stub for accessing system registers.
12786 We implement support for the DCZID register since this is used
12787 by the C library's memset function. */
12788
12789 static uint64_t
12790 system_get (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
12791 unsigned crm, unsigned op2)
12792 {
12793 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 7)
12794 /* DCZID_EL0 - the Data Cache Zero ID register.
12795 We do not support DC ZVA at the moment, so
12796 we return a value with the disable bit set. */
12797 return ((uint64_t) 1) << 4;
12798
12799 HALT_NYI;
12800 }
12801
12802 static void
12803 do_mrs (sim_cpu *cpu)
12804 {
12805 /* instr[31:20] = 1101 01010 0011
12806 instr[19] = op0
12807 instr[18,16] = op1
12808 instr[15,12] = CRn
12809 instr[11,8] = CRm
12810 instr[7,5] = op2
12811 instr[4,0] = Rt */
12812 unsigned sys_op0 = uimm (aarch64_get_instr (cpu), 19, 19) + 2;
12813 unsigned sys_op1 = uimm (aarch64_get_instr (cpu), 18, 16);
12814 unsigned sys_crn = uimm (aarch64_get_instr (cpu), 15, 12);
12815 unsigned sys_crm = uimm (aarch64_get_instr (cpu), 11, 8);
12816 unsigned sys_op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12817 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12818
12819 aarch64_set_reg_u64 (cpu, rt, NO_SP,
12820 system_get (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2));
12821 }
12822
12823 static void
12824 dexSystem (sim_cpu *cpu)
12825 {
12826 /* instr[31:22] = 1101 01010 0
12827 instr[21] = L
12828 instr[20,19] = op0
12829 instr[18,16] = op1
12830 instr[15,12] = CRn
12831 instr[11,8] = CRm
12832 instr[7,5] = op2
12833 instr[4,0] = uimm5 */
12834
12835 /* We are interested in HINT, DSB, DMB and ISB
12836
12837 Hint #0 encodes NOOP (this is the only hint we care about)
12838 L == 0, op0 == 0, op1 = 011, CRn = 0010, Rt = 11111,
12839 CRm op2 != 0000 000 OR CRm op2 == 0000 000 || CRm op > 0000 101
12840
12841 DSB, DMB, ISB are data store barrier, data memory barrier and
12842 instruction store barrier, respectively, where
12843
12844 L == 0, op0 == 0, op1 = 011, CRn = 0011, Rt = 11111,
12845 op2 : DSB ==> 100, DMB ==> 101, ISB ==> 110
12846 CRm<3:2> ==> domain, CRm<1:0> ==> types,
12847 domain : 00 ==> OuterShareable, 01 ==> Nonshareable,
12848 10 ==> InerShareable, 11 ==> FullSystem
12849 types : 01 ==> Reads, 10 ==> Writes,
12850 11 ==> All, 00 ==> All (domain == FullSystem). */
12851
12852 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12853 uint32_t l_op0_op1_crn = uimm (aarch64_get_instr (cpu), 21, 12);
12854
12855 NYI_assert (31, 22, 0x354);
12856
12857 switch (l_op0_op1_crn)
12858 {
12859 case 0x032:
12860 if (rt == 0x1F)
12861 {
12862 /* NOP has CRm != 0000 OR. */
12863 /* (CRm == 0000 AND (op2 == 000 OR op2 > 101)). */
12864 uint32_t crm = uimm (aarch64_get_instr (cpu), 11, 8);
12865 uint32_t op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12866
12867 if (crm != 0 || (op2 == 0 || op2 > 5))
12868 {
12869 /* Actually call nop method so we can reimplement it later. */
12870 nop (cpu);
12871 return;
12872 }
12873 }
12874 HALT_NYI;
12875
12876 case 0x033:
12877 {
12878 uint32_t op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12879
12880 switch (op2)
12881 {
12882 case 2: HALT_NYI;
12883 case 4: dsb (cpu); return;
12884 case 5: dmb (cpu); return;
12885 case 6: isb (cpu); return;
12886 case 7:
12887 default: HALT_UNALLOC;
12888 }
12889 }
12890
12891 case 0x3B0:
12892 /* MRS Wt, sys-reg. */
12893 do_mrs (cpu);
12894 return;
12895
12896 case 0x3B4:
12897 case 0x3BD:
12898 /* MRS Xt, sys-reg. */
12899 do_mrs (cpu);
12900 return;
12901
12902 case 0x0B7:
12903 /* DC <type>, x<n>. */
12904 HALT_NYI;
12905 return;
12906
12907 default:
12908 /* if (uimm (aarch64_get_instr (cpu), 21, 20) == 0x1)
12909 MRS Xt, sys-reg. */
12910 HALT_NYI;
12911 return;
12912 }
12913 }
12914
12915 static void
12916 dexBr (sim_cpu *cpu)
12917 {
12918 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12919 assert group == GROUP_BREXSYS_1010 || group == GROUP_BREXSYS_1011
12920 bits [31,29] of a BrExSys are the secondary dispatch vector. */
12921 uint32_t group2 = dispatchBrExSys (aarch64_get_instr (cpu));
12922
12923 switch (group2)
12924 {
12925 case BR_IMM_000:
12926 return dexBranchImmediate (cpu);
12927
12928 case BR_IMMCMP_001:
12929 /* Compare has bit 25 clear while test has it set. */
12930 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12931 dexCompareBranchImmediate (cpu);
12932 else
12933 dexTestBranchImmediate (cpu);
12934 return;
12935
12936 case BR_IMMCOND_010:
12937 /* This is a conditional branch if bit 25 is clear otherwise
12938 unallocated. */
12939 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12940 dexCondBranchImmediate (cpu);
12941 else
12942 HALT_UNALLOC;
12943 return;
12944
12945 case BR_UNALLOC_011:
12946 HALT_UNALLOC;
12947
12948 case BR_IMM_100:
12949 dexBranchImmediate (cpu);
12950 return;
12951
12952 case BR_IMMCMP_101:
12953 /* Compare has bit 25 clear while test has it set. */
12954 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12955 dexCompareBranchImmediate (cpu);
12956 else
12957 dexTestBranchImmediate (cpu);
12958 return;
12959
12960 case BR_REG_110:
12961 /* Unconditional branch reg has bit 25 set. */
12962 if (uimm (aarch64_get_instr (cpu), 25, 25))
12963 dexBranchRegister (cpu);
12964
12965 /* This includes both Excpn Gen, System and unalloc operations.
12966 We need to decode the Excpn Gen operation BRK so we can plant
12967 debugger entry points.
12968 Excpn Gen operations have aarch64_get_instr (cpu)[24] = 0.
12969 we need to decode at least one of the System operations NOP
12970 which is an alias for HINT #0.
12971 System operations have aarch64_get_instr (cpu)[24,22] = 100. */
12972 else if (uimm (aarch64_get_instr (cpu), 24, 24) == 0)
12973 dexExcpnGen (cpu);
12974
12975 else if (uimm (aarch64_get_instr (cpu), 24, 22) == 4)
12976 dexSystem (cpu);
12977
12978 else
12979 HALT_UNALLOC;
12980
12981 return;
12982
12983 case BR_UNALLOC_111:
12984 HALT_UNALLOC;
12985
12986 default:
12987 /* Should never reach here. */
12988 HALT_NYI;
12989 }
12990 }
12991
12992 static void
12993 aarch64_decode_and_execute (sim_cpu *cpu, uint64_t pc)
12994 {
12995 /* We need to check if gdb wants an in here. */
12996 /* checkBreak (cpu);. */
12997
12998 uint64_t group = dispatchGroup (aarch64_get_instr (cpu));
12999
13000 switch (group)
13001 {
13002 case GROUP_PSEUDO_0000: dexPseudo (cpu); break;
13003 case GROUP_LDST_0100: dexLdSt (cpu); break;
13004 case GROUP_DPREG_0101: dexDPReg (cpu); break;
13005 case GROUP_LDST_0110: dexLdSt (cpu); break;
13006 case GROUP_ADVSIMD_0111: dexAdvSIMD0 (cpu); break;
13007 case GROUP_DPIMM_1000: dexDPImm (cpu); break;
13008 case GROUP_DPIMM_1001: dexDPImm (cpu); break;
13009 case GROUP_BREXSYS_1010: dexBr (cpu); break;
13010 case GROUP_BREXSYS_1011: dexBr (cpu); break;
13011 case GROUP_LDST_1100: dexLdSt (cpu); break;
13012 case GROUP_DPREG_1101: dexDPReg (cpu); break;
13013 case GROUP_LDST_1110: dexLdSt (cpu); break;
13014 case GROUP_ADVSIMD_1111: dexAdvSIMD1 (cpu); break;
13015
13016 case GROUP_UNALLOC_0001:
13017 case GROUP_UNALLOC_0010:
13018 case GROUP_UNALLOC_0011:
13019 HALT_UNALLOC;
13020
13021 default:
13022 /* Should never reach here. */
13023 HALT_NYI;
13024 }
13025 }
13026
13027 static bfd_boolean
13028 aarch64_step (sim_cpu *cpu)
13029 {
13030 uint64_t pc = aarch64_get_PC (cpu);
13031
13032 if (pc == TOP_LEVEL_RETURN_PC)
13033 return FALSE;
13034
13035 aarch64_set_next_PC (cpu, pc + 4);
13036 aarch64_get_instr (cpu) = aarch64_get_mem_u32 (cpu, pc);
13037
13038 if (TRACE_INSN_P (cpu))
13039 {
13040 if (disas)
13041 TRACE_INSN (cpu, " pc = %" PRIx64 " ", pc);
13042 else
13043 TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %x", pc,
13044 aarch64_get_instr (cpu));
13045 }
13046 else if (disas)
13047 sim_io_eprintf (CPU_STATE (cpu), " %" PRIx64 " ", pc);
13048
13049 if (disas)
13050 aarch64_print_insn (CPU_STATE (cpu), pc);
13051
13052 aarch64_decode_and_execute (cpu, pc);
13053
13054 return TRUE;
13055 }
13056
13057 void
13058 aarch64_run (SIM_DESC sd)
13059 {
13060 sim_cpu *cpu = STATE_CPU (sd, 0);
13061
13062 while (aarch64_step (cpu))
13063 aarch64_update_PC (cpu);
13064
13065 sim_engine_halt (sd, NULL, NULL, aarch64_get_PC (cpu),
13066 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13067 }
13068
13069 void
13070 aarch64_init (sim_cpu *cpu, uint64_t pc)
13071 {
13072 uint64_t sp = aarch64_get_stack_start (cpu);
13073
13074 /* Install SP, FP and PC and set LR to -20
13075 so we can detect a top-level return. */
13076 aarch64_set_reg_u64 (cpu, SP, SP_OK, sp);
13077 aarch64_set_reg_u64 (cpu, FP, SP_OK, sp);
13078 aarch64_set_reg_u64 (cpu, LR, SP_OK, TOP_LEVEL_RETURN_PC);
13079 aarch64_set_next_PC (cpu, pc);
13080 aarch64_update_PC (cpu);
13081 aarch64_init_LIT_table ();
13082 }
This page took 0.305616 seconds and 5 git commands to generate.