]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/aarch64/simulator.c
sim: unify min/max macros
[thirdparty/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 static void
4112 do_vec_maxv (sim_cpu *cpu)
4113 {
4114 /* instr[31] = 0
4115 instr[30] = half(0)/full(1)
4116 instr[29] = signed (0)/unsigned(1)
4117 instr[28,24] = 0 1110
4118 instr[23,22] = size: byte(00), half(01), word (10)
4119 instr[21] = 1
4120 instr[20,17] = 1 000
4121 instr[16] = max(0)/min(1)
4122 instr[15,10] = 1010 10
4123 instr[9,5] = V source
4124 instr[4.0] = R dest. */
4125
4126 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4127 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
4128 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4129 unsigned i;
4130
4131 NYI_assert (28, 24, 0x0E);
4132 NYI_assert (21, 21, 1);
4133 NYI_assert (20, 17, 8);
4134 NYI_assert (15, 10, 0x2A);
4135
4136 switch ((uimm (aarch64_get_instr (cpu), 29, 29) << 1)
4137 | uimm (aarch64_get_instr (cpu), 16, 16))
4138 {
4139 case 0: /* SMAXV. */
4140 {
4141 int64_t smax;
4142 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4143 {
4144 case 0:
4145 smax = aarch64_get_vec_s8 (cpu, vs, 0);
4146 for (i = 1; i < (full ? 16 : 8); i++)
4147 smax = max (smax, aarch64_get_vec_s8 (cpu, vs, i));
4148 break;
4149 case 1:
4150 smax = aarch64_get_vec_s16 (cpu, vs, 0);
4151 for (i = 1; i < (full ? 8 : 4); i++)
4152 smax = max (smax, aarch64_get_vec_s16 (cpu, vs, i));
4153 break;
4154 case 2:
4155 smax = aarch64_get_vec_s32 (cpu, vs, 0);
4156 for (i = 1; i < (full ? 4 : 2); i++)
4157 smax = max (smax, aarch64_get_vec_s32 (cpu, vs, i));
4158 break;
4159 default:
4160 case 3:
4161 HALT_UNALLOC;
4162 }
4163 aarch64_set_reg_s64 (cpu, rd, NO_SP, smax);
4164 return;
4165 }
4166
4167 case 1: /* SMINV. */
4168 {
4169 int64_t smin;
4170 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4171 {
4172 case 0:
4173 smin = aarch64_get_vec_s8 (cpu, vs, 0);
4174 for (i = 1; i < (full ? 16 : 8); i++)
4175 smin = min (smin, aarch64_get_vec_s8 (cpu, vs, i));
4176 break;
4177 case 1:
4178 smin = aarch64_get_vec_s16 (cpu, vs, 0);
4179 for (i = 1; i < (full ? 8 : 4); i++)
4180 smin = min (smin, aarch64_get_vec_s16 (cpu, vs, i));
4181 break;
4182 case 2:
4183 smin = aarch64_get_vec_s32 (cpu, vs, 0);
4184 for (i = 1; i < (full ? 4 : 2); i++)
4185 smin = min (smin, aarch64_get_vec_s32 (cpu, vs, i));
4186 break;
4187 default:
4188 case 3:
4189 HALT_UNALLOC;
4190 }
4191 aarch64_set_reg_s64 (cpu, rd, NO_SP, smin);
4192 return;
4193 }
4194
4195 case 2: /* UMAXV. */
4196 {
4197 uint64_t umax;
4198 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4199 {
4200 case 0:
4201 umax = aarch64_get_vec_u8 (cpu, vs, 0);
4202 for (i = 1; i < (full ? 16 : 8); i++)
4203 umax = max (umax, aarch64_get_vec_u8 (cpu, vs, i));
4204 break;
4205 case 1:
4206 umax = aarch64_get_vec_u16 (cpu, vs, 0);
4207 for (i = 1; i < (full ? 8 : 4); i++)
4208 umax = max (umax, aarch64_get_vec_u16 (cpu, vs, i));
4209 break;
4210 case 2:
4211 umax = aarch64_get_vec_u32 (cpu, vs, 0);
4212 for (i = 1; i < (full ? 4 : 2); i++)
4213 umax = max (umax, aarch64_get_vec_u32 (cpu, vs, i));
4214 break;
4215 default:
4216 case 3:
4217 HALT_UNALLOC;
4218 }
4219 aarch64_set_reg_u64 (cpu, rd, NO_SP, umax);
4220 return;
4221 }
4222
4223 case 3: /* UMINV. */
4224 {
4225 uint64_t umin;
4226 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4227 {
4228 case 0:
4229 umin = aarch64_get_vec_u8 (cpu, vs, 0);
4230 for (i = 1; i < (full ? 16 : 8); i++)
4231 umin = min (umin, aarch64_get_vec_u8 (cpu, vs, i));
4232 break;
4233 case 1:
4234 umin = aarch64_get_vec_u16 (cpu, vs, 0);
4235 for (i = 1; i < (full ? 8 : 4); i++)
4236 umin = min (umin, aarch64_get_vec_u16 (cpu, vs, i));
4237 break;
4238 case 2:
4239 umin = aarch64_get_vec_u32 (cpu, vs, 0);
4240 for (i = 1; i < (full ? 4 : 2); i++)
4241 umin = min (umin, aarch64_get_vec_u32 (cpu, vs, i));
4242 break;
4243 default:
4244 case 3:
4245 HALT_UNALLOC;
4246 }
4247 aarch64_set_reg_u64 (cpu, rd, NO_SP, umin);
4248 return;
4249 }
4250
4251 default:
4252 HALT_UNALLOC;
4253 }
4254 }
4255
4256 static void
4257 do_vec_fminmaxV (sim_cpu *cpu)
4258 {
4259 /* instr[31,24] = 0110 1110
4260 instr[23] = max(0)/min(1)
4261 instr[22,14] = 011 0000 11
4262 instr[13,12] = nm(00)/normal(11)
4263 instr[11,10] = 10
4264 instr[9,5] = V source
4265 instr[4.0] = R dest. */
4266
4267 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4268 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
4269 unsigned i;
4270 float res = aarch64_get_vec_float (cpu, vs, 0);
4271
4272 NYI_assert (31, 24, 0x6E);
4273 NYI_assert (22, 14, 0x0C3);
4274 NYI_assert (11, 10, 2);
4275
4276 if (uimm (aarch64_get_instr (cpu), 23, 23))
4277 {
4278 switch (uimm (aarch64_get_instr (cpu), 13, 12))
4279 {
4280 case 0: /* FMNINNMV. */
4281 for (i = 1; i < 4; i++)
4282 res = fminnm (res, aarch64_get_vec_float (cpu, vs, i));
4283 break;
4284
4285 case 3: /* FMINV. */
4286 for (i = 1; i < 4; i++)
4287 res = min (res, aarch64_get_vec_float (cpu, vs, i));
4288 break;
4289
4290 default:
4291 HALT_NYI;
4292 }
4293 }
4294 else
4295 {
4296 switch (uimm (aarch64_get_instr (cpu), 13, 12))
4297 {
4298 case 0: /* FMNAXNMV. */
4299 for (i = 1; i < 4; i++)
4300 res = fmaxnm (res, aarch64_get_vec_float (cpu, vs, i));
4301 break;
4302
4303 case 3: /* FMAXV. */
4304 for (i = 1; i < 4; i++)
4305 res = max (res, aarch64_get_vec_float (cpu, vs, i));
4306 break;
4307
4308 default:
4309 HALT_NYI;
4310 }
4311 }
4312
4313 aarch64_set_FP_float (cpu, rd, res);
4314 }
4315
4316 static void
4317 do_vec_Fminmax (sim_cpu *cpu)
4318 {
4319 /* instr[31] = 0
4320 instr[30] = half(0)/full(1)
4321 instr[29,24] = 00 1110
4322 instr[23] = max(0)/min(1)
4323 instr[22] = float(0)/double(1)
4324 instr[21] = 1
4325 instr[20,16] = Vm
4326 instr[15,14] = 11
4327 instr[13,12] = nm(00)/normal(11)
4328 instr[11,10] = 01
4329 instr[9,5] = Vn
4330 instr[4,0] = Vd. */
4331
4332 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4333 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4334 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4335 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4336 unsigned min = uimm (aarch64_get_instr (cpu), 23, 23);
4337 unsigned i;
4338
4339 NYI_assert (29, 24, 0x0E);
4340 NYI_assert (21, 21, 1);
4341 NYI_assert (15, 14, 3);
4342 NYI_assert (11, 10, 1);
4343
4344 if (uimm (aarch64_get_instr (cpu), 22, 22))
4345 {
4346 double (* func)(double, double);
4347
4348 if (! full)
4349 HALT_NYI;
4350
4351 if (uimm (aarch64_get_instr (cpu), 13, 12) == 0)
4352 func = min ? dminnm : dmaxnm;
4353 else if (uimm (aarch64_get_instr (cpu), 13, 12) == 3)
4354 func = min ? fmin : fmax;
4355 else
4356 HALT_NYI;
4357
4358 for (i = 0; i < 2; i++)
4359 aarch64_set_vec_double (cpu, vd, i,
4360 func (aarch64_get_vec_double (cpu, vn, i),
4361 aarch64_get_vec_double (cpu, vm, i)));
4362 }
4363 else
4364 {
4365 float (* func)(float, float);
4366
4367 if (uimm (aarch64_get_instr (cpu), 13, 12) == 0)
4368 func = min ? fminnm : fmaxnm;
4369 else if (uimm (aarch64_get_instr (cpu), 13, 12) == 3)
4370 func = min ? fminf : fmaxf;
4371 else
4372 HALT_NYI;
4373
4374 for (i = 0; i < (full ? 4 : 2); i++)
4375 aarch64_set_vec_float (cpu, vd, i,
4376 func (aarch64_get_vec_float (cpu, vn, i),
4377 aarch64_get_vec_float (cpu, vm, i)));
4378 }
4379 }
4380
4381 static void
4382 do_vec_SCVTF (sim_cpu *cpu)
4383 {
4384 /* instr[31] = 0
4385 instr[30] = Q
4386 instr[29,23] = 00 1110 0
4387 instr[22] = float(0)/double(1)
4388 instr[21,10] = 10 0001 1101 10
4389 instr[9,5] = Vn
4390 instr[4,0] = Vd. */
4391
4392 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4393 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4394 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4395 unsigned size = uimm (aarch64_get_instr (cpu), 22, 22);
4396 unsigned i;
4397
4398 NYI_assert (29, 23, 0x1C);
4399 NYI_assert (21, 10, 0x876);
4400
4401 if (size)
4402 {
4403 if (! full)
4404 HALT_UNALLOC;
4405
4406 for (i = 0; i < 2; i++)
4407 {
4408 double val = (double) aarch64_get_vec_u64 (cpu, vn, i);
4409 aarch64_set_vec_double (cpu, vd, i, val);
4410 }
4411 }
4412 else
4413 {
4414 for (i = 0; i < (full ? 4 : 2); i++)
4415 {
4416 float val = (float) aarch64_get_vec_u32 (cpu, vn, i);
4417 aarch64_set_vec_float (cpu, vd, i, val);
4418 }
4419 }
4420 }
4421
4422 #define VEC_CMP(SOURCE, CMP) \
4423 do \
4424 { \
4425 switch (size) \
4426 { \
4427 case 0: \
4428 for (i = 0; i < (full ? 16 : 8); i++) \
4429 aarch64_set_vec_u8 (cpu, vd, i, \
4430 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4431 CMP \
4432 aarch64_get_vec_##SOURCE##8 (cpu, vm, i) \
4433 ? -1 : 0); \
4434 return; \
4435 case 1: \
4436 for (i = 0; i < (full ? 8 : 4); i++) \
4437 aarch64_set_vec_u16 (cpu, vd, i, \
4438 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4439 CMP \
4440 aarch64_get_vec_##SOURCE##16 (cpu, vm, i) \
4441 ? -1 : 0); \
4442 return; \
4443 case 2: \
4444 for (i = 0; i < (full ? 4 : 2); i++) \
4445 aarch64_set_vec_u32 (cpu, vd, i, \
4446 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4447 CMP \
4448 aarch64_get_vec_##SOURCE##32 (cpu, vm, i) \
4449 ? -1 : 0); \
4450 return; \
4451 case 3: \
4452 if (! full) \
4453 HALT_UNALLOC; \
4454 for (i = 0; i < 2; i++) \
4455 aarch64_set_vec_u64 (cpu, vd, i, \
4456 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4457 CMP \
4458 aarch64_get_vec_##SOURCE##64 (cpu, vm, i) \
4459 ? -1ULL : 0); \
4460 return; \
4461 default: \
4462 HALT_UNALLOC; \
4463 } \
4464 } \
4465 while (0)
4466
4467 #define VEC_CMP0(SOURCE, CMP) \
4468 do \
4469 { \
4470 switch (size) \
4471 { \
4472 case 0: \
4473 for (i = 0; i < (full ? 16 : 8); i++) \
4474 aarch64_set_vec_u8 (cpu, vd, i, \
4475 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4476 CMP 0 ? -1 : 0); \
4477 return; \
4478 case 1: \
4479 for (i = 0; i < (full ? 8 : 4); i++) \
4480 aarch64_set_vec_u16 (cpu, vd, i, \
4481 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4482 CMP 0 ? -1 : 0); \
4483 return; \
4484 case 2: \
4485 for (i = 0; i < (full ? 4 : 2); i++) \
4486 aarch64_set_vec_u32 (cpu, vd, i, \
4487 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4488 CMP 0 ? -1 : 0); \
4489 return; \
4490 case 3: \
4491 if (! full) \
4492 HALT_UNALLOC; \
4493 for (i = 0; i < 2; i++) \
4494 aarch64_set_vec_u64 (cpu, vd, i, \
4495 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4496 CMP 0 ? -1ULL : 0); \
4497 return; \
4498 default: \
4499 HALT_UNALLOC; \
4500 } \
4501 } \
4502 while (0)
4503
4504 #define VEC_FCMP0(CMP) \
4505 do \
4506 { \
4507 if (vm != 0) \
4508 HALT_NYI; \
4509 if (uimm (aarch64_get_instr (cpu), 22, 22)) \
4510 { \
4511 if (! full) \
4512 HALT_NYI; \
4513 for (i = 0; i < 2; i++) \
4514 aarch64_set_vec_u64 (cpu, vd, i, \
4515 aarch64_get_vec_double (cpu, vn, i) \
4516 CMP 0.0 ? -1 : 0); \
4517 } \
4518 else \
4519 { \
4520 for (i = 0; i < (full ? 4 : 2); i++) \
4521 aarch64_set_vec_u32 (cpu, vd, i, \
4522 aarch64_get_vec_float (cpu, vn, i) \
4523 CMP 0.0 ? -1 : 0); \
4524 } \
4525 return; \
4526 } \
4527 while (0)
4528
4529 #define VEC_FCMP(CMP) \
4530 do \
4531 { \
4532 if (uimm (aarch64_get_instr (cpu), 22, 22)) \
4533 { \
4534 if (! full) \
4535 HALT_NYI; \
4536 for (i = 0; i < 2; i++) \
4537 aarch64_set_vec_u64 (cpu, vd, i, \
4538 aarch64_get_vec_double (cpu, vn, i) \
4539 CMP \
4540 aarch64_get_vec_double (cpu, vm, i) \
4541 ? -1 : 0); \
4542 } \
4543 else \
4544 { \
4545 for (i = 0; i < (full ? 4 : 2); i++) \
4546 aarch64_set_vec_u32 (cpu, vd, i, \
4547 aarch64_get_vec_float (cpu, vn, i) \
4548 CMP \
4549 aarch64_get_vec_float (cpu, vm, i) \
4550 ? -1 : 0); \
4551 } \
4552 return; \
4553 } \
4554 while (0)
4555
4556 static void
4557 do_vec_compare (sim_cpu *cpu)
4558 {
4559 /* instr[31] = 0
4560 instr[30] = half(0)/full(1)
4561 instr[29] = part-of-comparison-type
4562 instr[28,24] = 0 1110
4563 instr[23,22] = size of integer compares: byte(00), half(01), word (10), long (11)
4564 type of float compares: single (-0) / double (-1)
4565 instr[21] = 1
4566 instr[20,16] = Vm or 00000 (compare vs 0)
4567 instr[15,10] = part-of-comparison-type
4568 instr[9,5] = Vn
4569 instr[4.0] = Vd. */
4570
4571 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4572 int size = uimm (aarch64_get_instr (cpu), 23, 22);
4573 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4574 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4575 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4576 unsigned i;
4577
4578 NYI_assert (28, 24, 0x0E);
4579 NYI_assert (21, 21, 1);
4580
4581 if ((uimm (aarch64_get_instr (cpu), 11, 11)
4582 && uimm (aarch64_get_instr (cpu), 14, 14))
4583 || ((uimm (aarch64_get_instr (cpu), 11, 11) == 0
4584 && uimm (aarch64_get_instr (cpu), 10, 10) == 0)))
4585 {
4586 /* A compare vs 0. */
4587 if (vm != 0)
4588 {
4589 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x2A)
4590 do_vec_maxv (cpu);
4591 else if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x32
4592 || uimm (aarch64_get_instr (cpu), 15, 10) == 0x3E)
4593 do_vec_fminmaxV (cpu);
4594 else if (uimm (aarch64_get_instr (cpu), 29, 23) == 0x1C
4595 && uimm (aarch64_get_instr (cpu), 21, 10) == 0x876)
4596 do_vec_SCVTF (cpu);
4597 else
4598 HALT_NYI;
4599 return;
4600 }
4601 }
4602
4603 if (uimm (aarch64_get_instr (cpu), 14, 14))
4604 {
4605 /* A floating point compare. */
4606 unsigned decode = (uimm (aarch64_get_instr (cpu), 29, 29) << 5)
4607 | (uimm (aarch64_get_instr (cpu), 23, 23) << 4)
4608 | uimm (aarch64_get_instr (cpu), 13, 10);
4609
4610 NYI_assert (15, 15, 1);
4611
4612 switch (decode)
4613 {
4614 case /* 0b010010: GT#0 */ 0x12: VEC_FCMP0 (>);
4615 case /* 0b110010: GE#0 */ 0x32: VEC_FCMP0 (>=);
4616 case /* 0b010110: EQ#0 */ 0x16: VEC_FCMP0 (==);
4617 case /* 0b110110: LE#0 */ 0x36: VEC_FCMP0 (<=);
4618 case /* 0b011010: LT#0 */ 0x1A: VEC_FCMP0 (<);
4619 case /* 0b111001: GT */ 0x39: VEC_FCMP (>);
4620 case /* 0b101001: GE */ 0x29: VEC_FCMP (>=);
4621 case /* 0b001001: EQ */ 0x09: VEC_FCMP (==);
4622
4623 default:
4624 HALT_NYI;
4625 }
4626 }
4627 else
4628 {
4629 unsigned decode = (uimm (aarch64_get_instr (cpu), 29, 29) << 6)
4630 | uimm (aarch64_get_instr (cpu), 15, 10);
4631
4632 switch (decode)
4633 {
4634 case 0x0D: /* 0001101 GT */ VEC_CMP (s, > );
4635 case 0x0F: /* 0001111 GE */ VEC_CMP (s, >= );
4636 case 0x22: /* 0100010 GT #0 */ VEC_CMP0 (s, > );
4637 case 0x26: /* 0100110 EQ #0 */ VEC_CMP0 (s, == );
4638 case 0x2A: /* 0101010 LT #0 */ VEC_CMP0 (s, < );
4639 case 0x4D: /* 1001101 HI */ VEC_CMP (u, > );
4640 case 0x4F: /* 1001111 HS */ VEC_CMP (u, >= );
4641 case 0x62: /* 1100010 GE #0 */ VEC_CMP0 (s, >= );
4642 case 0x63: /* 1100011 EQ */ VEC_CMP (u, == );
4643 case 0x66: /* 1100110 LE #0 */ VEC_CMP0 (s, <= );
4644 default:
4645 if (vm == 0)
4646 HALT_NYI;
4647 do_vec_maxv (cpu);
4648 }
4649 }
4650 }
4651
4652 static void
4653 do_vec_SSHL (sim_cpu *cpu)
4654 {
4655 /* instr[31] = 0
4656 instr[30] = first part (0)/ second part (1)
4657 instr[29,24] = 00 1110
4658 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4659 instr[21] = 1
4660 instr[20,16] = Vm
4661 instr[15,10] = 0100 01
4662 instr[9,5] = Vn
4663 instr[4,0] = Vd. */
4664
4665 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4666 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4667 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4668 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4669 unsigned i;
4670
4671 NYI_assert (29, 24, 0x0E);
4672 NYI_assert (21, 21, 1);
4673 NYI_assert (15, 10, 0x11);
4674
4675 /* FIXME: What is a signed shift left in this context ?. */
4676
4677 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4678 {
4679 case 0:
4680 for (i = 0; i < (full ? 16 : 8); i++)
4681 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4682 << aarch64_get_vec_s8 (cpu, vm, i));
4683 return;
4684
4685 case 1:
4686 for (i = 0; i < (full ? 8 : 4); i++)
4687 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4688 << aarch64_get_vec_s16 (cpu, vm, i));
4689 return;
4690
4691 case 2:
4692 for (i = 0; i < (full ? 4 : 2); i++)
4693 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4694 << aarch64_get_vec_s32 (cpu, vm, i));
4695 return;
4696
4697 case 3:
4698 if (! full)
4699 HALT_UNALLOC;
4700 for (i = 0; i < 2; i++)
4701 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4702 << aarch64_get_vec_s64 (cpu, vm, i));
4703 return;
4704
4705 default:
4706 HALT_NYI;
4707 }
4708 }
4709
4710 static void
4711 do_vec_USHL (sim_cpu *cpu)
4712 {
4713 /* instr[31] = 0
4714 instr[30] = first part (0)/ second part (1)
4715 instr[29,24] = 10 1110
4716 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4717 instr[21] = 1
4718 instr[20,16] = Vm
4719 instr[15,10] = 0100 01
4720 instr[9,5] = Vn
4721 instr[4,0] = Vd */
4722
4723 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4724 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4725 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4726 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4727 unsigned i;
4728
4729 NYI_assert (29, 24, 0x2E);
4730 NYI_assert (15, 10, 0x11);
4731
4732 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4733 {
4734 case 0:
4735 for (i = 0; i < (full ? 16 : 8); i++)
4736 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4737 << aarch64_get_vec_u8 (cpu, vm, i));
4738 return;
4739
4740 case 1:
4741 for (i = 0; i < (full ? 8 : 4); i++)
4742 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4743 << aarch64_get_vec_u16 (cpu, vm, i));
4744 return;
4745
4746 case 2:
4747 for (i = 0; i < (full ? 4 : 2); i++)
4748 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4749 << aarch64_get_vec_u32 (cpu, vm, i));
4750 return;
4751
4752 case 3:
4753 if (! full)
4754 HALT_UNALLOC;
4755 for (i = 0; i < 2; i++)
4756 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4757 << aarch64_get_vec_u64 (cpu, vm, i));
4758 return;
4759
4760 default:
4761 HALT_NYI;
4762 }
4763 }
4764
4765 static void
4766 do_vec_FMLA (sim_cpu *cpu)
4767 {
4768 /* instr[31] = 0
4769 instr[30] = full/half selector
4770 instr[29,23] = 0011100
4771 instr[22] = size: 0=>float, 1=>double
4772 instr[21] = 1
4773 instr[20,16] = Vn
4774 instr[15,10] = 1100 11
4775 instr[9,5] = Vm
4776 instr[4.0] = Vd. */
4777
4778 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4779 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4780 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4781 unsigned i;
4782 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4783
4784 NYI_assert (29, 23, 0x1C);
4785 NYI_assert (21, 21, 1);
4786 NYI_assert (15, 10, 0x33);
4787
4788 if (uimm (aarch64_get_instr (cpu), 22, 22))
4789 {
4790 if (! full)
4791 HALT_UNALLOC;
4792 for (i = 0; i < 2; i++)
4793 aarch64_set_vec_double (cpu, vd, i,
4794 aarch64_get_vec_double (cpu, vn, i) *
4795 aarch64_get_vec_double (cpu, vm, i) +
4796 aarch64_get_vec_double (cpu, vd, i));
4797 }
4798 else
4799 {
4800 for (i = 0; i < (full ? 4 : 2); i++)
4801 aarch64_set_vec_float (cpu, vd, i,
4802 aarch64_get_vec_float (cpu, vn, i) *
4803 aarch64_get_vec_float (cpu, vm, i) +
4804 aarch64_get_vec_float (cpu, vd, i));
4805 }
4806 }
4807
4808 static void
4809 do_vec_max (sim_cpu *cpu)
4810 {
4811 /* instr[31] = 0
4812 instr[30] = full/half selector
4813 instr[29] = SMAX (0) / UMAX (1)
4814 instr[28,24] = 0 1110
4815 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4816 instr[21] = 1
4817 instr[20,16] = Vn
4818 instr[15,10] = 0110 01
4819 instr[9,5] = Vm
4820 instr[4.0] = Vd. */
4821
4822 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4823 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4824 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4825 unsigned i;
4826 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4827
4828 NYI_assert (28, 24, 0x0E);
4829 NYI_assert (21, 21, 1);
4830 NYI_assert (15, 10, 0x19);
4831
4832 if (uimm (aarch64_get_instr (cpu), 29, 29))
4833 {
4834 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4835 {
4836 case 0:
4837 for (i = 0; i < (full ? 16 : 8); i++)
4838 aarch64_set_vec_u8 (cpu, vd, i,
4839 aarch64_get_vec_u8 (cpu, vn, i)
4840 > aarch64_get_vec_u8 (cpu, vm, i)
4841 ? aarch64_get_vec_u8 (cpu, vn, i)
4842 : aarch64_get_vec_u8 (cpu, vm, i));
4843 return;
4844
4845 case 1:
4846 for (i = 0; i < (full ? 8 : 4); i++)
4847 aarch64_set_vec_u16 (cpu, vd, i,
4848 aarch64_get_vec_u16 (cpu, vn, i)
4849 > aarch64_get_vec_u16 (cpu, vm, i)
4850 ? aarch64_get_vec_u16 (cpu, vn, i)
4851 : aarch64_get_vec_u16 (cpu, vm, i));
4852 return;
4853
4854 case 2:
4855 for (i = 0; i < (full ? 4 : 2); i++)
4856 aarch64_set_vec_u32 (cpu, vd, i,
4857 aarch64_get_vec_u32 (cpu, vn, i)
4858 > aarch64_get_vec_u32 (cpu, vm, i)
4859 ? aarch64_get_vec_u32 (cpu, vn, i)
4860 : aarch64_get_vec_u32 (cpu, vm, i));
4861 return;
4862
4863 default:
4864 case 3:
4865 HALT_UNALLOC;
4866 }
4867 }
4868 else
4869 {
4870 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4871 {
4872 case 0:
4873 for (i = 0; i < (full ? 16 : 8); i++)
4874 aarch64_set_vec_s8 (cpu, vd, i,
4875 aarch64_get_vec_s8 (cpu, vn, i)
4876 > aarch64_get_vec_s8 (cpu, vm, i)
4877 ? aarch64_get_vec_s8 (cpu, vn, i)
4878 : aarch64_get_vec_s8 (cpu, vm, i));
4879 return;
4880
4881 case 1:
4882 for (i = 0; i < (full ? 8 : 4); i++)
4883 aarch64_set_vec_s16 (cpu, vd, i,
4884 aarch64_get_vec_s16 (cpu, vn, i)
4885 > aarch64_get_vec_s16 (cpu, vm, i)
4886 ? aarch64_get_vec_s16 (cpu, vn, i)
4887 : aarch64_get_vec_s16 (cpu, vm, i));
4888 return;
4889
4890 case 2:
4891 for (i = 0; i < (full ? 4 : 2); i++)
4892 aarch64_set_vec_s32 (cpu, vd, i,
4893 aarch64_get_vec_s32 (cpu, vn, i)
4894 > aarch64_get_vec_s32 (cpu, vm, i)
4895 ? aarch64_get_vec_s32 (cpu, vn, i)
4896 : aarch64_get_vec_s32 (cpu, vm, i));
4897 return;
4898
4899 default:
4900 case 3:
4901 HALT_UNALLOC;
4902 }
4903 }
4904 }
4905
4906 static void
4907 do_vec_min (sim_cpu *cpu)
4908 {
4909 /* instr[31] = 0
4910 instr[30] = full/half selector
4911 instr[29] = SMIN (0) / UMIN (1)
4912 instr[28,24] = 0 1110
4913 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4914 instr[21] = 1
4915 instr[20,16] = Vn
4916 instr[15,10] = 0110 11
4917 instr[9,5] = Vm
4918 instr[4.0] = Vd. */
4919
4920 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4921 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4922 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4923 unsigned i;
4924 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4925
4926 NYI_assert (28, 24, 0x0E);
4927 NYI_assert (21, 21, 1);
4928 NYI_assert (15, 10, 0x1B);
4929
4930 if (uimm (aarch64_get_instr (cpu), 29, 29))
4931 {
4932 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4933 {
4934 case 0:
4935 for (i = 0; i < (full ? 16 : 8); i++)
4936 aarch64_set_vec_u8 (cpu, vd, i,
4937 aarch64_get_vec_u8 (cpu, vn, i)
4938 < aarch64_get_vec_u8 (cpu, vm, i)
4939 ? aarch64_get_vec_u8 (cpu, vn, i)
4940 : aarch64_get_vec_u8 (cpu, vm, i));
4941 return;
4942
4943 case 1:
4944 for (i = 0; i < (full ? 8 : 4); i++)
4945 aarch64_set_vec_u16 (cpu, vd, i,
4946 aarch64_get_vec_u16 (cpu, vn, i)
4947 < aarch64_get_vec_u16 (cpu, vm, i)
4948 ? aarch64_get_vec_u16 (cpu, vn, i)
4949 : aarch64_get_vec_u16 (cpu, vm, i));
4950 return;
4951
4952 case 2:
4953 for (i = 0; i < (full ? 4 : 2); i++)
4954 aarch64_set_vec_u32 (cpu, vd, i,
4955 aarch64_get_vec_u32 (cpu, vn, i)
4956 < aarch64_get_vec_u32 (cpu, vm, i)
4957 ? aarch64_get_vec_u32 (cpu, vn, i)
4958 : aarch64_get_vec_u32 (cpu, vm, i));
4959 return;
4960
4961 default:
4962 case 3:
4963 HALT_UNALLOC;
4964 }
4965 }
4966 else
4967 {
4968 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4969 {
4970 case 0:
4971 for (i = 0; i < (full ? 16 : 8); i++)
4972 aarch64_set_vec_s8 (cpu, vd, i,
4973 aarch64_get_vec_s8 (cpu, vn, i)
4974 < aarch64_get_vec_s8 (cpu, vm, i)
4975 ? aarch64_get_vec_s8 (cpu, vn, i)
4976 : aarch64_get_vec_s8 (cpu, vm, i));
4977 return;
4978
4979 case 1:
4980 for (i = 0; i < (full ? 8 : 4); i++)
4981 aarch64_set_vec_s16 (cpu, vd, i,
4982 aarch64_get_vec_s16 (cpu, vn, i)
4983 < aarch64_get_vec_s16 (cpu, vm, i)
4984 ? aarch64_get_vec_s16 (cpu, vn, i)
4985 : aarch64_get_vec_s16 (cpu, vm, i));
4986 return;
4987
4988 case 2:
4989 for (i = 0; i < (full ? 4 : 2); i++)
4990 aarch64_set_vec_s32 (cpu, vd, i,
4991 aarch64_get_vec_s32 (cpu, vn, i)
4992 < aarch64_get_vec_s32 (cpu, vm, i)
4993 ? aarch64_get_vec_s32 (cpu, vn, i)
4994 : aarch64_get_vec_s32 (cpu, vm, i));
4995 return;
4996
4997 default:
4998 case 3:
4999 HALT_UNALLOC;
5000 }
5001 }
5002 }
5003
5004 static void
5005 do_vec_sub_long (sim_cpu *cpu)
5006 {
5007 /* instr[31] = 0
5008 instr[30] = lower (0) / upper (1)
5009 instr[29] = signed (0) / unsigned (1)
5010 instr[28,24] = 0 1110
5011 instr[23,22] = size: bytes (00), half (01), word (10)
5012 instr[21] = 1
5013 insrt[20,16] = Vm
5014 instr[15,10] = 0010 00
5015 instr[9,5] = Vn
5016 instr[4,0] = V dest. */
5017
5018 unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
5019 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5020 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5021 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5022 unsigned bias = 0;
5023 unsigned i;
5024
5025 NYI_assert (28, 24, 0x0E);
5026 NYI_assert (21, 21, 1);
5027 NYI_assert (15, 10, 0x08);
5028
5029 if (size == 3)
5030 HALT_UNALLOC;
5031
5032 switch (uimm (aarch64_get_instr (cpu), 30, 29))
5033 {
5034 case 2: /* SSUBL2. */
5035 bias = 2;
5036 case 0: /* SSUBL. */
5037 switch (size)
5038 {
5039 case 0:
5040 bias *= 3;
5041 for (i = 0; i < 8; i++)
5042 aarch64_set_vec_s16 (cpu, vd, i,
5043 aarch64_get_vec_s8 (cpu, vn, i + bias)
5044 - aarch64_get_vec_s8 (cpu, vm, i + bias));
5045 break;
5046
5047 case 1:
5048 bias *= 2;
5049 for (i = 0; i < 4; i++)
5050 aarch64_set_vec_s32 (cpu, vd, i,
5051 aarch64_get_vec_s16 (cpu, vn, i + bias)
5052 - aarch64_get_vec_s16 (cpu, vm, i + bias));
5053 break;
5054
5055 case 2:
5056 for (i = 0; i < 2; i++)
5057 aarch64_set_vec_s64 (cpu, vd, i,
5058 aarch64_get_vec_s32 (cpu, vn, i + bias)
5059 - aarch64_get_vec_s32 (cpu, vm, i + bias));
5060 break;
5061
5062 default:
5063 HALT_UNALLOC;
5064 }
5065 break;
5066
5067 case 3: /* USUBL2. */
5068 bias = 2;
5069 case 1: /* USUBL. */
5070 switch (size)
5071 {
5072 case 0:
5073 bias *= 3;
5074 for (i = 0; i < 8; i++)
5075 aarch64_set_vec_u16 (cpu, vd, i,
5076 aarch64_get_vec_u8 (cpu, vn, i + bias)
5077 - aarch64_get_vec_u8 (cpu, vm, i + bias));
5078 break;
5079
5080 case 1:
5081 bias *= 2;
5082 for (i = 0; i < 4; i++)
5083 aarch64_set_vec_u32 (cpu, vd, i,
5084 aarch64_get_vec_u16 (cpu, vn, i + bias)
5085 - aarch64_get_vec_u16 (cpu, vm, i + bias));
5086 break;
5087
5088 case 2:
5089 for (i = 0; i < 2; i++)
5090 aarch64_set_vec_u64 (cpu, vd, i,
5091 aarch64_get_vec_u32 (cpu, vn, i + bias)
5092 - aarch64_get_vec_u32 (cpu, vm, i + bias));
5093 break;
5094
5095 default:
5096 HALT_UNALLOC;
5097 }
5098 break;
5099 }
5100 }
5101
5102 #define DO_ADDP(FN) \
5103 do \
5104 { \
5105 for (i = 0; i < range; i++) \
5106 { \
5107 aarch64_set_vec_##FN (cpu, vd, i, \
5108 aarch64_get_vec_##FN (cpu, vn, i * 2) \
5109 + aarch64_get_vec_##FN (cpu, vn, i * 2 + 1)); \
5110 aarch64_set_vec_##FN (cpu, vd, i + range, \
5111 aarch64_get_vec_##FN (cpu, vm, i * 2) \
5112 + aarch64_get_vec_##FN (cpu, vm, i * 2 + 1)); \
5113 } \
5114 } \
5115 while (0)
5116
5117 static void
5118 do_vec_ADDP (sim_cpu *cpu)
5119 {
5120 /* instr[31] = 0
5121 instr[30] = half(0)/full(1)
5122 instr[29,24] = 00 1110
5123 instr[23,22] = size: bytes (00), half (01), word (10), long (11)
5124 instr[21] = 1
5125 insrt[20,16] = Vm
5126 instr[15,10] = 1011 11
5127 instr[9,5] = Vn
5128 instr[4,0] = V dest. */
5129
5130 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5131 unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
5132 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5133 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5134 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5135 unsigned i, range;
5136
5137 NYI_assert (29, 24, 0x0E);
5138 NYI_assert (21, 21, 1);
5139 NYI_assert (15, 10, 0x2F);
5140
5141 switch (size)
5142 {
5143 case 0:
5144 range = full ? 8 : 4;
5145 DO_ADDP (u8);
5146 return;
5147
5148 case 1:
5149 range = full ? 4 : 2;
5150 DO_ADDP (u16);
5151 return;
5152
5153 case 2:
5154 range = full ? 2 : 1;
5155 DO_ADDP (u32);
5156 return;
5157
5158 case 3:
5159 if (! full)
5160 HALT_UNALLOC;
5161 range = 1;
5162 DO_ADDP (u64);
5163 return;
5164
5165 default:
5166 HALT_NYI;
5167 }
5168 }
5169
5170 static void
5171 do_vec_UMOV (sim_cpu *cpu)
5172 {
5173 /* instr[31] = 0
5174 instr[30] = 32-bit(0)/64-bit(1)
5175 instr[29,21] = 00 1110 000
5176 insrt[20,16] = size & index
5177 instr[15,10] = 0011 11
5178 instr[9,5] = V source
5179 instr[4,0] = R dest. */
5180
5181 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5182 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
5183 unsigned index;
5184
5185 NYI_assert (29, 21, 0x070);
5186 NYI_assert (15, 10, 0x0F);
5187
5188 if (uimm (aarch64_get_instr (cpu), 16, 16))
5189 {
5190 /* Byte transfer. */
5191 index = uimm (aarch64_get_instr (cpu), 20, 17);
5192 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5193 aarch64_get_vec_u8 (cpu, vs, index));
5194 }
5195 else if (uimm (aarch64_get_instr (cpu), 17, 17))
5196 {
5197 index = uimm (aarch64_get_instr (cpu), 20, 18);
5198 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5199 aarch64_get_vec_u16 (cpu, vs, index));
5200 }
5201 else if (uimm (aarch64_get_instr (cpu), 18, 18))
5202 {
5203 index = uimm (aarch64_get_instr (cpu), 20, 19);
5204 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5205 aarch64_get_vec_u32 (cpu, vs, index));
5206 }
5207 else
5208 {
5209 if (uimm (aarch64_get_instr (cpu), 30, 30) != 1)
5210 HALT_UNALLOC;
5211
5212 index = uimm (aarch64_get_instr (cpu), 20, 20);
5213 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5214 aarch64_get_vec_u64 (cpu, vs, index));
5215 }
5216 }
5217
5218 static void
5219 do_vec_FABS (sim_cpu *cpu)
5220 {
5221 /* instr[31] = 0
5222 instr[30] = half(0)/full(1)
5223 instr[29,23] = 00 1110 1
5224 instr[22] = float(0)/double(1)
5225 instr[21,16] = 10 0000
5226 instr[15,10] = 1111 10
5227 instr[9,5] = Vn
5228 instr[4,0] = Vd. */
5229
5230 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5231 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5232 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5233 unsigned i;
5234
5235 NYI_assert (29, 23, 0x1D);
5236 NYI_assert (21, 10, 0x83E);
5237
5238 if (uimm (aarch64_get_instr (cpu), 22, 22))
5239 {
5240 if (! full)
5241 HALT_NYI;
5242
5243 for (i = 0; i < 2; i++)
5244 aarch64_set_vec_double (cpu, vd, i,
5245 fabs (aarch64_get_vec_double (cpu, vn, i)));
5246 }
5247 else
5248 {
5249 for (i = 0; i < (full ? 4 : 2); i++)
5250 aarch64_set_vec_float (cpu, vd, i,
5251 fabsf (aarch64_get_vec_float (cpu, vn, i)));
5252 }
5253 }
5254
5255 static void
5256 do_vec_FCVTZS (sim_cpu *cpu)
5257 {
5258 /* instr[31] = 0
5259 instr[30] = half (0) / all (1)
5260 instr[29,23] = 00 1110 1
5261 instr[22] = single (0) / double (1)
5262 instr[21,10] = 10 0001 1011 10
5263 instr[9,5] = Rn
5264 instr[4,0] = Rd. */
5265
5266 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
5267 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
5268 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5269 unsigned i;
5270
5271 NYI_assert (31, 31, 0);
5272 NYI_assert (29, 23, 0x1D);
5273 NYI_assert (21, 10, 0x86E);
5274
5275 if (uimm (aarch64_get_instr (cpu), 22, 22))
5276 {
5277 if (! full)
5278 HALT_UNALLOC;
5279
5280 for (i = 0; i < 2; i++)
5281 aarch64_set_vec_s64 (cpu, rd, i,
5282 (int64_t) aarch64_get_vec_double (cpu, rn, i));
5283 }
5284 else
5285 for (i = 0; i < (full ? 4 : 2); i++)
5286 aarch64_set_vec_s32 (cpu, rd, i,
5287 (int32_t) aarch64_get_vec_float (cpu, rn, i));
5288 }
5289
5290 static void
5291 do_vec_op1 (sim_cpu *cpu)
5292 {
5293 /* instr[31] = 0
5294 instr[30] = half/full
5295 instr[29,24] = 00 1110
5296 instr[23,21] = ???
5297 instr[20,16] = Vm
5298 instr[15,10] = sub-opcode
5299 instr[9,5] = Vn
5300 instr[4,0] = Vd */
5301 NYI_assert (29, 24, 0x0E);
5302
5303 if (uimm (aarch64_get_instr (cpu), 21, 21) == 0)
5304 {
5305 if (uimm (aarch64_get_instr (cpu), 23, 22) == 0)
5306 {
5307 if (uimm (aarch64_get_instr (cpu), 30, 30) == 1
5308 && uimm (aarch64_get_instr (cpu), 17, 14) == 0
5309 && uimm (aarch64_get_instr (cpu), 12, 10) == 7)
5310 return do_vec_ins_2 (cpu);
5311
5312 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5313 {
5314 case 0x01: do_vec_DUP_vector_into_vector (cpu); return;
5315 case 0x03: do_vec_DUP_scalar_into_vector (cpu); return;
5316 case 0x07: do_vec_INS (cpu); return;
5317 case 0x0A: do_vec_TRN (cpu); return;
5318
5319 case 0x0F:
5320 if (uimm (aarch64_get_instr (cpu), 17, 16) == 0)
5321 {
5322 do_vec_MOV_into_scalar (cpu);
5323 return;
5324 }
5325 break;
5326
5327 case 0x00:
5328 case 0x08:
5329 case 0x10:
5330 case 0x18:
5331 do_vec_TBL (cpu); return;
5332
5333 case 0x06:
5334 case 0x16:
5335 do_vec_UZP (cpu); return;
5336
5337 case 0x0E:
5338 case 0x1E:
5339 do_vec_ZIP (cpu); return;
5340
5341 default:
5342 HALT_NYI;
5343 }
5344 }
5345
5346 switch (uimm (aarch64_get_instr (cpu), 13, 10))
5347 {
5348 case 0x6: do_vec_UZP (cpu); return;
5349 case 0xE: do_vec_ZIP (cpu); return;
5350 case 0xA: do_vec_TRN (cpu); return;
5351 case 0xF: do_vec_UMOV (cpu); return;
5352 default: HALT_NYI;
5353 }
5354 }
5355
5356 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5357 {
5358 case 0x07:
5359 switch (uimm (aarch64_get_instr (cpu), 23, 21))
5360 {
5361 case 1: do_vec_AND (cpu); return;
5362 case 3: do_vec_BIC (cpu); return;
5363 case 5: do_vec_ORR (cpu); return;
5364 case 7: do_vec_ORN (cpu); return;
5365 default: HALT_NYI;
5366 }
5367
5368 case 0x08: do_vec_sub_long (cpu); return;
5369 case 0x0a: do_vec_XTN (cpu); return;
5370 case 0x11: do_vec_SSHL (cpu); return;
5371 case 0x19: do_vec_max (cpu); return;
5372 case 0x1B: do_vec_min (cpu); return;
5373 case 0x21: do_vec_add (cpu); return;
5374 case 0x25: do_vec_MLA (cpu); return;
5375 case 0x27: do_vec_mul (cpu); return;
5376 case 0x2F: do_vec_ADDP (cpu); return;
5377 case 0x30: do_vec_mull (cpu); return;
5378 case 0x33: do_vec_FMLA (cpu); return;
5379 case 0x35: do_vec_fadd (cpu); return;
5380
5381 case 0x2E:
5382 switch (uimm (aarch64_get_instr (cpu), 20, 16))
5383 {
5384 case 0x00: do_vec_ABS (cpu); return;
5385 case 0x01: do_vec_FCVTZS (cpu); return;
5386 case 0x11: do_vec_ADDV (cpu); return;
5387 default: HALT_NYI;
5388 }
5389
5390 case 0x31:
5391 case 0x3B:
5392 do_vec_Fminmax (cpu); return;
5393
5394 case 0x0D:
5395 case 0x0F:
5396 case 0x22:
5397 case 0x23:
5398 case 0x26:
5399 case 0x2A:
5400 case 0x32:
5401 case 0x36:
5402 case 0x39:
5403 case 0x3A:
5404 do_vec_compare (cpu); return;
5405
5406 case 0x3E:
5407 do_vec_FABS (cpu); return;
5408
5409 default:
5410 HALT_NYI;
5411 }
5412 }
5413
5414 static void
5415 do_vec_xtl (sim_cpu *cpu)
5416 {
5417 /* instr[31] = 0
5418 instr[30,29] = SXTL (00), UXTL (01), SXTL2 (10), UXTL2 (11)
5419 instr[28,22] = 0 1111 00
5420 instr[21,16] = size & shift (USHLL, SSHLL, USHLL2, SSHLL2)
5421 instr[15,10] = 1010 01
5422 instr[9,5] = V source
5423 instr[4,0] = V dest. */
5424
5425 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5426 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5427 unsigned i, shift, bias = 0;
5428
5429 NYI_assert (28, 22, 0x3C);
5430 NYI_assert (15, 10, 0x29);
5431
5432 switch (uimm (aarch64_get_instr (cpu), 30, 29))
5433 {
5434 case 2: /* SXTL2, SSHLL2. */
5435 bias = 2;
5436 case 0: /* SXTL, SSHLL. */
5437 if (uimm (aarch64_get_instr (cpu), 21, 21))
5438 {
5439 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5440 aarch64_set_vec_s64
5441 (cpu, vd, 0, aarch64_get_vec_s32 (cpu, vs, bias) << shift);
5442 aarch64_set_vec_s64
5443 (cpu, vd, 1, aarch64_get_vec_s32 (cpu, vs, bias + 1) << shift);
5444 }
5445 else if (uimm (aarch64_get_instr (cpu), 20, 20))
5446 {
5447 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5448 bias *= 2;
5449 for (i = 0; i < 4; i++)
5450 aarch64_set_vec_s32
5451 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vs, i + bias) << shift);
5452 }
5453 else
5454 {
5455 NYI_assert (19, 19, 1);
5456
5457 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5458 bias *= 3;
5459 for (i = 0; i < 8; i++)
5460 aarch64_set_vec_s16
5461 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vs, i + bias) << shift);
5462 }
5463 return;
5464
5465 case 3: /* UXTL2, USHLL2. */
5466 bias = 2;
5467 case 1: /* UXTL, USHLL. */
5468 if (uimm (aarch64_get_instr (cpu), 21, 21))
5469 {
5470 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5471 aarch64_set_vec_u64
5472 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, vs, bias) << shift);
5473 aarch64_set_vec_u64
5474 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, vs, bias + 1) << shift);
5475 }
5476 else if (uimm (aarch64_get_instr (cpu), 20, 20))
5477 {
5478 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5479 bias *= 2;
5480 for (i = 0; i < 4; i++)
5481 aarch64_set_vec_u32
5482 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i + bias) << shift);
5483 }
5484 else
5485 {
5486 NYI_assert (19, 19, 1);
5487
5488 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5489 bias *= 3;
5490 for (i = 0; i < 8; i++)
5491 aarch64_set_vec_u16
5492 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, i + bias) << shift);
5493 }
5494 return;
5495
5496 default:
5497 HALT_NYI;
5498 }
5499 }
5500
5501 static void
5502 do_vec_SHL (sim_cpu *cpu)
5503 {
5504 /* instr [31] = 0
5505 instr [30] = half(0)/full(1)
5506 instr [29,23] = 001 1110
5507 instr [22,16] = size and shift amount
5508 instr [15,10] = 01 0101
5509 instr [9, 5] = Vs
5510 instr [4, 0] = Vd. */
5511
5512 int shift;
5513 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5514 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5515 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5516 unsigned i;
5517
5518 NYI_assert (29, 23, 0x1E);
5519 NYI_assert (15, 10, 0x15);
5520
5521 if (uimm (aarch64_get_instr (cpu), 22, 22))
5522 {
5523 shift = uimm (aarch64_get_instr (cpu), 21, 16) - 1;
5524
5525 if (full == 0)
5526 HALT_UNALLOC;
5527
5528 for (i = 0; i < 2; i++)
5529 {
5530 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5531 aarch64_set_vec_u64 (cpu, vd, i, val << shift);
5532 }
5533
5534 return;
5535 }
5536
5537 if (uimm (aarch64_get_instr (cpu), 21, 21))
5538 {
5539 shift = uimm (aarch64_get_instr (cpu), 20, 16) - 1;
5540
5541 for (i = 0; i < (full ? 4 : 2); i++)
5542 {
5543 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5544 aarch64_set_vec_u32 (cpu, vd, i, val << shift);
5545 }
5546
5547 return;
5548 }
5549
5550 if (uimm (aarch64_get_instr (cpu), 20, 20))
5551 {
5552 shift = uimm (aarch64_get_instr (cpu), 19, 16) - 1;
5553
5554 for (i = 0; i < (full ? 8 : 4); i++)
5555 {
5556 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5557 aarch64_set_vec_u16 (cpu, vd, i, val << shift);
5558 }
5559
5560 return;
5561 }
5562
5563 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
5564 HALT_UNALLOC;
5565
5566 shift = uimm (aarch64_get_instr (cpu), 18, 16) - 1;
5567
5568 for (i = 0; i < (full ? 16 : 8); i++)
5569 {
5570 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5571 aarch64_set_vec_u8 (cpu, vd, i, val << shift);
5572 }
5573 }
5574
5575 static void
5576 do_vec_SSHR_USHR (sim_cpu *cpu)
5577 {
5578 /* instr [31] = 0
5579 instr [30] = half(0)/full(1)
5580 instr [29] = signed(0)/unsigned(1)
5581 instr [28,23] = 01 1110
5582 instr [22,16] = size and shift amount
5583 instr [15,10] = 0000 01
5584 instr [9, 5] = Vs
5585 instr [4, 0] = Vd. */
5586
5587 int shift;
5588 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5589 int sign = uimm (aarch64_get_instr (cpu), 29, 29);
5590 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5591 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5592 unsigned i;
5593
5594 NYI_assert (28, 23, 0x1E);
5595 NYI_assert (15, 10, 0x01);
5596
5597 if (uimm (aarch64_get_instr (cpu), 22, 22))
5598 {
5599 shift = uimm (aarch64_get_instr (cpu), 21, 16);
5600
5601 if (full == 0)
5602 HALT_UNALLOC;
5603
5604 if (sign)
5605 for (i = 0; i < 2; i++)
5606 {
5607 int64_t val = aarch64_get_vec_s64 (cpu, vs, i);
5608 aarch64_set_vec_s64 (cpu, vd, i, val >> shift);
5609 }
5610 else
5611 for (i = 0; i < 2; i++)
5612 {
5613 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5614 aarch64_set_vec_u64 (cpu, vd, i, val >> shift);
5615 }
5616
5617 return;
5618 }
5619
5620 if (uimm (aarch64_get_instr (cpu), 21, 21))
5621 {
5622 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5623
5624 if (sign)
5625 for (i = 0; i < (full ? 4 : 2); i++)
5626 {
5627 int32_t val = aarch64_get_vec_s32 (cpu, vs, i);
5628 aarch64_set_vec_s32 (cpu, vd, i, val >> shift);
5629 }
5630 else
5631 for (i = 0; i < (full ? 4 : 2); i++)
5632 {
5633 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5634 aarch64_set_vec_u32 (cpu, vd, i, val >> shift);
5635 }
5636
5637 return;
5638 }
5639
5640 if (uimm (aarch64_get_instr (cpu), 20, 20))
5641 {
5642 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5643
5644 if (sign)
5645 for (i = 0; i < (full ? 8 : 4); i++)
5646 {
5647 int16_t val = aarch64_get_vec_s16 (cpu, vs, i);
5648 aarch64_set_vec_s16 (cpu, vd, i, val >> shift);
5649 }
5650 else
5651 for (i = 0; i < (full ? 8 : 4); i++)
5652 {
5653 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5654 aarch64_set_vec_u16 (cpu, vd, i, val >> shift);
5655 }
5656
5657 return;
5658 }
5659
5660 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
5661 HALT_UNALLOC;
5662
5663 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5664
5665 if (sign)
5666 for (i = 0; i < (full ? 16 : 8); i++)
5667 {
5668 int8_t val = aarch64_get_vec_s8 (cpu, vs, i);
5669 aarch64_set_vec_s8 (cpu, vd, i, val >> shift);
5670 }
5671 else
5672 for (i = 0; i < (full ? 16 : 8); i++)
5673 {
5674 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5675 aarch64_set_vec_u8 (cpu, vd, i, val >> shift);
5676 }
5677 }
5678
5679 static void
5680 do_vec_op2 (sim_cpu *cpu)
5681 {
5682 /* instr[31] = 0
5683 instr[30] = half/full
5684 instr[29,24] = 00 1111
5685 instr[23] = ?
5686 instr[22,16] = element size & index
5687 instr[15,10] = sub-opcode
5688 instr[9,5] = Vm
5689 instr[4.0] = Vd */
5690
5691 NYI_assert (29, 24, 0x0F);
5692
5693 if (uimm (aarch64_get_instr (cpu), 23, 23) != 0)
5694 HALT_NYI;
5695
5696 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5697 {
5698 case 0x01: do_vec_SSHR_USHR (cpu); return;
5699 case 0x15: do_vec_SHL (cpu); return;
5700 case 0x29: do_vec_xtl (cpu); return;
5701 default: HALT_NYI;
5702 }
5703 }
5704
5705 static void
5706 do_vec_neg (sim_cpu *cpu)
5707 {
5708 /* instr[31] = 0
5709 instr[30] = full(1)/half(0)
5710 instr[29,24] = 10 1110
5711 instr[23,22] = size: byte(00), half (01), word (10), long (11)
5712 instr[21,10] = 1000 0010 1110
5713 instr[9,5] = Vs
5714 instr[4,0] = Vd */
5715
5716 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5717 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5718 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5719 unsigned i;
5720
5721 NYI_assert (29, 24, 0x2E);
5722 NYI_assert (21, 10, 0x82E);
5723
5724 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5725 {
5726 case 0:
5727 for (i = 0; i < (full ? 16 : 8); i++)
5728 aarch64_set_vec_s8 (cpu, vd, i, - aarch64_get_vec_s8 (cpu, vs, i));
5729 return;
5730
5731 case 1:
5732 for (i = 0; i < (full ? 8 : 4); i++)
5733 aarch64_set_vec_s16 (cpu, vd, i, - aarch64_get_vec_s16 (cpu, vs, i));
5734 return;
5735
5736 case 2:
5737 for (i = 0; i < (full ? 4 : 2); i++)
5738 aarch64_set_vec_s32 (cpu, vd, i, - aarch64_get_vec_s32 (cpu, vs, i));
5739 return;
5740
5741 case 3:
5742 if (! full)
5743 HALT_NYI;
5744 for (i = 0; i < 2; i++)
5745 aarch64_set_vec_s64 (cpu, vd, i, - aarch64_get_vec_s64 (cpu, vs, i));
5746 return;
5747
5748 default:
5749 HALT_UNREACHABLE;
5750 }
5751 }
5752
5753 static void
5754 do_vec_sqrt (sim_cpu *cpu)
5755 {
5756 /* instr[31] = 0
5757 instr[30] = full(1)/half(0)
5758 instr[29,23] = 101 1101
5759 instr[22] = single(0)/double(1)
5760 instr[21,10] = 1000 0111 1110
5761 instr[9,5] = Vs
5762 instr[4,0] = Vd. */
5763
5764 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5765 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5766 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5767 unsigned i;
5768
5769 NYI_assert (29, 23, 0x5B);
5770 NYI_assert (21, 10, 0x87E);
5771
5772 if (uimm (aarch64_get_instr (cpu), 22, 22) == 0)
5773 for (i = 0; i < (full ? 4 : 2); i++)
5774 aarch64_set_vec_float (cpu, vd, i,
5775 sqrtf (aarch64_get_vec_float (cpu, vs, i)));
5776 else
5777 for (i = 0; i < 2; i++)
5778 aarch64_set_vec_double (cpu, vd, i,
5779 sqrt (aarch64_get_vec_double (cpu, vs, i)));
5780 }
5781
5782 static void
5783 do_vec_mls_indexed (sim_cpu *cpu)
5784 {
5785 /* instr[31] = 0
5786 instr[30] = half(0)/full(1)
5787 instr[29,24] = 10 1111
5788 instr[23,22] = 16-bit(01)/32-bit(10)
5789 instr[21,20+11] = index (if 16-bit)
5790 instr[21+11] = index (if 32-bit)
5791 instr[20,16] = Vm
5792 instr[15,12] = 0100
5793 instr[11] = part of index
5794 instr[10] = 0
5795 instr[9,5] = Vs
5796 instr[4,0] = Vd. */
5797
5798 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5799 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5800 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5801 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5802 unsigned i;
5803
5804 NYI_assert (15, 12, 4);
5805 NYI_assert (10, 10, 0);
5806
5807 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5808 {
5809 case 1:
5810 {
5811 unsigned elem;
5812 uint32_t val;
5813
5814 if (vm > 15)
5815 HALT_NYI;
5816
5817 elem = (uimm (aarch64_get_instr (cpu), 21, 20) << 1)
5818 | uimm (aarch64_get_instr (cpu), 11, 11);
5819 val = aarch64_get_vec_u16 (cpu, vm, elem);
5820
5821 for (i = 0; i < (full ? 8 : 4); i++)
5822 aarch64_set_vec_u32 (cpu, vd, i,
5823 aarch64_get_vec_u32 (cpu, vd, i) -
5824 (aarch64_get_vec_u32 (cpu, vs, i) * val));
5825 return;
5826 }
5827
5828 case 2:
5829 {
5830 unsigned elem = (uimm (aarch64_get_instr (cpu), 21, 21) << 1)
5831 | uimm (aarch64_get_instr (cpu), 11, 11);
5832 uint64_t val = aarch64_get_vec_u32 (cpu, vm, elem);
5833
5834 for (i = 0; i < (full ? 4 : 2); i++)
5835 aarch64_set_vec_u64 (cpu, vd, i,
5836 aarch64_get_vec_u64 (cpu, vd, i) -
5837 (aarch64_get_vec_u64 (cpu, vs, i) * val));
5838 return;
5839 }
5840
5841 case 0:
5842 case 3:
5843 default:
5844 HALT_NYI;
5845 }
5846 }
5847
5848 static void
5849 do_vec_SUB (sim_cpu *cpu)
5850 {
5851 /* instr [31] = 0
5852 instr [30] = half(0)/full(1)
5853 instr [29,24] = 10 1110
5854 instr [23,22] = size: byte(00, half(01), word (10), long (11)
5855 instr [21] = 1
5856 instr [20,16] = Vm
5857 instr [15,10] = 10 0001
5858 instr [9, 5] = Vn
5859 instr [4, 0] = Vd. */
5860
5861 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5862 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5863 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5864 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5865 unsigned i;
5866
5867 NYI_assert (29, 24, 0x2E);
5868 NYI_assert (21, 21, 1);
5869 NYI_assert (15, 10, 0x21);
5870
5871 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5872 {
5873 case 0:
5874 for (i = 0; i < (full ? 16 : 8); i++)
5875 aarch64_set_vec_s8 (cpu, vd, i,
5876 aarch64_get_vec_s8 (cpu, vn, i)
5877 - aarch64_get_vec_s8 (cpu, vm, i));
5878 return;
5879
5880 case 1:
5881 for (i = 0; i < (full ? 8 : 4); i++)
5882 aarch64_set_vec_s16 (cpu, vd, i,
5883 aarch64_get_vec_s16 (cpu, vn, i)
5884 - aarch64_get_vec_s16 (cpu, vm, i));
5885 return;
5886
5887 case 2:
5888 for (i = 0; i < (full ? 4 : 2); i++)
5889 aarch64_set_vec_s32 (cpu, vd, i,
5890 aarch64_get_vec_s32 (cpu, vn, i)
5891 - aarch64_get_vec_s32 (cpu, vm, i));
5892 return;
5893
5894 case 3:
5895 if (full == 0)
5896 HALT_UNALLOC;
5897
5898 for (i = 0; i < 2; i++)
5899 aarch64_set_vec_s64 (cpu, vd, i,
5900 aarch64_get_vec_s64 (cpu, vn, i)
5901 - aarch64_get_vec_s64 (cpu, vm, i));
5902 return;
5903
5904 default:
5905 HALT_UNREACHABLE;
5906 }
5907 }
5908
5909 static void
5910 do_vec_MLS (sim_cpu *cpu)
5911 {
5912 /* instr [31] = 0
5913 instr [30] = half(0)/full(1)
5914 instr [29,24] = 10 1110
5915 instr [23,22] = size: byte(00, half(01), word (10)
5916 instr [21] = 1
5917 instr [20,16] = Vm
5918 instr [15,10] = 10 0101
5919 instr [9, 5] = Vn
5920 instr [4, 0] = Vd. */
5921
5922 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5923 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5924 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5925 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5926 unsigned i;
5927
5928 NYI_assert (29, 24, 0x2E);
5929 NYI_assert (21, 21, 1);
5930 NYI_assert (15, 10, 0x25);
5931
5932 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5933 {
5934 case 0:
5935 for (i = 0; i < (full ? 16 : 8); i++)
5936 aarch64_set_vec_u8 (cpu, vd, i,
5937 (aarch64_get_vec_u8 (cpu, vn, i)
5938 * aarch64_get_vec_u8 (cpu, vm, i))
5939 - aarch64_get_vec_u8 (cpu, vd, i));
5940 return;
5941
5942 case 1:
5943 for (i = 0; i < (full ? 8 : 4); i++)
5944 aarch64_set_vec_u16 (cpu, vd, i,
5945 (aarch64_get_vec_u16 (cpu, vn, i)
5946 * aarch64_get_vec_u16 (cpu, vm, i))
5947 - aarch64_get_vec_u16 (cpu, vd, i));
5948 return;
5949
5950 case 2:
5951 for (i = 0; i < (full ? 4 : 2); i++)
5952 aarch64_set_vec_u32 (cpu, vd, i,
5953 (aarch64_get_vec_u32 (cpu, vn, i)
5954 * aarch64_get_vec_u32 (cpu, vm, i))
5955 - aarch64_get_vec_u32 (cpu, vd, i));
5956 return;
5957
5958 default:
5959 HALT_UNALLOC;
5960 }
5961 }
5962
5963 static void
5964 do_vec_FDIV (sim_cpu *cpu)
5965 {
5966 /* instr [31] = 0
5967 instr [30] = half(0)/full(1)
5968 instr [29,23] = 10 1110 0
5969 instr [22] = float()/double(1)
5970 instr [21] = 1
5971 instr [20,16] = Vm
5972 instr [15,10] = 1111 11
5973 instr [9, 5] = Vn
5974 instr [4, 0] = Vd. */
5975
5976 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5977 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5978 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5979 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5980 unsigned i;
5981
5982 NYI_assert (29, 23, 0x5C);
5983 NYI_assert (21, 21, 1);
5984 NYI_assert (15, 10, 0x3F);
5985
5986 if (uimm (aarch64_get_instr (cpu), 22, 22))
5987 {
5988 if (! full)
5989 HALT_UNALLOC;
5990
5991 for (i = 0; i < 2; i++)
5992 aarch64_set_vec_double (cpu, vd, i,
5993 aarch64_get_vec_double (cpu, vn, i)
5994 / aarch64_get_vec_double (cpu, vm, i));
5995 }
5996 else
5997 for (i = 0; i < (full ? 4 : 2); i++)
5998 aarch64_set_vec_float (cpu, vd, i,
5999 aarch64_get_vec_float (cpu, vn, i)
6000 / aarch64_get_vec_float (cpu, vm, i));
6001 }
6002
6003 static void
6004 do_vec_FMUL (sim_cpu *cpu)
6005 {
6006 /* instr [31] = 0
6007 instr [30] = half(0)/full(1)
6008 instr [29,23] = 10 1110 0
6009 instr [22] = float(0)/double(1)
6010 instr [21] = 1
6011 instr [20,16] = Vm
6012 instr [15,10] = 1101 11
6013 instr [9, 5] = Vn
6014 instr [4, 0] = Vd. */
6015
6016 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6017 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6018 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6019 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6020 unsigned i;
6021
6022 NYI_assert (29, 23, 0x5C);
6023 NYI_assert (21, 21, 1);
6024 NYI_assert (15, 10, 0x37);
6025
6026 if (uimm (aarch64_get_instr (cpu), 22, 22))
6027 {
6028 if (! full)
6029 HALT_UNALLOC;
6030
6031 for (i = 0; i < 2; i++)
6032 aarch64_set_vec_double (cpu, vd, i,
6033 aarch64_get_vec_double (cpu, vn, i)
6034 * aarch64_get_vec_double (cpu, vm, i));
6035 }
6036 else
6037 for (i = 0; i < (full ? 4 : 2); i++)
6038 aarch64_set_vec_float (cpu, vd, i,
6039 aarch64_get_vec_float (cpu, vn, i)
6040 * aarch64_get_vec_float (cpu, vm, i));
6041 }
6042
6043 static void
6044 do_vec_FADDP (sim_cpu *cpu)
6045 {
6046 /* instr [31] = 0
6047 instr [30] = half(0)/full(1)
6048 instr [29,23] = 10 1110 0
6049 instr [22] = float(0)/double(1)
6050 instr [21] = 1
6051 instr [20,16] = Vm
6052 instr [15,10] = 1101 01
6053 instr [9, 5] = Vn
6054 instr [4, 0] = Vd. */
6055
6056 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6057 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6058 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6059 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6060
6061 NYI_assert (29, 23, 0x5C);
6062 NYI_assert (21, 21, 1);
6063 NYI_assert (15, 10, 0x35);
6064
6065 if (uimm (aarch64_get_instr (cpu), 22, 22))
6066 {
6067 if (! full)
6068 HALT_UNALLOC;
6069
6070 aarch64_set_vec_double (cpu, vd, 0, aarch64_get_vec_double (cpu, vn, 0)
6071 + aarch64_get_vec_double (cpu, vn, 1));
6072 aarch64_set_vec_double (cpu, vd, 1, aarch64_get_vec_double (cpu, vm, 0)
6073 + aarch64_get_vec_double (cpu, vm, 1));
6074 }
6075 else
6076 {
6077 aarch64_set_vec_float (cpu, vd, 0, aarch64_get_vec_float (cpu, vn, 0)
6078 + aarch64_get_vec_float (cpu, vn, 1));
6079 if (full)
6080 aarch64_set_vec_float (cpu, vd, 1, aarch64_get_vec_float (cpu, vn, 2)
6081 + aarch64_get_vec_float (cpu, vn, 3));
6082 aarch64_set_vec_float (cpu, vd, full ? 2 : 1,
6083 aarch64_get_vec_float (cpu, vm, 0)
6084 + aarch64_get_vec_float (cpu, vm, 1));
6085 if (full)
6086 aarch64_set_vec_float (cpu, vd, 3,
6087 aarch64_get_vec_float (cpu, vm, 2)
6088 + aarch64_get_vec_float (cpu, vm, 3));
6089 }
6090 }
6091
6092 static void
6093 do_vec_FSQRT (sim_cpu *cpu)
6094 {
6095 /* instr[31] = 0
6096 instr[30] = half(0)/full(1)
6097 instr[29,23] = 10 1110 1
6098 instr[22] = single(0)/double(1)
6099 instr[21,10] = 10 0001 1111 10
6100 instr[9,5] = Vsrc
6101 instr[4,0] = Vdest. */
6102
6103 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6104 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6105 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6106 int i;
6107
6108 NYI_assert (29, 23, 0x5D);
6109 NYI_assert (21, 10, 0x87E);
6110
6111 if (uimm (aarch64_get_instr (cpu), 22, 22))
6112 {
6113 if (! full)
6114 HALT_UNALLOC;
6115
6116 for (i = 0; i < 2; i++)
6117 aarch64_set_vec_double (cpu, vd, i,
6118 sqrt (aarch64_get_vec_double (cpu, vn, i)));
6119 }
6120 else
6121 {
6122 for (i = 0; i < (full ? 4 : 2); i++)
6123 aarch64_set_vec_float (cpu, vd, i,
6124 sqrtf (aarch64_get_vec_float (cpu, vn, i)));
6125 }
6126 }
6127
6128 static void
6129 do_vec_FNEG (sim_cpu *cpu)
6130 {
6131 /* instr[31] = 0
6132 instr[30] = half (0)/full (1)
6133 instr[29,23] = 10 1110 1
6134 instr[22] = single (0)/double (1)
6135 instr[21,10] = 10 0000 1111 10
6136 instr[9,5] = Vsrc
6137 instr[4,0] = Vdest. */
6138
6139 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6140 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6141 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6142 int i;
6143
6144 NYI_assert (29, 23, 0x5D);
6145 NYI_assert (21, 10, 0x83E);
6146
6147 if (uimm (aarch64_get_instr (cpu), 22, 22))
6148 {
6149 if (! full)
6150 HALT_UNALLOC;
6151
6152 for (i = 0; i < 2; i++)
6153 aarch64_set_vec_double (cpu, vd, i,
6154 - aarch64_get_vec_double (cpu, vn, i));
6155 }
6156 else
6157 {
6158 for (i = 0; i < (full ? 4 : 2); i++)
6159 aarch64_set_vec_float (cpu, vd, i,
6160 - aarch64_get_vec_float (cpu, vn, i));
6161 }
6162 }
6163
6164 static void
6165 do_vec_NOT (sim_cpu *cpu)
6166 {
6167 /* instr[31] = 0
6168 instr[30] = half (0)/full (1)
6169 instr[29,21] = 10 1110 001
6170 instr[20,16] = 0 0000
6171 instr[15,10] = 0101 10
6172 instr[9,5] = Vn
6173 instr[4.0] = Vd. */
6174
6175 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6176 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6177 unsigned i;
6178 int full = uimm (aarch64_get_instr (cpu), 30, 30);
6179
6180 NYI_assert (29, 10, 0xB8816);
6181
6182 for (i = 0; i < (full ? 16 : 8); i++)
6183 aarch64_set_vec_u8 (cpu, vd, i, ~ aarch64_get_vec_u8 (cpu, vn, i));
6184 }
6185
6186 static void
6187 do_vec_MOV_element (sim_cpu *cpu)
6188 {
6189 /* instr[31,21] = 0110 1110 000
6190 instr[20,16] = size & dest index
6191 instr[15] = 0
6192 instr[14,11] = source index
6193 instr[10] = 1
6194 instr[9,5] = Vs
6195 instr[4.0] = Vd. */
6196
6197 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
6198 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6199 unsigned src_index;
6200 unsigned dst_index;
6201
6202 NYI_assert (31, 21, 0x370);
6203 NYI_assert (15, 15, 0);
6204 NYI_assert (10, 10, 1);
6205
6206 if (uimm (aarch64_get_instr (cpu), 16, 16))
6207 {
6208 /* Move a byte. */
6209 src_index = uimm (aarch64_get_instr (cpu), 14, 11);
6210 dst_index = uimm (aarch64_get_instr (cpu), 20, 17);
6211 aarch64_set_vec_u8 (cpu, vd, dst_index,
6212 aarch64_get_vec_u8 (cpu, vs, src_index));
6213 }
6214 else if (uimm (aarch64_get_instr (cpu), 17, 17))
6215 {
6216 /* Move 16-bits. */
6217 NYI_assert (11, 11, 0);
6218 src_index = uimm (aarch64_get_instr (cpu), 14, 12);
6219 dst_index = uimm (aarch64_get_instr (cpu), 20, 18);
6220 aarch64_set_vec_u16 (cpu, vd, dst_index,
6221 aarch64_get_vec_u16 (cpu, vs, src_index));
6222 }
6223 else if (uimm (aarch64_get_instr (cpu), 18, 18))
6224 {
6225 /* Move 32-bits. */
6226 NYI_assert (12, 11, 0);
6227 src_index = uimm (aarch64_get_instr (cpu), 14, 13);
6228 dst_index = uimm (aarch64_get_instr (cpu), 20, 19);
6229 aarch64_set_vec_u32 (cpu, vd, dst_index,
6230 aarch64_get_vec_u32 (cpu, vs, src_index));
6231 }
6232 else
6233 {
6234 NYI_assert (19, 19, 1);
6235 NYI_assert (13, 11, 0);
6236 src_index = uimm (aarch64_get_instr (cpu), 14, 14);
6237 dst_index = uimm (aarch64_get_instr (cpu), 20, 20);
6238 aarch64_set_vec_u64 (cpu, vd, dst_index,
6239 aarch64_get_vec_u64 (cpu, vs, src_index));
6240 }
6241 }
6242
6243 static void
6244 dexAdvSIMD0 (sim_cpu *cpu)
6245 {
6246 /* instr [28,25] = 0 111. */
6247 if ( uimm (aarch64_get_instr (cpu), 15, 10) == 0x07
6248 && (uimm (aarch64_get_instr (cpu), 9, 5) ==
6249 uimm (aarch64_get_instr (cpu), 20, 16)))
6250 {
6251 if (uimm (aarch64_get_instr (cpu), 31, 21) == 0x075
6252 || uimm (aarch64_get_instr (cpu), 31, 21) == 0x275)
6253 {
6254 do_vec_MOV_whole_vector (cpu);
6255 return;
6256 }
6257 }
6258
6259 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x1E0)
6260 {
6261 do_vec_MOV_immediate (cpu);
6262 return;
6263 }
6264
6265 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x5E0)
6266 {
6267 do_vec_MVNI (cpu);
6268 return;
6269 }
6270
6271 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x1C0
6272 || uimm (aarch64_get_instr (cpu), 29, 19) == 0x1C1)
6273 {
6274 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x03)
6275 {
6276 do_vec_DUP_scalar_into_vector (cpu);
6277 return;
6278 }
6279 }
6280
6281 switch (uimm (aarch64_get_instr (cpu), 29, 24))
6282 {
6283 case 0x0E: do_vec_op1 (cpu); return;
6284 case 0x0F: do_vec_op2 (cpu); return;
6285
6286 case 0x2f:
6287 switch (uimm (aarch64_get_instr (cpu), 15, 10))
6288 {
6289 case 0x01: do_vec_SSHR_USHR (cpu); return;
6290 case 0x10:
6291 case 0x12: do_vec_mls_indexed (cpu); return;
6292 case 0x29: do_vec_xtl (cpu); return;
6293 default:
6294 HALT_NYI;
6295 }
6296
6297 case 0x2E:
6298 if (uimm (aarch64_get_instr (cpu), 21, 21) == 1)
6299 {
6300 switch (uimm (aarch64_get_instr (cpu), 15, 10))
6301 {
6302 case 0x07:
6303 switch (uimm (aarch64_get_instr (cpu), 23, 22))
6304 {
6305 case 0: do_vec_EOR (cpu); return;
6306 case 1: do_vec_BSL (cpu); return;
6307 case 2:
6308 case 3: do_vec_bit (cpu); return;
6309 }
6310 break;
6311
6312 case 0x08: do_vec_sub_long (cpu); return;
6313 case 0x11: do_vec_USHL (cpu); return;
6314 case 0x16: do_vec_NOT (cpu); return;
6315 case 0x19: do_vec_max (cpu); return;
6316 case 0x1B: do_vec_min (cpu); return;
6317 case 0x21: do_vec_SUB (cpu); return;
6318 case 0x25: do_vec_MLS (cpu); return;
6319 case 0x31: do_vec_FminmaxNMP (cpu); return;
6320 case 0x35: do_vec_FADDP (cpu); return;
6321 case 0x37: do_vec_FMUL (cpu); return;
6322 case 0x3F: do_vec_FDIV (cpu); return;
6323
6324 case 0x3E:
6325 switch (uimm (aarch64_get_instr (cpu), 20, 16))
6326 {
6327 case 0x00: do_vec_FNEG (cpu); return;
6328 case 0x01: do_vec_FSQRT (cpu); return;
6329 default: HALT_NYI;
6330 }
6331
6332 case 0x0D:
6333 case 0x0F:
6334 case 0x22:
6335 case 0x23:
6336 case 0x26:
6337 case 0x2A:
6338 case 0x32:
6339 case 0x36:
6340 case 0x39:
6341 case 0x3A:
6342 do_vec_compare (cpu); return;
6343
6344 default: break;
6345 }
6346 }
6347
6348 if (uimm (aarch64_get_instr (cpu), 31, 21) == 0x370)
6349 {
6350 do_vec_MOV_element (cpu);
6351 return;
6352 }
6353
6354 switch (uimm (aarch64_get_instr (cpu), 21, 10))
6355 {
6356 case 0x82E: do_vec_neg (cpu); return;
6357 case 0x87E: do_vec_sqrt (cpu); return;
6358 default:
6359 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x30)
6360 {
6361 do_vec_mull (cpu);
6362 return;
6363 }
6364 break;
6365 }
6366 break;
6367
6368 default:
6369 break;
6370 }
6371
6372 HALT_NYI;
6373 }
6374
6375 /* 3 sources. */
6376
6377 /* Float multiply add. */
6378 static void
6379 fmadds (sim_cpu *cpu)
6380 {
6381 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6382 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6383 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6384 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6385
6386 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6387 + aarch64_get_FP_float (cpu, sn)
6388 * aarch64_get_FP_float (cpu, sm));
6389 }
6390
6391 /* Double multiply add. */
6392 static void
6393 fmaddd (sim_cpu *cpu)
6394 {
6395 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6396 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6397 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6398 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6399
6400 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6401 + aarch64_get_FP_double (cpu, sn)
6402 * aarch64_get_FP_double (cpu, sm));
6403 }
6404
6405 /* Float multiply subtract. */
6406 static void
6407 fmsubs (sim_cpu *cpu)
6408 {
6409 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6410 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6411 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6412 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6413
6414 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6415 - aarch64_get_FP_float (cpu, sn)
6416 * aarch64_get_FP_float (cpu, sm));
6417 }
6418
6419 /* Double multiply subtract. */
6420 static void
6421 fmsubd (sim_cpu *cpu)
6422 {
6423 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6424 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6425 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6426 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6427
6428 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6429 - aarch64_get_FP_double (cpu, sn)
6430 * aarch64_get_FP_double (cpu, sm));
6431 }
6432
6433 /* Float negative multiply add. */
6434 static void
6435 fnmadds (sim_cpu *cpu)
6436 {
6437 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6438 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6439 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6440 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6441
6442 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6443 + (- aarch64_get_FP_float (cpu, sn))
6444 * aarch64_get_FP_float (cpu, sm));
6445 }
6446
6447 /* Double negative multiply add. */
6448 static void
6449 fnmaddd (sim_cpu *cpu)
6450 {
6451 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6452 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6453 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6454 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6455
6456 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6457 + (- aarch64_get_FP_double (cpu, sn))
6458 * aarch64_get_FP_double (cpu, sm));
6459 }
6460
6461 /* Float negative multiply subtract. */
6462 static void
6463 fnmsubs (sim_cpu *cpu)
6464 {
6465 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6466 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6467 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6468 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6469
6470 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6471 + aarch64_get_FP_float (cpu, sn)
6472 * aarch64_get_FP_float (cpu, sm));
6473 }
6474
6475 /* Double negative multiply subtract. */
6476 static void
6477 fnmsubd (sim_cpu *cpu)
6478 {
6479 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6480 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6481 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6482 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6483
6484 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6485 + aarch64_get_FP_double (cpu, sn)
6486 * aarch64_get_FP_double (cpu, sm));
6487 }
6488
6489 static void
6490 dexSimpleFPDataProc3Source (sim_cpu *cpu)
6491 {
6492 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
6493 instr[30] = 0
6494 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
6495 instr[28,25] = 1111
6496 instr[24] = 1
6497 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
6498 instr[21] ==> o1 : 0 ==> unnegated, 1 ==> negated
6499 instr[15] ==> o2 : 0 ==> ADD, 1 ==> SUB */
6500
6501 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
6502 | uimm (aarch64_get_instr (cpu), 29, 29);
6503 /* dispatch on combined type:o1:o2. */
6504 uint32_t dispatch = (uimm (aarch64_get_instr (cpu), 23, 21) << 1)
6505 | uimm (aarch64_get_instr (cpu), 15, 15);
6506
6507 if (M_S != 0)
6508 HALT_UNALLOC;
6509
6510 switch (dispatch)
6511 {
6512 case 0: fmadds (cpu); return;
6513 case 1: fmsubs (cpu); return;
6514 case 2: fnmadds (cpu); return;
6515 case 3: fnmsubs (cpu); return;
6516 case 4: fmaddd (cpu); return;
6517 case 5: fmsubd (cpu); return;
6518 case 6: fnmaddd (cpu); return;
6519 case 7: fnmsubd (cpu); return;
6520 default:
6521 /* type > 1 is currently unallocated. */
6522 HALT_UNALLOC;
6523 }
6524 }
6525
6526 static void
6527 dexSimpleFPFixedConvert (sim_cpu *cpu)
6528 {
6529 HALT_NYI;
6530 }
6531
6532 static void
6533 dexSimpleFPCondCompare (sim_cpu *cpu)
6534 {
6535 HALT_NYI;
6536 }
6537
6538 /* 2 sources. */
6539
6540 /* Float add. */
6541 static void
6542 fadds (sim_cpu *cpu)
6543 {
6544 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6545 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6546 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6547
6548 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6549 + aarch64_get_FP_float (cpu, sm));
6550 }
6551
6552 /* Double add. */
6553 static void
6554 faddd (sim_cpu *cpu)
6555 {
6556 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6557 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6558 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6559
6560 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6561 + aarch64_get_FP_double (cpu, sm));
6562 }
6563
6564 /* Float divide. */
6565 static void
6566 fdivs (sim_cpu *cpu)
6567 {
6568 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6569 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6570 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6571
6572 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6573 / aarch64_get_FP_float (cpu, sm));
6574 }
6575
6576 /* Double divide. */
6577 static void
6578 fdivd (sim_cpu *cpu)
6579 {
6580 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6581 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6582 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6583
6584 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6585 / aarch64_get_FP_double (cpu, sm));
6586 }
6587
6588 /* Float multiply. */
6589 static void
6590 fmuls (sim_cpu *cpu)
6591 {
6592 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6593 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6594 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6595
6596 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6597 * aarch64_get_FP_float (cpu, sm));
6598 }
6599
6600 /* Double multiply. */
6601 static void
6602 fmuld (sim_cpu *cpu)
6603 {
6604 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6605 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6606 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6607
6608 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6609 * aarch64_get_FP_double (cpu, sm));
6610 }
6611
6612 /* Float negate and multiply. */
6613 static void
6614 fnmuls (sim_cpu *cpu)
6615 {
6616 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6617 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6618 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6619
6620 aarch64_set_FP_float (cpu, sd, - (aarch64_get_FP_float (cpu, sn)
6621 * aarch64_get_FP_float (cpu, sm)));
6622 }
6623
6624 /* Double negate and multiply. */
6625 static void
6626 fnmuld (sim_cpu *cpu)
6627 {
6628 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6629 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6630 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6631
6632 aarch64_set_FP_double (cpu, sd, - (aarch64_get_FP_double (cpu, sn)
6633 * aarch64_get_FP_double (cpu, sm)));
6634 }
6635
6636 /* Float subtract. */
6637 static void
6638 fsubs (sim_cpu *cpu)
6639 {
6640 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6641 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6642 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6643
6644 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6645 - aarch64_get_FP_float (cpu, sm));
6646 }
6647
6648 /* Double subtract. */
6649 static void
6650 fsubd (sim_cpu *cpu)
6651 {
6652 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6653 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6654 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6655
6656 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6657 - aarch64_get_FP_double (cpu, sm));
6658 }
6659
6660 static void
6661 do_FMINNM (sim_cpu *cpu)
6662 {
6663 /* instr[31,23] = 0 0011 1100
6664 instr[22] = float(0)/double(1)
6665 instr[21] = 1
6666 instr[20,16] = Sm
6667 instr[15,10] = 01 1110
6668 instr[9,5] = Sn
6669 instr[4,0] = Cpu */
6670
6671 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6672 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6673 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6674
6675 NYI_assert (31, 23, 0x03C);
6676 NYI_assert (15, 10, 0x1E);
6677
6678 if (uimm (aarch64_get_instr (cpu), 22, 22))
6679 aarch64_set_FP_double (cpu, sd,
6680 dminnm (aarch64_get_FP_double (cpu, sn),
6681 aarch64_get_FP_double (cpu, sm)));
6682 else
6683 aarch64_set_FP_float (cpu, sd,
6684 fminnm (aarch64_get_FP_float (cpu, sn),
6685 aarch64_get_FP_float (cpu, sm)));
6686 }
6687
6688 static void
6689 do_FMAXNM (sim_cpu *cpu)
6690 {
6691 /* instr[31,23] = 0 0011 1100
6692 instr[22] = float(0)/double(1)
6693 instr[21] = 1
6694 instr[20,16] = Sm
6695 instr[15,10] = 01 1010
6696 instr[9,5] = Sn
6697 instr[4,0] = Cpu */
6698
6699 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6700 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6701 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6702
6703 NYI_assert (31, 23, 0x03C);
6704 NYI_assert (15, 10, 0x1A);
6705
6706 if (uimm (aarch64_get_instr (cpu), 22, 22))
6707 aarch64_set_FP_double (cpu, sd,
6708 dmaxnm (aarch64_get_FP_double (cpu, sn),
6709 aarch64_get_FP_double (cpu, sm)));
6710 else
6711 aarch64_set_FP_float (cpu, sd,
6712 fmaxnm (aarch64_get_FP_float (cpu, sn),
6713 aarch64_get_FP_float (cpu, sm)));
6714 }
6715
6716 static void
6717 dexSimpleFPDataProc2Source (sim_cpu *cpu)
6718 {
6719 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
6720 instr[30] = 0
6721 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
6722 instr[28,25] = 1111
6723 instr[24] = 0
6724 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
6725 instr[21] = 1
6726 instr[20,16] = Vm
6727 instr[15,12] ==> opcode : 0000 ==> FMUL, 0001 ==> FDIV
6728 0010 ==> FADD, 0011 ==> FSUB,
6729 0100 ==> FMAX, 0101 ==> FMIN
6730 0110 ==> FMAXNM, 0111 ==> FMINNM
6731 1000 ==> FNMUL, ow ==> UNALLOC
6732 instr[11,10] = 10
6733 instr[9,5] = Vn
6734 instr[4,0] = Vd */
6735
6736 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
6737 | uimm (aarch64_get_instr (cpu), 29, 29);
6738 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
6739 /* Dispatch on opcode. */
6740 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 15, 12);
6741
6742 if (type > 1)
6743 HALT_UNALLOC;
6744
6745 if (M_S != 0)
6746 HALT_UNALLOC;
6747
6748 if (type)
6749 switch (dispatch)
6750 {
6751 case 0: fmuld (cpu); return;
6752 case 1: fdivd (cpu); return;
6753 case 2: faddd (cpu); return;
6754 case 3: fsubd (cpu); return;
6755 case 6: do_FMAXNM (cpu); return;
6756 case 7: do_FMINNM (cpu); return;
6757 case 8: fnmuld (cpu); return;
6758
6759 /* Have not yet implemented fmax and fmin. */
6760 case 4:
6761 case 5:
6762 HALT_NYI;
6763
6764 default:
6765 HALT_UNALLOC;
6766 }
6767 else /* type == 0 => floats. */
6768 switch (dispatch)
6769 {
6770 case 0: fmuls (cpu); return;
6771 case 1: fdivs (cpu); return;
6772 case 2: fadds (cpu); return;
6773 case 3: fsubs (cpu); return;
6774 case 6: do_FMAXNM (cpu); return;
6775 case 7: do_FMINNM (cpu); return;
6776 case 8: fnmuls (cpu); return;
6777
6778 case 4:
6779 case 5:
6780 HALT_NYI;
6781
6782 default:
6783 HALT_UNALLOC;
6784 }
6785 }
6786
6787 static void
6788 dexSimpleFPCondSelect (sim_cpu *cpu)
6789 {
6790 /* FCSEL
6791 instr[31,23] = 0 0011 1100
6792 instr[22] = 0=>single 1=>double
6793 instr[21] = 1
6794 instr[20,16] = Sm
6795 instr[15,12] = cond
6796 instr[11,10] = 11
6797 instr[9,5] = Sn
6798 instr[4,0] = Cpu */
6799 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6800 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6801 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6802 uint32_t set = testConditionCode (cpu, uimm (aarch64_get_instr (cpu), 15, 12));
6803
6804 NYI_assert (31, 23, 0x03C);
6805 NYI_assert (11, 10, 0x3);
6806
6807 if (uimm (aarch64_get_instr (cpu), 22, 22))
6808 aarch64_set_FP_double (cpu, sd, set ? sn : sm);
6809 else
6810 aarch64_set_FP_float (cpu, sd, set ? sn : sm);
6811 }
6812
6813 /* Store 32 bit unscaled signed 9 bit. */
6814 static void
6815 fsturs (sim_cpu *cpu, int32_t offset)
6816 {
6817 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6818 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6819
6820 aarch64_set_mem_float (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
6821 aarch64_get_FP_float (cpu, rn));
6822 }
6823
6824 /* Store 64 bit unscaled signed 9 bit. */
6825 static void
6826 fsturd (sim_cpu *cpu, int32_t offset)
6827 {
6828 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6829 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6830
6831 aarch64_set_mem_double (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
6832 aarch64_get_FP_double (cpu, rn));
6833 }
6834
6835 /* Store 128 bit unscaled signed 9 bit. */
6836 static void
6837 fsturq (sim_cpu *cpu, int32_t offset)
6838 {
6839 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6840 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6841 FRegister a;
6842
6843 aarch64_get_FP_long_double (cpu, rn, & a);
6844 aarch64_set_mem_long_double (cpu,
6845 aarch64_get_reg_u64 (cpu, st, 1)
6846 + offset, a);
6847 }
6848
6849 /* TODO FP move register. */
6850
6851 /* 32 bit fp to fp move register. */
6852 static void
6853 ffmovs (sim_cpu *cpu)
6854 {
6855 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6856 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6857
6858 aarch64_set_FP_float (cpu, st, aarch64_get_FP_float (cpu, rn));
6859 }
6860
6861 /* 64 bit fp to fp move register. */
6862 static void
6863 ffmovd (sim_cpu *cpu)
6864 {
6865 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6866 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6867
6868 aarch64_set_FP_double (cpu, st, aarch64_get_FP_double (cpu, rn));
6869 }
6870
6871 /* 32 bit GReg to Vec move register. */
6872 static void
6873 fgmovs (sim_cpu *cpu)
6874 {
6875 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6876 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6877
6878 aarch64_set_vec_u32 (cpu, st, 0, aarch64_get_reg_u32 (cpu, rn, NO_SP));
6879 }
6880
6881 /* 64 bit g to fp move register. */
6882 static void
6883 fgmovd (sim_cpu *cpu)
6884 {
6885 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6886 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6887
6888 aarch64_set_vec_u64 (cpu, st, 0, aarch64_get_reg_u64 (cpu, rn, NO_SP));
6889 }
6890
6891 /* 32 bit fp to g move register. */
6892 static void
6893 gfmovs (sim_cpu *cpu)
6894 {
6895 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6896 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6897
6898 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u32 (cpu, rn, 0));
6899 }
6900
6901 /* 64 bit fp to g move register. */
6902 static void
6903 gfmovd (sim_cpu *cpu)
6904 {
6905 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6906 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6907
6908 aarch64_set_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u64 (cpu, rn, 0));
6909 }
6910
6911 /* FP move immediate
6912
6913 These install an immediate 8 bit value in the target register
6914 where the 8 bits comprise 1 sign bit, 4 bits of fraction and a 3
6915 bit exponent. */
6916
6917 static void
6918 fmovs (sim_cpu *cpu)
6919 {
6920 unsigned int sd = uimm (aarch64_get_instr (cpu), 4, 0);
6921 uint32_t imm = uimm (aarch64_get_instr (cpu), 20, 13);
6922 float f = fp_immediate_for_encoding_32 (imm);
6923
6924 aarch64_set_FP_float (cpu, sd, f);
6925 }
6926
6927 static void
6928 fmovd (sim_cpu *cpu)
6929 {
6930 unsigned int sd = uimm (aarch64_get_instr (cpu), 4, 0);
6931 uint32_t imm = uimm (aarch64_get_instr (cpu), 20, 13);
6932 double d = fp_immediate_for_encoding_64 (imm);
6933
6934 aarch64_set_FP_double (cpu, sd, d);
6935 }
6936
6937 static void
6938 dexSimpleFPImmediate (sim_cpu *cpu)
6939 {
6940 /* instr[31,23] == 00111100
6941 instr[22] == type : single(0)/double(1)
6942 instr[21] == 1
6943 instr[20,13] == imm8
6944 instr[12,10] == 100
6945 instr[9,5] == imm5 : 00000 ==> PK, ow ==> UNALLOC
6946 instr[4,0] == Rd */
6947 uint32_t imm5 = uimm (aarch64_get_instr (cpu), 9, 5);
6948
6949 NYI_assert (31, 23, 0x3C);
6950
6951 if (imm5 != 0)
6952 HALT_UNALLOC;
6953
6954 if (uimm (aarch64_get_instr (cpu), 22, 22))
6955 fmovd (cpu);
6956 else
6957 fmovs (cpu);
6958 }
6959
6960 /* TODO specific decode and execute for group Load Store. */
6961
6962 /* TODO FP load/store single register (unscaled offset). */
6963
6964 /* TODO load 8 bit unscaled signed 9 bit. */
6965 /* TODO load 16 bit unscaled signed 9 bit. */
6966
6967 /* Load 32 bit unscaled signed 9 bit. */
6968 static void
6969 fldurs (sim_cpu *cpu, int32_t offset)
6970 {
6971 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6972 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6973
6974 aarch64_set_FP_float (cpu, st, aarch64_get_mem_float
6975 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
6976 }
6977
6978 /* Load 64 bit unscaled signed 9 bit. */
6979 static void
6980 fldurd (sim_cpu *cpu, int32_t offset)
6981 {
6982 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6983 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6984
6985 aarch64_set_FP_double (cpu, st, aarch64_get_mem_double
6986 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
6987 }
6988
6989 /* Load 128 bit unscaled signed 9 bit. */
6990 static void
6991 fldurq (sim_cpu *cpu, int32_t offset)
6992 {
6993 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6994 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6995 FRegister a;
6996 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
6997
6998 aarch64_get_mem_long_double (cpu, addr, & a);
6999 aarch64_set_FP_long_double (cpu, st, a);
7000 }
7001
7002 /* TODO store 8 bit unscaled signed 9 bit. */
7003 /* TODO store 16 bit unscaled signed 9 bit. */
7004
7005
7006 /* 1 source. */
7007
7008 /* Float absolute value. */
7009 static void
7010 fabss (sim_cpu *cpu)
7011 {
7012 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7013 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7014 float value = aarch64_get_FP_float (cpu, sn);
7015
7016 aarch64_set_FP_float (cpu, sd, fabsf (value));
7017 }
7018
7019 /* Double absolute value. */
7020 static void
7021 fabcpu (sim_cpu *cpu)
7022 {
7023 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7024 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7025 double value = aarch64_get_FP_double (cpu, sn);
7026
7027 aarch64_set_FP_double (cpu, sd, fabs (value));
7028 }
7029
7030 /* Float negative value. */
7031 static void
7032 fnegs (sim_cpu *cpu)
7033 {
7034 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7035 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7036
7037 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sn));
7038 }
7039
7040 /* Double negative value. */
7041 static void
7042 fnegd (sim_cpu *cpu)
7043 {
7044 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7045 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7046
7047 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sn));
7048 }
7049
7050 /* Float square root. */
7051 static void
7052 fsqrts (sim_cpu *cpu)
7053 {
7054 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7055 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7056
7057 aarch64_set_FP_float (cpu, sd, sqrt (aarch64_get_FP_float (cpu, sn)));
7058 }
7059
7060 /* Double square root. */
7061 static void
7062 fsqrtd (sim_cpu *cpu)
7063 {
7064 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7065 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7066
7067 aarch64_set_FP_double (cpu, sd,
7068 sqrt (aarch64_get_FP_double (cpu, sn)));
7069 }
7070
7071 /* Convert double to float. */
7072 static void
7073 fcvtds (sim_cpu *cpu)
7074 {
7075 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7076 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7077
7078 aarch64_set_FP_float (cpu, sd, (float) aarch64_get_FP_double (cpu, sn));
7079 }
7080
7081 /* Convert float to double. */
7082 static void
7083 fcvtcpu (sim_cpu *cpu)
7084 {
7085 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7086 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7087
7088 aarch64_set_FP_double (cpu, sd, (double) aarch64_get_FP_float (cpu, sn));
7089 }
7090
7091 static void
7092 do_FRINT (sim_cpu *cpu)
7093 {
7094 /* instr[31,23] = 0001 1110 0
7095 instr[22] = single(0)/double(1)
7096 instr[21,18] = 1001
7097 instr[17,15] = rounding mode
7098 instr[14,10] = 10000
7099 instr[9,5] = source
7100 instr[4,0] = dest */
7101
7102 float val;
7103 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7104 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7105 unsigned int rmode = uimm (aarch64_get_instr (cpu), 17, 15);
7106
7107 NYI_assert (31, 23, 0x03C);
7108 NYI_assert (21, 18, 0x9);
7109 NYI_assert (14, 10, 0x10);
7110
7111 if (rmode == 6 || rmode == 7)
7112 /* FIXME: Add support for rmode == 6 exactness check. */
7113 rmode = uimm (aarch64_get_FPSR (cpu), 23, 22);
7114
7115 if (uimm (aarch64_get_instr (cpu), 22, 22))
7116 {
7117 double val = aarch64_get_FP_double (cpu, rs);
7118
7119 switch (rmode)
7120 {
7121 case 0: /* mode N: nearest or even. */
7122 {
7123 double rval = round (val);
7124
7125 if (val - rval == 0.5)
7126 {
7127 if (((rval / 2.0) * 2.0) != rval)
7128 rval += 1.0;
7129 }
7130
7131 aarch64_set_FP_double (cpu, rd, round (val));
7132 return;
7133 }
7134
7135 case 1: /* mode P: towards +inf. */
7136 if (val < 0.0)
7137 aarch64_set_FP_double (cpu, rd, trunc (val));
7138 else
7139 aarch64_set_FP_double (cpu, rd, round (val));
7140 return;
7141
7142 case 2: /* mode M: towards -inf. */
7143 if (val < 0.0)
7144 aarch64_set_FP_double (cpu, rd, round (val));
7145 else
7146 aarch64_set_FP_double (cpu, rd, trunc (val));
7147 return;
7148
7149 case 3: /* mode Z: towards 0. */
7150 aarch64_set_FP_double (cpu, rd, trunc (val));
7151 return;
7152
7153 case 4: /* mode A: away from 0. */
7154 aarch64_set_FP_double (cpu, rd, round (val));
7155 return;
7156
7157 case 6: /* mode X: use FPCR with exactness check. */
7158 case 7: /* mode I: use FPCR mode. */
7159 HALT_NYI;
7160
7161 default:
7162 HALT_UNALLOC;
7163 }
7164 }
7165
7166 val = aarch64_get_FP_float (cpu, rs);
7167
7168 switch (rmode)
7169 {
7170 case 0: /* mode N: nearest or even. */
7171 {
7172 float rval = roundf (val);
7173
7174 if (val - rval == 0.5)
7175 {
7176 if (((rval / 2.0) * 2.0) != rval)
7177 rval += 1.0;
7178 }
7179
7180 aarch64_set_FP_float (cpu, rd, rval);
7181 return;
7182 }
7183
7184 case 1: /* mode P: towards +inf. */
7185 if (val < 0.0)
7186 aarch64_set_FP_float (cpu, rd, truncf (val));
7187 else
7188 aarch64_set_FP_float (cpu, rd, roundf (val));
7189 return;
7190
7191 case 2: /* mode M: towards -inf. */
7192 if (val < 0.0)
7193 aarch64_set_FP_float (cpu, rd, truncf (val));
7194 else
7195 aarch64_set_FP_float (cpu, rd, roundf (val));
7196 return;
7197
7198 case 3: /* mode Z: towards 0. */
7199 aarch64_set_FP_float (cpu, rd, truncf (val));
7200 return;
7201
7202 case 4: /* mode A: away from 0. */
7203 aarch64_set_FP_float (cpu, rd, roundf (val));
7204 return;
7205
7206 case 6: /* mode X: use FPCR with exactness check. */
7207 case 7: /* mode I: use FPCR mode. */
7208 HALT_NYI;
7209
7210 default:
7211 HALT_UNALLOC;
7212 }
7213 }
7214
7215 static void
7216 dexSimpleFPDataProc1Source (sim_cpu *cpu)
7217 {
7218 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7219 instr[30] = 0
7220 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7221 instr[28,25] = 1111
7222 instr[24] = 0
7223 instr[23,22] ==> type : 00 ==> source is single,
7224 01 ==> source is double
7225 10 ==> UNALLOC
7226 11 ==> UNALLOC or source is half
7227 instr[21] = 1
7228 instr[20,15] ==> opcode : with type 00 or 01
7229 000000 ==> FMOV, 000001 ==> FABS,
7230 000010 ==> FNEG, 000011 ==> FSQRT,
7231 000100 ==> UNALLOC, 000101 ==> FCVT,(to single/double)
7232 000110 ==> UNALLOC, 000111 ==> FCVT (to half)
7233 001000 ==> FRINTN, 001001 ==> FRINTP,
7234 001010 ==> FRINTM, 001011 ==> FRINTZ,
7235 001100 ==> FRINTA, 001101 ==> UNALLOC
7236 001110 ==> FRINTX, 001111 ==> FRINTI
7237 with type 11
7238 000100 ==> FCVT (half-to-single)
7239 000101 ==> FCVT (half-to-double)
7240 instr[14,10] = 10000. */
7241
7242 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
7243 | uimm (aarch64_get_instr (cpu), 29, 29);
7244 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
7245 uint32_t opcode = uimm (aarch64_get_instr (cpu), 20, 15);
7246
7247 if (M_S != 0)
7248 HALT_UNALLOC;
7249
7250 if (type == 3)
7251 {
7252 if (opcode == 4 || opcode == 5)
7253 HALT_NYI;
7254 else
7255 HALT_UNALLOC;
7256 }
7257
7258 if (type == 2)
7259 HALT_UNALLOC;
7260
7261 switch (opcode)
7262 {
7263 case 0:
7264 if (type)
7265 ffmovd (cpu);
7266 else
7267 ffmovs (cpu);
7268 return;
7269
7270 case 1:
7271 if (type)
7272 fabcpu (cpu);
7273 else
7274 fabss (cpu);
7275 return;
7276
7277 case 2:
7278 if (type)
7279 fnegd (cpu);
7280 else
7281 fnegs (cpu);
7282 return;
7283
7284 case 3:
7285 if (type)
7286 fsqrtd (cpu);
7287 else
7288 fsqrts (cpu);
7289 return;
7290
7291 case 4:
7292 if (type)
7293 fcvtds (cpu);
7294 else
7295 HALT_UNALLOC;
7296 return;
7297
7298 case 5:
7299 if (type)
7300 HALT_UNALLOC;
7301 fcvtcpu (cpu);
7302 return;
7303
7304 case 8: /* FRINTN etc. */
7305 case 9:
7306 case 10:
7307 case 11:
7308 case 12:
7309 case 14:
7310 case 15:
7311 do_FRINT (cpu);
7312 return;
7313
7314 case 7: /* FCVT double/single to half precision. */
7315 case 13:
7316 HALT_NYI;
7317
7318 default:
7319 HALT_UNALLOC;
7320 }
7321 }
7322
7323 /* 32 bit signed int to float. */
7324 static void
7325 scvtf32 (sim_cpu *cpu)
7326 {
7327 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7328 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7329
7330 aarch64_set_FP_float
7331 (cpu, sd, (float) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7332 }
7333
7334 /* signed int to float. */
7335 static void
7336 scvtf (sim_cpu *cpu)
7337 {
7338 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7339 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7340
7341 aarch64_set_FP_float
7342 (cpu, sd, (float) aarch64_get_reg_s64 (cpu, rn, NO_SP));
7343 }
7344
7345 /* 32 bit signed int to double. */
7346 static void
7347 scvtd32 (sim_cpu *cpu)
7348 {
7349 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7350 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7351
7352 aarch64_set_FP_double
7353 (cpu, sd, (double) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7354 }
7355
7356 /* signed int to double. */
7357 static void
7358 scvtd (sim_cpu *cpu)
7359 {
7360 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7361 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7362
7363 aarch64_set_FP_double
7364 (cpu, sd, (double) aarch64_get_reg_s64 (cpu, rn, NO_SP));
7365 }
7366
7367 static const float FLOAT_INT_MAX = (float) INT_MAX;
7368 static const float FLOAT_INT_MIN = (float) INT_MIN;
7369 static const double DOUBLE_INT_MAX = (double) INT_MAX;
7370 static const double DOUBLE_INT_MIN = (double) INT_MIN;
7371 static const float FLOAT_LONG_MAX = (float) LONG_MAX;
7372 static const float FLOAT_LONG_MIN = (float) LONG_MIN;
7373 static const double DOUBLE_LONG_MAX = (double) LONG_MAX;
7374 static const double DOUBLE_LONG_MIN = (double) LONG_MIN;
7375
7376 /* Check for FP exception conditions:
7377 NaN raises IO
7378 Infinity raises IO
7379 Out of Range raises IO and IX and saturates value
7380 Denormal raises ID and IX and sets to zero. */
7381 #define RAISE_EXCEPTIONS(F, VALUE, FTYPE, ITYPE) \
7382 do \
7383 { \
7384 switch (fpclassify (F)) \
7385 { \
7386 case FP_INFINITE: \
7387 case FP_NAN: \
7388 aarch64_set_FPSR (cpu, IO); \
7389 if (signbit (F)) \
7390 VALUE = ITYPE##_MAX; \
7391 else \
7392 VALUE = ITYPE##_MIN; \
7393 break; \
7394 \
7395 case FP_NORMAL: \
7396 if (F >= FTYPE##_##ITYPE##_MAX) \
7397 { \
7398 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7399 VALUE = ITYPE##_MAX; \
7400 } \
7401 else if (F <= FTYPE##_##ITYPE##_MIN) \
7402 { \
7403 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7404 VALUE = ITYPE##_MIN; \
7405 } \
7406 break; \
7407 \
7408 case FP_SUBNORMAL: \
7409 aarch64_set_FPSR_bits (cpu, IO | IX | ID, IX | ID); \
7410 VALUE = 0; \
7411 break; \
7412 \
7413 default: \
7414 case FP_ZERO: \
7415 VALUE = 0; \
7416 break; \
7417 } \
7418 } \
7419 while (0)
7420
7421 /* 32 bit convert float to signed int truncate towards zero. */
7422 static void
7423 fcvtszs32 (sim_cpu *cpu)
7424 {
7425 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7426 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7427 /* TODO : check that this rounds toward zero. */
7428 float f = aarch64_get_FP_float (cpu, sn);
7429 int32_t value = (int32_t) f;
7430
7431 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
7432
7433 /* Avoid sign extension to 64 bit. */
7434 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7435 }
7436
7437 /* 64 bit convert float to signed int truncate towards zero. */
7438 static void
7439 fcvtszs (sim_cpu *cpu)
7440 {
7441 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7442 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7443 float f = aarch64_get_FP_float (cpu, sn);
7444 int64_t value = (int64_t) f;
7445
7446 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
7447
7448 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7449 }
7450
7451 /* 32 bit convert double to signed int truncate towards zero. */
7452 static void
7453 fcvtszd32 (sim_cpu *cpu)
7454 {
7455 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7456 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7457 /* TODO : check that this rounds toward zero. */
7458 double d = aarch64_get_FP_double (cpu, sn);
7459 int32_t value = (int32_t) d;
7460
7461 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
7462
7463 /* Avoid sign extension to 64 bit. */
7464 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7465 }
7466
7467 /* 64 bit convert double to signed int truncate towards zero. */
7468 static void
7469 fcvtszd (sim_cpu *cpu)
7470 {
7471 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7472 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7473 /* TODO : check that this rounds toward zero. */
7474 double d = aarch64_get_FP_double (cpu, sn);
7475 int64_t value;
7476
7477 value = (int64_t) d;
7478
7479 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7480
7481 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7482 }
7483
7484 static void
7485 do_fcvtzu (sim_cpu *cpu)
7486 {
7487 /* instr[31] = size: 32-bit (0), 64-bit (1)
7488 instr[30,23] = 00111100
7489 instr[22] = type: single (0)/ double (1)
7490 instr[21] = enable (0)/disable(1) precision
7491 instr[20,16] = 11001
7492 instr[15,10] = precision
7493 instr[9,5] = Rs
7494 instr[4,0] = Rd. */
7495
7496 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7497 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7498
7499 NYI_assert (30, 23, 0x3C);
7500 NYI_assert (20, 16, 0x19);
7501
7502 if (uimm (aarch64_get_instr (cpu), 21, 21) != 1)
7503 /* Convert to fixed point. */
7504 HALT_NYI;
7505
7506 if (uimm (aarch64_get_instr (cpu), 31, 31))
7507 {
7508 /* Convert to unsigned 64-bit integer. */
7509 if (uimm (aarch64_get_instr (cpu), 22, 22))
7510 {
7511 double d = aarch64_get_FP_double (cpu, rs);
7512 uint64_t value = (uint64_t) d;
7513
7514 /* Do not raise an exception if we have reached ULONG_MAX. */
7515 if (value != (1UL << 63))
7516 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7517
7518 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7519 }
7520 else
7521 {
7522 float f = aarch64_get_FP_float (cpu, rs);
7523 uint64_t value = (uint64_t) f;
7524
7525 /* Do not raise an exception if we have reached ULONG_MAX. */
7526 if (value != (1UL << 63))
7527 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
7528
7529 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7530 }
7531 }
7532 else
7533 {
7534 uint32_t value;
7535
7536 /* Convert to unsigned 32-bit integer. */
7537 if (uimm (aarch64_get_instr (cpu), 22, 22))
7538 {
7539 double d = aarch64_get_FP_double (cpu, rs);
7540
7541 value = (uint32_t) d;
7542 /* Do not raise an exception if we have reached UINT_MAX. */
7543 if (value != (1UL << 31))
7544 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
7545 }
7546 else
7547 {
7548 float f = aarch64_get_FP_float (cpu, rs);
7549
7550 value = (uint32_t) f;
7551 /* Do not raise an exception if we have reached UINT_MAX. */
7552 if (value != (1UL << 31))
7553 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
7554 }
7555
7556 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7557 }
7558 }
7559
7560 static void
7561 do_UCVTF (sim_cpu *cpu)
7562 {
7563 /* instr[31] = size: 32-bit (0), 64-bit (1)
7564 instr[30,23] = 001 1110 0
7565 instr[22] = type: single (0)/ double (1)
7566 instr[21] = enable (0)/disable(1) precision
7567 instr[20,16] = 0 0011
7568 instr[15,10] = precision
7569 instr[9,5] = Rs
7570 instr[4,0] = Rd. */
7571
7572 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7573 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7574
7575 NYI_assert (30, 23, 0x3C);
7576 NYI_assert (20, 16, 0x03);
7577
7578 if (uimm (aarch64_get_instr (cpu), 21, 21) != 1)
7579 HALT_NYI;
7580
7581 /* FIXME: Add exception raising. */
7582 if (uimm (aarch64_get_instr (cpu), 31, 31))
7583 {
7584 uint64_t value = aarch64_get_reg_u64 (cpu, rs, NO_SP);
7585
7586 if (uimm (aarch64_get_instr (cpu), 22, 22))
7587 aarch64_set_FP_double (cpu, rd, (double) value);
7588 else
7589 aarch64_set_FP_float (cpu, rd, (float) value);
7590 }
7591 else
7592 {
7593 uint32_t value = aarch64_get_reg_u32 (cpu, rs, NO_SP);
7594
7595 if (uimm (aarch64_get_instr (cpu), 22, 22))
7596 aarch64_set_FP_double (cpu, rd, (double) value);
7597 else
7598 aarch64_set_FP_float (cpu, rd, (float) value);
7599 }
7600 }
7601
7602 static void
7603 float_vector_move (sim_cpu *cpu)
7604 {
7605 /* instr[31,17] == 100 1111 0101 0111
7606 instr[16] ==> direction 0=> to GR, 1=> from GR
7607 instr[15,10] => ???
7608 instr[9,5] ==> source
7609 instr[4,0] ==> dest. */
7610
7611 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7612 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7613
7614 NYI_assert (31, 17, 0x4F57);
7615
7616 if (uimm (aarch64_get_instr (cpu), 15, 10) != 0)
7617 HALT_UNALLOC;
7618
7619 if (uimm (aarch64_get_instr (cpu), 16, 16))
7620 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_reg_u64 (cpu, rn, NO_SP));
7621 else
7622 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, rn, 1));
7623 }
7624
7625 static void
7626 dexSimpleFPIntegerConvert (sim_cpu *cpu)
7627 {
7628 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
7629 instr[30 = 0
7630 instr[29] = S : 0 ==> OK, 1 ==> UNALLOC
7631 instr[28,25] = 1111
7632 instr[24] = 0
7633 instr[23,22] = type : 00 ==> single, 01 ==> double, 1x ==> UNALLOC
7634 instr[21] = 1
7635 instr[20,19] = rmode
7636 instr[18,16] = opcode
7637 instr[15,10] = 10 0000 */
7638
7639 uint32_t rmode_opcode;
7640 uint32_t size_type;
7641 uint32_t type;
7642 uint32_t size;
7643 uint32_t S;
7644
7645 if (uimm (aarch64_get_instr (cpu), 31, 17) == 0x4F57)
7646 {
7647 float_vector_move (cpu);
7648 return;
7649 }
7650
7651 size = uimm (aarch64_get_instr (cpu), 31, 31);
7652 S = uimm (aarch64_get_instr (cpu), 29, 29);
7653 if (S != 0)
7654 HALT_UNALLOC;
7655
7656 type = uimm (aarch64_get_instr (cpu), 23, 22);
7657 if (type > 1)
7658 HALT_UNALLOC;
7659
7660 rmode_opcode = uimm (aarch64_get_instr (cpu), 20, 16);
7661 size_type = (size << 1) | type; /* 0==32f, 1==32d, 2==64f, 3==64d. */
7662
7663 switch (rmode_opcode)
7664 {
7665 case 2: /* SCVTF. */
7666 switch (size_type)
7667 {
7668 case 0: scvtf32 (cpu); return;
7669 case 1: scvtd32 (cpu); return;
7670 case 2: scvtf (cpu); return;
7671 case 3: scvtd (cpu); return;
7672 default:
7673 HALT_UNREACHABLE;
7674 }
7675
7676 case 6: /* FMOV GR, Vec. */
7677 switch (size_type)
7678 {
7679 case 0: gfmovs (cpu); return;
7680 case 3: gfmovd (cpu); return;
7681 default: HALT_UNALLOC;
7682 }
7683
7684 case 7: /* FMOV vec, GR. */
7685 switch (size_type)
7686 {
7687 case 0: fgmovs (cpu); return;
7688 case 3: fgmovd (cpu); return;
7689 default: HALT_UNALLOC;
7690 }
7691
7692 case 24: /* FCVTZS. */
7693 switch (size_type)
7694 {
7695 case 0: fcvtszs32 (cpu); return;
7696 case 1: fcvtszd32 (cpu); return;
7697 case 2: fcvtszs (cpu); return;
7698 case 3: fcvtszd (cpu); return;
7699 default: HALT_UNREACHABLE;
7700 }
7701
7702 case 25: do_fcvtzu (cpu); return;
7703 case 3: do_UCVTF (cpu); return;
7704
7705 case 0: /* FCVTNS. */
7706 case 1: /* FCVTNU. */
7707 case 4: /* FCVTAS. */
7708 case 5: /* FCVTAU. */
7709 case 8: /* FCVPTS. */
7710 case 9: /* FCVTPU. */
7711 case 16: /* FCVTMS. */
7712 case 17: /* FCVTMU. */
7713 default:
7714 HALT_NYI;
7715 }
7716 }
7717
7718 static void
7719 set_flags_for_float_compare (sim_cpu *cpu, float fvalue1, float fvalue2)
7720 {
7721 uint32_t flags;
7722
7723 if (isnan (fvalue1) || isnan (fvalue2))
7724 flags = C|V;
7725 else
7726 {
7727 float result = fvalue1 - fvalue2;
7728
7729 if (result == 0.0)
7730 flags = Z|C;
7731 else if (result < 0)
7732 flags = N;
7733 else /* (result > 0). */
7734 flags = C;
7735 }
7736
7737 aarch64_set_CPSR (cpu, flags);
7738 }
7739
7740 static void
7741 fcmps (sim_cpu *cpu)
7742 {
7743 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7744 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7745
7746 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7747 float fvalue2 = aarch64_get_FP_float (cpu, sm);
7748
7749 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
7750 }
7751
7752 /* Float compare to zero -- Invalid Operation exception
7753 only on signaling NaNs. */
7754 static void
7755 fcmpzs (sim_cpu *cpu)
7756 {
7757 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7758 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7759
7760 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
7761 }
7762
7763 /* Float compare -- Invalid Operation exception on all NaNs. */
7764 static void
7765 fcmpes (sim_cpu *cpu)
7766 {
7767 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7768 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7769
7770 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7771 float fvalue2 = aarch64_get_FP_float (cpu, sm);
7772
7773 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
7774 }
7775
7776 /* Float compare to zero -- Invalid Operation exception on all NaNs. */
7777 static void
7778 fcmpzes (sim_cpu *cpu)
7779 {
7780 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7781 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7782
7783 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
7784 }
7785
7786 static void
7787 set_flags_for_double_compare (sim_cpu *cpu, double dval1, double dval2)
7788 {
7789 uint32_t flags;
7790
7791 if (isnan (dval1) || isnan (dval2))
7792 flags = C|V;
7793 else
7794 {
7795 double result = dval1 - dval2;
7796
7797 if (result == 0.0)
7798 flags = Z|C;
7799 else if (result < 0)
7800 flags = N;
7801 else /* (result > 0). */
7802 flags = C;
7803 }
7804
7805 aarch64_set_CPSR (cpu, flags);
7806 }
7807
7808 /* Double compare -- Invalid Operation exception only on signaling NaNs. */
7809 static void
7810 fcmpd (sim_cpu *cpu)
7811 {
7812 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7813 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7814
7815 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7816 double dvalue2 = aarch64_get_FP_double (cpu, sm);
7817
7818 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
7819 }
7820
7821 /* Double compare to zero -- Invalid Operation exception
7822 only on signaling NaNs. */
7823 static void
7824 fcmpzd (sim_cpu *cpu)
7825 {
7826 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7827 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7828
7829 set_flags_for_double_compare (cpu, dvalue1, 0.0);
7830 }
7831
7832 /* Double compare -- Invalid Operation exception on all NaNs. */
7833 static void
7834 fcmped (sim_cpu *cpu)
7835 {
7836 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7837 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7838
7839 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7840 double dvalue2 = aarch64_get_FP_double (cpu, sm);
7841
7842 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
7843 }
7844
7845 /* Double compare to zero -- Invalid Operation exception on all NaNs. */
7846 static void
7847 fcmpzed (sim_cpu *cpu)
7848 {
7849 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7850 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7851
7852 set_flags_for_double_compare (cpu, dvalue1, 0.0);
7853 }
7854
7855 static void
7856 dexSimpleFPCompare (sim_cpu *cpu)
7857 {
7858 /* assert instr[28,25] == 1111
7859 instr[30:24:21:13,10] = 0011000
7860 instr[31] = M : 0 ==> OK, 1 ==> UNALLOC
7861 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7862 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7863 instr[15,14] ==> op : 00 ==> OK, ow ==> UNALLOC
7864 instr[4,0] ==> opcode2 : 00000 ==> FCMP, 10000 ==> FCMPE,
7865 01000 ==> FCMPZ, 11000 ==> FCMPEZ,
7866 ow ==> UNALLOC */
7867 uint32_t dispatch;
7868 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
7869 | uimm (aarch64_get_instr (cpu), 29, 29);
7870 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
7871 uint32_t op = uimm (aarch64_get_instr (cpu), 15, 14);
7872 uint32_t op2_2_0 = uimm (aarch64_get_instr (cpu), 2, 0);
7873
7874 if (op2_2_0 != 0)
7875 HALT_UNALLOC;
7876
7877 if (M_S != 0)
7878 HALT_UNALLOC;
7879
7880 if (type > 1)
7881 HALT_UNALLOC;
7882
7883 if (op != 0)
7884 HALT_UNALLOC;
7885
7886 /* dispatch on type and top 2 bits of opcode. */
7887 dispatch = (type << 2) | uimm (aarch64_get_instr (cpu), 4, 3);
7888
7889 switch (dispatch)
7890 {
7891 case 0: fcmps (cpu); return;
7892 case 1: fcmpzs (cpu); return;
7893 case 2: fcmpes (cpu); return;
7894 case 3: fcmpzes (cpu); return;
7895 case 4: fcmpd (cpu); return;
7896 case 5: fcmpzd (cpu); return;
7897 case 6: fcmped (cpu); return;
7898 case 7: fcmpzed (cpu); return;
7899 default: HALT_UNREACHABLE;
7900 }
7901 }
7902
7903 static void
7904 do_scalar_FADDP (sim_cpu *cpu)
7905 {
7906 /* instr [31,23] = 011111100
7907 instr [22] = single(0)/double(1)
7908 instr [21,10] = 1100 0011 0110
7909 instr [9,5] = Fn
7910 instr [4,0] = Fd. */
7911
7912 unsigned Fn = uimm (aarch64_get_instr (cpu), 9, 5);
7913 unsigned Fd = uimm (aarch64_get_instr (cpu), 4, 0);
7914
7915 NYI_assert (31, 23, 0x0FC);
7916 NYI_assert (21, 10, 0xC36);
7917
7918 if (uimm (aarch64_get_instr (cpu), 22, 22))
7919 {
7920 double val1 = aarch64_get_vec_double (cpu, Fn, 0);
7921 double val2 = aarch64_get_vec_double (cpu, Fn, 1);
7922
7923 aarch64_set_FP_double (cpu, Fd, val1 + val2);
7924 }
7925 else
7926 {
7927 float val1 = aarch64_get_vec_float (cpu, Fn, 0);
7928 float val2 = aarch64_get_vec_float (cpu, Fn, 1);
7929
7930 aarch64_set_FP_float (cpu, Fd, val1 + val2);
7931 }
7932 }
7933
7934 /* Floating point absolute difference. */
7935
7936 static void
7937 do_scalar_FABD (sim_cpu *cpu)
7938 {
7939 /* instr [31,23] = 0111 1110 1
7940 instr [22] = float(0)/double(1)
7941 instr [21] = 1
7942 instr [20,16] = Rm
7943 instr [15,10] = 1101 01
7944 instr [9, 5] = Rn
7945 instr [4, 0] = Rd. */
7946
7947 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
7948 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7949 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7950
7951 NYI_assert (31, 23, 0x0FD);
7952 NYI_assert (21, 21, 1);
7953 NYI_assert (15, 10, 0x35);
7954
7955 if (uimm (aarch64_get_instr (cpu), 22, 22))
7956 aarch64_set_FP_double (cpu, rd,
7957 fabs (aarch64_get_FP_double (cpu, rn)
7958 - aarch64_get_FP_double (cpu, rm)));
7959 else
7960 aarch64_set_FP_float (cpu, rd,
7961 fabsf (aarch64_get_FP_float (cpu, rn)
7962 - aarch64_get_FP_float (cpu, rm)));
7963 }
7964
7965 static void
7966 do_scalar_CMGT (sim_cpu *cpu)
7967 {
7968 /* instr [31,21] = 0101 1110 111
7969 instr [20,16] = Rm
7970 instr [15,10] = 00 1101
7971 instr [9, 5] = Rn
7972 instr [4, 0] = Rd. */
7973
7974 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
7975 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7976 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7977
7978 NYI_assert (31, 21, 0x2F7);
7979 NYI_assert (15, 10, 0x0D);
7980
7981 aarch64_set_vec_u64 (cpu, rd, 0,
7982 aarch64_get_vec_u64 (cpu, rn, 0) >
7983 aarch64_get_vec_u64 (cpu, rm, 0) ? -1L : 0L);
7984 }
7985
7986 static void
7987 do_scalar_USHR (sim_cpu *cpu)
7988 {
7989 /* instr [31,23] = 0111 1111 0
7990 instr [22,16] = shift amount
7991 instr [15,10] = 0000 01
7992 instr [9, 5] = Rn
7993 instr [4, 0] = Rd. */
7994
7995 unsigned amount = 128 - uimm (aarch64_get_instr (cpu), 22, 16);
7996 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7997 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7998
7999 NYI_assert (31, 23, 0x0FE);
8000 NYI_assert (15, 10, 0x01);
8001
8002 aarch64_set_vec_u64 (cpu, rd, 0,
8003 aarch64_get_vec_u64 (cpu, rn, 0) >> amount);
8004 }
8005
8006 static void
8007 do_scalar_SHL (sim_cpu *cpu)
8008 {
8009 /* instr [31,23] = 0111 1101 0
8010 instr [22,16] = shift amount
8011 instr [15,10] = 0101 01
8012 instr [9, 5] = Rn
8013 instr [4, 0] = Rd. */
8014
8015 unsigned amount = uimm (aarch64_get_instr (cpu), 22, 16) - 64;
8016 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8017 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8018
8019 NYI_assert (31, 23, 0x0BE);
8020 NYI_assert (15, 10, 0x15);
8021
8022 if (uimm (aarch64_get_instr (cpu), 22, 22) == 0)
8023 HALT_UNALLOC;
8024
8025 aarch64_set_vec_u64 (cpu, rd, 0,
8026 aarch64_get_vec_u64 (cpu, rn, 0) << amount);
8027 }
8028
8029 /* FCMEQ FCMGT FCMGE. */
8030 static void
8031 do_scalar_FCM (sim_cpu *cpu)
8032 {
8033 /* instr [31,30] = 01
8034 instr [29] = U
8035 instr [28,24] = 1 1110
8036 instr [23] = E
8037 instr [22] = size
8038 instr [21] = 1
8039 instr [20,16] = Rm
8040 instr [15,12] = 1110
8041 instr [11] = AC
8042 instr [10] = 1
8043 instr [9, 5] = Rn
8044 instr [4, 0] = Rd. */
8045
8046 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8047 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8048 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8049 unsigned EUac = (uimm (aarch64_get_instr (cpu), 23, 23) << 2)
8050 | (uimm (aarch64_get_instr (cpu), 29, 29) << 1)
8051 | uimm (aarch64_get_instr (cpu), 11, 11);
8052 unsigned result;
8053 float val1;
8054 float val2;
8055
8056 NYI_assert (31, 30, 1);
8057 NYI_assert (28, 24, 0x1E);
8058 NYI_assert (21, 21, 1);
8059 NYI_assert (15, 12, 0xE);
8060 NYI_assert (10, 10, 1);
8061
8062 if (uimm (aarch64_get_instr (cpu), 22, 22))
8063 {
8064 double val1 = aarch64_get_FP_double (cpu, rn);
8065 double val2 = aarch64_get_FP_double (cpu, rm);
8066
8067 switch (EUac)
8068 {
8069 case 0: /* 000 */
8070 result = val1 == val2;
8071 break;
8072
8073 case 3: /* 011 */
8074 val1 = fabs (val1);
8075 val2 = fabs (val2);
8076 /* Fall through. */
8077 case 2: /* 010 */
8078 result = val1 >= val2;
8079 break;
8080
8081 case 7: /* 111 */
8082 val1 = fabs (val1);
8083 val2 = fabs (val2);
8084 /* Fall through. */
8085 case 6: /* 110 */
8086 result = val1 > val2;
8087 break;
8088
8089 default:
8090 HALT_UNALLOC;
8091 }
8092
8093 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8094 return;
8095 }
8096
8097 val1 = aarch64_get_FP_float (cpu, rn);
8098 val2 = aarch64_get_FP_float (cpu, rm);
8099
8100 switch (EUac)
8101 {
8102 case 0: /* 000 */
8103 result = val1 == val2;
8104 break;
8105
8106 case 3: /* 011 */
8107 val1 = fabsf (val1);
8108 val2 = fabsf (val2);
8109 /* Fall through. */
8110 case 2: /* 010 */
8111 result = val1 >= val2;
8112 break;
8113
8114 case 7: /* 111 */
8115 val1 = fabsf (val1);
8116 val2 = fabsf (val2);
8117 /* Fall through. */
8118 case 6: /* 110 */
8119 result = val1 > val2;
8120 break;
8121
8122 default:
8123 HALT_UNALLOC;
8124 }
8125
8126 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8127 }
8128
8129 /* An alias of DUP. */
8130 static void
8131 do_scalar_MOV (sim_cpu *cpu)
8132 {
8133 /* instr [31,21] = 0101 1110 000
8134 instr [20,16] = imm5
8135 instr [15,10] = 0000 01
8136 instr [9, 5] = Rn
8137 instr [4, 0] = Rd. */
8138
8139 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8140 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8141 unsigned index;
8142
8143 NYI_assert (31, 21, 0x2F0);
8144 NYI_assert (15, 10, 0x01);
8145
8146 if (uimm (aarch64_get_instr (cpu), 16, 16))
8147 {
8148 /* 8-bit. */
8149 index = uimm (aarch64_get_instr (cpu), 20, 17);
8150 aarch64_set_vec_u8
8151 (cpu, rd, 0, aarch64_get_vec_u8 (cpu, rn, index));
8152 }
8153 else if (uimm (aarch64_get_instr (cpu), 17, 17))
8154 {
8155 /* 16-bit. */
8156 index = uimm (aarch64_get_instr (cpu), 20, 18);
8157 aarch64_set_vec_u16
8158 (cpu, rd, 0, aarch64_get_vec_u16 (cpu, rn, index));
8159 }
8160 else if (uimm (aarch64_get_instr (cpu), 18, 18))
8161 {
8162 /* 32-bit. */
8163 index = uimm (aarch64_get_instr (cpu), 20, 19);
8164 aarch64_set_vec_u32
8165 (cpu, rd, 0, aarch64_get_vec_u32 (cpu, rn, index));
8166 }
8167 else if (uimm (aarch64_get_instr (cpu), 19, 19))
8168 {
8169 /* 64-bit. */
8170 index = uimm (aarch64_get_instr (cpu), 20, 20);
8171 aarch64_set_vec_u64
8172 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, index));
8173 }
8174 else
8175 HALT_UNALLOC;
8176 }
8177
8178 static void
8179 do_double_add (sim_cpu *cpu)
8180 {
8181 /* instr [28,25] = 1111. */
8182 unsigned Fd;
8183 unsigned Fm;
8184 unsigned Fn;
8185 double val1;
8186 double val2;
8187
8188 switch (uimm (aarch64_get_instr (cpu), 31, 23))
8189 {
8190 case 0xBC:
8191 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8192 {
8193 case 0x01: do_scalar_MOV (cpu); return;
8194 case 0x39: do_scalar_FCM (cpu); return;
8195 case 0x3B: do_scalar_FCM (cpu); return;
8196 }
8197 break;
8198
8199 case 0xBE: do_scalar_SHL (cpu); return;
8200
8201 case 0xFC:
8202 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8203 {
8204 case 0x36: do_scalar_FADDP (cpu); return;
8205 case 0x39: do_scalar_FCM (cpu); return;
8206 case 0x3B: do_scalar_FCM (cpu); return;
8207 }
8208 break;
8209
8210 case 0xFD:
8211 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8212 {
8213 case 0x0D: do_scalar_CMGT (cpu); return;
8214 case 0x35: do_scalar_FABD (cpu); return;
8215 case 0x39: do_scalar_FCM (cpu); return;
8216 case 0x3B: do_scalar_FCM (cpu); return;
8217 default:
8218 HALT_NYI;
8219 }
8220
8221 case 0xFE: do_scalar_USHR (cpu); return;
8222 default:
8223 break;
8224 }
8225
8226 /* instr [31,21] = 0101 1110 111
8227 instr [20,16] = Fn
8228 instr [15,10] = 1000 01
8229 instr [9,5] = Fm
8230 instr [4,0] = Fd. */
8231 if (uimm (aarch64_get_instr (cpu), 31, 21) != 0x2F7
8232 || uimm (aarch64_get_instr (cpu), 15, 10) != 0x21)
8233 HALT_NYI;
8234
8235 Fd = uimm (aarch64_get_instr (cpu), 4, 0);
8236 Fm = uimm (aarch64_get_instr (cpu), 9, 5);
8237 Fn = uimm (aarch64_get_instr (cpu), 20, 16);
8238
8239 val1 = aarch64_get_FP_double (cpu, Fm);
8240 val2 = aarch64_get_FP_double (cpu, Fn);
8241
8242 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8243 }
8244
8245 static void
8246 dexAdvSIMD1 (sim_cpu *cpu)
8247 {
8248 /* instr [28,25] = 1 111. */
8249
8250 /* we are currently only interested in the basic
8251 scalar fp routines which all have bit 30 = 0. */
8252 if (uimm (aarch64_get_instr (cpu), 30, 30))
8253 do_double_add (cpu);
8254
8255 /* instr[24] is set for FP data processing 3-source and clear for
8256 all other basic scalar fp instruction groups. */
8257 else if (uimm (aarch64_get_instr (cpu), 24, 24))
8258 dexSimpleFPDataProc3Source (cpu);
8259
8260 /* instr[21] is clear for floating <-> fixed conversions and set for
8261 all other basic scalar fp instruction groups. */
8262 else if (!uimm (aarch64_get_instr (cpu), 21, 21))
8263 dexSimpleFPFixedConvert (cpu);
8264
8265 /* instr[11,10] : 01 ==> cond compare, 10 ==> Data Proc 2 Source
8266 11 ==> cond select, 00 ==> other. */
8267 else
8268 switch (uimm (aarch64_get_instr (cpu), 11, 10))
8269 {
8270 case 1: dexSimpleFPCondCompare (cpu); return;
8271 case 2: dexSimpleFPDataProc2Source (cpu); return;
8272 case 3: dexSimpleFPCondSelect (cpu); return;
8273
8274 default:
8275 /* Now an ordered cascade of tests.
8276 FP immediate has aarch64_get_instr (cpu)[12] == 1.
8277 FP compare has aarch64_get_instr (cpu)[13] == 1.
8278 FP Data Proc 1 Source has aarch64_get_instr (cpu)[14] == 1.
8279 FP floating <--> integer conversions has aarch64_get_instr (cpu)[15] == 0. */
8280 if (uimm (aarch64_get_instr (cpu), 12, 12))
8281 dexSimpleFPImmediate (cpu);
8282
8283 else if (uimm (aarch64_get_instr (cpu), 13, 13))
8284 dexSimpleFPCompare (cpu);
8285
8286 else if (uimm (aarch64_get_instr (cpu), 14, 14))
8287 dexSimpleFPDataProc1Source (cpu);
8288
8289 else if (!uimm (aarch64_get_instr (cpu), 15, 15))
8290 dexSimpleFPIntegerConvert (cpu);
8291
8292 else
8293 /* If we get here then instr[15] == 1 which means UNALLOC. */
8294 HALT_UNALLOC;
8295 }
8296 }
8297
8298 /* PC relative addressing. */
8299
8300 static void
8301 pcadr (sim_cpu *cpu)
8302 {
8303 /* instr[31] = op : 0 ==> ADR, 1 ==> ADRP
8304 instr[30,29] = immlo
8305 instr[23,5] = immhi. */
8306 uint64_t address;
8307 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8308 uint32_t isPage = uimm (aarch64_get_instr (cpu), 31, 31);
8309 union { int64_t u64; uint64_t s64; } imm;
8310 uint64_t offset;
8311
8312 imm.s64 = simm64 (aarch64_get_instr (cpu), 23, 5);
8313 offset = imm.u64;
8314 offset = (offset << 2) | uimm (aarch64_get_instr (cpu), 30, 29);
8315
8316 address = aarch64_get_PC (cpu);
8317
8318 if (isPage)
8319 {
8320 offset <<= 12;
8321 address &= ~0xfff;
8322 }
8323
8324 aarch64_set_reg_u64 (cpu, rd, NO_SP, address + offset);
8325 }
8326
8327 /* Specific decode and execute for group Data Processing Immediate. */
8328
8329 static void
8330 dexPCRelAddressing (sim_cpu *cpu)
8331 {
8332 /* assert instr[28,24] = 10000. */
8333 pcadr (cpu);
8334 }
8335
8336 /* Immediate logical.
8337 The bimm32/64 argument is constructed by replicating a 2, 4, 8,
8338 16, 32 or 64 bit sequence pulled out at decode and possibly
8339 inverting it..
8340
8341 N.B. the output register (dest) can normally be Xn or SP
8342 the exception occurs for flag setting instructions which may
8343 only use Xn for the output (dest). The input register can
8344 never be SP. */
8345
8346 /* 32 bit and immediate. */
8347 static void
8348 and32 (sim_cpu *cpu, uint32_t bimm)
8349 {
8350 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8351 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8352
8353 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8354 aarch64_get_reg_u32 (cpu, rn, NO_SP) & bimm);
8355 }
8356
8357 /* 64 bit and immediate. */
8358 static void
8359 and64 (sim_cpu *cpu, uint64_t bimm)
8360 {
8361 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8362 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8363
8364 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8365 aarch64_get_reg_u64 (cpu, rn, NO_SP) & bimm);
8366 }
8367
8368 /* 32 bit and immediate set flags. */
8369 static void
8370 ands32 (sim_cpu *cpu, uint32_t bimm)
8371 {
8372 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8373 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8374
8375 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8376 uint32_t value2 = bimm;
8377
8378 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8379 set_flags_for_binop32 (cpu, value1 & value2);
8380 }
8381
8382 /* 64 bit and immediate set flags. */
8383 static void
8384 ands64 (sim_cpu *cpu, uint64_t bimm)
8385 {
8386 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8387 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8388
8389 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8390 uint64_t value2 = bimm;
8391
8392 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8393 set_flags_for_binop64 (cpu, value1 & value2);
8394 }
8395
8396 /* 32 bit exclusive or immediate. */
8397 static void
8398 eor32 (sim_cpu *cpu, uint32_t bimm)
8399 {
8400 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8401 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8402
8403 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8404 aarch64_get_reg_u32 (cpu, rn, NO_SP) ^ bimm);
8405 }
8406
8407 /* 64 bit exclusive or immediate. */
8408 static void
8409 eor64 (sim_cpu *cpu, uint64_t bimm)
8410 {
8411 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8412 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8413
8414 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8415 aarch64_get_reg_u64 (cpu, rn, NO_SP) ^ bimm);
8416 }
8417
8418 /* 32 bit or immediate. */
8419 static void
8420 orr32 (sim_cpu *cpu, uint32_t bimm)
8421 {
8422 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8423 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8424
8425 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8426 aarch64_get_reg_u32 (cpu, rn, NO_SP) | bimm);
8427 }
8428
8429 /* 64 bit or immediate. */
8430 static void
8431 orr64 (sim_cpu *cpu, uint64_t bimm)
8432 {
8433 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8434 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8435
8436 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8437 aarch64_get_reg_u64 (cpu, rn, NO_SP) | bimm);
8438 }
8439
8440 /* Logical shifted register.
8441 These allow an optional LSL, ASR, LSR or ROR to the second source
8442 register with a count up to the register bit count.
8443 N.B register args may not be SP. */
8444
8445 /* 32 bit AND shifted register. */
8446 static void
8447 and32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8448 {
8449 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8450 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8451 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8452
8453 aarch64_set_reg_u64
8454 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8455 & shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8456 }
8457
8458 /* 64 bit AND shifted register. */
8459 static void
8460 and64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8461 {
8462 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8463 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8464 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8465
8466 aarch64_set_reg_u64
8467 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8468 & shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8469 }
8470
8471 /* 32 bit AND shifted register setting flags. */
8472 static void
8473 ands32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8474 {
8475 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8476 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8477 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8478
8479 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8480 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
8481 shift, count);
8482
8483 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8484 set_flags_for_binop32 (cpu, value1 & value2);
8485 }
8486
8487 /* 64 bit AND shifted register setting flags. */
8488 static void
8489 ands64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8490 {
8491 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8492 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8493 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8494
8495 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8496 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
8497 shift, count);
8498
8499 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8500 set_flags_for_binop64 (cpu, value1 & value2);
8501 }
8502
8503 /* 32 bit BIC shifted register. */
8504 static void
8505 bic32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8506 {
8507 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8508 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8509 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8510
8511 aarch64_set_reg_u64
8512 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8513 & ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8514 }
8515
8516 /* 64 bit BIC shifted register. */
8517 static void
8518 bic64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8519 {
8520 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8521 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8522 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8523
8524 aarch64_set_reg_u64
8525 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8526 & ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8527 }
8528
8529 /* 32 bit BIC shifted register setting flags. */
8530 static void
8531 bics32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8532 {
8533 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8534 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8535 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8536
8537 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8538 uint32_t value2 = ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
8539 shift, count);
8540
8541 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8542 set_flags_for_binop32 (cpu, value1 & value2);
8543 }
8544
8545 /* 64 bit BIC shifted register setting flags. */
8546 static void
8547 bics64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8548 {
8549 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8550 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8551 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8552
8553 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8554 uint64_t value2 = ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
8555 shift, count);
8556
8557 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8558 set_flags_for_binop64 (cpu, value1 & value2);
8559 }
8560
8561 /* 32 bit EON shifted register. */
8562 static void
8563 eon32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8564 {
8565 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8566 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8567 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8568
8569 aarch64_set_reg_u64
8570 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8571 ^ ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8572 }
8573
8574 /* 64 bit EON shifted register. */
8575 static void
8576 eon64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8577 {
8578 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8579 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8580 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8581
8582 aarch64_set_reg_u64
8583 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8584 ^ ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8585 }
8586
8587 /* 32 bit EOR shifted register. */
8588 static void
8589 eor32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8590 {
8591 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8592 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8593 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8594
8595 aarch64_set_reg_u64
8596 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8597 ^ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8598 }
8599
8600 /* 64 bit EOR shifted register. */
8601 static void
8602 eor64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8603 {
8604 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8605 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8606 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8607
8608 aarch64_set_reg_u64
8609 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8610 ^ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8611 }
8612
8613 /* 32 bit ORR shifted register. */
8614 static void
8615 orr32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8616 {
8617 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8618 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8619 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8620
8621 aarch64_set_reg_u64
8622 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8623 | shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8624 }
8625
8626 /* 64 bit ORR shifted register. */
8627 static void
8628 orr64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8629 {
8630 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8631 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8632 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8633
8634 aarch64_set_reg_u64
8635 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8636 | shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8637 }
8638
8639 /* 32 bit ORN shifted register. */
8640 static void
8641 orn32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8642 {
8643 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8644 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8645 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8646
8647 aarch64_set_reg_u64
8648 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8649 | ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8650 }
8651
8652 /* 64 bit ORN shifted register. */
8653 static void
8654 orn64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8655 {
8656 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8657 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8658 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8659
8660 aarch64_set_reg_u64
8661 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8662 | ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8663 }
8664
8665 static void
8666 dexLogicalImmediate (sim_cpu *cpu)
8667 {
8668 /* assert instr[28,23] = 1001000
8669 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8670 instr[30,29] = op : 0 ==> AND, 1 ==> ORR, 2 ==> EOR, 3 ==> ANDS
8671 instr[22] = N : used to construct immediate mask
8672 instr[21,16] = immr
8673 instr[15,10] = imms
8674 instr[9,5] = Rn
8675 instr[4,0] = Rd */
8676
8677 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
8678 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
8679 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
8680 /* uint32_t immr = uimm (aarch64_get_instr (cpu), 21, 16);. */
8681 /* uint32_t imms = uimm (aarch64_get_instr (cpu), 15, 10);. */
8682 uint32_t index = uimm (aarch64_get_instr (cpu), 22, 10);
8683 uint64_t bimm64 = LITable [index];
8684 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 30, 29);
8685
8686 if (~size & N)
8687 HALT_UNALLOC;
8688
8689 if (!bimm64)
8690 HALT_UNALLOC;
8691
8692 if (size == 0)
8693 {
8694 uint32_t bimm = (uint32_t) bimm64;
8695
8696 switch (dispatch)
8697 {
8698 case 0: and32 (cpu, bimm); return;
8699 case 1: orr32 (cpu, bimm); return;
8700 case 2: eor32 (cpu, bimm); return;
8701 case 3: ands32 (cpu, bimm); return;
8702 }
8703 }
8704 else
8705 {
8706 switch (dispatch)
8707 {
8708 case 0: and64 (cpu, bimm64); return;
8709 case 1: orr64 (cpu, bimm64); return;
8710 case 2: eor64 (cpu, bimm64); return;
8711 case 3: ands64 (cpu, bimm64); return;
8712 }
8713 }
8714 HALT_UNALLOC;
8715 }
8716
8717 /* Immediate move.
8718 The uimm argument is a 16 bit value to be inserted into the
8719 target register the pos argument locates the 16 bit word in the
8720 dest register i.e. it is in {0, 1} for 32 bit and {0, 1, 2,
8721 3} for 64 bit.
8722 N.B register arg may not be SP so it should be.
8723 accessed using the setGZRegisterXXX accessors. */
8724
8725 /* 32 bit move 16 bit immediate zero remaining shorts. */
8726 static void
8727 movz32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8728 {
8729 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8730
8731 aarch64_set_reg_u64 (cpu, rd, NO_SP, val << (pos * 16));
8732 }
8733
8734 /* 64 bit move 16 bit immediate zero remaining shorts. */
8735 static void
8736 movz64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8737 {
8738 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8739
8740 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((uint64_t) val) << (pos * 16));
8741 }
8742
8743 /* 32 bit move 16 bit immediate negated. */
8744 static void
8745 movn32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8746 {
8747 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8748
8749 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((val << (pos * 16)) ^ 0xffffffffU));
8750 }
8751
8752 /* 64 bit move 16 bit immediate negated. */
8753 static void
8754 movn64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8755 {
8756 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8757
8758 aarch64_set_reg_u64
8759 (cpu, rd, NO_SP, ((((uint64_t) val) << (pos * 16))
8760 ^ 0xffffffffffffffffULL));
8761 }
8762
8763 /* 32 bit move 16 bit immediate keep remaining shorts. */
8764 static void
8765 movk32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8766 {
8767 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8768 uint32_t current = aarch64_get_reg_u32 (cpu, rd, NO_SP);
8769 uint32_t value = val << (pos * 16);
8770 uint32_t mask = ~(0xffffU << (pos * 16));
8771
8772 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
8773 }
8774
8775 /* 64 bit move 16 it immediate keep remaining shorts. */
8776 static void
8777 movk64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8778 {
8779 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8780 uint64_t current = aarch64_get_reg_u64 (cpu, rd, NO_SP);
8781 uint64_t value = (uint64_t) val << (pos * 16);
8782 uint64_t mask = ~(0xffffULL << (pos * 16));
8783
8784 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
8785 }
8786
8787 static void
8788 dexMoveWideImmediate (sim_cpu *cpu)
8789 {
8790 /* assert instr[28:23] = 100101
8791 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8792 instr[30,29] = op : 0 ==> MOVN, 1 ==> UNALLOC, 2 ==> MOVZ, 3 ==> MOVK
8793 instr[22,21] = shift : 00 == LSL#0, 01 = LSL#16, 10 = LSL#32, 11 = LSL#48
8794 instr[20,5] = uimm16
8795 instr[4,0] = Rd */
8796
8797 /* N.B. the (multiple of 16) shift is applied by the called routine,
8798 we just pass the multiplier. */
8799
8800 uint32_t imm;
8801 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
8802 uint32_t op = uimm (aarch64_get_instr (cpu), 30, 29);
8803 uint32_t shift = uimm (aarch64_get_instr (cpu), 22, 21);
8804
8805 /* 32 bit can only shift 0 or 1 lot of 16.
8806 anything else is an unallocated instruction. */
8807 if (size == 0 && (shift > 1))
8808 HALT_UNALLOC;
8809
8810 if (op == 1)
8811 HALT_UNALLOC;
8812
8813 imm = uimm (aarch64_get_instr (cpu), 20, 5);
8814
8815 if (size == 0)
8816 {
8817 if (op == 0)
8818 movn32 (cpu, imm, shift);
8819 else if (op == 2)
8820 movz32 (cpu, imm, shift);
8821 else
8822 movk32 (cpu, imm, shift);
8823 }
8824 else
8825 {
8826 if (op == 0)
8827 movn64 (cpu, imm, shift);
8828 else if (op == 2)
8829 movz64 (cpu, imm, shift);
8830 else
8831 movk64 (cpu, imm, shift);
8832 }
8833 }
8834
8835 /* Bitfield operations.
8836 These take a pair of bit positions r and s which are in {0..31}
8837 or {0..63} depending on the instruction word size.
8838 N.B register args may not be SP. */
8839
8840 /* OK, we start with ubfm which just needs to pick
8841 some bits out of source zero the rest and write
8842 the result to dest. Just need two logical shifts. */
8843
8844 /* 32 bit bitfield move, left and right of affected zeroed
8845 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8846 static void
8847 ubfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8848 {
8849 unsigned rd;
8850 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8851 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8852
8853 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
8854 if (r <= s)
8855 {
8856 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
8857 We want only bits s:xxx:r at the bottom of the word
8858 so we LSL bit s up to bit 31 i.e. by 31 - s
8859 and then we LSR to bring bit 31 down to bit s - r
8860 i.e. by 31 + r - s. */
8861 value <<= 31 - s;
8862 value >>= 31 + r - s;
8863 }
8864 else
8865 {
8866 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0
8867 We want only bits s:xxx:0 starting at it 31-(r-1)
8868 so we LSL bit s up to bit 31 i.e. by 31 - s
8869 and then we LSL to bring bit 31 down to 31-(r-1)+s
8870 i.e. by r - (s + 1). */
8871 value <<= 31 - s;
8872 value >>= r - (s + 1);
8873 }
8874
8875 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8876 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8877 }
8878
8879 /* 64 bit bitfield move, left and right of affected zeroed
8880 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
8881 static void
8882 ubfm (sim_cpu *cpu, uint32_t r, uint32_t s)
8883 {
8884 unsigned rd;
8885 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8886 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8887
8888 if (r <= s)
8889 {
8890 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
8891 We want only bits s:xxx:r at the bottom of the word.
8892 So we LSL bit s up to bit 63 i.e. by 63 - s
8893 and then we LSR to bring bit 63 down to bit s - r
8894 i.e. by 63 + r - s. */
8895 value <<= 63 - s;
8896 value >>= 63 + r - s;
8897 }
8898 else
8899 {
8900 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0.
8901 We want only bits s:xxx:0 starting at it 63-(r-1).
8902 So we LSL bit s up to bit 63 i.e. by 63 - s
8903 and then we LSL to bring bit 63 down to 63-(r-1)+s
8904 i.e. by r - (s + 1). */
8905 value <<= 63 - s;
8906 value >>= r - (s + 1);
8907 }
8908
8909 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8910 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8911 }
8912
8913 /* The signed versions need to insert sign bits
8914 on the left of the inserted bit field. so we do
8915 much the same as the unsigned version except we
8916 use an arithmetic shift right -- this just means
8917 we need to operate on signed values. */
8918
8919 /* 32 bit bitfield move, left of affected sign-extended, right zeroed. */
8920 /* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8921 static void
8922 sbfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8923 {
8924 unsigned rd;
8925 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8926 /* as per ubfm32 but use an ASR instead of an LSR. */
8927 int32_t value = aarch64_get_reg_s32 (cpu, rn, NO_SP);
8928
8929 if (r <= s)
8930 {
8931 value <<= 31 - s;
8932 value >>= 31 + r - s;
8933 }
8934 else
8935 {
8936 value <<= 31 - s;
8937 value >>= r - (s + 1);
8938 }
8939
8940 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8941 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8942 }
8943
8944 /* 64 bit bitfield move, left of affected sign-extended, right zeroed. */
8945 /* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
8946 static void
8947 sbfm (sim_cpu *cpu, uint32_t r, uint32_t s)
8948 {
8949 unsigned rd;
8950 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8951 /* acpu per ubfm but use an ASR instead of an LSR. */
8952 int64_t value = aarch64_get_reg_s64 (cpu, rn, NO_SP);
8953
8954 if (r <= s)
8955 {
8956 value <<= 63 - s;
8957 value >>= 63 + r - s;
8958 }
8959 else
8960 {
8961 value <<= 63 - s;
8962 value >>= r - (s + 1);
8963 }
8964
8965 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8966 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8967 }
8968
8969 /* Finally, these versions leave non-affected bits
8970 as is. so we need to generate the bits as per
8971 ubfm and also generate a mask to pick the
8972 bits from the original and computed values. */
8973
8974 /* 32 bit bitfield move, non-affected bits left as is.
8975 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8976 static void
8977 bfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8978 {
8979 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8980 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8981 uint32_t mask = -1;
8982 unsigned rd;
8983 uint32_t value2;
8984
8985 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
8986 if (r <= s)
8987 {
8988 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
8989 We want only bits s:xxx:r at the bottom of the word
8990 so we LSL bit s up to bit 31 i.e. by 31 - s
8991 and then we LSR to bring bit 31 down to bit s - r
8992 i.e. by 31 + r - s. */
8993 value <<= 31 - s;
8994 value >>= 31 + r - s;
8995 /* the mask must include the same bits. */
8996 mask <<= 31 - s;
8997 mask >>= 31 + r - s;
8998 }
8999 else
9000 {
9001 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0.
9002 We want only bits s:xxx:0 starting at it 31-(r-1)
9003 so we LSL bit s up to bit 31 i.e. by 31 - s
9004 and then we LSL to bring bit 31 down to 31-(r-1)+s
9005 i.e. by r - (s + 1). */
9006 value <<= 31 - s;
9007 value >>= r - (s + 1);
9008 /* The mask must include the same bits. */
9009 mask <<= 31 - s;
9010 mask >>= r - (s + 1);
9011 }
9012
9013 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9014 value2 = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9015
9016 value2 &= ~mask;
9017 value2 |= value;
9018
9019 aarch64_set_reg_u64
9020 (cpu, rd, NO_SP, (aarch64_get_reg_u32 (cpu, rd, NO_SP) & ~mask) | value);
9021 }
9022
9023 /* 64 bit bitfield move, non-affected bits left as is.
9024 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9025 static void
9026 bfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9027 {
9028 unsigned rd;
9029 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9030 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9031 uint64_t mask = 0xffffffffffffffffULL;
9032
9033 if (r <= s)
9034 {
9035 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9036 We want only bits s:xxx:r at the bottom of the word
9037 so we LSL bit s up to bit 63 i.e. by 63 - s
9038 and then we LSR to bring bit 63 down to bit s - r
9039 i.e. by 63 + r - s. */
9040 value <<= 63 - s;
9041 value >>= 63 + r - s;
9042 /* The mask must include the same bits. */
9043 mask <<= 63 - s;
9044 mask >>= 63 + r - s;
9045 }
9046 else
9047 {
9048 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0
9049 We want only bits s:xxx:0 starting at it 63-(r-1)
9050 so we LSL bit s up to bit 63 i.e. by 63 - s
9051 and then we LSL to bring bit 63 down to 63-(r-1)+s
9052 i.e. by r - (s + 1). */
9053 value <<= 63 - s;
9054 value >>= r - (s + 1);
9055 /* The mask must include the same bits. */
9056 mask <<= 63 - s;
9057 mask >>= r - (s + 1);
9058 }
9059
9060 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9061 aarch64_set_reg_u64
9062 (cpu, rd, NO_SP, (aarch64_get_reg_u64 (cpu, rd, NO_SP) & ~mask) | value);
9063 }
9064
9065 static void
9066 dexBitfieldImmediate (sim_cpu *cpu)
9067 {
9068 /* assert instr[28:23] = 100110
9069 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9070 instr[30,29] = op : 0 ==> SBFM, 1 ==> BFM, 2 ==> UBFM, 3 ==> UNALLOC
9071 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit ow UNALLOC
9072 instr[21,16] = immr : 0xxxxx for 32 bit, xxxxxx for 64 bit
9073 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9074 instr[9,5] = Rn
9075 instr[4,0] = Rd */
9076
9077 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9078 uint32_t dispatch;
9079 uint32_t imms;
9080 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
9081 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
9082 /* 32 bit operations must have immr[5] = 0 and imms[5] = 0. */
9083 /* or else we have an UNALLOC. */
9084 uint32_t immr = uimm (aarch64_get_instr (cpu), 21, 16);
9085
9086 if (~size & N)
9087 HALT_UNALLOC;
9088
9089 if (!size && uimm (immr, 5, 5))
9090 HALT_UNALLOC;
9091
9092 imms = uimm (aarch64_get_instr (cpu), 15, 10);
9093 if (!size && uimm (imms, 5, 5))
9094 HALT_UNALLOC;
9095
9096 /* Switch on combined size and op. */
9097 dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
9098 switch (dispatch)
9099 {
9100 case 0: sbfm32 (cpu, immr, imms); return;
9101 case 1: bfm32 (cpu, immr, imms); return;
9102 case 2: ubfm32 (cpu, immr, imms); return;
9103 case 4: sbfm (cpu, immr, imms); return;
9104 case 5: bfm (cpu, immr, imms); return;
9105 case 6: ubfm (cpu, immr, imms); return;
9106 default: HALT_UNALLOC;
9107 }
9108 }
9109
9110 static void
9111 do_EXTR_32 (sim_cpu *cpu)
9112 {
9113 /* instr[31:21] = 00010011100
9114 instr[20,16] = Rm
9115 instr[15,10] = imms : 0xxxxx for 32 bit
9116 instr[9,5] = Rn
9117 instr[4,0] = Rd */
9118 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9119 unsigned imms = uimm (aarch64_get_instr (cpu), 15, 10) & 31;
9120 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9121 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
9122 uint64_t val1;
9123 uint64_t val2;
9124
9125 val1 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
9126 val1 >>= imms;
9127 val2 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9128 val2 <<= (32 - imms);
9129
9130 aarch64_set_reg_u64 (cpu, rd, NO_SP, val1 | val2);
9131 }
9132
9133 static void
9134 do_EXTR_64 (sim_cpu *cpu)
9135 {
9136 /* instr[31:21] = 10010011100
9137 instr[20,16] = Rm
9138 instr[15,10] = imms
9139 instr[9,5] = Rn
9140 instr[4,0] = Rd */
9141 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9142 unsigned imms = uimm (aarch64_get_instr (cpu), 15, 10) & 63;
9143 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9144 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
9145 uint64_t val;
9146
9147 val = aarch64_get_reg_u64 (cpu, rm, NO_SP);
9148 val >>= imms;
9149 val |= (aarch64_get_reg_u64 (cpu, rn, NO_SP) << (64 - imms));
9150
9151 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
9152 }
9153
9154 static void
9155 dexExtractImmediate (sim_cpu *cpu)
9156 {
9157 /* assert instr[28:23] = 100111
9158 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9159 instr[30,29] = op21 : 0 ==> EXTR, 1,2,3 ==> UNALLOC
9160 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit or UNALLOC
9161 instr[21] = op0 : must be 0 or UNALLOC
9162 instr[20,16] = Rm
9163 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9164 instr[9,5] = Rn
9165 instr[4,0] = Rd */
9166
9167 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9168 /* 64 bit operations must have N = 1 or else we have an UNALLOC. */
9169 uint32_t dispatch;
9170 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
9171 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
9172 /* 32 bit operations must have imms[5] = 0
9173 or else we have an UNALLOC. */
9174 uint32_t imms = uimm (aarch64_get_instr (cpu), 15, 10);
9175
9176 if (size ^ N)
9177 HALT_UNALLOC;
9178
9179 if (!size && uimm (imms, 5, 5))
9180 HALT_UNALLOC;
9181
9182 /* Switch on combined size and op. */
9183 dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
9184
9185 if (dispatch == 0)
9186 do_EXTR_32 (cpu);
9187
9188 else if (dispatch == 4)
9189 do_EXTR_64 (cpu);
9190
9191 else if (dispatch == 1)
9192 HALT_NYI;
9193 else
9194 HALT_UNALLOC;
9195 }
9196
9197 static void
9198 dexDPImm (sim_cpu *cpu)
9199 {
9200 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
9201 assert group == GROUP_DPIMM_1000 || grpoup == GROUP_DPIMM_1001
9202 bits [25,23] of a DPImm are the secondary dispatch vector. */
9203 uint32_t group2 = dispatchDPImm (aarch64_get_instr (cpu));
9204
9205 switch (group2)
9206 {
9207 case DPIMM_PCADR_000:
9208 case DPIMM_PCADR_001:
9209 dexPCRelAddressing (cpu);
9210 return;
9211
9212 case DPIMM_ADDSUB_010:
9213 case DPIMM_ADDSUB_011:
9214 dexAddSubtractImmediate (cpu);
9215 return;
9216
9217 case DPIMM_LOG_100:
9218 dexLogicalImmediate (cpu);
9219 return;
9220
9221 case DPIMM_MOV_101:
9222 dexMoveWideImmediate (cpu);
9223 return;
9224
9225 case DPIMM_BITF_110:
9226 dexBitfieldImmediate (cpu);
9227 return;
9228
9229 case DPIMM_EXTR_111:
9230 dexExtractImmediate (cpu);
9231 return;
9232
9233 default:
9234 /* Should never reach here. */
9235 HALT_NYI;
9236 }
9237 }
9238
9239 static void
9240 dexLoadUnscaledImmediate (sim_cpu *cpu)
9241 {
9242 /* instr[29,24] == 111_00
9243 instr[21] == 0
9244 instr[11,10] == 00
9245 instr[31,30] = size
9246 instr[26] = V
9247 instr[23,22] = opc
9248 instr[20,12] = simm9
9249 instr[9,5] = rn may be SP. */
9250 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9251 uint32_t V = uimm (aarch64_get_instr (cpu), 26, 26);
9252 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9253 | uimm (aarch64_get_instr (cpu), 23, 22));
9254 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
9255
9256 if (!V)
9257 {
9258 /* GReg operations. */
9259 switch (dispatch)
9260 {
9261 case 0: sturb (cpu, imm); return;
9262 case 1: ldurb32 (cpu, imm); return;
9263 case 2: ldursb64 (cpu, imm); return;
9264 case 3: ldursb32 (cpu, imm); return;
9265 case 4: sturh (cpu, imm); return;
9266 case 5: ldurh32 (cpu, imm); return;
9267 case 6: ldursh64 (cpu, imm); return;
9268 case 7: ldursh32 (cpu, imm); return;
9269 case 8: stur32 (cpu, imm); return;
9270 case 9: ldur32 (cpu, imm); return;
9271 case 10: ldursw (cpu, imm); return;
9272 case 12: stur64 (cpu, imm); return;
9273 case 13: ldur64 (cpu, imm); return;
9274
9275 case 14:
9276 /* PRFUM NYI. */
9277 HALT_NYI;
9278
9279 default:
9280 case 11:
9281 case 15:
9282 HALT_UNALLOC;
9283 }
9284 }
9285
9286 /* FReg operations. */
9287 switch (dispatch)
9288 {
9289 case 2: fsturq (cpu, imm); return;
9290 case 3: fldurq (cpu, imm); return;
9291 case 8: fsturs (cpu, imm); return;
9292 case 9: fldurs (cpu, imm); return;
9293 case 12: fsturd (cpu, imm); return;
9294 case 13: fldurd (cpu, imm); return;
9295
9296 case 0: /* STUR 8 bit FP. */
9297 case 1: /* LDUR 8 bit FP. */
9298 case 4: /* STUR 16 bit FP. */
9299 case 5: /* LDUR 8 bit FP. */
9300 HALT_NYI;
9301
9302 default:
9303 case 6:
9304 case 7:
9305 case 10:
9306 case 11:
9307 case 14:
9308 case 15:
9309 HALT_UNALLOC;
9310 }
9311 }
9312
9313 /* N.B. A preliminary note regarding all the ldrs<x>32
9314 instructions
9315
9316 The signed value loaded by these instructions is cast to unsigned
9317 before being assigned to aarch64_get_reg_u64 (cpu, N) i.e. to the
9318 64 bit element of the GReg union. this performs a 32 bit sign extension
9319 (as required) but avoids 64 bit sign extension, thus ensuring that the
9320 top half of the register word is zero. this is what the spec demands
9321 when a 32 bit load occurs. */
9322
9323 /* 32 bit load sign-extended byte scaled unsigned 12 bit. */
9324 static void
9325 ldrsb32_abs (sim_cpu *cpu, uint32_t offset)
9326 {
9327 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9328 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9329
9330 /* The target register may not be SP but the source may be
9331 there is no scaling required for a byte load. */
9332 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
9333 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9334 (int64_t) aarch64_get_mem_s8 (cpu, address));
9335 }
9336
9337 /* 32 bit load sign-extended byte scaled or unscaled zero-
9338 or sign-extended 32-bit register offset. */
9339 static void
9340 ldrsb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9341 {
9342 unsigned int rm = uimm (aarch64_get_instr (cpu), 20, 16);
9343 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9344 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9345
9346 /* rn may reference SP, rm and rt must reference ZR. */
9347
9348 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9349 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9350 extension);
9351
9352 /* There is no scaling required for a byte load. */
9353 aarch64_set_reg_u64
9354 (cpu, rt, NO_SP, (int64_t) aarch64_get_mem_s8 (cpu, address
9355 + displacement));
9356 }
9357
9358 /* 32 bit load sign-extended byte unscaled signed 9 bit with
9359 pre- or post-writeback. */
9360 static void
9361 ldrsb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9362 {
9363 uint64_t address;
9364 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9365 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9366
9367 if (rn == rt && wb != NoWriteBack)
9368 HALT_UNALLOC;
9369
9370 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9371
9372 if (wb == Pre)
9373 address += offset;
9374
9375 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9376 (int64_t) aarch64_get_mem_s8 (cpu, address));
9377
9378 if (wb == Post)
9379 address += offset;
9380
9381 if (wb != NoWriteBack)
9382 aarch64_set_reg_u64 (cpu, rn, NO_SP, address);
9383 }
9384
9385 /* 8 bit store scaled. */
9386 static void
9387 fstrb_abs (sim_cpu *cpu, uint32_t offset)
9388 {
9389 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9390 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9391
9392 aarch64_set_mem_u8 (cpu,
9393 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
9394 aarch64_get_vec_u8 (cpu, st, 0));
9395 }
9396
9397 /* 8 bit store scaled or unscaled zero- or
9398 sign-extended 8-bit register offset. */
9399 static void
9400 fstrb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9401 {
9402 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9403 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9404 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9405
9406 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9407 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9408 extension);
9409 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9410
9411 aarch64_set_mem_u8
9412 (cpu, address + displacement, aarch64_get_vec_u8 (cpu, st, 0));
9413 }
9414
9415 /* 16 bit store scaled. */
9416 static void
9417 fstrh_abs (sim_cpu *cpu, uint32_t offset)
9418 {
9419 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9420 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9421
9422 aarch64_set_mem_u16
9423 (cpu,
9424 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16),
9425 aarch64_get_vec_u16 (cpu, st, 0));
9426 }
9427
9428 /* 16 bit store scaled or unscaled zero-
9429 or sign-extended 16-bit register offset. */
9430 static void
9431 fstrh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9432 {
9433 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9434 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9435 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9436
9437 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9438 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9439 extension);
9440 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9441
9442 aarch64_set_mem_u16
9443 (cpu, address + displacement, aarch64_get_vec_u16 (cpu, st, 0));
9444 }
9445
9446 /* 32 bit store scaled unsigned 12 bit. */
9447 static void
9448 fstrs_abs (sim_cpu *cpu, uint32_t offset)
9449 {
9450 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9451 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9452
9453 aarch64_set_mem_float
9454 (cpu,
9455 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
9456 aarch64_get_FP_float (cpu, st));
9457 }
9458
9459 /* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
9460 static void
9461 fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9462 {
9463 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9464 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9465
9466 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9467
9468 if (wb != Post)
9469 address += offset;
9470
9471 aarch64_set_mem_float (cpu, address, aarch64_get_FP_float (cpu, st));
9472
9473 if (wb == Post)
9474 address += offset;
9475
9476 if (wb != NoWriteBack)
9477 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9478 }
9479
9480 /* 32 bit store scaled or unscaled zero-
9481 or sign-extended 32-bit register offset. */
9482 static void
9483 fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9484 {
9485 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9486 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9487 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9488
9489 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9490 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9491 extension);
9492 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9493
9494 aarch64_set_mem_float
9495 (cpu, address + displacement, aarch64_get_FP_float (cpu, st));
9496 }
9497
9498 /* 64 bit store scaled unsigned 12 bit. */
9499 static void
9500 fstrd_abs (sim_cpu *cpu, uint32_t offset)
9501 {
9502 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9503 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9504
9505 aarch64_set_mem_double
9506 (cpu,
9507 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
9508 aarch64_get_FP_double (cpu, st));
9509 }
9510
9511 /* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
9512 static void
9513 fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9514 {
9515 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9516 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9517
9518 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9519
9520 if (wb != Post)
9521 address += offset;
9522
9523 aarch64_set_mem_double (cpu, address, aarch64_get_FP_double (cpu, st));
9524
9525 if (wb == Post)
9526 address += offset;
9527
9528 if (wb != NoWriteBack)
9529 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9530 }
9531
9532 /* 64 bit store scaled or unscaled zero-
9533 or sign-extended 32-bit register offset. */
9534 static void
9535 fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9536 {
9537 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9538 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9539 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9540
9541 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9542 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9543 extension);
9544 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
9545
9546 aarch64_set_mem_double
9547 (cpu, address + displacement, aarch64_get_FP_double (cpu, st));
9548 }
9549
9550 /* 128 bit store scaled unsigned 12 bit. */
9551 static void
9552 fstrq_abs (sim_cpu *cpu, uint32_t offset)
9553 {
9554 FRegister a;
9555 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9556 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9557 uint64_t addr;
9558
9559 aarch64_get_FP_long_double (cpu, st, & a);
9560
9561 addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
9562 aarch64_set_mem_long_double (cpu, addr, a);
9563 }
9564
9565 /* 128 bit store unscaled signed 9 bit with pre- or post-writeback. */
9566 static void
9567 fstrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9568 {
9569 FRegister a;
9570 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9571 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9572 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9573
9574 if (wb != Post)
9575 address += offset;
9576
9577 aarch64_get_FP_long_double (cpu, st, & a);
9578 aarch64_set_mem_long_double (cpu, address, a);
9579
9580 if (wb == Post)
9581 address += offset;
9582
9583 if (wb != NoWriteBack)
9584 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9585 }
9586
9587 /* 128 bit store scaled or unscaled zero-
9588 or sign-extended 32-bit register offset. */
9589 static void
9590 fstrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9591 {
9592 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9593 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9594 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9595
9596 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9597 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9598 extension);
9599 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
9600
9601 FRegister a;
9602
9603 aarch64_get_FP_long_double (cpu, st, & a);
9604 aarch64_set_mem_long_double (cpu, address + displacement, a);
9605 }
9606
9607 static void
9608 dexLoadImmediatePrePost (sim_cpu *cpu)
9609 {
9610 /* instr[29,24] == 111_00
9611 instr[21] == 0
9612 instr[11,10] == 00
9613 instr[31,30] = size
9614 instr[26] = V
9615 instr[23,22] = opc
9616 instr[20,12] = simm9
9617 instr[11] = wb : 0 ==> Post, 1 ==> Pre
9618 instr[9,5] = rn may be SP. */
9619 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9620 uint32_t V = uimm (aarch64_get_instr (cpu), 26, 26);
9621 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9622 | uimm (aarch64_get_instr (cpu), 23, 22));
9623 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
9624 WriteBack wb = writeback (aarch64_get_instr (cpu), 11);
9625
9626 if (!V)
9627 {
9628 /* GReg operations. */
9629 switch (dispatch)
9630 {
9631 case 0: strb_wb (cpu, imm, wb); return;
9632 case 1: ldrb32_wb (cpu, imm, wb); return;
9633 case 2: ldrsb_wb (cpu, imm, wb); return;
9634 case 3: ldrsb32_wb (cpu, imm, wb); return;
9635 case 4: strh_wb (cpu, imm, wb); return;
9636 case 5: ldrh32_wb (cpu, imm, wb); return;
9637 case 6: ldrsh64_wb (cpu, imm, wb); return;
9638 case 7: ldrsh32_wb (cpu, imm, wb); return;
9639 case 8: str32_wb (cpu, imm, wb); return;
9640 case 9: ldr32_wb (cpu, imm, wb); return;
9641 case 10: ldrsw_wb (cpu, imm, wb); return;
9642 case 12: str_wb (cpu, imm, wb); return;
9643 case 13: ldr_wb (cpu, imm, wb); return;
9644
9645 default:
9646 case 11:
9647 case 14:
9648 case 15:
9649 HALT_UNALLOC;
9650 }
9651 }
9652
9653 /* FReg operations. */
9654 switch (dispatch)
9655 {
9656 case 2: fstrq_wb (cpu, imm, wb); return;
9657 case 3: fldrq_wb (cpu, imm, wb); return;
9658 case 8: fstrs_wb (cpu, imm, wb); return;
9659 case 9: fldrs_wb (cpu, imm, wb); return;
9660 case 12: fstrd_wb (cpu, imm, wb); return;
9661 case 13: fldrd_wb (cpu, imm, wb); return;
9662
9663 case 0: /* STUR 8 bit FP. */
9664 case 1: /* LDUR 8 bit FP. */
9665 case 4: /* STUR 16 bit FP. */
9666 case 5: /* LDUR 8 bit FP. */
9667 HALT_NYI;
9668
9669 default:
9670 case 6:
9671 case 7:
9672 case 10:
9673 case 11:
9674 case 14:
9675 case 15:
9676 HALT_UNALLOC;
9677 }
9678 }
9679
9680 static void
9681 dexLoadRegisterOffset (sim_cpu *cpu)
9682 {
9683 /* instr[31,30] = size
9684 instr[29,27] = 111
9685 instr[26] = V
9686 instr[25,24] = 00
9687 instr[23,22] = opc
9688 instr[21] = 1
9689 instr[20,16] = rm
9690 instr[15,13] = option : 010 ==> UXTW, 011 ==> UXTX/LSL,
9691 110 ==> SXTW, 111 ==> SXTX,
9692 ow ==> RESERVED
9693 instr[12] = scaled
9694 instr[11,10] = 10
9695 instr[9,5] = rn
9696 instr[4,0] = rt. */
9697
9698 uint32_t V = uimm (aarch64_get_instr (cpu), 26,26);
9699 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9700 | uimm (aarch64_get_instr (cpu), 23, 22));
9701 Scaling scale = scaling (aarch64_get_instr (cpu), 12);
9702 Extension extensionType = extension (aarch64_get_instr (cpu), 13);
9703
9704 /* Check for illegal extension types. */
9705 if (uimm (extensionType, 1, 1) == 0)
9706 HALT_UNALLOC;
9707
9708 if (extensionType == UXTX || extensionType == SXTX)
9709 extensionType = NoExtension;
9710
9711 if (!V)
9712 {
9713 /* GReg operations. */
9714 switch (dispatch)
9715 {
9716 case 0: strb_scale_ext (cpu, scale, extensionType); return;
9717 case 1: ldrb32_scale_ext (cpu, scale, extensionType); return;
9718 case 2: ldrsb_scale_ext (cpu, scale, extensionType); return;
9719 case 3: ldrsb32_scale_ext (cpu, scale, extensionType); return;
9720 case 4: strh_scale_ext (cpu, scale, extensionType); return;
9721 case 5: ldrh32_scale_ext (cpu, scale, extensionType); return;
9722 case 6: ldrsh_scale_ext (cpu, scale, extensionType); return;
9723 case 7: ldrsh32_scale_ext (cpu, scale, extensionType); return;
9724 case 8: str32_scale_ext (cpu, scale, extensionType); return;
9725 case 9: ldr32_scale_ext (cpu, scale, extensionType); return;
9726 case 10: ldrsw_scale_ext (cpu, scale, extensionType); return;
9727 case 12: str_scale_ext (cpu, scale, extensionType); return;
9728 case 13: ldr_scale_ext (cpu, scale, extensionType); return;
9729 case 14: prfm_scale_ext (cpu, scale, extensionType); return;
9730
9731 default:
9732 case 11:
9733 case 15:
9734 HALT_UNALLOC;
9735 }
9736 }
9737
9738 /* FReg operations. */
9739 switch (dispatch)
9740 {
9741 case 1: /* LDUR 8 bit FP. */
9742 HALT_NYI;
9743 case 3: fldrq_scale_ext (cpu, scale, extensionType); return;
9744 case 5: /* LDUR 8 bit FP. */
9745 HALT_NYI;
9746 case 9: fldrs_scale_ext (cpu, scale, extensionType); return;
9747 case 13: fldrd_scale_ext (cpu, scale, extensionType); return;
9748
9749 case 0: fstrb_scale_ext (cpu, scale, extensionType); return;
9750 case 2: fstrq_scale_ext (cpu, scale, extensionType); return;
9751 case 4: fstrh_scale_ext (cpu, scale, extensionType); return;
9752 case 8: fstrs_scale_ext (cpu, scale, extensionType); return;
9753 case 12: fstrd_scale_ext (cpu, scale, extensionType); return;
9754
9755 default:
9756 case 6:
9757 case 7:
9758 case 10:
9759 case 11:
9760 case 14:
9761 case 15:
9762 HALT_UNALLOC;
9763 }
9764 }
9765
9766 static void
9767 dexLoadUnsignedImmediate (sim_cpu *cpu)
9768 {
9769 /* assert instr[29,24] == 111_01
9770 instr[31,30] = size
9771 instr[26] = V
9772 instr[23,22] = opc
9773 instr[21,10] = uimm12 : unsigned immediate offset
9774 instr[9,5] = rn may be SP. */
9775 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9776 uint32_t V = uimm (aarch64_get_instr (cpu), 26,26);
9777 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9778 | uimm (aarch64_get_instr (cpu), 23, 22));
9779 uint32_t imm = uimm (aarch64_get_instr (cpu), 21, 10);
9780
9781 if (!V)
9782 {
9783 /* GReg operations. */
9784 switch (dispatch)
9785 {
9786 case 0: strb_abs (cpu, imm); return;
9787 case 1: ldrb32_abs (cpu, imm); return;
9788 case 2: ldrsb_abs (cpu, imm); return;
9789 case 3: ldrsb32_abs (cpu, imm); return;
9790 case 4: strh_abs (cpu, imm); return;
9791 case 5: ldrh32_abs (cpu, imm); return;
9792 case 6: ldrsh_abs (cpu, imm); return;
9793 case 7: ldrsh32_abs (cpu, imm); return;
9794 case 8: str32_abs (cpu, imm); return;
9795 case 9: ldr32_abs (cpu, imm); return;
9796 case 10: ldrsw_abs (cpu, imm); return;
9797 case 12: str_abs (cpu, imm); return;
9798 case 13: ldr_abs (cpu, imm); return;
9799 case 14: prfm_abs (cpu, imm); return;
9800
9801 default:
9802 case 11:
9803 case 15:
9804 HALT_UNALLOC;
9805 }
9806 }
9807
9808 /* FReg operations. */
9809 switch (dispatch)
9810 {
9811 case 3: fldrq_abs (cpu, imm); return;
9812 case 9: fldrs_abs (cpu, imm); return;
9813 case 13: fldrd_abs (cpu, imm); return;
9814
9815 case 0: fstrb_abs (cpu, imm); return;
9816 case 2: fstrq_abs (cpu, imm); return;
9817 case 4: fstrh_abs (cpu, imm); return;
9818 case 8: fstrs_abs (cpu, imm); return;
9819 case 12: fstrd_abs (cpu, imm); return;
9820
9821 case 1: /* LDR 8 bit FP. */
9822 case 5: /* LDR 8 bit FP. */
9823 HALT_NYI;
9824
9825 default:
9826 case 6:
9827 case 7:
9828 case 10:
9829 case 11:
9830 case 14:
9831 case 15:
9832 HALT_UNALLOC;
9833 }
9834 }
9835
9836 static void
9837 dexLoadExclusive (sim_cpu *cpu)
9838 {
9839 /* assert instr[29:24] = 001000;
9840 instr[31,30] = size
9841 instr[23] = 0 if exclusive
9842 instr[22] = L : 1 if load, 0 if store
9843 instr[21] = 1 if pair
9844 instr[20,16] = Rs
9845 instr[15] = o0 : 1 if ordered
9846 instr[14,10] = Rt2
9847 instr[9,5] = Rn
9848 instr[4.0] = Rt. */
9849
9850 switch (uimm (aarch64_get_instr (cpu), 22, 21))
9851 {
9852 case 2: ldxr (cpu); return;
9853 case 0: stxr (cpu); return;
9854 default: HALT_NYI;
9855 }
9856 }
9857
9858 static void
9859 dexLoadOther (sim_cpu *cpu)
9860 {
9861 uint32_t dispatch;
9862
9863 /* instr[29,25] = 111_0
9864 instr[24] == 0 ==> dispatch, 1 ==> ldst reg unsigned immediate
9865 instr[21:11,10] is the secondary dispatch. */
9866 if (uimm (aarch64_get_instr (cpu), 24, 24))
9867 {
9868 dexLoadUnsignedImmediate (cpu);
9869 return;
9870 }
9871
9872 dispatch = ( (uimm (aarch64_get_instr (cpu), 21, 21) << 2)
9873 | uimm (aarch64_get_instr (cpu), 11, 10));
9874 switch (dispatch)
9875 {
9876 case 0: dexLoadUnscaledImmediate (cpu); return;
9877 case 1: dexLoadImmediatePrePost (cpu); return;
9878 case 3: dexLoadImmediatePrePost (cpu); return;
9879 case 6: dexLoadRegisterOffset (cpu); return;
9880
9881 default:
9882 case 2:
9883 case 4:
9884 case 5:
9885 case 7:
9886 HALT_NYI;
9887 }
9888 }
9889
9890 static void
9891 store_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9892 {
9893 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9894 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9895 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9896 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9897
9898 if ((rn == rd || rm == rd) && wb != NoWriteBack)
9899 HALT_UNALLOC; /* ??? */
9900
9901 offset <<= 2;
9902
9903 if (wb != Post)
9904 address += offset;
9905
9906 aarch64_set_mem_u32 (cpu, address,
9907 aarch64_get_reg_u32 (cpu, rm, NO_SP));
9908 aarch64_set_mem_u32 (cpu, address + 4,
9909 aarch64_get_reg_u32 (cpu, rn, NO_SP));
9910
9911 if (wb == Post)
9912 address += offset;
9913
9914 if (wb != NoWriteBack)
9915 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9916 }
9917
9918 static void
9919 store_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9920 {
9921 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9922 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9923 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9924 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9925
9926 if ((rn == rd || rm == rd) && wb != NoWriteBack)
9927 HALT_UNALLOC; /* ??? */
9928
9929 offset <<= 3;
9930
9931 if (wb != Post)
9932 address += offset;
9933
9934 aarch64_set_mem_u64 (cpu, address,
9935 aarch64_get_reg_u64 (cpu, rm, SP_OK));
9936 aarch64_set_mem_u64 (cpu, address + 8,
9937 aarch64_get_reg_u64 (cpu, rn, SP_OK));
9938
9939 if (wb == Post)
9940 address += offset;
9941
9942 if (wb != NoWriteBack)
9943 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9944 }
9945
9946 static void
9947 load_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9948 {
9949 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9950 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9951 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9952 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9953
9954 /* treat this as unalloc to make sure we don't do it. */
9955 if (rn == rm)
9956 HALT_UNALLOC;
9957
9958 offset <<= 2;
9959
9960 if (wb != Post)
9961 address += offset;
9962
9963 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u32 (cpu, address));
9964 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u32 (cpu, address + 4));
9965
9966 if (wb == Post)
9967 address += offset;
9968
9969 if (wb != NoWriteBack)
9970 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9971 }
9972
9973 static void
9974 load_pair_s32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9975 {
9976 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9977 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9978 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9979 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9980
9981 /* Treat this as unalloc to make sure we don't do it. */
9982 if (rn == rm)
9983 HALT_UNALLOC;
9984
9985 offset <<= 2;
9986
9987 if (wb != Post)
9988 address += offset;
9989
9990 aarch64_set_reg_s64 (cpu, rm, SP_OK, aarch64_get_mem_s32 (cpu, address));
9991 aarch64_set_reg_s64 (cpu, rn, SP_OK, aarch64_get_mem_s32 (cpu, address + 4));
9992
9993 if (wb == Post)
9994 address += offset;
9995
9996 if (wb != NoWriteBack)
9997 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9998 }
9999
10000 static void
10001 load_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
10002 {
10003 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10004 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10005 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10006 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10007
10008 /* Treat this as unalloc to make sure we don't do it. */
10009 if (rn == rm)
10010 HALT_UNALLOC;
10011
10012 offset <<= 3;
10013
10014 if (wb != Post)
10015 address += offset;
10016
10017 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u64 (cpu, address));
10018 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u64 (cpu, address + 8));
10019
10020 if (wb == Post)
10021 address += offset;
10022
10023 if (wb != NoWriteBack)
10024 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10025 }
10026
10027 static void
10028 dex_load_store_pair_gr (sim_cpu *cpu)
10029 {
10030 /* instr[31,30] = size (10=> 64-bit, 01=> signed 32-bit, 00=> 32-bit)
10031 instr[29,25] = instruction encoding: 101_0
10032 instr[26] = V : 1 if fp 0 if gp
10033 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10034 instr[22] = load/store (1=> load)
10035 instr[21,15] = signed, scaled, offset
10036 instr[14,10] = Rn
10037 instr[ 9, 5] = Rd
10038 instr[ 4, 0] = Rm. */
10039
10040 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 3)
10041 | uimm (aarch64_get_instr (cpu), 24, 22));
10042 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10043
10044 switch (dispatch)
10045 {
10046 case 2: store_pair_u32 (cpu, offset, Post); return;
10047 case 3: load_pair_u32 (cpu, offset, Post); return;
10048 case 4: store_pair_u32 (cpu, offset, NoWriteBack); return;
10049 case 5: load_pair_u32 (cpu, offset, NoWriteBack); return;
10050 case 6: store_pair_u32 (cpu, offset, Pre); return;
10051 case 7: load_pair_u32 (cpu, offset, Pre); return;
10052
10053 case 11: load_pair_s32 (cpu, offset, Post); return;
10054 case 13: load_pair_s32 (cpu, offset, NoWriteBack); return;
10055 case 15: load_pair_s32 (cpu, offset, Pre); return;
10056
10057 case 18: store_pair_u64 (cpu, offset, Post); return;
10058 case 19: load_pair_u64 (cpu, offset, Post); return;
10059 case 20: store_pair_u64 (cpu, offset, NoWriteBack); return;
10060 case 21: load_pair_u64 (cpu, offset, NoWriteBack); return;
10061 case 22: store_pair_u64 (cpu, offset, Pre); return;
10062 case 23: load_pair_u64 (cpu, offset, Pre); return;
10063
10064 default:
10065 HALT_UNALLOC;
10066 }
10067 }
10068
10069 static void
10070 store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10071 {
10072 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10073 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10074 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10075 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10076
10077 offset <<= 2;
10078
10079 if (wb != Post)
10080 address += offset;
10081
10082 aarch64_set_mem_float (cpu, address, aarch64_get_FP_float (cpu, rm));
10083 aarch64_set_mem_float (cpu, address + 4, aarch64_get_FP_float (cpu, rn));
10084
10085 if (wb == Post)
10086 address += offset;
10087
10088 if (wb != NoWriteBack)
10089 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10090 }
10091
10092 static void
10093 store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10094 {
10095 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10096 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10097 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10098 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10099
10100 offset <<= 3;
10101
10102 if (wb != Post)
10103 address += offset;
10104
10105 aarch64_set_mem_double (cpu, address, aarch64_get_FP_double (cpu, rm));
10106 aarch64_set_mem_double (cpu, address + 8, aarch64_get_FP_double (cpu, rn));
10107
10108 if (wb == Post)
10109 address += offset;
10110
10111 if (wb != NoWriteBack)
10112 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10113 }
10114
10115 static void
10116 store_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10117 {
10118 FRegister a;
10119 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10120 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10121 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10122 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10123
10124 offset <<= 4;
10125
10126 if (wb != Post)
10127 address += offset;
10128
10129 aarch64_get_FP_long_double (cpu, rm, & a);
10130 aarch64_set_mem_long_double (cpu, address, a);
10131 aarch64_get_FP_long_double (cpu, rn, & a);
10132 aarch64_set_mem_long_double (cpu, address + 16, a);
10133
10134 if (wb == Post)
10135 address += offset;
10136
10137 if (wb != NoWriteBack)
10138 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10139 }
10140
10141 static void
10142 load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10143 {
10144 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10145 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10146 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10147 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10148
10149 if (rm == rn)
10150 HALT_UNALLOC;
10151
10152 offset <<= 2;
10153
10154 if (wb != Post)
10155 address += offset;
10156
10157 aarch64_set_FP_float (cpu, rm, aarch64_get_mem_float (cpu, address));
10158 aarch64_set_FP_float (cpu, rn, aarch64_get_mem_float (cpu, address + 4));
10159
10160 if (wb == Post)
10161 address += offset;
10162
10163 if (wb != NoWriteBack)
10164 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10165 }
10166
10167 static void
10168 load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10169 {
10170 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10171 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10172 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10173 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10174
10175 if (rm == rn)
10176 HALT_UNALLOC;
10177
10178 offset <<= 3;
10179
10180 if (wb != Post)
10181 address += offset;
10182
10183 aarch64_set_FP_double (cpu, rm, aarch64_get_mem_double (cpu, address));
10184 aarch64_set_FP_double (cpu, rn, aarch64_get_mem_double (cpu, address + 8));
10185
10186 if (wb == Post)
10187 address += offset;
10188
10189 if (wb != NoWriteBack)
10190 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10191 }
10192
10193 static void
10194 load_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10195 {
10196 FRegister a;
10197 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10198 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10199 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10200 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10201
10202 if (rm == rn)
10203 HALT_UNALLOC;
10204
10205 offset <<= 4;
10206
10207 if (wb != Post)
10208 address += offset;
10209
10210 aarch64_get_mem_long_double (cpu, address, & a);
10211 aarch64_set_FP_long_double (cpu, rm, a);
10212 aarch64_get_mem_long_double (cpu, address + 16, & a);
10213 aarch64_set_FP_long_double (cpu, rn, a);
10214
10215 if (wb == Post)
10216 address += offset;
10217
10218 if (wb != NoWriteBack)
10219 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10220 }
10221
10222 static void
10223 dex_load_store_pair_fp (sim_cpu *cpu)
10224 {
10225 /* instr[31,30] = size (10=> 128-bit, 01=> 64-bit, 00=> 32-bit)
10226 instr[29,25] = instruction encoding
10227 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10228 instr[22] = load/store (1=> load)
10229 instr[21,15] = signed, scaled, offset
10230 instr[14,10] = Rn
10231 instr[ 9, 5] = Rd
10232 instr[ 4, 0] = Rm */
10233
10234 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 3)
10235 | uimm (aarch64_get_instr (cpu), 24, 22));
10236 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10237
10238 switch (dispatch)
10239 {
10240 case 2: store_pair_float (cpu, offset, Post); return;
10241 case 3: load_pair_float (cpu, offset, Post); return;
10242 case 4: store_pair_float (cpu, offset, NoWriteBack); return;
10243 case 5: load_pair_float (cpu, offset, NoWriteBack); return;
10244 case 6: store_pair_float (cpu, offset, Pre); return;
10245 case 7: load_pair_float (cpu, offset, Pre); return;
10246
10247 case 10: store_pair_double (cpu, offset, Post); return;
10248 case 11: load_pair_double (cpu, offset, Post); return;
10249 case 12: store_pair_double (cpu, offset, NoWriteBack); return;
10250 case 13: load_pair_double (cpu, offset, NoWriteBack); return;
10251 case 14: store_pair_double (cpu, offset, Pre); return;
10252 case 15: load_pair_double (cpu, offset, Pre); return;
10253
10254 case 18: store_pair_long_double (cpu, offset, Post); return;
10255 case 19: load_pair_long_double (cpu, offset, Post); return;
10256 case 20: store_pair_long_double (cpu, offset, NoWriteBack); return;
10257 case 21: load_pair_long_double (cpu, offset, NoWriteBack); return;
10258 case 22: store_pair_long_double (cpu, offset, Pre); return;
10259 case 23: load_pair_long_double (cpu, offset, Pre); return;
10260
10261 default:
10262 HALT_UNALLOC;
10263 }
10264 }
10265
10266 static inline unsigned
10267 vec_reg (unsigned v, unsigned o)
10268 {
10269 return (v + o) & 0x3F;
10270 }
10271
10272 /* Load multiple N-element structures to N consecutive registers. */
10273 static void
10274 vec_load (sim_cpu *cpu, uint64_t address, unsigned N)
10275 {
10276 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10277 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10278 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10279 unsigned i;
10280
10281 switch (size)
10282 {
10283 case 0: /* 8-bit operations. */
10284 if (all)
10285 for (i = 0; i < (16 * N); i++)
10286 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15,
10287 aarch64_get_mem_u8 (cpu, address + i));
10288 else
10289 for (i = 0; i < (8 * N); i++)
10290 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7,
10291 aarch64_get_mem_u8 (cpu, address + i));
10292 return;
10293
10294 case 1: /* 16-bit operations. */
10295 if (all)
10296 for (i = 0; i < (8 * N); i++)
10297 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7,
10298 aarch64_get_mem_u16 (cpu, address + i * 2));
10299 else
10300 for (i = 0; i < (4 * N); i++)
10301 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3,
10302 aarch64_get_mem_u16 (cpu, address + i * 2));
10303 return;
10304
10305 case 2: /* 32-bit operations. */
10306 if (all)
10307 for (i = 0; i < (4 * N); i++)
10308 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3,
10309 aarch64_get_mem_u32 (cpu, address + i * 4));
10310 else
10311 for (i = 0; i < (2 * N); i++)
10312 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1,
10313 aarch64_get_mem_u32 (cpu, address + i * 4));
10314 return;
10315
10316 case 3: /* 64-bit operations. */
10317 if (all)
10318 for (i = 0; i < (2 * N); i++)
10319 aarch64_set_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1,
10320 aarch64_get_mem_u64 (cpu, address + i * 8));
10321 else
10322 for (i = 0; i < N; i++)
10323 aarch64_set_vec_u64 (cpu, vec_reg (vd, i), 0,
10324 aarch64_get_mem_u64 (cpu, address + i * 8));
10325 return;
10326
10327 default:
10328 HALT_UNREACHABLE;
10329 }
10330 }
10331
10332 /* LD4: load multiple 4-element to four consecutive registers. */
10333 static void
10334 LD4 (sim_cpu *cpu, uint64_t address)
10335 {
10336 vec_load (cpu, address, 4);
10337 }
10338
10339 /* LD3: load multiple 3-element structures to three consecutive registers. */
10340 static void
10341 LD3 (sim_cpu *cpu, uint64_t address)
10342 {
10343 vec_load (cpu, address, 3);
10344 }
10345
10346 /* LD2: load multiple 2-element structures to two consecutive registers. */
10347 static void
10348 LD2 (sim_cpu *cpu, uint64_t address)
10349 {
10350 vec_load (cpu, address, 2);
10351 }
10352
10353 /* Load multiple 1-element structures into one register. */
10354 static void
10355 LD1_1 (sim_cpu *cpu, uint64_t address)
10356 {
10357 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10358 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10359 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10360 unsigned i;
10361
10362 switch (size)
10363 {
10364 case 0:
10365 /* LD1 {Vd.16b}, addr, #16 */
10366 /* LD1 {Vd.8b}, addr, #8 */
10367 for (i = 0; i < (all ? 16 : 8); i++)
10368 aarch64_set_vec_u8 (cpu, vd, i,
10369 aarch64_get_mem_u8 (cpu, address + i));
10370 return;
10371
10372 case 1:
10373 /* LD1 {Vd.8h}, addr, #16 */
10374 /* LD1 {Vd.4h}, addr, #8 */
10375 for (i = 0; i < (all ? 8 : 4); i++)
10376 aarch64_set_vec_u16 (cpu, vd, i,
10377 aarch64_get_mem_u16 (cpu, address + i * 2));
10378 return;
10379
10380 case 2:
10381 /* LD1 {Vd.4s}, addr, #16 */
10382 /* LD1 {Vd.2s}, addr, #8 */
10383 for (i = 0; i < (all ? 4 : 2); i++)
10384 aarch64_set_vec_u32 (cpu, vd, i,
10385 aarch64_get_mem_u32 (cpu, address + i * 4));
10386 return;
10387
10388 case 3:
10389 /* LD1 {Vd.2d}, addr, #16 */
10390 /* LD1 {Vd.1d}, addr, #8 */
10391 for (i = 0; i < (all ? 2 : 1); i++)
10392 aarch64_set_vec_u64 (cpu, vd, i,
10393 aarch64_get_mem_u64 (cpu, address + i * 8));
10394 return;
10395
10396 default:
10397 HALT_UNREACHABLE;
10398 }
10399 }
10400
10401 /* Load multiple 1-element structures into two registers. */
10402 static void
10403 LD1_2 (sim_cpu *cpu, uint64_t address)
10404 {
10405 /* FIXME: This algorithm is *exactly* the same as the LD2 version.
10406 So why have two different instructions ? There must be something
10407 wrong somewhere. */
10408 vec_load (cpu, address, 2);
10409 }
10410
10411 /* Load multiple 1-element structures into three registers. */
10412 static void
10413 LD1_3 (sim_cpu *cpu, uint64_t address)
10414 {
10415 /* FIXME: This algorithm is *exactly* the same as the LD3 version.
10416 So why have two different instructions ? There must be something
10417 wrong somewhere. */
10418 vec_load (cpu, address, 3);
10419 }
10420
10421 /* Load multiple 1-element structures into four registers. */
10422 static void
10423 LD1_4 (sim_cpu *cpu, uint64_t address)
10424 {
10425 /* FIXME: This algorithm is *exactly* the same as the LD4 version.
10426 So why have two different instructions ? There must be something
10427 wrong somewhere. */
10428 vec_load (cpu, address, 4);
10429 }
10430
10431 /* Store multiple N-element structures to N consecutive registers. */
10432 static void
10433 vec_store (sim_cpu *cpu, uint64_t address, unsigned N)
10434 {
10435 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10436 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10437 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10438 unsigned i;
10439
10440 switch (size)
10441 {
10442 case 0: /* 8-bit operations. */
10443 if (all)
10444 for (i = 0; i < (16 * N); i++)
10445 aarch64_set_mem_u8
10446 (cpu, address + i,
10447 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15));
10448 else
10449 for (i = 0; i < (8 * N); i++)
10450 aarch64_set_mem_u8
10451 (cpu, address + i,
10452 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7));
10453 return;
10454
10455 case 1: /* 16-bit operations. */
10456 if (all)
10457 for (i = 0; i < (8 * N); i++)
10458 aarch64_set_mem_u16
10459 (cpu, address + i * 2,
10460 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7));
10461 else
10462 for (i = 0; i < (4 * N); i++)
10463 aarch64_set_mem_u16
10464 (cpu, address + i * 2,
10465 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3));
10466 return;
10467
10468 case 2: /* 32-bit operations. */
10469 if (all)
10470 for (i = 0; i < (4 * N); i++)
10471 aarch64_set_mem_u32
10472 (cpu, address + i * 4,
10473 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3));
10474 else
10475 for (i = 0; i < (2 * N); i++)
10476 aarch64_set_mem_u32
10477 (cpu, address + i * 4,
10478 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1));
10479 return;
10480
10481 case 3: /* 64-bit operations. */
10482 if (all)
10483 for (i = 0; i < (2 * N); i++)
10484 aarch64_set_mem_u64
10485 (cpu, address + i * 8,
10486 aarch64_get_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1));
10487 else
10488 for (i = 0; i < N; i++)
10489 aarch64_set_mem_u64
10490 (cpu, address + i * 8,
10491 aarch64_get_vec_u64 (cpu, vec_reg (vd, i), 0));
10492 return;
10493
10494 default:
10495 HALT_UNREACHABLE;
10496 }
10497 }
10498
10499 /* Store multiple 4-element structure to four consecutive registers. */
10500 static void
10501 ST4 (sim_cpu *cpu, uint64_t address)
10502 {
10503 vec_store (cpu, address, 4);
10504 }
10505
10506 /* Store multiple 3-element structures to three consecutive registers. */
10507 static void
10508 ST3 (sim_cpu *cpu, uint64_t address)
10509 {
10510 vec_store (cpu, address, 3);
10511 }
10512
10513 /* Store multiple 2-element structures to two consecutive registers. */
10514 static void
10515 ST2 (sim_cpu *cpu, uint64_t address)
10516 {
10517 vec_store (cpu, address, 2);
10518 }
10519
10520 /* Store multiple 1-element structures into one register. */
10521 static void
10522 ST1_1 (sim_cpu *cpu, uint64_t address)
10523 {
10524 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10525 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10526 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10527 unsigned i;
10528
10529 switch (size)
10530 {
10531 case 0:
10532 for (i = 0; i < (all ? 16 : 8); i++)
10533 aarch64_set_mem_u8 (cpu, address + i,
10534 aarch64_get_vec_u8 (cpu, vd, i));
10535 return;
10536
10537 case 1:
10538 for (i = 0; i < (all ? 8 : 4); i++)
10539 aarch64_set_mem_u16 (cpu, address + i * 2,
10540 aarch64_get_vec_u16 (cpu, vd, i));
10541 return;
10542
10543 case 2:
10544 for (i = 0; i < (all ? 4 : 2); i++)
10545 aarch64_set_mem_u32 (cpu, address + i * 4,
10546 aarch64_get_vec_u32 (cpu, vd, i));
10547 return;
10548
10549 case 3:
10550 for (i = 0; i < (all ? 2 : 1); i++)
10551 aarch64_set_mem_u64 (cpu, address + i * 8,
10552 aarch64_get_vec_u64 (cpu, vd, i));
10553 return;
10554
10555 default:
10556 HALT_UNREACHABLE;
10557 }
10558 }
10559
10560 /* Store multiple 1-element structures into two registers. */
10561 static void
10562 ST1_2 (sim_cpu *cpu, uint64_t address)
10563 {
10564 /* FIXME: This algorithm is *exactly* the same as the ST2 version.
10565 So why have two different instructions ? There must be
10566 something wrong somewhere. */
10567 vec_store (cpu, address, 2);
10568 }
10569
10570 /* Store multiple 1-element structures into three registers. */
10571 static void
10572 ST1_3 (sim_cpu *cpu, uint64_t address)
10573 {
10574 /* FIXME: This algorithm is *exactly* the same as the ST3 version.
10575 So why have two different instructions ? There must be
10576 something wrong somewhere. */
10577 vec_store (cpu, address, 3);
10578 }
10579
10580 /* Store multiple 1-element structures into four registers. */
10581 static void
10582 ST1_4 (sim_cpu *cpu, uint64_t address)
10583 {
10584 /* FIXME: This algorithm is *exactly* the same as the ST4 version.
10585 So why have two different instructions ? There must be
10586 something wrong somewhere. */
10587 vec_store (cpu, address, 4);
10588 }
10589
10590 static void
10591 do_vec_LDnR (sim_cpu *cpu, uint64_t address)
10592 {
10593 /* instr[31] = 0
10594 instr[30] = element selector 0=>half, 1=>all elements
10595 instr[29,24] = 00 1101
10596 instr[23] = 0=>simple, 1=>post
10597 instr[22] = 1
10598 instr[21] = width: LD1R-or-LD3R (0) / LD2R-or-LD4R (1)
10599 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
10600 11111 (immediate post inc)
10601 instr[15,14] = 11
10602 instr[13] = width: LD1R-or-LD2R (0) / LD3R-or-LD4R (1)
10603 instr[12] = 0
10604 instr[11,10] = element size 00=> byte(b), 01=> half(h),
10605 10=> word(s), 11=> double(d)
10606 instr[9,5] = address
10607 instr[4,0] = Vd */
10608
10609 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
10610 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10611 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10612 int i;
10613
10614 NYI_assert (29, 24, 0x0D);
10615 NYI_assert (22, 22, 1);
10616 NYI_assert (15, 14, 3);
10617 NYI_assert (12, 12, 0);
10618
10619 switch ((uimm (aarch64_get_instr (cpu), 13, 13) << 1)
10620 | uimm (aarch64_get_instr (cpu), 21, 21))
10621 {
10622 case 0: /* LD1R. */
10623 switch (size)
10624 {
10625 case 0:
10626 {
10627 uint8_t val = aarch64_get_mem_u8 (cpu, address);
10628 for (i = 0; i < (full ? 16 : 8); i++)
10629 aarch64_set_vec_u8 (cpu, vd, i, val);
10630 break;
10631 }
10632
10633 case 1:
10634 {
10635 uint16_t val = aarch64_get_mem_u16 (cpu, address);
10636 for (i = 0; i < (full ? 8 : 4); i++)
10637 aarch64_set_vec_u16 (cpu, vd, i, val);
10638 break;
10639 }
10640
10641 case 2:
10642 {
10643 uint32_t val = aarch64_get_mem_u32 (cpu, address);
10644 for (i = 0; i < (full ? 4 : 2); i++)
10645 aarch64_set_vec_u32 (cpu, vd, i, val);
10646 break;
10647 }
10648
10649 case 3:
10650 {
10651 uint64_t val = aarch64_get_mem_u64 (cpu, address);
10652 for (i = 0; i < (full ? 2 : 1); i++)
10653 aarch64_set_vec_u64 (cpu, vd, i, val);
10654 break;
10655 }
10656
10657 default:
10658 HALT_UNALLOC;
10659 }
10660 break;
10661
10662 case 1: /* LD2R. */
10663 switch (size)
10664 {
10665 case 0:
10666 {
10667 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10668 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10669
10670 for (i = 0; i < (full ? 16 : 8); i++)
10671 {
10672 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10673 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10674 }
10675 break;
10676 }
10677
10678 case 1:
10679 {
10680 uint16_t val1 = aarch64_get_mem_u16 (cpu, address);
10681 uint16_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10682
10683 for (i = 0; i < (full ? 8 : 4); i++)
10684 {
10685 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10686 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10687 }
10688 break;
10689 }
10690
10691 case 2:
10692 {
10693 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10694 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10695
10696 for (i = 0; i < (full ? 4 : 2); i++)
10697 {
10698 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10699 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10700 }
10701 break;
10702 }
10703
10704 case 3:
10705 {
10706 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10707 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10708
10709 for (i = 0; i < (full ? 2 : 1); i++)
10710 {
10711 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10712 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10713 }
10714 break;
10715 }
10716
10717 default:
10718 HALT_UNALLOC;
10719 }
10720 break;
10721
10722 case 2: /* LD3R. */
10723 switch (size)
10724 {
10725 case 0:
10726 {
10727 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10728 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10729 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
10730
10731 for (i = 0; i < (full ? 16 : 8); i++)
10732 {
10733 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10734 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10735 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
10736 }
10737 }
10738 break;
10739
10740 case 1:
10741 {
10742 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
10743 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10744 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
10745
10746 for (i = 0; i < (full ? 8 : 4); i++)
10747 {
10748 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10749 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10750 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
10751 }
10752 }
10753 break;
10754
10755 case 2:
10756 {
10757 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10758 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10759 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
10760
10761 for (i = 0; i < (full ? 4 : 2); i++)
10762 {
10763 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10764 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10765 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
10766 }
10767 }
10768 break;
10769
10770 case 3:
10771 {
10772 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10773 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10774 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
10775
10776 for (i = 0; i < (full ? 2 : 1); i++)
10777 {
10778 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10779 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10780 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
10781 }
10782 }
10783 break;
10784
10785 default:
10786 HALT_UNALLOC;
10787 }
10788 break;
10789
10790 case 3: /* LD4R. */
10791 switch (size)
10792 {
10793 case 0:
10794 {
10795 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10796 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10797 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
10798 uint8_t val4 = aarch64_get_mem_u8 (cpu, address + 3);
10799
10800 for (i = 0; i < (full ? 16 : 8); i++)
10801 {
10802 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10803 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10804 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
10805 aarch64_set_vec_u8 (cpu, vd + 3, 0, val4);
10806 }
10807 }
10808 break;
10809
10810 case 1:
10811 {
10812 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
10813 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10814 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
10815 uint32_t val4 = aarch64_get_mem_u16 (cpu, address + 6);
10816
10817 for (i = 0; i < (full ? 8 : 4); i++)
10818 {
10819 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10820 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10821 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
10822 aarch64_set_vec_u16 (cpu, vd + 3, 0, val4);
10823 }
10824 }
10825 break;
10826
10827 case 2:
10828 {
10829 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10830 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10831 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
10832 uint32_t val4 = aarch64_get_mem_u32 (cpu, address + 12);
10833
10834 for (i = 0; i < (full ? 4 : 2); i++)
10835 {
10836 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10837 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10838 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
10839 aarch64_set_vec_u32 (cpu, vd + 3, 0, val4);
10840 }
10841 }
10842 break;
10843
10844 case 3:
10845 {
10846 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10847 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10848 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
10849 uint64_t val4 = aarch64_get_mem_u64 (cpu, address + 24);
10850
10851 for (i = 0; i < (full ? 2 : 1); i++)
10852 {
10853 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10854 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10855 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
10856 aarch64_set_vec_u64 (cpu, vd + 3, 0, val4);
10857 }
10858 }
10859 break;
10860
10861 default:
10862 HALT_UNALLOC;
10863 }
10864 break;
10865
10866 default:
10867 HALT_UNALLOC;
10868 }
10869 }
10870
10871 static void
10872 do_vec_load_store (sim_cpu *cpu)
10873 {
10874 /* {LD|ST}<N> {Vd..Vd+N}, vaddr
10875
10876 instr[31] = 0
10877 instr[30] = element selector 0=>half, 1=>all elements
10878 instr[29,25] = 00110
10879 instr[24] = ?
10880 instr[23] = 0=>simple, 1=>post
10881 instr[22] = 0=>store, 1=>load
10882 instr[21] = 0 (LDn) / small(0)-large(1) selector (LDnR)
10883 instr[20,16] = 00000 (simple), Vinc (reg-post-inc, no SP),
10884 11111 (immediate post inc)
10885 instr[15,12] = elements and destinations. eg for load:
10886 0000=>LD4 => load multiple 4-element to
10887 four consecutive registers
10888 0100=>LD3 => load multiple 3-element to
10889 three consecutive registers
10890 1000=>LD2 => load multiple 2-element to
10891 two consecutive registers
10892 0010=>LD1 => load multiple 1-element to
10893 four consecutive registers
10894 0110=>LD1 => load multiple 1-element to
10895 three consecutive registers
10896 1010=>LD1 => load multiple 1-element to
10897 two consecutive registers
10898 0111=>LD1 => load multiple 1-element to
10899 one register
10900 1100=>LDR1,LDR2
10901 1110=>LDR3,LDR4
10902 instr[11,10] = element size 00=> byte(b), 01=> half(h),
10903 10=> word(s), 11=> double(d)
10904 instr[9,5] = Vn, can be SP
10905 instr[4,0] = Vd */
10906
10907 int post;
10908 int load;
10909 unsigned vn;
10910 uint64_t address;
10911 int type;
10912
10913 if (uimm (aarch64_get_instr (cpu), 31, 31) != 0
10914 || uimm (aarch64_get_instr (cpu), 29, 25) != 0x06)
10915 HALT_NYI;
10916
10917 type = uimm (aarch64_get_instr (cpu), 15, 12);
10918 if (type != 0xE && type != 0xE && uimm (aarch64_get_instr (cpu), 21, 21) != 0)
10919 HALT_NYI;
10920
10921 post = uimm (aarch64_get_instr (cpu), 23, 23);
10922 load = uimm (aarch64_get_instr (cpu), 22, 22);
10923 vn = uimm (aarch64_get_instr (cpu), 9, 5);
10924 address = aarch64_get_reg_u64 (cpu, vn, SP_OK);
10925
10926 if (post)
10927 {
10928 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
10929
10930 if (vm == R31)
10931 {
10932 unsigned sizeof_operation;
10933
10934 switch (type)
10935 {
10936 case 0: sizeof_operation = 32; break;
10937 case 4: sizeof_operation = 24; break;
10938 case 8: sizeof_operation = 16; break;
10939
10940 case 0xC:
10941 sizeof_operation = uimm (aarch64_get_instr (cpu), 21, 21) ? 2 : 1;
10942 sizeof_operation <<= uimm (aarch64_get_instr (cpu), 11, 10);
10943 break;
10944
10945 case 0xE:
10946 sizeof_operation = uimm (aarch64_get_instr (cpu), 21, 21) ? 8 : 4;
10947 sizeof_operation <<= uimm (aarch64_get_instr (cpu), 11, 10);
10948 break;
10949
10950 case 2:
10951 case 6:
10952 case 10:
10953 case 7:
10954 sizeof_operation = 2 << uimm (aarch64_get_instr (cpu), 11, 10);
10955 break;
10956
10957 default:
10958 HALT_UNALLOC;
10959 }
10960
10961 if (uimm (aarch64_get_instr (cpu), 30, 30))
10962 sizeof_operation *= 2;
10963
10964 aarch64_set_reg_u64 (cpu, vn, SP_OK, address + sizeof_operation);
10965 }
10966 else
10967 aarch64_set_reg_u64 (cpu, vn, SP_OK,
10968 address + aarch64_get_reg_u64 (cpu, vm, NO_SP));
10969 }
10970 else
10971 {
10972 NYI_assert (20, 16, 0);
10973 }
10974
10975 if (load)
10976 {
10977 switch (type)
10978 {
10979 case 0: LD4 (cpu, address); return;
10980 case 4: LD3 (cpu, address); return;
10981 case 8: LD2 (cpu, address); return;
10982 case 2: LD1_4 (cpu, address); return;
10983 case 6: LD1_3 (cpu, address); return;
10984 case 10: LD1_2 (cpu, address); return;
10985 case 7: LD1_1 (cpu, address); return;
10986
10987 case 0xE:
10988 case 0xC: do_vec_LDnR (cpu, address); return;
10989
10990 default:
10991 HALT_NYI;
10992 }
10993 }
10994
10995 /* Stores. */
10996 switch (type)
10997 {
10998 case 0: ST4 (cpu, address); return;
10999 case 4: ST3 (cpu, address); return;
11000 case 8: ST2 (cpu, address); return;
11001 case 2: ST1_4 (cpu, address); return;
11002 case 6: ST1_3 (cpu, address); return;
11003 case 10: ST1_2 (cpu, address); return;
11004 case 7: ST1_1 (cpu, address); return;
11005 default:
11006 HALT_NYI;
11007 }
11008 }
11009
11010 static void
11011 dexLdSt (sim_cpu *cpu)
11012 {
11013 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
11014 assert group == GROUP_LDST_0100 || group == GROUP_LDST_0110 ||
11015 group == GROUP_LDST_1100 || group == GROUP_LDST_1110
11016 bits [29,28:26] of a LS are the secondary dispatch vector. */
11017 uint32_t group2 = dispatchLS (aarch64_get_instr (cpu));
11018
11019 switch (group2)
11020 {
11021 case LS_EXCL_000:
11022 dexLoadExclusive (cpu); return;
11023
11024 case LS_LIT_010:
11025 case LS_LIT_011:
11026 dexLoadLiteral (cpu); return;
11027
11028 case LS_OTHER_110:
11029 case LS_OTHER_111:
11030 dexLoadOther (cpu); return;
11031
11032 case LS_ADVSIMD_001:
11033 do_vec_load_store (cpu); return;
11034
11035 case LS_PAIR_100:
11036 dex_load_store_pair_gr (cpu); return;
11037
11038 case LS_PAIR_101:
11039 dex_load_store_pair_fp (cpu); return;
11040
11041 default:
11042 /* Should never reach here. */
11043 HALT_NYI;
11044 }
11045 }
11046
11047 /* Specific decode and execute for group Data Processing Register. */
11048
11049 static void
11050 dexLogicalShiftedRegister (sim_cpu *cpu)
11051 {
11052 /* assert instr[28:24] = 01010
11053 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11054 instr[30,29:21] = op,N : 000 ==> AND, 001 ==> BIC,
11055 010 ==> ORR, 011 ==> ORN
11056 100 ==> EOR, 101 ==> EON,
11057 110 ==> ANDS, 111 ==> BICS
11058 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> ROR
11059 instr[15,10] = count : must be 0xxxxx for 32 bit
11060 instr[9,5] = Rn
11061 instr[4,0] = Rd */
11062
11063 /* unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16); */
11064 uint32_t dispatch;
11065 Shift shiftType;
11066 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
11067
11068 /* 32 bit operations must have count[5] = 0. */
11069 /* or else we have an UNALLOC. */
11070 uint32_t count = uimm (aarch64_get_instr (cpu), 15, 10);
11071
11072 if (!size && uimm (count, 5, 5))
11073 HALT_UNALLOC;
11074
11075 shiftType = shift (aarch64_get_instr (cpu), 22);
11076
11077 /* dispatch on size:op:N i.e aarch64_get_instr (cpu)[31,29:21]. */
11078 dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 29) << 1)
11079 | uimm (aarch64_get_instr (cpu), 21, 21));
11080
11081 switch (dispatch)
11082 {
11083 case 0: and32_shift (cpu, shiftType, count); return;
11084 case 1: bic32_shift (cpu, shiftType, count); return;
11085 case 2: orr32_shift (cpu, shiftType, count); return;
11086 case 3: orn32_shift (cpu, shiftType, count); return;
11087 case 4: eor32_shift (cpu, shiftType, count); return;
11088 case 5: eon32_shift (cpu, shiftType, count); return;
11089 case 6: ands32_shift (cpu, shiftType, count); return;
11090 case 7: bics32_shift (cpu, shiftType, count); return;
11091 case 8: and64_shift (cpu, shiftType, count); return;
11092 case 9: bic64_shift (cpu, shiftType, count); return;
11093 case 10:orr64_shift (cpu, shiftType, count); return;
11094 case 11:orn64_shift (cpu, shiftType, count); return;
11095 case 12:eor64_shift (cpu, shiftType, count); return;
11096 case 13:eon64_shift (cpu, shiftType, count); return;
11097 case 14:ands64_shift (cpu, shiftType, count); return;
11098 case 15:bics64_shift (cpu, shiftType, count); return;
11099 default: HALT_UNALLOC;
11100 }
11101 }
11102
11103 /* 32 bit conditional select. */
11104 static void
11105 csel32 (sim_cpu *cpu, CondCode cc)
11106 {
11107 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11108 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11109 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11110
11111 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11112 testConditionCode (cpu, cc)
11113 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11114 : aarch64_get_reg_u32 (cpu, rm, NO_SP));
11115 }
11116
11117 /* 64 bit conditional select. */
11118 static void
11119 csel64 (sim_cpu *cpu, CondCode cc)
11120 {
11121 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11122 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11123 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11124
11125 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11126 testConditionCode (cpu, cc)
11127 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11128 : aarch64_get_reg_u64 (cpu, rm, NO_SP));
11129 }
11130
11131 /* 32 bit conditional increment. */
11132 static void
11133 csinc32 (sim_cpu *cpu, CondCode cc)
11134 {
11135 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11136 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11137 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11138
11139 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11140 testConditionCode (cpu, cc)
11141 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11142 : aarch64_get_reg_u32 (cpu, rm, NO_SP) + 1);
11143 }
11144
11145 /* 64 bit conditional increment. */
11146 static void
11147 csinc64 (sim_cpu *cpu, CondCode cc)
11148 {
11149 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11150 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11151 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11152
11153 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11154 testConditionCode (cpu, cc)
11155 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11156 : aarch64_get_reg_u64 (cpu, rm, NO_SP) + 1);
11157 }
11158
11159 /* 32 bit conditional invert. */
11160 static void
11161 csinv32 (sim_cpu *cpu, CondCode cc)
11162 {
11163 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11164 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11165 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11166
11167 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11168 testConditionCode (cpu, cc)
11169 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11170 : ~ aarch64_get_reg_u32 (cpu, rm, NO_SP));
11171 }
11172
11173 /* 64 bit conditional invert. */
11174 static void
11175 csinv64 (sim_cpu *cpu, CondCode cc)
11176 {
11177 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11178 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11179 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11180
11181 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11182 testConditionCode (cpu, cc)
11183 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11184 : ~ aarch64_get_reg_u64 (cpu, rm, NO_SP));
11185 }
11186
11187 /* 32 bit conditional negate. */
11188 static void
11189 csneg32 (sim_cpu *cpu, CondCode cc)
11190 {
11191 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11192 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11193 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11194
11195 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11196 testConditionCode (cpu, cc)
11197 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11198 : - aarch64_get_reg_u32 (cpu, rm, NO_SP));
11199 }
11200
11201 /* 64 bit conditional negate. */
11202 static void
11203 csneg64 (sim_cpu *cpu, CondCode cc)
11204 {
11205 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11206 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11207 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11208
11209 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11210 testConditionCode (cpu, cc)
11211 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11212 : - aarch64_get_reg_u64 (cpu, rm, NO_SP));
11213 }
11214
11215 static void
11216 dexCondSelect (sim_cpu *cpu)
11217 {
11218 /* assert instr[28,21] = 11011011
11219 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11220 instr[30:11,10] = op : 000 ==> CSEL, 001 ==> CSINC,
11221 100 ==> CSINV, 101 ==> CSNEG,
11222 _1_ ==> UNALLOC
11223 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11224 instr[15,12] = cond
11225 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC */
11226
11227 CondCode cc;
11228 uint32_t dispatch;
11229 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11230 uint32_t op2 = uimm (aarch64_get_instr (cpu), 11, 10);
11231
11232 if (S == 1)
11233 HALT_UNALLOC;
11234
11235 if (op2 & 0x2)
11236 HALT_UNALLOC;
11237
11238 cc = condcode (aarch64_get_instr (cpu), 12);
11239 dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 1) | op2);
11240
11241 switch (dispatch)
11242 {
11243 case 0: csel32 (cpu, cc); return;
11244 case 1: csinc32 (cpu, cc); return;
11245 case 2: csinv32 (cpu, cc); return;
11246 case 3: csneg32 (cpu, cc); return;
11247 case 4: csel64 (cpu, cc); return;
11248 case 5: csinc64 (cpu, cc); return;
11249 case 6: csinv64 (cpu, cc); return;
11250 case 7: csneg64 (cpu, cc); return;
11251 default: HALT_UNALLOC;
11252 }
11253 }
11254
11255 /* Some helpers for counting leading 1 or 0 bits. */
11256
11257 /* Counts the number of leading bits which are the same
11258 in a 32 bit value in the range 1 to 32. */
11259 static uint32_t
11260 leading32 (uint32_t value)
11261 {
11262 int32_t mask= 0xffff0000;
11263 uint32_t count= 16; /* Counts number of bits set in mask. */
11264 uint32_t lo = 1; /* Lower bound for number of sign bits. */
11265 uint32_t hi = 32; /* Upper bound for number of sign bits. */
11266
11267 while (lo + 1 < hi)
11268 {
11269 int32_t test = (value & mask);
11270
11271 if (test == 0 || test == mask)
11272 {
11273 lo = count;
11274 count = (lo + hi) / 2;
11275 mask >>= (count - lo);
11276 }
11277 else
11278 {
11279 hi = count;
11280 count = (lo + hi) / 2;
11281 mask <<= hi - count;
11282 }
11283 }
11284
11285 if (lo != hi)
11286 {
11287 int32_t test;
11288
11289 mask >>= 1;
11290 test = (value & mask);
11291
11292 if (test == 0 || test == mask)
11293 count = hi;
11294 else
11295 count = lo;
11296 }
11297
11298 return count;
11299 }
11300
11301 /* Counts the number of leading bits which are the same
11302 in a 64 bit value in the range 1 to 64. */
11303 static uint64_t
11304 leading64 (uint64_t value)
11305 {
11306 int64_t mask= 0xffffffff00000000LL;
11307 uint64_t count = 32; /* Counts number of bits set in mask. */
11308 uint64_t lo = 1; /* Lower bound for number of sign bits. */
11309 uint64_t hi = 64; /* Upper bound for number of sign bits. */
11310
11311 while (lo + 1 < hi)
11312 {
11313 int64_t test = (value & mask);
11314
11315 if (test == 0 || test == mask)
11316 {
11317 lo = count;
11318 count = (lo + hi) / 2;
11319 mask >>= (count - lo);
11320 }
11321 else
11322 {
11323 hi = count;
11324 count = (lo + hi) / 2;
11325 mask <<= hi - count;
11326 }
11327 }
11328
11329 if (lo != hi)
11330 {
11331 int64_t test;
11332
11333 mask >>= 1;
11334 test = (value & mask);
11335
11336 if (test == 0 || test == mask)
11337 count = hi;
11338 else
11339 count = lo;
11340 }
11341
11342 return count;
11343 }
11344
11345 /* Bit operations. */
11346 /* N.B register args may not be SP. */
11347
11348 /* 32 bit count leading sign bits. */
11349 static void
11350 cls32 (sim_cpu *cpu)
11351 {
11352 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11353 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11354
11355 /* N.B. the result needs to exclude the leading bit. */
11356 aarch64_set_reg_u64
11357 (cpu, rd, NO_SP, leading32 (aarch64_get_reg_u32 (cpu, rn, NO_SP)) - 1);
11358 }
11359
11360 /* 64 bit count leading sign bits. */
11361 static void
11362 cls64 (sim_cpu *cpu)
11363 {
11364 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11365 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11366
11367 /* N.B. the result needs to exclude the leading bit. */
11368 aarch64_set_reg_u64
11369 (cpu, rd, NO_SP, leading64 (aarch64_get_reg_u64 (cpu, rn, NO_SP)) - 1);
11370 }
11371
11372 /* 32 bit count leading zero bits. */
11373 static void
11374 clz32 (sim_cpu *cpu)
11375 {
11376 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11377 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11378 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11379
11380 /* if the sign (top) bit is set then the count is 0. */
11381 if (pick32 (value, 31, 31))
11382 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11383 else
11384 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading32 (value));
11385 }
11386
11387 /* 64 bit count leading zero bits. */
11388 static void
11389 clz64 (sim_cpu *cpu)
11390 {
11391 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11392 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11393 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11394
11395 /* if the sign (top) bit is set then the count is 0. */
11396 if (pick64 (value, 63, 63))
11397 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11398 else
11399 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading64 (value));
11400 }
11401
11402 /* 32 bit reverse bits. */
11403 static void
11404 rbit32 (sim_cpu *cpu)
11405 {
11406 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11407 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11408 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11409 uint32_t result = 0;
11410 int i;
11411
11412 for (i = 0; i < 32; i++)
11413 {
11414 result <<= 1;
11415 result |= (value & 1);
11416 value >>= 1;
11417 }
11418 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11419 }
11420
11421 /* 64 bit reverse bits. */
11422 static void
11423 rbit64 (sim_cpu *cpu)
11424 {
11425 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11426 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11427 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11428 uint64_t result = 0;
11429 int i;
11430
11431 for (i = 0; i < 64; i++)
11432 {
11433 result <<= 1;
11434 result |= (value & 1L);
11435 value >>= 1;
11436 }
11437 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11438 }
11439
11440 /* 32 bit reverse bytes. */
11441 static void
11442 rev32 (sim_cpu *cpu)
11443 {
11444 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11445 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11446 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11447 uint32_t result = 0;
11448 int i;
11449
11450 for (i = 0; i < 4; i++)
11451 {
11452 result <<= 8;
11453 result |= (value & 0xff);
11454 value >>= 8;
11455 }
11456 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11457 }
11458
11459 /* 64 bit reverse bytes. */
11460 static void
11461 rev64 (sim_cpu *cpu)
11462 {
11463 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11464 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11465 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11466 uint64_t result = 0;
11467 int i;
11468
11469 for (i = 0; i < 8; i++)
11470 {
11471 result <<= 8;
11472 result |= (value & 0xffULL);
11473 value >>= 8;
11474 }
11475 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11476 }
11477
11478 /* 32 bit reverse shorts. */
11479 /* N.B.this reverses the order of the bytes in each half word. */
11480 static void
11481 revh32 (sim_cpu *cpu)
11482 {
11483 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11484 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11485 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11486 uint32_t result = 0;
11487 int i;
11488
11489 for (i = 0; i < 2; i++)
11490 {
11491 result <<= 8;
11492 result |= (value & 0x00ff00ff);
11493 value >>= 8;
11494 }
11495 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11496 }
11497
11498 /* 64 bit reverse shorts. */
11499 /* N.B.this reverses the order of the bytes in each half word. */
11500 static void
11501 revh64 (sim_cpu *cpu)
11502 {
11503 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11504 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11505 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11506 uint64_t result = 0;
11507 int i;
11508
11509 for (i = 0; i < 2; i++)
11510 {
11511 result <<= 8;
11512 result |= (value & 0x00ff00ff00ff00ffULL);
11513 value >>= 8;
11514 }
11515 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11516 }
11517
11518 static void
11519 dexDataProc1Source (sim_cpu *cpu)
11520 {
11521 /* assert instr[30] == 1
11522 aarch64_get_instr (cpu)[28,21] == 111010110
11523 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11524 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11525 instr[20,16] = opcode2 : 00000 ==> ok, ow ==> UNALLOC
11526 instr[15,10] = opcode : 000000 ==> RBIT, 000001 ==> REV16,
11527 000010 ==> REV, 000011 ==> UNALLOC
11528 000100 ==> CLZ, 000101 ==> CLS
11529 ow ==> UNALLOC
11530 instr[9,5] = rn : may not be SP
11531 instr[4,0] = rd : may not be SP. */
11532
11533 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11534 uint32_t opcode2 = uimm (aarch64_get_instr (cpu), 20, 16);
11535 uint32_t opcode = uimm (aarch64_get_instr (cpu), 15, 10);
11536 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 31) << 3) | opcode);
11537
11538 if (S == 1)
11539 HALT_UNALLOC;
11540
11541 if (opcode2 != 0)
11542 HALT_UNALLOC;
11543
11544 if (opcode & 0x38)
11545 HALT_UNALLOC;
11546
11547 switch (dispatch)
11548 {
11549 case 0: rbit32 (cpu); return;
11550 case 1: revh32 (cpu); return;
11551 case 2: rev32 (cpu); return;
11552 case 4: clz32 (cpu); return;
11553 case 5: cls32 (cpu); return;
11554 case 8: rbit64 (cpu); return;
11555 case 9: revh64 (cpu); return;
11556 case 10:rev32 (cpu); return;
11557 case 11:rev64 (cpu); return;
11558 case 12:clz64 (cpu); return;
11559 case 13:cls64 (cpu); return;
11560 default: HALT_UNALLOC;
11561 }
11562 }
11563
11564 /* Variable shift.
11565 Shifts by count supplied in register.
11566 N.B register args may not be SP.
11567 These all use the shifted auxiliary function for
11568 simplicity and clarity. Writing the actual shift
11569 inline would avoid a branch and so be faster but
11570 would also necessitate getting signs right. */
11571
11572 /* 32 bit arithmetic shift right. */
11573 static void
11574 asrv32 (sim_cpu *cpu)
11575 {
11576 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11577 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11578 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11579
11580 aarch64_set_reg_u64
11581 (cpu, rd, NO_SP,
11582 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ASR,
11583 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11584 }
11585
11586 /* 64 bit arithmetic shift right. */
11587 static void
11588 asrv64 (sim_cpu *cpu)
11589 {
11590 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11591 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11592 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11593
11594 aarch64_set_reg_u64
11595 (cpu, rd, NO_SP,
11596 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ASR,
11597 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11598 }
11599
11600 /* 32 bit logical shift left. */
11601 static void
11602 lslv32 (sim_cpu *cpu)
11603 {
11604 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11605 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11606 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11607
11608 aarch64_set_reg_u64
11609 (cpu, rd, NO_SP,
11610 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSL,
11611 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11612 }
11613
11614 /* 64 bit arithmetic shift left. */
11615 static void
11616 lslv64 (sim_cpu *cpu)
11617 {
11618 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11619 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11620 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11621
11622 aarch64_set_reg_u64
11623 (cpu, rd, NO_SP,
11624 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSL,
11625 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11626 }
11627
11628 /* 32 bit logical shift right. */
11629 static void
11630 lsrv32 (sim_cpu *cpu)
11631 {
11632 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11633 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11634 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11635
11636 aarch64_set_reg_u64
11637 (cpu, rd, NO_SP,
11638 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSR,
11639 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11640 }
11641
11642 /* 64 bit logical shift right. */
11643 static void
11644 lsrv64 (sim_cpu *cpu)
11645 {
11646 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11647 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11648 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11649
11650 aarch64_set_reg_u64
11651 (cpu, rd, NO_SP,
11652 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSR,
11653 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11654 }
11655
11656 /* 32 bit rotate right. */
11657 static void
11658 rorv32 (sim_cpu *cpu)
11659 {
11660 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11661 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11662 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11663
11664 aarch64_set_reg_u64
11665 (cpu, rd, NO_SP,
11666 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ROR,
11667 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11668 }
11669
11670 /* 64 bit rotate right. */
11671 static void
11672 rorv64 (sim_cpu *cpu)
11673 {
11674 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11675 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11676 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11677
11678 aarch64_set_reg_u64
11679 (cpu, rd, NO_SP,
11680 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ROR,
11681 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11682 }
11683
11684
11685 /* divide. */
11686
11687 /* 32 bit signed divide. */
11688 static void
11689 cpuiv32 (sim_cpu *cpu)
11690 {
11691 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11692 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11693 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11694 /* N.B. the pseudo-code does the divide using 64 bit data. */
11695 /* TODO : check that this rounds towards zero as required. */
11696 int64_t dividend = aarch64_get_reg_s32 (cpu, rn, NO_SP);
11697 int64_t divisor = aarch64_get_reg_s32 (cpu, rm, NO_SP);
11698
11699 aarch64_set_reg_s64 (cpu, rd, NO_SP,
11700 divisor ? ((int32_t) (dividend / divisor)) : 0);
11701 }
11702
11703 /* 64 bit signed divide. */
11704 static void
11705 cpuiv64 (sim_cpu *cpu)
11706 {
11707 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11708 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11709 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11710
11711 /* TODO : check that this rounds towards zero as required. */
11712 int64_t divisor = aarch64_get_reg_s64 (cpu, rm, NO_SP);
11713
11714 aarch64_set_reg_s64
11715 (cpu, rd, NO_SP,
11716 divisor ? (aarch64_get_reg_s64 (cpu, rn, NO_SP) / divisor) : 0);
11717 }
11718
11719 /* 32 bit unsigned divide. */
11720 static void
11721 udiv32 (sim_cpu *cpu)
11722 {
11723 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11724 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11725 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11726
11727 /* N.B. the pseudo-code does the divide using 64 bit data. */
11728 uint64_t dividend = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11729 uint64_t divisor = aarch64_get_reg_u32 (cpu, rm, NO_SP);
11730
11731 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11732 divisor ? (uint32_t) (dividend / divisor) : 0);
11733 }
11734
11735 /* 64 bit unsigned divide. */
11736 static void
11737 udiv64 (sim_cpu *cpu)
11738 {
11739 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11740 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11741 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11742
11743 /* TODO : check that this rounds towards zero as required. */
11744 uint64_t divisor = aarch64_get_reg_u64 (cpu, rm, NO_SP);
11745
11746 aarch64_set_reg_u64
11747 (cpu, rd, NO_SP,
11748 divisor ? (aarch64_get_reg_u64 (cpu, rn, NO_SP) / divisor) : 0);
11749 }
11750
11751 static void
11752 dexDataProc2Source (sim_cpu *cpu)
11753 {
11754 /* assert instr[30] == 0
11755 instr[28,21] == 11010110
11756 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11757 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11758 instr[15,10] = opcode : 000010 ==> UDIV, 000011 ==> CPUIV,
11759 001000 ==> LSLV, 001001 ==> LSRV
11760 001010 ==> ASRV, 001011 ==> RORV
11761 ow ==> UNALLOC. */
11762
11763 uint32_t dispatch;
11764 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11765 uint32_t opcode = uimm (aarch64_get_instr (cpu), 15, 10);
11766
11767 if (S == 1)
11768 HALT_UNALLOC;
11769
11770 if (opcode & 0x34)
11771 HALT_UNALLOC;
11772
11773 dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 31) << 3)
11774 | (uimm (opcode, 3, 3) << 2)
11775 | uimm (opcode, 1, 0));
11776 switch (dispatch)
11777 {
11778 case 2: udiv32 (cpu); return;
11779 case 3: cpuiv32 (cpu); return;
11780 case 4: lslv32 (cpu); return;
11781 case 5: lsrv32 (cpu); return;
11782 case 6: asrv32 (cpu); return;
11783 case 7: rorv32 (cpu); return;
11784 case 10: udiv64 (cpu); return;
11785 case 11: cpuiv64 (cpu); return;
11786 case 12: lslv64 (cpu); return;
11787 case 13: lsrv64 (cpu); return;
11788 case 14: asrv64 (cpu); return;
11789 case 15: rorv64 (cpu); return;
11790 default: HALT_UNALLOC;
11791 }
11792 }
11793
11794
11795 /* Multiply. */
11796
11797 /* 32 bit multiply and add. */
11798 static void
11799 madd32 (sim_cpu *cpu)
11800 {
11801 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11802 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11803 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11804 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11805
11806 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11807 aarch64_get_reg_u32 (cpu, ra, NO_SP)
11808 + aarch64_get_reg_u32 (cpu, rn, NO_SP)
11809 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
11810 }
11811
11812 /* 64 bit multiply and add. */
11813 static void
11814 madd64 (sim_cpu *cpu)
11815 {
11816 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11817 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11818 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11819 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11820
11821 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11822 aarch64_get_reg_u64 (cpu, ra, NO_SP)
11823 + aarch64_get_reg_u64 (cpu, rn, NO_SP)
11824 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
11825 }
11826
11827 /* 32 bit multiply and sub. */
11828 static void
11829 msub32 (sim_cpu *cpu)
11830 {
11831 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11832 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11833 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11834 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11835
11836 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11837 aarch64_get_reg_u32 (cpu, ra, NO_SP)
11838 - aarch64_get_reg_u32 (cpu, rn, NO_SP)
11839 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
11840 }
11841
11842 /* 64 bit multiply and sub. */
11843 static void
11844 msub64 (sim_cpu *cpu)
11845 {
11846 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11847 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11848 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11849 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11850
11851 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11852 aarch64_get_reg_u64 (cpu, ra, NO_SP)
11853 - aarch64_get_reg_u64 (cpu, rn, NO_SP)
11854 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
11855 }
11856
11857 /* Signed multiply add long -- source, source2 : 32 bit, source3 : 64 bit. */
11858 static void
11859 smaddl (sim_cpu *cpu)
11860 {
11861 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11862 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11863 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11864 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11865
11866 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
11867 obtain a 64 bit product. */
11868 aarch64_set_reg_s64
11869 (cpu, rd, NO_SP,
11870 aarch64_get_reg_s64 (cpu, ra, NO_SP)
11871 + ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
11872 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
11873 }
11874
11875 /* Signed multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
11876 static void
11877 smsubl (sim_cpu *cpu)
11878 {
11879 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11880 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11881 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11882 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11883
11884 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
11885 obtain a 64 bit product. */
11886 aarch64_set_reg_s64
11887 (cpu, rd, NO_SP,
11888 aarch64_get_reg_s64 (cpu, ra, NO_SP)
11889 - ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
11890 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
11891 }
11892
11893 /* Integer Multiply/Divide. */
11894
11895 /* First some macros and a helper function. */
11896 /* Macros to test or access elements of 64 bit words. */
11897
11898 /* Mask used to access lo 32 bits of 64 bit unsigned int. */
11899 #define LOW_WORD_MASK ((1ULL << 32) - 1)
11900 /* Return the lo 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
11901 #define lowWordToU64(_value_u64) ((_value_u64) & LOW_WORD_MASK)
11902 /* Return the hi 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
11903 #define highWordToU64(_value_u64) ((_value_u64) >> 32)
11904
11905 /* Offset of sign bit in 64 bit signed integger. */
11906 #define SIGN_SHIFT_U64 63
11907 /* The sign bit itself -- also identifies the minimum negative int value. */
11908 #define SIGN_BIT_U64 (1UL << SIGN_SHIFT_U64)
11909 /* Return true if a 64 bit signed int presented as an unsigned int is the
11910 most negative value. */
11911 #define isMinimumU64(_value_u64) ((_value_u64) == SIGN_BIT_U64)
11912 /* Return true (non-zero) if a 64 bit signed int presented as an unsigned
11913 int has its sign bit set to false. */
11914 #define isSignSetU64(_value_u64) ((_value_u64) & SIGN_BIT_U64)
11915 /* Return 1L or -1L according to whether a 64 bit signed int presented as
11916 an unsigned int has its sign bit set or not. */
11917 #define signOfU64(_value_u64) (1L + (((value_u64) >> SIGN_SHIFT_U64) * -2L)
11918 /* Clear the sign bit of a 64 bit signed int presented as an unsigned int. */
11919 #define clearSignU64(_value_u64) ((_value_u64) &= ~SIGN_BIT_U64)
11920
11921 /* Multiply two 64 bit ints and return.
11922 the hi 64 bits of the 128 bit product. */
11923
11924 static uint64_t
11925 mul64hi (uint64_t value1, uint64_t value2)
11926 {
11927 uint64_t resultmid1;
11928 uint64_t result;
11929 uint64_t value1_lo = lowWordToU64 (value1);
11930 uint64_t value1_hi = highWordToU64 (value1) ;
11931 uint64_t value2_lo = lowWordToU64 (value2);
11932 uint64_t value2_hi = highWordToU64 (value2);
11933
11934 /* Cross-multiply and collect results. */
11935
11936 uint64_t xproductlo = value1_lo * value2_lo;
11937 uint64_t xproductmid1 = value1_lo * value2_hi;
11938 uint64_t xproductmid2 = value1_hi * value2_lo;
11939 uint64_t xproducthi = value1_hi * value2_hi;
11940 uint64_t carry = 0;
11941 /* Start accumulating 64 bit results. */
11942 /* Drop bottom half of lowest cross-product. */
11943 uint64_t resultmid = xproductlo >> 32;
11944 /* Add in middle products. */
11945 resultmid = resultmid + xproductmid1;
11946
11947 /* Check for overflow. */
11948 if (resultmid < xproductmid1)
11949 /* Carry over 1 into top cross-product. */
11950 carry++;
11951
11952 resultmid1 = resultmid + xproductmid2;
11953
11954 /* Check for overflow. */
11955 if (resultmid1 < xproductmid2)
11956 /* Carry over 1 into top cross-product. */
11957 carry++;
11958
11959 /* Drop lowest 32 bits of middle cross-product. */
11960 result = resultmid1 >> 32;
11961
11962 /* Add top cross-product plus and any carry. */
11963 result += xproducthi + carry;
11964
11965 return result;
11966 }
11967
11968 /* Signed multiply high, source, source2 :
11969 64 bit, dest <-- high 64-bit of result. */
11970 static void
11971 smulh (sim_cpu *cpu)
11972 {
11973 uint64_t uresult;
11974 int64_t result;
11975 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11976 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11977 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11978 GReg ra = greg (aarch64_get_instr (cpu), 10);
11979 int64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11980 int64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
11981 uint64_t uvalue1;
11982 uint64_t uvalue2;
11983 int64_t signum = 1;
11984
11985 if (ra != R31)
11986 HALT_UNALLOC;
11987
11988 /* Convert to unsigned and use the unsigned mul64hi routine
11989 the fix the sign up afterwards. */
11990 if (value1 < 0)
11991 {
11992 signum *= -1L;
11993 uvalue1 = -value1;
11994 }
11995 else
11996 {
11997 uvalue1 = value1;
11998 }
11999
12000 if (value2 < 0)
12001 {
12002 signum *= -1L;
12003 uvalue2 = -value2;
12004 }
12005 else
12006 {
12007 uvalue2 = value2;
12008 }
12009
12010 uresult = mul64hi (uvalue1, uvalue2);
12011 result = uresult;
12012 result *= signum;
12013
12014 aarch64_set_reg_s64 (cpu, rd, NO_SP, result);
12015 }
12016
12017 /* Unsigned multiply add long -- source, source2 :
12018 32 bit, source3 : 64 bit. */
12019 static void
12020 umaddl (sim_cpu *cpu)
12021 {
12022 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12023 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
12024 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12025 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12026
12027 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12028 obtain a 64 bit product. */
12029 aarch64_set_reg_u64
12030 (cpu, rd, NO_SP,
12031 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12032 + ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12033 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12034 }
12035
12036 /* Unsigned multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12037 static void
12038 umsubl (sim_cpu *cpu)
12039 {
12040 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12041 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
12042 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12043 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12044
12045 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12046 obtain a 64 bit product. */
12047 aarch64_set_reg_u64
12048 (cpu, rd, NO_SP,
12049 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12050 - ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12051 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12052 }
12053
12054 /* Unsigned multiply high, source, source2 :
12055 64 bit, dest <-- high 64-bit of result. */
12056 static void
12057 umulh (sim_cpu *cpu)
12058 {
12059 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12060 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12061 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12062 GReg ra = greg (aarch64_get_instr (cpu), 10);
12063
12064 if (ra != R31)
12065 HALT_UNALLOC;
12066
12067 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12068 mul64hi (aarch64_get_reg_u64 (cpu, rn, NO_SP),
12069 aarch64_get_reg_u64 (cpu, rm, NO_SP)));
12070 }
12071
12072 static void
12073 dexDataProc3Source (sim_cpu *cpu)
12074 {
12075 /* assert instr[28,24] == 11011. */
12076 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit (for rd at least)
12077 instr[30,29] = op54 : 00 ==> ok, ow ==> UNALLOC
12078 instr[23,21] = op31 : 111 ==> UNALLOC, o2 ==> ok
12079 instr[15] = o0 : 0/1 ==> ok
12080 instr[23,21:15] ==> op : 0000 ==> MADD, 0001 ==> MSUB, (32/64 bit)
12081 0010 ==> SMADDL, 0011 ==> SMSUBL, (64 bit only)
12082 0100 ==> SMULH, (64 bit only)
12083 1010 ==> UMADDL, 1011 ==> UNSUBL, (64 bit only)
12084 1100 ==> UMULH (64 bit only)
12085 ow ==> UNALLOC. */
12086
12087 uint32_t dispatch;
12088 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
12089 uint32_t op54 = uimm (aarch64_get_instr (cpu), 30, 29);
12090 uint32_t op31 = uimm (aarch64_get_instr (cpu), 23, 21);
12091 uint32_t o0 = uimm (aarch64_get_instr (cpu), 15, 15);
12092
12093 if (op54 != 0)
12094 HALT_UNALLOC;
12095
12096 if (size == 0)
12097 {
12098 if (op31 != 0)
12099 HALT_UNALLOC;
12100
12101 if (o0 == 0)
12102 madd32 (cpu);
12103 else
12104 msub32 (cpu);
12105 return;
12106 }
12107
12108 dispatch = (op31 << 1) | o0;
12109
12110 switch (dispatch)
12111 {
12112 case 0: madd64 (cpu); return;
12113 case 1: msub64 (cpu); return;
12114 case 2: smaddl (cpu); return;
12115 case 3: smsubl (cpu); return;
12116 case 4: smulh (cpu); return;
12117 case 10: umaddl (cpu); return;
12118 case 11: umsubl (cpu); return;
12119 case 12: umulh (cpu); return;
12120 default: HALT_UNALLOC;
12121 }
12122 }
12123
12124 static void
12125 dexDPReg (sim_cpu *cpu)
12126 {
12127 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12128 assert group == GROUP_DPREG_0101 || group == GROUP_DPREG_1101
12129 bits [28:24:21] of a DPReg are the secondary dispatch vector. */
12130 uint32_t group2 = dispatchDPReg (aarch64_get_instr (cpu));
12131
12132 switch (group2)
12133 {
12134 case DPREG_LOG_000:
12135 case DPREG_LOG_001:
12136 dexLogicalShiftedRegister (cpu); return;
12137
12138 case DPREG_ADDSHF_010:
12139 dexAddSubtractShiftedRegister (cpu); return;
12140
12141 case DPREG_ADDEXT_011:
12142 dexAddSubtractExtendedRegister (cpu); return;
12143
12144 case DPREG_ADDCOND_100:
12145 {
12146 /* This set bundles a variety of different operations. */
12147 /* Check for. */
12148 /* 1) add/sub w carry. */
12149 uint32_t mask1 = 0x1FE00000U;
12150 uint32_t val1 = 0x1A000000U;
12151 /* 2) cond compare register/immediate. */
12152 uint32_t mask2 = 0x1FE00000U;
12153 uint32_t val2 = 0x1A400000U;
12154 /* 3) cond select. */
12155 uint32_t mask3 = 0x1FE00000U;
12156 uint32_t val3 = 0x1A800000U;
12157 /* 4) data proc 1/2 source. */
12158 uint32_t mask4 = 0x1FE00000U;
12159 uint32_t val4 = 0x1AC00000U;
12160
12161 if ((aarch64_get_instr (cpu) & mask1) == val1)
12162 dexAddSubtractWithCarry (cpu);
12163
12164 else if ((aarch64_get_instr (cpu) & mask2) == val2)
12165 CondCompare (cpu);
12166
12167 else if ((aarch64_get_instr (cpu) & mask3) == val3)
12168 dexCondSelect (cpu);
12169
12170 else if ((aarch64_get_instr (cpu) & mask4) == val4)
12171 {
12172 /* Bit 30 is clear for data proc 2 source
12173 and set for data proc 1 source. */
12174 if (aarch64_get_instr (cpu) & (1U << 30))
12175 dexDataProc1Source (cpu);
12176 else
12177 dexDataProc2Source (cpu);
12178 }
12179
12180 else
12181 /* Should not reach here. */
12182 HALT_NYI;
12183
12184 return;
12185 }
12186
12187 case DPREG_3SRC_110:
12188 dexDataProc3Source (cpu); return;
12189
12190 case DPREG_UNALLOC_101:
12191 HALT_UNALLOC;
12192
12193 case DPREG_3SRC_111:
12194 dexDataProc3Source (cpu); return;
12195
12196 default:
12197 /* Should never reach here. */
12198 HALT_NYI;
12199 }
12200 }
12201
12202 /* Unconditional Branch immediate.
12203 Offset is a PC-relative byte offset in the range +/- 128MiB.
12204 The offset is assumed to be raw from the decode i.e. the
12205 simulator is expected to scale them from word offsets to byte. */
12206
12207 /* Unconditional branch. */
12208 static void
12209 buc (sim_cpu *cpu, int32_t offset)
12210 {
12211 aarch64_set_next_PC_by_offset (cpu, offset);
12212 }
12213
12214 static unsigned stack_depth = 0;
12215
12216 /* Unconditional branch and link -- writes return PC to LR. */
12217 static void
12218 bl (sim_cpu *cpu, int32_t offset)
12219 {
12220 aarch64_save_LR (cpu);
12221 aarch64_set_next_PC_by_offset (cpu, offset);
12222
12223 if (TRACE_BRANCH_P (cpu))
12224 {
12225 ++ stack_depth;
12226 TRACE_BRANCH (cpu,
12227 " %*scall %" PRIx64 " [%s]"
12228 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12229 stack_depth, " ", aarch64_get_next_PC (cpu),
12230 aarch64_get_func (aarch64_get_next_PC (cpu)),
12231 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12232 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12233 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12234 );
12235 }
12236 }
12237
12238 /* Unconditional Branch register.
12239 Branch/return address is in source register. */
12240
12241 /* Unconditional branch. */
12242 static void
12243 br (sim_cpu *cpu)
12244 {
12245 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12246 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12247 }
12248
12249 /* Unconditional branch and link -- writes return PC to LR. */
12250 static void
12251 blr (sim_cpu *cpu)
12252 {
12253 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12254
12255 /* The pseudo code in the spec says we update LR before fetching.
12256 the value from the rn. */
12257 aarch64_save_LR (cpu);
12258 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12259
12260 if (TRACE_BRANCH_P (cpu))
12261 {
12262 ++ stack_depth;
12263 TRACE_BRANCH (cpu,
12264 " %*scall %" PRIx64 " [%s]"
12265 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12266 stack_depth, " ", aarch64_get_next_PC (cpu),
12267 aarch64_get_func (aarch64_get_next_PC (cpu)),
12268 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12269 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12270 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12271 );
12272 }
12273 }
12274
12275 /* Return -- assembler will default source to LR this is functionally
12276 equivalent to br but, presumably, unlike br it side effects the
12277 branch predictor. */
12278 static void
12279 ret (sim_cpu *cpu)
12280 {
12281 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12282 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12283
12284 if (TRACE_BRANCH_P (cpu))
12285 {
12286 TRACE_BRANCH (cpu,
12287 " %*sreturn [result: %" PRIx64 "]",
12288 stack_depth, " ", aarch64_get_reg_u64 (cpu, 0, NO_SP));
12289 -- stack_depth;
12290 }
12291 }
12292
12293 /* NOP -- we implement this and call it from the decode in case we
12294 want to intercept it later. */
12295
12296 static void
12297 nop (sim_cpu *cpu)
12298 {
12299 }
12300
12301 /* Data synchronization barrier. */
12302
12303 static void
12304 dsb (sim_cpu *cpu)
12305 {
12306 }
12307
12308 /* Data memory barrier. */
12309
12310 static void
12311 dmb (sim_cpu *cpu)
12312 {
12313 }
12314
12315 /* Instruction synchronization barrier. */
12316
12317 static void
12318 isb (sim_cpu *cpu)
12319 {
12320 }
12321
12322 static void
12323 dexBranchImmediate (sim_cpu *cpu)
12324 {
12325 /* assert instr[30,26] == 00101
12326 instr[31] ==> 0 == B, 1 == BL
12327 instr[25,0] == imm26 branch offset counted in words. */
12328
12329 uint32_t top = uimm (aarch64_get_instr (cpu), 31, 31);
12330 /* We have a 26 byte signed word offset which we need to pass to the
12331 execute routine as a signed byte offset. */
12332 int32_t offset = simm32 (aarch64_get_instr (cpu), 25, 0) << 2;
12333
12334 if (top)
12335 bl (cpu, offset);
12336 else
12337 buc (cpu, offset);
12338 }
12339
12340 /* Control Flow. */
12341
12342 /* Conditional branch
12343
12344 Offset is a PC-relative byte offset in the range +/- 1MiB pos is
12345 a bit position in the range 0 .. 63
12346
12347 cc is a CondCode enum value as pulled out of the decode
12348
12349 N.B. any offset register (source) can only be Xn or Wn. */
12350
12351 static void
12352 bcc (sim_cpu *cpu, int32_t offset, CondCode cc)
12353 {
12354 /* the test returns TRUE if CC is met. */
12355 if (testConditionCode (cpu, cc))
12356 aarch64_set_next_PC_by_offset (cpu, offset);
12357 }
12358
12359 /* 32 bit branch on register non-zero. */
12360 static void
12361 cbnz32 (sim_cpu *cpu, int32_t offset)
12362 {
12363 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12364
12365 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) != 0)
12366 aarch64_set_next_PC_by_offset (cpu, offset);
12367 }
12368
12369 /* 64 bit branch on register zero. */
12370 static void
12371 cbnz (sim_cpu *cpu, int32_t offset)
12372 {
12373 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12374
12375 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) != 0)
12376 aarch64_set_next_PC_by_offset (cpu, offset);
12377 }
12378
12379 /* 32 bit branch on register non-zero. */
12380 static void
12381 cbz32 (sim_cpu *cpu, int32_t offset)
12382 {
12383 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12384
12385 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) == 0)
12386 aarch64_set_next_PC_by_offset (cpu, offset);
12387 }
12388
12389 /* 64 bit branch on register zero. */
12390 static void
12391 cbz (sim_cpu *cpu, int32_t offset)
12392 {
12393 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12394
12395 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) == 0)
12396 aarch64_set_next_PC_by_offset (cpu, offset);
12397 }
12398
12399 /* Branch on register bit test non-zero -- one size fits all. */
12400 static void
12401 tbnz (sim_cpu *cpu, uint32_t pos, int32_t offset)
12402 {
12403 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12404
12405 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) & (1 << pos))
12406 aarch64_set_next_PC_by_offset (cpu, offset);
12407 }
12408
12409 /* branch on register bit test zero -- one size fits all. */
12410 static void
12411 tbz (sim_cpu *cpu, uint32_t pos, int32_t offset)
12412 {
12413 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12414
12415 if (!(aarch64_get_reg_u64 (cpu, rt, NO_SP) & (1 << pos)))
12416 aarch64_set_next_PC_by_offset (cpu, offset);
12417 }
12418
12419 static void
12420 dexCompareBranchImmediate (sim_cpu *cpu)
12421 {
12422 /* instr[30,25] = 01 1010
12423 instr[31] = size : 0 ==> 32, 1 ==> 64
12424 instr[24] = op : 0 ==> CBZ, 1 ==> CBNZ
12425 instr[23,5] = simm19 branch offset counted in words
12426 instr[4,0] = rt */
12427
12428 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
12429 uint32_t op = uimm (aarch64_get_instr (cpu), 24, 24);
12430 int32_t offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
12431
12432 if (size == 0)
12433 {
12434 if (op == 0)
12435 cbz32 (cpu, offset);
12436 else
12437 cbnz32 (cpu, offset);
12438 }
12439 else
12440 {
12441 if (op == 0)
12442 cbz (cpu, offset);
12443 else
12444 cbnz (cpu, offset);
12445 }
12446 }
12447
12448 static void
12449 dexTestBranchImmediate (sim_cpu *cpu)
12450 {
12451 /* instr[31] = b5 : bit 5 of test bit idx
12452 instr[30,25] = 01 1011
12453 instr[24] = op : 0 ==> TBZ, 1 == TBNZ
12454 instr[23,19] = b40 : bits 4 to 0 of test bit idx
12455 instr[18,5] = simm14 : signed offset counted in words
12456 instr[4,0] = uimm5 */
12457
12458 uint32_t pos = ((uimm (aarch64_get_instr (cpu), 31, 31) << 4)
12459 | uimm (aarch64_get_instr (cpu), 23,19));
12460 int32_t offset = simm32 (aarch64_get_instr (cpu), 18, 5) << 2;
12461
12462 NYI_assert (30, 25, 0x1b);
12463
12464 if (uimm (aarch64_get_instr (cpu), 24, 24) == 0)
12465 tbz (cpu, pos, offset);
12466 else
12467 tbnz (cpu, pos, offset);
12468 }
12469
12470 static void
12471 dexCondBranchImmediate (sim_cpu *cpu)
12472 {
12473 /* instr[31,25] = 010 1010
12474 instr[24] = op1; op => 00 ==> B.cond
12475 instr[23,5] = simm19 : signed offset counted in words
12476 instr[4] = op0
12477 instr[3,0] = cond */
12478
12479 int32_t offset;
12480 CondCode cc;
12481 uint32_t op = ((uimm (aarch64_get_instr (cpu), 24, 24) << 1)
12482 | uimm (aarch64_get_instr (cpu), 4, 4));
12483
12484 NYI_assert (31, 25, 0x2a);
12485
12486 if (op != 0)
12487 HALT_UNALLOC;
12488
12489 offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
12490 cc = condcode (aarch64_get_instr (cpu), 0);
12491
12492 bcc (cpu, offset, cc);
12493 }
12494
12495 static void
12496 dexBranchRegister (sim_cpu *cpu)
12497 {
12498 /* instr[31,25] = 110 1011
12499 instr[24,21] = op : 0 ==> BR, 1 => BLR, 2 => RET, 3 => ERET, 4 => DRPS
12500 instr[20,16] = op2 : must be 11111
12501 instr[15,10] = op3 : must be 000000
12502 instr[4,0] = op2 : must be 11111. */
12503
12504 uint32_t op = uimm (aarch64_get_instr (cpu), 24, 21);
12505 uint32_t op2 = uimm (aarch64_get_instr (cpu), 20, 16);
12506 uint32_t op3 = uimm (aarch64_get_instr (cpu), 15, 10);
12507 uint32_t op4 = uimm (aarch64_get_instr (cpu), 4, 0);
12508
12509 NYI_assert (31, 25, 0x6b);
12510
12511 if (op2 != 0x1F || op3 != 0 || op4 != 0)
12512 HALT_UNALLOC;
12513
12514 if (op == 0)
12515 br (cpu);
12516
12517 else if (op == 1)
12518 blr (cpu);
12519
12520 else if (op == 2)
12521 ret (cpu);
12522
12523 else
12524 {
12525 /* ERET and DRPS accept 0b11111 for rn = aarch64_get_instr (cpu)[4,0]. */
12526 /* anything else is unallocated. */
12527 uint32_t rn = greg (aarch64_get_instr (cpu), 0);
12528
12529 if (rn != 0x1f)
12530 HALT_UNALLOC;
12531
12532 if (op == 4 || op == 5)
12533 HALT_NYI;
12534
12535 HALT_UNALLOC;
12536 }
12537 }
12538
12539 /* FIXME: We should get the Angel SWI values from ../../libgloss/aarch64/svc.h
12540 but this may not be available. So instead we define the values we need
12541 here. */
12542 #define AngelSVC_Reason_Open 0x01
12543 #define AngelSVC_Reason_Close 0x02
12544 #define AngelSVC_Reason_Write 0x05
12545 #define AngelSVC_Reason_Read 0x06
12546 #define AngelSVC_Reason_IsTTY 0x09
12547 #define AngelSVC_Reason_Seek 0x0A
12548 #define AngelSVC_Reason_FLen 0x0C
12549 #define AngelSVC_Reason_Remove 0x0E
12550 #define AngelSVC_Reason_Rename 0x0F
12551 #define AngelSVC_Reason_Clock 0x10
12552 #define AngelSVC_Reason_Time 0x11
12553 #define AngelSVC_Reason_System 0x12
12554 #define AngelSVC_Reason_Errno 0x13
12555 #define AngelSVC_Reason_GetCmdLine 0x15
12556 #define AngelSVC_Reason_HeapInfo 0x16
12557 #define AngelSVC_Reason_ReportException 0x18
12558 #define AngelSVC_Reason_Elapsed 0x30
12559
12560
12561 static void
12562 handle_halt (sim_cpu *cpu, uint32_t val)
12563 {
12564 uint64_t result = 0;
12565
12566 if (val != 0xf000)
12567 {
12568 TRACE_SYSCALL (cpu, " HLT [0x%x]", val);
12569 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12570 sim_stopped, SIM_SIGTRAP);
12571 }
12572
12573 /* We have encountered an Angel SVC call. See if we can process it. */
12574 switch (aarch64_get_reg_u32 (cpu, 0, NO_SP))
12575 {
12576 case AngelSVC_Reason_HeapInfo:
12577 {
12578 /* Get the values. */
12579 uint64_t stack_top = aarch64_get_stack_start (cpu);
12580 uint64_t heap_base = aarch64_get_heap_start (cpu);
12581
12582 /* Get the pointer */
12583 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12584 ptr = aarch64_get_mem_u64 (cpu, ptr);
12585
12586 /* Fill in the memory block. */
12587 /* Start addr of heap. */
12588 aarch64_set_mem_u64 (cpu, ptr + 0, heap_base);
12589 /* End addr of heap. */
12590 aarch64_set_mem_u64 (cpu, ptr + 8, stack_top);
12591 /* Lowest stack addr. */
12592 aarch64_set_mem_u64 (cpu, ptr + 16, heap_base);
12593 /* Initial stack addr. */
12594 aarch64_set_mem_u64 (cpu, ptr + 24, stack_top);
12595
12596 TRACE_SYSCALL (cpu, " AngelSVC: Get Heap Info");
12597 }
12598 break;
12599
12600 case AngelSVC_Reason_Open:
12601 {
12602 /* Get the pointer */
12603 /* uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);. */
12604 /* FIXME: For now we just assume that we will only be asked
12605 to open the standard file descriptors. */
12606 static int fd = 0;
12607 result = fd ++;
12608
12609 TRACE_SYSCALL (cpu, " AngelSVC: Open file %d", fd - 1);
12610 }
12611 break;
12612
12613 case AngelSVC_Reason_Close:
12614 {
12615 uint64_t fh = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12616 TRACE_SYSCALL (cpu, " AngelSVC: Close file %d", (int) fh);
12617 result = 0;
12618 }
12619 break;
12620
12621 case AngelSVC_Reason_Errno:
12622 result = 0;
12623 TRACE_SYSCALL (cpu, " AngelSVC: Get Errno");
12624 break;
12625
12626 case AngelSVC_Reason_Clock:
12627 result =
12628 #ifdef CLOCKS_PER_SEC
12629 (CLOCKS_PER_SEC >= 100)
12630 ? (clock () / (CLOCKS_PER_SEC / 100))
12631 : ((clock () * 100) / CLOCKS_PER_SEC)
12632 #else
12633 /* Presume unix... clock() returns microseconds. */
12634 (clock () / 10000)
12635 #endif
12636 ;
12637 TRACE_SYSCALL (cpu, " AngelSVC: Get Clock");
12638 break;
12639
12640 case AngelSVC_Reason_GetCmdLine:
12641 {
12642 /* Get the pointer */
12643 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12644 ptr = aarch64_get_mem_u64 (cpu, ptr);
12645
12646 /* FIXME: No command line for now. */
12647 aarch64_set_mem_u64 (cpu, ptr, 0);
12648 TRACE_SYSCALL (cpu, " AngelSVC: Get Command Line");
12649 }
12650 break;
12651
12652 case AngelSVC_Reason_IsTTY:
12653 result = 1;
12654 TRACE_SYSCALL (cpu, " AngelSVC: IsTTY ?");
12655 break;
12656
12657 case AngelSVC_Reason_Write:
12658 {
12659 /* Get the pointer */
12660 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12661 /* Get the write control block. */
12662 uint64_t fd = aarch64_get_mem_u64 (cpu, ptr);
12663 uint64_t buf = aarch64_get_mem_u64 (cpu, ptr + 8);
12664 uint64_t len = aarch64_get_mem_u64 (cpu, ptr + 16);
12665
12666 TRACE_SYSCALL (cpu, "write of %" PRIx64 " bytes from %"
12667 PRIx64 " on descriptor %" PRIx64,
12668 len, buf, fd);
12669
12670 if (len > 1280)
12671 {
12672 TRACE_SYSCALL (cpu,
12673 " AngelSVC: Write: Suspiciously long write: %ld",
12674 (long) len);
12675 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12676 sim_stopped, SIM_SIGBUS);
12677 }
12678 else if (fd == 1)
12679 {
12680 printf ("%.*s", (int) len, aarch64_get_mem_ptr (cpu, buf));
12681 if (disas)
12682 /* So that the output stays in sync with trace output. */
12683 fflush (stdout);
12684 }
12685 else if (fd == 2)
12686 {
12687 TRACE (cpu, 0, "\n");
12688 sim_io_eprintf (CPU_STATE (cpu), "%.*s",
12689 (int) len, aarch64_get_mem_ptr (cpu, buf));
12690 TRACE (cpu, 0, "\n");
12691 }
12692 else
12693 {
12694 TRACE_SYSCALL (cpu,
12695 " AngelSVC: Write: Unexpected file handle: %d",
12696 (int) fd);
12697 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12698 sim_stopped, SIM_SIGABRT);
12699 }
12700 }
12701 break;
12702
12703 case AngelSVC_Reason_ReportException:
12704 {
12705 /* Get the pointer */
12706 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12707 /*ptr = aarch64_get_mem_u64 (cpu, ptr);. */
12708 uint64_t type = aarch64_get_mem_u64 (cpu, ptr);
12709 uint64_t state = aarch64_get_mem_u64 (cpu, ptr + 8);
12710
12711 TRACE_SYSCALL (cpu,
12712 "Angel Exception: type 0x%" PRIx64 " state %" PRIx64,
12713 type, state);
12714
12715 if (type == 0x20026)
12716 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12717 sim_exited, state);
12718 else
12719 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12720 sim_stopped, SIM_SIGINT);
12721 }
12722 break;
12723
12724 case AngelSVC_Reason_Read:
12725 case AngelSVC_Reason_FLen:
12726 case AngelSVC_Reason_Seek:
12727 case AngelSVC_Reason_Remove:
12728 case AngelSVC_Reason_Time:
12729 case AngelSVC_Reason_System:
12730 case AngelSVC_Reason_Rename:
12731 case AngelSVC_Reason_Elapsed:
12732 default:
12733 TRACE_SYSCALL (cpu, " HLT [Unknown angel %x]",
12734 aarch64_get_reg_u32 (cpu, 0, NO_SP));
12735 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12736 sim_stopped, SIM_SIGTRAP);
12737 }
12738
12739 aarch64_set_reg_u64 (cpu, 0, NO_SP, result);
12740 }
12741
12742 static void
12743 dexExcpnGen (sim_cpu *cpu)
12744 {
12745 /* instr[31:24] = 11010100
12746 instr[23,21] = opc : 000 ==> GEN EXCPN, 001 ==> BRK
12747 010 ==> HLT, 101 ==> DBG GEN EXCPN
12748 instr[20,5] = imm16
12749 instr[4,2] = opc2 000 ==> OK, ow ==> UNALLOC
12750 instr[1,0] = LL : discriminates opc */
12751
12752 uint32_t opc = uimm (aarch64_get_instr (cpu), 23, 21);
12753 uint32_t imm16 = uimm (aarch64_get_instr (cpu), 20, 5);
12754 uint32_t opc2 = uimm (aarch64_get_instr (cpu), 4, 2);
12755 uint32_t LL;
12756
12757 NYI_assert (31, 24, 0xd4);
12758
12759 if (opc2 != 0)
12760 HALT_UNALLOC;
12761
12762 LL = uimm (aarch64_get_instr (cpu), 1, 0);
12763
12764 /* We only implement HLT and BRK for now. */
12765 if (opc == 1 && LL == 0)
12766 {
12767 TRACE_EVENTS (cpu, " BRK [0x%x]", imm16);
12768 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12769 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
12770 }
12771
12772 if (opc == 2 && LL == 0)
12773 handle_halt (cpu, imm16);
12774
12775 else if (opc == 0 || opc == 5)
12776 HALT_NYI;
12777
12778 else
12779 HALT_UNALLOC;
12780 }
12781
12782 /* Stub for accessing system registers.
12783 We implement support for the DCZID register since this is used
12784 by the C library's memset function. */
12785
12786 static uint64_t
12787 system_get (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
12788 unsigned crm, unsigned op2)
12789 {
12790 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 7)
12791 /* DCZID_EL0 - the Data Cache Zero ID register.
12792 We do not support DC ZVA at the moment, so
12793 we return a value with the disable bit set. */
12794 return ((uint64_t) 1) << 4;
12795
12796 HALT_NYI;
12797 }
12798
12799 static void
12800 do_mrs (sim_cpu *cpu)
12801 {
12802 /* instr[31:20] = 1101 01010 0011
12803 instr[19] = op0
12804 instr[18,16] = op1
12805 instr[15,12] = CRn
12806 instr[11,8] = CRm
12807 instr[7,5] = op2
12808 instr[4,0] = Rt */
12809 unsigned sys_op0 = uimm (aarch64_get_instr (cpu), 19, 19) + 2;
12810 unsigned sys_op1 = uimm (aarch64_get_instr (cpu), 18, 16);
12811 unsigned sys_crn = uimm (aarch64_get_instr (cpu), 15, 12);
12812 unsigned sys_crm = uimm (aarch64_get_instr (cpu), 11, 8);
12813 unsigned sys_op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12814 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12815
12816 aarch64_set_reg_u64 (cpu, rt, NO_SP,
12817 system_get (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2));
12818 }
12819
12820 static void
12821 dexSystem (sim_cpu *cpu)
12822 {
12823 /* instr[31:22] = 1101 01010 0
12824 instr[21] = L
12825 instr[20,19] = op0
12826 instr[18,16] = op1
12827 instr[15,12] = CRn
12828 instr[11,8] = CRm
12829 instr[7,5] = op2
12830 instr[4,0] = uimm5 */
12831
12832 /* We are interested in HINT, DSB, DMB and ISB
12833
12834 Hint #0 encodes NOOP (this is the only hint we care about)
12835 L == 0, op0 == 0, op1 = 011, CRn = 0010, Rt = 11111,
12836 CRm op2 != 0000 000 OR CRm op2 == 0000 000 || CRm op > 0000 101
12837
12838 DSB, DMB, ISB are data store barrier, data memory barrier and
12839 instruction store barrier, respectively, where
12840
12841 L == 0, op0 == 0, op1 = 011, CRn = 0011, Rt = 11111,
12842 op2 : DSB ==> 100, DMB ==> 101, ISB ==> 110
12843 CRm<3:2> ==> domain, CRm<1:0> ==> types,
12844 domain : 00 ==> OuterShareable, 01 ==> Nonshareable,
12845 10 ==> InerShareable, 11 ==> FullSystem
12846 types : 01 ==> Reads, 10 ==> Writes,
12847 11 ==> All, 00 ==> All (domain == FullSystem). */
12848
12849 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12850 uint32_t l_op0_op1_crn = uimm (aarch64_get_instr (cpu), 21, 12);
12851
12852 NYI_assert (31, 22, 0x354);
12853
12854 switch (l_op0_op1_crn)
12855 {
12856 case 0x032:
12857 if (rt == 0x1F)
12858 {
12859 /* NOP has CRm != 0000 OR. */
12860 /* (CRm == 0000 AND (op2 == 000 OR op2 > 101)). */
12861 uint32_t crm = uimm (aarch64_get_instr (cpu), 11, 8);
12862 uint32_t op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12863
12864 if (crm != 0 || (op2 == 0 || op2 > 5))
12865 {
12866 /* Actually call nop method so we can reimplement it later. */
12867 nop (cpu);
12868 return;
12869 }
12870 }
12871 HALT_NYI;
12872
12873 case 0x033:
12874 {
12875 uint32_t op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12876
12877 switch (op2)
12878 {
12879 case 2: HALT_NYI;
12880 case 4: dsb (cpu); return;
12881 case 5: dmb (cpu); return;
12882 case 6: isb (cpu); return;
12883 case 7:
12884 default: HALT_UNALLOC;
12885 }
12886 }
12887
12888 case 0x3B0:
12889 /* MRS Wt, sys-reg. */
12890 do_mrs (cpu);
12891 return;
12892
12893 case 0x3B4:
12894 case 0x3BD:
12895 /* MRS Xt, sys-reg. */
12896 do_mrs (cpu);
12897 return;
12898
12899 case 0x0B7:
12900 /* DC <type>, x<n>. */
12901 HALT_NYI;
12902 return;
12903
12904 default:
12905 /* if (uimm (aarch64_get_instr (cpu), 21, 20) == 0x1)
12906 MRS Xt, sys-reg. */
12907 HALT_NYI;
12908 return;
12909 }
12910 }
12911
12912 static void
12913 dexBr (sim_cpu *cpu)
12914 {
12915 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12916 assert group == GROUP_BREXSYS_1010 || group == GROUP_BREXSYS_1011
12917 bits [31,29] of a BrExSys are the secondary dispatch vector. */
12918 uint32_t group2 = dispatchBrExSys (aarch64_get_instr (cpu));
12919
12920 switch (group2)
12921 {
12922 case BR_IMM_000:
12923 return dexBranchImmediate (cpu);
12924
12925 case BR_IMMCMP_001:
12926 /* Compare has bit 25 clear while test has it set. */
12927 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12928 dexCompareBranchImmediate (cpu);
12929 else
12930 dexTestBranchImmediate (cpu);
12931 return;
12932
12933 case BR_IMMCOND_010:
12934 /* This is a conditional branch if bit 25 is clear otherwise
12935 unallocated. */
12936 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12937 dexCondBranchImmediate (cpu);
12938 else
12939 HALT_UNALLOC;
12940 return;
12941
12942 case BR_UNALLOC_011:
12943 HALT_UNALLOC;
12944
12945 case BR_IMM_100:
12946 dexBranchImmediate (cpu);
12947 return;
12948
12949 case BR_IMMCMP_101:
12950 /* Compare has bit 25 clear while test has it set. */
12951 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12952 dexCompareBranchImmediate (cpu);
12953 else
12954 dexTestBranchImmediate (cpu);
12955 return;
12956
12957 case BR_REG_110:
12958 /* Unconditional branch reg has bit 25 set. */
12959 if (uimm (aarch64_get_instr (cpu), 25, 25))
12960 dexBranchRegister (cpu);
12961
12962 /* This includes both Excpn Gen, System and unalloc operations.
12963 We need to decode the Excpn Gen operation BRK so we can plant
12964 debugger entry points.
12965 Excpn Gen operations have aarch64_get_instr (cpu)[24] = 0.
12966 we need to decode at least one of the System operations NOP
12967 which is an alias for HINT #0.
12968 System operations have aarch64_get_instr (cpu)[24,22] = 100. */
12969 else if (uimm (aarch64_get_instr (cpu), 24, 24) == 0)
12970 dexExcpnGen (cpu);
12971
12972 else if (uimm (aarch64_get_instr (cpu), 24, 22) == 4)
12973 dexSystem (cpu);
12974
12975 else
12976 HALT_UNALLOC;
12977
12978 return;
12979
12980 case BR_UNALLOC_111:
12981 HALT_UNALLOC;
12982
12983 default:
12984 /* Should never reach here. */
12985 HALT_NYI;
12986 }
12987 }
12988
12989 static void
12990 aarch64_decode_and_execute (sim_cpu *cpu, uint64_t pc)
12991 {
12992 /* We need to check if gdb wants an in here. */
12993 /* checkBreak (cpu);. */
12994
12995 uint64_t group = dispatchGroup (aarch64_get_instr (cpu));
12996
12997 switch (group)
12998 {
12999 case GROUP_PSEUDO_0000: dexPseudo (cpu); break;
13000 case GROUP_LDST_0100: dexLdSt (cpu); break;
13001 case GROUP_DPREG_0101: dexDPReg (cpu); break;
13002 case GROUP_LDST_0110: dexLdSt (cpu); break;
13003 case GROUP_ADVSIMD_0111: dexAdvSIMD0 (cpu); break;
13004 case GROUP_DPIMM_1000: dexDPImm (cpu); break;
13005 case GROUP_DPIMM_1001: dexDPImm (cpu); break;
13006 case GROUP_BREXSYS_1010: dexBr (cpu); break;
13007 case GROUP_BREXSYS_1011: dexBr (cpu); break;
13008 case GROUP_LDST_1100: dexLdSt (cpu); break;
13009 case GROUP_DPREG_1101: dexDPReg (cpu); break;
13010 case GROUP_LDST_1110: dexLdSt (cpu); break;
13011 case GROUP_ADVSIMD_1111: dexAdvSIMD1 (cpu); break;
13012
13013 case GROUP_UNALLOC_0001:
13014 case GROUP_UNALLOC_0010:
13015 case GROUP_UNALLOC_0011:
13016 HALT_UNALLOC;
13017
13018 default:
13019 /* Should never reach here. */
13020 HALT_NYI;
13021 }
13022 }
13023
13024 static bfd_boolean
13025 aarch64_step (sim_cpu *cpu)
13026 {
13027 uint64_t pc = aarch64_get_PC (cpu);
13028
13029 if (pc == TOP_LEVEL_RETURN_PC)
13030 return FALSE;
13031
13032 aarch64_set_next_PC (cpu, pc + 4);
13033 aarch64_get_instr (cpu) = aarch64_get_mem_u32 (cpu, pc);
13034
13035 if (TRACE_INSN_P (cpu))
13036 {
13037 if (disas)
13038 TRACE_INSN (cpu, " pc = %" PRIx64 " ", pc);
13039 else
13040 TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %x", pc,
13041 aarch64_get_instr (cpu));
13042 }
13043 else if (disas)
13044 sim_io_eprintf (CPU_STATE (cpu), " %" PRIx64 " ", pc);
13045
13046 if (disas)
13047 aarch64_print_insn (CPU_STATE (cpu), pc);
13048
13049 aarch64_decode_and_execute (cpu, pc);
13050
13051 return TRUE;
13052 }
13053
13054 void
13055 aarch64_run (SIM_DESC sd)
13056 {
13057 sim_cpu *cpu = STATE_CPU (sd, 0);
13058
13059 while (aarch64_step (cpu))
13060 aarch64_update_PC (cpu);
13061
13062 sim_engine_halt (sd, NULL, NULL, aarch64_get_PC (cpu),
13063 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13064 }
13065
13066 void
13067 aarch64_init (sim_cpu *cpu, uint64_t pc)
13068 {
13069 uint64_t sp = aarch64_get_stack_start (cpu);
13070
13071 /* Install SP, FP and PC and set LR to -20
13072 so we can detect a top-level return. */
13073 aarch64_set_reg_u64 (cpu, SP, SP_OK, sp);
13074 aarch64_set_reg_u64 (cpu, FP, SP_OK, sp);
13075 aarch64_set_reg_u64 (cpu, LR, SP_OK, TOP_LEVEL_RETURN_PC);
13076 aarch64_set_next_PC (cpu, pc);
13077 aarch64_update_PC (cpu);
13078 aarch64_init_LIT_table ();
13079 }