]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/aarch64/simulator.c
sim: aarch64: switch to common disassembler tracing
[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 "simulator.h"
32 #include "cpustate.h"
33 #include "memory.h"
34
35 #define NO_SP 0
36 #define SP_OK 1
37
38 #define TST(_flag) (aarch64_test_CPSR_bit (cpu, _flag))
39 #define IS_SET(_X) ( TST (( _X )))
40 #define IS_CLEAR(_X) (!TST (( _X )))
41
42 #define HALT_UNALLOC \
43 do \
44 { \
45 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
46 TRACE_INSN (cpu, \
47 "Unallocated instruction detected at sim line %d," \
48 " exe addr %" PRIx64, \
49 __LINE__, aarch64_get_PC (cpu)); \
50 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
51 sim_stopped, SIM_SIGILL); \
52 } \
53 while (0)
54
55 #define HALT_NYI \
56 do \
57 { \
58 TRACE_DISASM (cpu, aarch64_get_PC (cpu)); \
59 TRACE_INSN (cpu, \
60 "Unimplemented instruction detected at sim line %d," \
61 " exe addr %" PRIx64, \
62 __LINE__, aarch64_get_PC (cpu)); \
63 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),\
64 sim_stopped, SIM_SIGABRT); \
65 } \
66 while (0)
67
68 #define NYI_assert(HI, LO, EXPECTED) \
69 do \
70 { \
71 if (uimm (aarch64_get_instr (cpu), (HI), (LO)) != (EXPECTED)) \
72 HALT_NYI; \
73 } \
74 while (0)
75
76 #define HALT_UNREACHABLE \
77 do \
78 { \
79 TRACE_EVENTS (cpu, "ISE: unreachable code point"); \
80 sim_engine_abort (NULL, cpu, aarch64_get_PC (cpu), "Internal Error"); \
81 } \
82 while (0)
83
84 /* Helper functions used by expandLogicalImmediate. */
85
86 /* for i = 1, ... N result<i-1> = 1 other bits are zero */
87 static inline uint64_t
88 ones (int N)
89 {
90 return (N == 64 ? (uint64_t)-1UL : ((1UL << N) - 1));
91 }
92
93 /* result<0> to val<N> */
94 static inline uint64_t
95 pickbit (uint64_t val, int N)
96 {
97 return pickbits64 (val, N, N);
98 }
99
100 static uint64_t
101 expand_logical_immediate (uint32_t S, uint32_t R, uint32_t N)
102 {
103 uint64_t mask;
104 uint64_t imm;
105 unsigned simd_size;
106
107 /* The immediate value is S+1 bits to 1, left rotated by SIMDsize - R
108 (in other words, right rotated by R), then replicated. */
109 if (N != 0)
110 {
111 simd_size = 64;
112 mask = 0xffffffffffffffffull;
113 }
114 else
115 {
116 switch (S)
117 {
118 case 0x00 ... 0x1f: /* 0xxxxx */ simd_size = 32; break;
119 case 0x20 ... 0x2f: /* 10xxxx */ simd_size = 16; S &= 0xf; break;
120 case 0x30 ... 0x37: /* 110xxx */ simd_size = 8; S &= 0x7; break;
121 case 0x38 ... 0x3b: /* 1110xx */ simd_size = 4; S &= 0x3; break;
122 case 0x3c ... 0x3d: /* 11110x */ simd_size = 2; S &= 0x1; break;
123 default: return 0;
124 }
125 mask = (1ull << simd_size) - 1;
126 /* Top bits are IGNORED. */
127 R &= simd_size - 1;
128 }
129
130 /* NOTE: if S = simd_size - 1 we get 0xf..f which is rejected. */
131 if (S == simd_size - 1)
132 return 0;
133
134 /* S+1 consecutive bits to 1. */
135 /* NOTE: S can't be 63 due to detection above. */
136 imm = (1ull << (S + 1)) - 1;
137
138 /* Rotate to the left by simd_size - R. */
139 if (R != 0)
140 imm = ((imm << (simd_size - R)) & mask) | (imm >> R);
141
142 /* Replicate the value according to SIMD size. */
143 switch (simd_size)
144 {
145 case 2: imm = (imm << 2) | imm;
146 case 4: imm = (imm << 4) | imm;
147 case 8: imm = (imm << 8) | imm;
148 case 16: imm = (imm << 16) | imm;
149 case 32: imm = (imm << 32) | imm;
150 case 64: break;
151 default: return 0;
152 }
153
154 return imm;
155 }
156
157 /* Instr[22,10] encodes N immr and imms. we want a lookup table
158 for each possible combination i.e. 13 bits worth of int entries. */
159 #define LI_TABLE_SIZE (1 << 13)
160 static uint64_t LITable[LI_TABLE_SIZE];
161
162 void
163 aarch64_init_LIT_table (void)
164 {
165 unsigned index;
166
167 for (index = 0; index < LI_TABLE_SIZE; index++)
168 {
169 uint32_t N = uimm (index, 12, 12);
170 uint32_t immr = uimm (index, 11, 6);
171 uint32_t imms = uimm (index, 5, 0);
172
173 LITable [index] = expand_logical_immediate (imms, immr, N);
174 }
175 }
176
177 static void
178 dexNotify (sim_cpu *cpu)
179 {
180 /* instr[14,0] == type : 0 ==> method entry, 1 ==> method reentry
181 2 ==> exit Java, 3 ==> start next bytecode. */
182 uint32_t type = uimm (aarch64_get_instr (cpu), 14, 0);
183
184 TRACE_EVENTS (cpu, "Notify Insn encountered, type = 0x%x", type);
185
186 switch (type)
187 {
188 case 0:
189 /* aarch64_notifyMethodEntry (aarch64_get_reg_u64 (cpu, R23, 0),
190 aarch64_get_reg_u64 (cpu, R22, 0)); */
191 break;
192 case 1:
193 /* aarch64_notifyMethodReentry (aarch64_get_reg_u64 (cpu, R23, 0),
194 aarch64_get_reg_u64 (cpu, R22, 0)); */
195 break;
196 case 2:
197 /* aarch64_notifyMethodExit (); */
198 break;
199 case 3:
200 /* aarch64_notifyBCStart (aarch64_get_reg_u64 (cpu, R23, 0),
201 aarch64_get_reg_u64 (cpu, R22, 0)); */
202 break;
203 }
204 }
205
206 /* secondary decode within top level groups */
207
208 static void
209 dexPseudo (sim_cpu *cpu)
210 {
211 /* assert instr[28,27] = 00
212
213 We provide 2 pseudo instructions:
214
215 HALT stops execution of the simulator causing an immediate
216 return to the x86 code which entered it.
217
218 CALLOUT initiates recursive entry into x86 code. A register
219 argument holds the address of the x86 routine. Immediate
220 values in the instruction identify the number of general
221 purpose and floating point register arguments to be passed
222 and the type of any value to be returned. */
223
224 uint32_t PSEUDO_HALT = 0xE0000000U;
225 uint32_t PSEUDO_CALLOUT = 0x00018000U;
226 uint32_t PSEUDO_CALLOUTR = 0x00018001U;
227 uint32_t PSEUDO_NOTIFY = 0x00014000U;
228 uint32_t dispatch;
229
230 if (aarch64_get_instr (cpu) == PSEUDO_HALT)
231 {
232 TRACE_EVENTS (cpu, " Pseudo Halt Instruction");
233 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
234 sim_stopped, SIM_SIGTRAP);
235 }
236
237 dispatch = uimm (aarch64_get_instr (cpu), 31, 15);
238
239 /* We do not handle callouts at the moment. */
240 if (dispatch == PSEUDO_CALLOUT || dispatch == PSEUDO_CALLOUTR)
241 {
242 TRACE_EVENTS (cpu, " Callout");
243 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
244 sim_stopped, SIM_SIGABRT);
245 }
246
247 else if (dispatch == PSEUDO_NOTIFY)
248 dexNotify (cpu);
249
250 else
251 HALT_UNALLOC;
252 }
253
254 /* Load-store single register (unscaled offset)
255 These instructions employ a base register plus an unscaled signed
256 9 bit offset.
257
258 N.B. the base register (source) can be Xn or SP. all other
259 registers may not be SP. */
260
261 /* 32 bit load 32 bit unscaled signed 9 bit. */
262 static void
263 ldur32 (sim_cpu *cpu, int32_t offset)
264 {
265 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
266 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
267
268 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
269 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
270 + offset));
271 }
272
273 /* 64 bit load 64 bit unscaled signed 9 bit. */
274 static void
275 ldur64 (sim_cpu *cpu, int32_t offset)
276 {
277 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
278 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
279
280 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
281 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
282 + offset));
283 }
284
285 /* 32 bit load zero-extended byte unscaled signed 9 bit. */
286 static void
287 ldurb32 (sim_cpu *cpu, int32_t offset)
288 {
289 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
290 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
291
292 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8
293 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
294 + offset));
295 }
296
297 /* 32 bit load sign-extended byte unscaled signed 9 bit. */
298 static void
299 ldursb32 (sim_cpu *cpu, int32_t offset)
300 {
301 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
302 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
303
304 aarch64_set_reg_u64 (cpu, rt, NO_SP, (uint32_t) aarch64_get_mem_s8
305 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
306 + offset));
307 }
308
309 /* 64 bit load sign-extended byte unscaled signed 9 bit. */
310 static void
311 ldursb64 (sim_cpu *cpu, int32_t offset)
312 {
313 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
314 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
315
316 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s8
317 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
318 + offset));
319 }
320
321 /* 32 bit load zero-extended short unscaled signed 9 bit */
322 static void
323 ldurh32 (sim_cpu *cpu, int32_t offset)
324 {
325 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
326 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
327
328 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_mem_u16
329 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
330 + offset));
331 }
332
333 /* 32 bit load sign-extended short unscaled signed 9 bit */
334 static void
335 ldursh32 (sim_cpu *cpu, int32_t offset)
336 {
337 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
338 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
339
340 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s16
341 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
342 + offset));
343 }
344
345 /* 64 bit load sign-extended short unscaled signed 9 bit */
346 static void
347 ldursh64 (sim_cpu *cpu, int32_t offset)
348 {
349 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
350 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
351
352 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s16
353 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
354 + offset));
355 }
356
357 /* 64 bit load sign-extended word unscaled signed 9 bit */
358 static void
359 ldursw (sim_cpu *cpu, int32_t offset)
360 {
361 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
362 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
363
364 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) aarch64_get_mem_s32
365 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
366 + offset));
367 }
368
369 /* N.B. with stores the value in source is written to the address
370 identified by source2 modified by offset. */
371
372 /* 32 bit store 32 bit unscaled signed 9 bit. */
373 static void
374 stur32 (sim_cpu *cpu, int32_t offset)
375 {
376 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
377 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
378
379 aarch64_set_mem_u32 (cpu,
380 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
381 aarch64_get_reg_u32 (cpu, rd, NO_SP));
382 }
383
384 /* 64 bit store 64 bit unscaled signed 9 bit */
385 static void
386 stur64 (sim_cpu *cpu, int32_t offset)
387 {
388 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
389 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
390
391 aarch64_set_mem_u64 (cpu,
392 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
393 aarch64_get_reg_u64 (cpu, rd, NO_SP));
394 }
395
396 /* 32 bit store byte unscaled signed 9 bit */
397 static void
398 sturb (sim_cpu *cpu, int32_t offset)
399 {
400 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
401 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
402
403 aarch64_set_mem_u8 (cpu,
404 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
405 aarch64_get_reg_u8 (cpu, rd, NO_SP));
406 }
407
408 /* 32 bit store short unscaled signed 9 bit */
409 static void
410 sturh (sim_cpu *cpu, int32_t offset)
411 {
412 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
413 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
414
415 aarch64_set_mem_u16 (cpu,
416 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
417 aarch64_get_reg_u16 (cpu, rd, NO_SP));
418 }
419
420 /* Load single register pc-relative label
421 Offset is a signed 19 bit immediate count in words
422 rt may not be SP. */
423
424 /* 32 bit pc-relative load */
425 static void
426 ldr32_pcrel (sim_cpu *cpu, int32_t offset)
427 {
428 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
429
430 aarch64_set_reg_u64 (cpu, rd, NO_SP,
431 aarch64_get_mem_u32
432 (cpu, aarch64_get_PC (cpu) + offset * 4));
433 }
434
435 /* 64 bit pc-relative load */
436 static void
437 ldr_pcrel (sim_cpu *cpu, int32_t offset)
438 {
439 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
440
441 aarch64_set_reg_u64 (cpu, rd, NO_SP,
442 aarch64_get_mem_u64
443 (cpu, aarch64_get_PC (cpu) + offset * 4));
444 }
445
446 /* sign extended 32 bit pc-relative load */
447 static void
448 ldrsw_pcrel (sim_cpu *cpu, int32_t offset)
449 {
450 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
451
452 aarch64_set_reg_u64 (cpu, rd, NO_SP,
453 aarch64_get_mem_s32
454 (cpu, aarch64_get_PC (cpu) + offset * 4));
455 }
456
457 /* float pc-relative load */
458 static void
459 fldrs_pcrel (sim_cpu *cpu, int32_t offset)
460 {
461 unsigned int rd = uimm (aarch64_get_instr (cpu), 4, 0);
462
463 aarch64_set_FP_float (cpu, rd,
464 aarch64_get_mem_float
465 (cpu, aarch64_get_PC (cpu) + offset * 4));
466 }
467
468 /* double pc-relative load */
469 static void
470 fldrd_pcrel (sim_cpu *cpu, int32_t offset)
471 {
472 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
473
474 aarch64_set_FP_double (cpu, st,
475 aarch64_get_mem_double
476 (cpu, aarch64_get_PC (cpu) + offset * 4));
477 }
478
479 /* long double pc-relative load. */
480 static void
481 fldrq_pcrel (sim_cpu *cpu, int32_t offset)
482 {
483 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
484 uint64_t addr = aarch64_get_PC (cpu) + offset * 4;
485 FRegister a;
486
487 aarch64_get_mem_long_double (cpu, addr, & a);
488 aarch64_set_FP_long_double (cpu, st, a);
489 }
490
491 /* This can be used to scale an offset by applying
492 the requisite shift. the second argument is either
493 16, 32 or 64. */
494
495 #define SCALE(_offset, _elementSize) \
496 ((_offset) << ScaleShift ## _elementSize)
497
498 /* This can be used to optionally scale a register derived offset
499 by applying the requisite shift as indicated by the Scaling
500 argument. the second argument is either Byte, Short, Word
501 or Long. The third argument is either Scaled or Unscaled.
502 N.B. when _Scaling is Scaled the shift gets ANDed with
503 all 1s while when it is Unscaled it gets ANDed with 0. */
504
505 #define OPT_SCALE(_offset, _elementType, _Scaling) \
506 ((_offset) << (_Scaling ? ScaleShift ## _elementType : 0))
507
508 /* This can be used to zero or sign extend a 32 bit register derived
509 value to a 64 bit value. the first argument must be the value as
510 a uint32_t and the second must be either UXTW or SXTW. The result
511 is returned as an int64_t. */
512
513 static inline int64_t
514 extend (uint32_t value, Extension extension)
515 {
516 union
517 {
518 uint32_t u;
519 int32_t n;
520 } x;
521
522 /* A branchless variant of this ought to be possible. */
523 if (extension == UXTW || extension == NoExtension)
524 return value;
525
526 x.u = value;
527 return x.n;
528 }
529
530 /* Scalar Floating Point
531
532 FP load/store single register (4 addressing modes)
533
534 N.B. the base register (source) can be the stack pointer.
535 The secondary source register (source2) can only be an Xn register. */
536
537 /* Load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
538 static void
539 fldrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
540 {
541 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
542 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
543 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
544
545 if (wb != Post)
546 address += offset;
547
548 aarch64_set_FP_float (cpu, st, aarch64_get_mem_float (cpu, address));
549 if (wb == Post)
550 address += offset;
551
552 if (wb != NoWriteBack)
553 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
554 }
555
556 /* Load 32 bit scaled unsigned 12 bit. */
557 static void
558 fldrs_abs (sim_cpu *cpu, uint32_t offset)
559 {
560 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
561 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
562
563 aarch64_set_FP_float (cpu, st,
564 aarch64_get_mem_float
565 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
566 + SCALE (offset, 32)));
567 }
568
569 /* Load 32 bit scaled or unscaled zero- or sign-extended
570 32-bit register offset. */
571 static void
572 fldrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
573 {
574 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
575 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
576 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
577 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
578 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
579 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
580
581 aarch64_set_FP_float (cpu, st,
582 aarch64_get_mem_float
583 (cpu, address + displacement));
584 }
585
586 /* Load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
587 static void
588 fldrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
589 {
590 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
591 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
592 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
593
594 if (wb != Post)
595 address += offset;
596
597 aarch64_set_FP_double (cpu, st, aarch64_get_mem_double (cpu, address));
598
599 if (wb == Post)
600 address += offset;
601
602 if (wb != NoWriteBack)
603 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
604 }
605
606 /* Load 64 bit scaled unsigned 12 bit. */
607 static void
608 fldrd_abs (sim_cpu *cpu, uint32_t offset)
609 {
610 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
611 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
612 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64);
613
614 aarch64_set_FP_double (cpu, st, aarch64_get_mem_double (cpu, address));
615 }
616
617 /* Load 64 bit scaled or unscaled zero- or sign-extended 32-bit register offset. */
618 static void
619 fldrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
620 {
621 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
622 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
623 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
624
625 fldrd_wb (cpu, displacement, NoWriteBack);
626 }
627
628 /* Load 128 bit unscaled signed 9 bit with pre- or post-writeback. */
629 static void
630 fldrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
631 {
632 FRegister a;
633 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
634 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
635 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
636
637 if (wb != Post)
638 address += offset;
639
640 aarch64_get_mem_long_double (cpu, address, & a);
641 aarch64_set_FP_long_double (cpu, st, a);
642
643 if (wb == Post)
644 address += offset;
645
646 if (wb != NoWriteBack)
647 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
648 }
649
650 /* Load 128 bit scaled unsigned 12 bit. */
651 static void
652 fldrq_abs (sim_cpu *cpu, uint32_t offset)
653 {
654 FRegister a;
655 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
656 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
657 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
658
659 aarch64_get_mem_long_double (cpu, address, & a);
660 aarch64_set_FP_long_double (cpu, st, a);
661 }
662
663 /* Load 128 bit scaled or unscaled zero- or sign-extended 32-bit register offset */
664 static void
665 fldrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
666 {
667 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
668 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
669 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
670
671 fldrq_wb (cpu, displacement, NoWriteBack);
672 }
673
674 /* Memory Access
675
676 load-store single register
677 There are four addressing modes available here which all employ a
678 64 bit source (base) register.
679
680 N.B. the base register (source) can be the stack pointer.
681 The secondary source register (source2)can only be an Xn register.
682
683 Scaled, 12-bit, unsigned immediate offset, without pre- and
684 post-index options.
685 Unscaled, 9-bit, signed immediate offset with pre- or post-index
686 writeback.
687 scaled or unscaled 64-bit register offset.
688 scaled or unscaled 32-bit extended register offset.
689
690 All offsets are assumed to be raw from the decode i.e. the
691 simulator is expected to adjust scaled offsets based on the
692 accessed data size with register or extended register offset
693 versions the same applies except that in the latter case the
694 operation may also require a sign extend.
695
696 A separate method is provided for each possible addressing mode. */
697
698 /* 32 bit load 32 bit scaled unsigned 12 bit */
699 static void
700 ldr32_abs (sim_cpu *cpu, uint32_t offset)
701 {
702 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
703 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
704
705 /* The target register may not be SP but the source may be. */
706 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32
707 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
708 + SCALE (offset, 32)));
709 }
710
711 /* 32 bit load 32 bit unscaled signed 9 bit with pre- or post-writeback. */
712 static void
713 ldr32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
714 {
715 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
716 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
717 uint64_t address;
718
719 if (rn == rt && wb != NoWriteBack)
720 HALT_UNALLOC;
721
722 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
723
724 if (wb != Post)
725 address += offset;
726
727 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
728
729 if (wb == Post)
730 address += offset;
731
732 if (wb != NoWriteBack)
733 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
734 }
735
736 /* 32 bit load 32 bit scaled or unscaled
737 zero- or sign-extended 32-bit register offset */
738 static void
739 ldr32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
740 {
741 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
742 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
743 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
744 /* rn may reference SP, rm and rt must reference ZR */
745
746 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
747 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
748 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
749
750 aarch64_set_reg_u64 (cpu, rt, NO_SP,
751 aarch64_get_mem_u32 (cpu, address + displacement));
752 }
753
754 /* 64 bit load 64 bit scaled unsigned 12 bit */
755 static void
756 ldr_abs (sim_cpu *cpu, uint32_t offset)
757 {
758 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
759 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
760
761 /* The target register may not be SP but the source may be. */
762 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64
763 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
764 + SCALE (offset, 64)));
765 }
766
767 /* 64 bit load 64 bit unscaled signed 9 bit with pre- or post-writeback. */
768 static void
769 ldr_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
770 {
771 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
772 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
773 uint64_t address;
774
775 if (rn == rt && wb != NoWriteBack)
776 HALT_UNALLOC;
777
778 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
779
780 if (wb != Post)
781 address += offset;
782
783 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
784
785 if (wb == Post)
786 address += offset;
787
788 if (wb != NoWriteBack)
789 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
790 }
791
792 /* 64 bit load 64 bit scaled or unscaled zero-
793 or sign-extended 32-bit register offset. */
794 static void
795 ldr_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
796 {
797 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
798 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
799 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
800 /* rn may reference SP, rm and rt must reference ZR */
801
802 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
803 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
804 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
805
806 aarch64_set_reg_u64 (cpu, rt, NO_SP,
807 aarch64_get_mem_u64 (cpu, address + displacement));
808 }
809
810 /* 32 bit load zero-extended byte scaled unsigned 12 bit. */
811 static void
812 ldrb32_abs (sim_cpu *cpu, uint32_t offset)
813 {
814 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
815 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
816
817 /* The target register may not be SP but the source may be
818 there is no scaling required for a byte load. */
819 aarch64_set_reg_u64 (cpu, rt, NO_SP,
820 aarch64_get_mem_u8
821 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
822 }
823
824 /* 32 bit load zero-extended byte unscaled signed 9 bit with pre- or post-writeback. */
825 static void
826 ldrb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
827 {
828 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
829 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
830 uint64_t address;
831
832 if (rn == rt && wb != NoWriteBack)
833 HALT_UNALLOC;
834
835 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
836
837 if (wb != Post)
838 address += offset;
839
840 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
841
842 if (wb == Post)
843 address += offset;
844
845 if (wb != NoWriteBack)
846 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
847 }
848
849 /* 32 bit load zero-extended byte scaled or unscaled zero-
850 or sign-extended 32-bit register offset. */
851 static void
852 ldrb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
853 {
854 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
855 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
856 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
857 /* rn may reference SP, rm and rt must reference ZR */
858
859 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
860 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
861 extension);
862
863 /* There is no scaling required for a byte load. */
864 aarch64_set_reg_u64 (cpu, rt, NO_SP,
865 aarch64_get_mem_u8 (cpu, address + displacement));
866 }
867
868 /* 64 bit load sign-extended byte unscaled signed 9 bit
869 with pre- or post-writeback. */
870 static void
871 ldrsb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
872 {
873 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
874 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
875 uint64_t address;
876
877 if (rn == rt && wb != NoWriteBack)
878 HALT_UNALLOC;
879
880 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
881
882 if (wb != Post)
883 address += offset;
884
885 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s8 (cpu, address));
886
887 if (wb == Post)
888 address += offset;
889
890 if (wb != NoWriteBack)
891 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
892 }
893
894 /* 64 bit load sign-extended byte scaled unsigned 12 bit. */
895 static void
896 ldrsb_abs (sim_cpu *cpu, uint32_t offset)
897 {
898 ldrsb_wb (cpu, offset, NoWriteBack);
899 }
900
901 /* 64 bit load sign-extended byte scaled or unscaled zero-
902 or sign-extended 32-bit register offset. */
903 static void
904 ldrsb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
905 {
906 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
907 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
908 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
909 /* rn may reference SP, rm and rt must reference ZR */
910
911 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
912 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
913 extension);
914 /* There is no scaling required for a byte load. */
915 aarch64_set_reg_u64 (cpu, rt, NO_SP,
916 aarch64_get_mem_s8 (cpu, address + displacement));
917 }
918
919 /* 32 bit load zero-extended short scaled unsigned 12 bit. */
920 static void
921 ldrh32_abs (sim_cpu *cpu, uint32_t offset)
922 {
923 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
924 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
925
926 /* The target register may not be SP but the source may be. */
927 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16
928 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
929 + SCALE (offset, 16)));
930 }
931
932 /* 32 bit load zero-extended short unscaled signed 9 bit
933 with pre- or post-writeback. */
934 static void
935 ldrh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
936 {
937 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
938 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
939 uint64_t address;
940
941 if (rn == rt && wb != NoWriteBack)
942 HALT_UNALLOC;
943
944 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
945
946 if (wb != Post)
947 address += offset;
948
949 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
950
951 if (wb == Post)
952 address += offset;
953
954 if (wb != NoWriteBack)
955 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
956 }
957
958 /* 32 bit load zero-extended short scaled or unscaled zero-
959 or sign-extended 32-bit register offset. */
960 static void
961 ldrh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
962 {
963 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
964 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
965 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
966 /* rn may reference SP, rm and rt must reference ZR */
967
968 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
969 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
970 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
971
972 aarch64_set_reg_u64 (cpu, rt, NO_SP,
973 aarch64_get_mem_u16 (cpu, address + displacement));
974 }
975
976 /* 32 bit load sign-extended short scaled unsigned 12 bit. */
977 static void
978 ldrsh32_abs (sim_cpu *cpu, uint32_t offset)
979 {
980 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
981 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
982
983 /* The target register may not be SP but the source may be. */
984 aarch64_set_reg_u64 (cpu, rt, NO_SP, (uint32_t) aarch64_get_mem_s16
985 (cpu,
986 aarch64_get_reg_u64 (cpu, rn, SP_OK)
987 + SCALE (offset, 16)));
988 }
989
990 /* 32 bit load sign-extended short unscaled signed 9 bit
991 with pre- or post-writeback. */
992 static void
993 ldrsh32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
994 {
995 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
996 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
997 uint64_t address;
998
999 if (rn == rt && wb != NoWriteBack)
1000 HALT_UNALLOC;
1001
1002 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1003
1004 if (wb != Post)
1005 address += offset;
1006
1007 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1008 (uint32_t) aarch64_get_mem_s16 (cpu, address));
1009
1010 if (wb == Post)
1011 address += offset;
1012
1013 if (wb != NoWriteBack)
1014 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1015 }
1016
1017 /* 32 bit load sign-extended short scaled or unscaled zero-
1018 or sign-extended 32-bit register offset. */
1019 static void
1020 ldrsh32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1021 {
1022 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1023 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1024 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1025 /* rn may reference SP, rm and rt must reference ZR */
1026
1027 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1028 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1029 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1030
1031 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1032 (uint32_t) aarch64_get_mem_s16
1033 (cpu, address + displacement));
1034 }
1035
1036 /* 64 bit load sign-extended short scaled unsigned 12 bit. */
1037 static void
1038 ldrsh_abs (sim_cpu *cpu, uint32_t offset)
1039 {
1040 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1041 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1042
1043 /* The target register may not be SP but the source may be. */
1044 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s16
1045 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1046 + SCALE (offset, 16)));
1047 }
1048
1049 /* 64 bit load sign-extended short unscaled signed 9 bit
1050 with pre- or post-writeback. */
1051 static void
1052 ldrsh64_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1053 {
1054 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1055 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1056 uint64_t address;
1057
1058 if (rn == rt && wb != NoWriteBack)
1059 HALT_UNALLOC;
1060
1061 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1062
1063 if (wb != Post)
1064 address += offset;
1065
1066 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_s16 (cpu, address));
1067
1068 if (wb == Post)
1069 address += offset;
1070
1071 if (wb != NoWriteBack)
1072 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1073 }
1074
1075 /* 64 bit load sign-extended short scaled or unscaled zero-
1076 or sign-extended 32-bit register offset. */
1077 static void
1078 ldrsh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1079 {
1080 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1081 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1082 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1083 /* rn may reference SP, rm and rt must reference ZR */
1084
1085 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1086 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1087 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1088
1089 aarch64_set_reg_u64 (cpu, rt, NO_SP,
1090 aarch64_get_mem_s16 (cpu, address + displacement));
1091 }
1092
1093 /* 64 bit load sign-extended 32 bit scaled unsigned 12 bit. */
1094 static void
1095 ldrsw_abs (sim_cpu *cpu, uint32_t offset)
1096 {
1097 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1098 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1099
1100 /* The target register may not be SP but the source may be. */
1101 return aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32
1102 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1103 + SCALE (offset, 32)));
1104 }
1105
1106 /* 64 bit load sign-extended 32 bit unscaled signed 9 bit
1107 with pre- or post-writeback. */
1108 static void
1109 ldrsw_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1110 {
1111 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1112 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1113 uint64_t address;
1114
1115 if (rn == rt && wb != NoWriteBack)
1116 HALT_UNALLOC;
1117
1118 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1119
1120 if (wb != Post)
1121 address += offset;
1122
1123 aarch64_set_reg_s64 (cpu, rt, NO_SP, aarch64_get_mem_s32 (cpu, address));
1124
1125 if (wb == Post)
1126 address += offset;
1127
1128 if (wb != NoWriteBack)
1129 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1130 }
1131
1132 /* 64 bit load sign-extended 32 bit scaled or unscaled zero-
1133 or sign-extended 32-bit register offset. */
1134 static void
1135 ldrsw_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1136 {
1137 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1138 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1139 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1140 /* rn may reference SP, rm and rt must reference ZR */
1141
1142 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1143 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1144 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1145
1146 aarch64_set_reg_s64 (cpu, rt, NO_SP,
1147 aarch64_get_mem_s32 (cpu, address + displacement));
1148 }
1149
1150 /* N.B. with stores the value in source is written to the
1151 address identified by source2 modified by source3/offset. */
1152
1153 /* 32 bit store scaled unsigned 12 bit. */
1154 static void
1155 str32_abs (sim_cpu *cpu, uint32_t offset)
1156 {
1157 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1158 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1159
1160 /* The target register may not be SP but the source may be. */
1161 aarch64_set_mem_u32 (cpu, (aarch64_get_reg_u64 (cpu, rn, SP_OK)
1162 + SCALE (offset, 32)),
1163 aarch64_get_reg_u32 (cpu, rt, NO_SP));
1164 }
1165
1166 /* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
1167 static void
1168 str32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1169 {
1170 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1171 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1172 uint64_t address;
1173
1174 if (rn == rt && wb != NoWriteBack)
1175 HALT_UNALLOC;
1176
1177 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1178 if (wb != Post)
1179 address += offset;
1180
1181 aarch64_set_mem_u32 (cpu, address, aarch64_get_reg_u32 (cpu, rt, NO_SP));
1182
1183 if (wb == Post)
1184 address += offset;
1185
1186 if (wb != NoWriteBack)
1187 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1188 }
1189
1190 /* 32 bit store scaled or unscaled zero- or
1191 sign-extended 32-bit register offset. */
1192 static void
1193 str32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1194 {
1195 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1196 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1197 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1198
1199 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1200 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1201 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
1202
1203 aarch64_set_mem_u32 (cpu, address + displacement,
1204 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1205 }
1206
1207 /* 64 bit store scaled unsigned 12 bit. */
1208 static void
1209 str_abs (sim_cpu *cpu, uint32_t offset)
1210 {
1211 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1212 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1213
1214 aarch64_set_mem_u64 (cpu,
1215 aarch64_get_reg_u64 (cpu, rn, SP_OK)
1216 + SCALE (offset, 64),
1217 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1218 }
1219
1220 /* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
1221 static void
1222 str_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1223 {
1224 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1225 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1226 uint64_t address;
1227
1228 if (rn == rt && wb != NoWriteBack)
1229 HALT_UNALLOC;
1230
1231 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1232
1233 if (wb != Post)
1234 address += offset;
1235
1236 aarch64_set_mem_u64 (cpu, address, aarch64_get_reg_u64 (cpu, rt, NO_SP));
1237
1238 if (wb == Post)
1239 address += offset;
1240
1241 if (wb != NoWriteBack)
1242 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1243 }
1244
1245 /* 64 bit store scaled or unscaled zero-
1246 or sign-extended 32-bit register offset. */
1247 static void
1248 str_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1249 {
1250 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1251 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1252 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1253 /* rn may reference SP, rm and rt must reference ZR */
1254
1255 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1256 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1257 extension);
1258 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1259
1260 aarch64_set_mem_u64 (cpu, address + displacement,
1261 aarch64_get_reg_u64 (cpu, rt, NO_SP));
1262 }
1263
1264 /* 32 bit store byte scaled unsigned 12 bit. */
1265 static void
1266 strb_abs (sim_cpu *cpu, uint32_t offset)
1267 {
1268 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1269 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1270
1271 /* The target register may not be SP but the source may be.
1272 There is no scaling required for a byte load. */
1273 aarch64_set_mem_u8 (cpu,
1274 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
1275 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1276 }
1277
1278 /* 32 bit store byte unscaled signed 9 bit with pre- or post-writeback. */
1279 static void
1280 strb_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1281 {
1282 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1283 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1284 uint64_t address;
1285
1286 if (rn == rt && wb != NoWriteBack)
1287 HALT_UNALLOC;
1288
1289 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1290
1291 if (wb != Post)
1292 address += offset;
1293
1294 aarch64_set_mem_u8 (cpu, address, aarch64_get_reg_u8 (cpu, rt, NO_SP));
1295
1296 if (wb == Post)
1297 address += offset;
1298
1299 if (wb != NoWriteBack)
1300 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1301 }
1302
1303 /* 32 bit store byte scaled or unscaled zero-
1304 or sign-extended 32-bit register offset. */
1305 static void
1306 strb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1307 {
1308 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1309 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1310 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1311 /* rn may reference SP, rm and rt must reference ZR */
1312
1313 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1314 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1315 extension);
1316
1317 /* There is no scaling required for a byte load. */
1318 aarch64_set_mem_u8 (cpu, address + displacement,
1319 aarch64_get_reg_u8 (cpu, rt, NO_SP));
1320 }
1321
1322 /* 32 bit store short scaled unsigned 12 bit. */
1323 static void
1324 strh_abs (sim_cpu *cpu, uint32_t offset)
1325 {
1326 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1327 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1328
1329 /* The target register may not be SP but the source may be. */
1330 aarch64_set_mem_u16 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK)
1331 + SCALE (offset, 16),
1332 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1333 }
1334
1335 /* 32 bit store short unscaled signed 9 bit with pre- or post-writeback. */
1336 static void
1337 strh_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
1338 {
1339 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1340 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1341 uint64_t address;
1342
1343 if (rn == rt && wb != NoWriteBack)
1344 HALT_UNALLOC;
1345
1346 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1347
1348 if (wb != Post)
1349 address += offset;
1350
1351 aarch64_set_mem_u16 (cpu, address, aarch64_get_reg_u16 (cpu, rt, NO_SP));
1352
1353 if (wb == Post)
1354 address += offset;
1355
1356 if (wb != NoWriteBack)
1357 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
1358 }
1359
1360 /* 32 bit store short scaled or unscaled zero-
1361 or sign-extended 32-bit register offset. */
1362 static void
1363 strh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1364 {
1365 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1366 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1367 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1368 /* rn may reference SP, rm and rt must reference ZR */
1369
1370 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1371 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP), extension);
1372 uint64_t displacement = OPT_SCALE (extended, 16, scaling);
1373
1374 aarch64_set_mem_u16 (cpu, address + displacement,
1375 aarch64_get_reg_u16 (cpu, rt, NO_SP));
1376 }
1377
1378 /* Prefetch unsigned 12 bit. */
1379 static void
1380 prfm_abs (sim_cpu *cpu, uint32_t offset)
1381 {
1382 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1383 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1384 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1385 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1386 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1387 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1388 ow ==> UNALLOC
1389 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1390 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK)
1391 + SCALE (offset, 64). */
1392
1393 /* TODO : implement prefetch of address. */
1394 }
1395
1396 /* Prefetch scaled or unscaled zero- or sign-extended 32-bit register offset. */
1397 static void
1398 prfm_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
1399 {
1400 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1401 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1402 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1403 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1404 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1405 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1406 ow ==> UNALLOC
1407 rn may reference SP, rm may only reference ZR
1408 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1409 uint64_t base = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1410 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1411 extension);
1412 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
1413 uint64_t address = base + displacement. */
1414
1415 /* TODO : implement prefetch of address */
1416 }
1417
1418 /* 64 bit pc-relative prefetch. */
1419 static void
1420 prfm_pcrel (sim_cpu *cpu, int32_t offset)
1421 {
1422 /* instr[4,0] = prfop : 00000 ==> PLDL1KEEP, 00001 ==> PLDL1STRM,
1423 00010 ==> PLDL2KEEP, 00001 ==> PLDL2STRM,
1424 00100 ==> PLDL3KEEP, 00101 ==> PLDL3STRM,
1425 10000 ==> PSTL1KEEP, 10001 ==> PSTL1STRM,
1426 10010 ==> PSTL2KEEP, 10001 ==> PSTL2STRM,
1427 10100 ==> PSTL3KEEP, 10101 ==> PSTL3STRM,
1428 ow ==> UNALLOC
1429 PrfOp prfop = prfop (aarch64_get_instr (cpu), 4, 0);
1430 uint64_t address = aarch64_get_PC (cpu) + offset. */
1431
1432 /* TODO : implement this */
1433 }
1434
1435 /* Load-store exclusive. */
1436
1437 static void
1438 ldxr (sim_cpu *cpu)
1439 {
1440 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1441 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1442 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1443 int size = uimm (aarch64_get_instr (cpu), 31, 30);
1444 /* int ordered = uimm (aarch64_get_instr (cpu), 15, 15); */
1445 /* int exclusive = ! uimm (aarch64_get_instr (cpu), 23, 23); */
1446
1447 switch (size)
1448 {
1449 case 0:
1450 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u8 (cpu, address));
1451 break;
1452 case 1:
1453 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u16 (cpu, address));
1454 break;
1455 case 2:
1456 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u32 (cpu, address));
1457 break;
1458 case 3:
1459 aarch64_set_reg_u64 (cpu, rt, NO_SP, aarch64_get_mem_u64 (cpu, address));
1460 break;
1461 default:
1462 HALT_UNALLOC;
1463 }
1464 }
1465
1466 static void
1467 stxr (sim_cpu *cpu)
1468 {
1469 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1470 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
1471 unsigned rs = uimm (aarch64_get_instr (cpu), 20, 16);
1472 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1473 int size = uimm (aarch64_get_instr (cpu), 31, 30);
1474 uint64_t data = aarch64_get_reg_u64 (cpu, rt, NO_SP);
1475
1476 switch (size)
1477 {
1478 case 0: aarch64_set_mem_u8 (cpu, address, data); break;
1479 case 1: aarch64_set_mem_u16 (cpu, address, data); break;
1480 case 2: aarch64_set_mem_u32 (cpu, address, data); break;
1481 case 3: aarch64_set_mem_u64 (cpu, address, data); break;
1482 default: HALT_UNALLOC;
1483 }
1484
1485 aarch64_set_reg_u64 (cpu, rs, NO_SP, 0); /* Always exclusive... */
1486 }
1487
1488 static void
1489 dexLoadLiteral (sim_cpu *cpu)
1490 {
1491 /* instr[29,27] == 011
1492 instr[25,24] == 00
1493 instr[31,30:26] = opc: 000 ==> LDRW, 001 ==> FLDRS
1494 010 ==> LDRX, 011 ==> FLDRD
1495 100 ==> LDRSW, 101 ==> FLDRQ
1496 110 ==> PRFM, 111 ==> UNALLOC
1497 instr[26] ==> V : 0 ==> GReg, 1 ==> FReg
1498 instr[23, 5] == simm19 */
1499
1500 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
1501 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 1)
1502 | uimm (aarch64_get_instr (cpu), 26, 26));
1503 int32_t imm = simm32 (aarch64_get_instr (cpu), 23, 5);
1504
1505 switch (dispatch)
1506 {
1507 case 0: ldr32_pcrel (cpu, imm); break;
1508 case 1: fldrs_pcrel (cpu, imm); break;
1509 case 2: ldr_pcrel (cpu, imm); break;
1510 case 3: fldrd_pcrel (cpu, imm); break;
1511 case 4: ldrsw_pcrel (cpu, imm); break;
1512 case 5: fldrq_pcrel (cpu, imm); break;
1513 case 6: prfm_pcrel (cpu, imm); break;
1514 case 7:
1515 default:
1516 HALT_UNALLOC;
1517 }
1518 }
1519
1520 /* Immediate arithmetic
1521 The aimm argument is a 12 bit unsigned value or a 12 bit unsigned
1522 value left shifted by 12 bits (done at decode).
1523
1524 N.B. the register args (dest, source) can normally be Xn or SP.
1525 the exception occurs for flag setting instructions which may
1526 only use Xn for the output (dest). */
1527
1528 /* 32 bit add immediate. */
1529 static void
1530 add32 (sim_cpu *cpu, uint32_t aimm)
1531 {
1532 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1533 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1534
1535 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1536 aarch64_get_reg_u32 (cpu, rn, SP_OK) + aimm);
1537 }
1538
1539 /* 64 bit add immediate. */
1540 static void
1541 add64 (sim_cpu *cpu, uint32_t aimm)
1542 {
1543 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1544 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1545
1546 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1547 aarch64_get_reg_u64 (cpu, rn, SP_OK) + aimm);
1548 }
1549
1550 static void
1551 set_flags_for_add32 (sim_cpu *cpu, int32_t value1, int32_t value2)
1552 {
1553 int32_t result = value1 + value2;
1554 int64_t sresult = (int64_t) value1 + (int64_t) value2;
1555 uint64_t uresult = (uint64_t)(uint32_t) value1
1556 + (uint64_t)(uint32_t) value2;
1557 uint32_t flags = 0;
1558
1559 if (result == 0)
1560 flags |= Z;
1561
1562 if (result & (1 << 31))
1563 flags |= N;
1564
1565 if (uresult != result)
1566 flags |= C;
1567
1568 if (sresult != result)
1569 flags |= V;
1570
1571 aarch64_set_CPSR (cpu, flags);
1572 }
1573
1574 static void
1575 set_flags_for_add64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1576 {
1577 int64_t sval1 = value1;
1578 int64_t sval2 = value2;
1579 uint64_t result = value1 + value2;
1580 int64_t sresult = sval1 + sval2;
1581 uint32_t flags = 0;
1582
1583 if (result == 0)
1584 flags |= Z;
1585
1586 if (result & (1ULL << 63))
1587 flags |= N;
1588
1589 if (sval1 < 0)
1590 {
1591 if (sval2 < 0)
1592 {
1593 /* Negative plus a negative. Overflow happens if
1594 the result is greater than either of the operands. */
1595 if (sresult > sval1 || sresult > sval2)
1596 flags |= V;
1597 }
1598 /* else Negative plus a positive. Overflow cannot happen. */
1599 }
1600 else /* value1 is +ve. */
1601 {
1602 if (sval2 < 0)
1603 {
1604 /* Overflow can only occur if we computed "0 - MININT". */
1605 if (sval1 == 0 && sval2 == (1LL << 63))
1606 flags |= V;
1607 }
1608 else
1609 {
1610 /* Postive plus positive - overflow has happened if the
1611 result is smaller than either of the operands. */
1612 if (result < value1 || result < value2)
1613 flags |= V | C;
1614 }
1615 }
1616
1617 aarch64_set_CPSR (cpu, flags);
1618 }
1619
1620 #define NEG(a) (((a) & signbit) == signbit)
1621 #define POS(a) (((a) & signbit) == 0)
1622
1623 static void
1624 set_flags_for_sub32 (sim_cpu *cpu, uint32_t value1, uint32_t value2)
1625 {
1626 uint32_t result = value1 - value2;
1627 uint32_t flags = 0;
1628 uint32_t signbit = 1ULL << 31;
1629
1630 if (result == 0)
1631 flags |= Z;
1632
1633 if (NEG (result))
1634 flags |= N;
1635
1636 if ( (NEG (value1) && POS (value2))
1637 || (NEG (value1) && POS (result))
1638 || (POS (value2) && POS (result)))
1639 flags |= C;
1640
1641 if ( (NEG (value1) && POS (value2) && POS (result))
1642 || (POS (value1) && NEG (value2) && NEG (result)))
1643 flags |= V;
1644
1645 aarch64_set_CPSR (cpu, flags);
1646 }
1647
1648 static void
1649 set_flags_for_sub64 (sim_cpu *cpu, uint64_t value1, uint64_t value2)
1650 {
1651 uint64_t result = value1 - value2;
1652 uint32_t flags = 0;
1653 uint64_t signbit = 1ULL << 63;
1654
1655 if (result == 0)
1656 flags |= Z;
1657
1658 if (NEG (result))
1659 flags |= N;
1660
1661 if ( (NEG (value1) && POS (value2))
1662 || (NEG (value1) && POS (result))
1663 || (POS (value2) && POS (result)))
1664 flags |= C;
1665
1666 if ( (NEG (value1) && POS (value2) && POS (result))
1667 || (POS (value1) && NEG (value2) && NEG (result)))
1668 flags |= V;
1669
1670 aarch64_set_CPSR (cpu, flags);
1671 }
1672
1673 static void
1674 set_flags_for_binop32 (sim_cpu *cpu, uint32_t result)
1675 {
1676 uint32_t flags = 0;
1677
1678 if (result == 0)
1679 flags |= Z;
1680 else
1681 flags &= ~ Z;
1682
1683 if (result & (1 << 31))
1684 flags |= N;
1685 else
1686 flags &= ~ N;
1687
1688 aarch64_set_CPSR (cpu, flags);
1689 }
1690
1691 static void
1692 set_flags_for_binop64 (sim_cpu *cpu, uint64_t result)
1693 {
1694 uint32_t flags = 0;
1695
1696 if (result == 0)
1697 flags |= Z;
1698 else
1699 flags &= ~ Z;
1700
1701 if (result & (1ULL << 63))
1702 flags |= N;
1703 else
1704 flags &= ~ N;
1705
1706 aarch64_set_CPSR (cpu, flags);
1707 }
1708
1709 /* 32 bit add immediate set flags. */
1710 static void
1711 adds32 (sim_cpu *cpu, uint32_t aimm)
1712 {
1713 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1714 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1715 /* TODO : do we need to worry about signs here? */
1716 int32_t value1 = aarch64_get_reg_s32 (cpu, rn, SP_OK);
1717
1718 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + aimm);
1719 set_flags_for_add32 (cpu, value1, aimm);
1720 }
1721
1722 /* 64 bit add immediate set flags. */
1723 static void
1724 adds64 (sim_cpu *cpu, uint32_t aimm)
1725 {
1726 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1727 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1728 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1729 uint64_t value2 = aimm;
1730
1731 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1732 set_flags_for_add64 (cpu, value1, value2);
1733 }
1734
1735 /* 32 bit sub immediate. */
1736 static void
1737 sub32 (sim_cpu *cpu, uint32_t aimm)
1738 {
1739 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1740 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1741
1742 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1743 aarch64_get_reg_u32 (cpu, rn, SP_OK) - aimm);
1744 }
1745
1746 /* 64 bit sub immediate. */
1747 static void
1748 sub64 (sim_cpu *cpu, uint32_t aimm)
1749 {
1750 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1751 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1752
1753 aarch64_set_reg_u64 (cpu, rd, SP_OK,
1754 aarch64_get_reg_u64 (cpu, rn, SP_OK) - aimm);
1755 }
1756
1757 /* 32 bit sub immediate set flags. */
1758 static void
1759 subs32 (sim_cpu *cpu, uint32_t aimm)
1760 {
1761 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1762 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1763 uint32_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1764 uint32_t value2 = aimm;
1765
1766 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1767 set_flags_for_sub32 (cpu, value1, value2);
1768 }
1769
1770 /* 64 bit sub immediate set flags. */
1771 static void
1772 subs64 (sim_cpu *cpu, uint32_t aimm)
1773 {
1774 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1775 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1776 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
1777 uint32_t value2 = aimm;
1778
1779 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1780 set_flags_for_sub64 (cpu, value1, value2);
1781 }
1782
1783 /* Data Processing Register. */
1784
1785 /* First two helpers to perform the shift operations. */
1786
1787 static inline uint32_t
1788 shifted32 (uint32_t value, Shift shift, uint32_t count)
1789 {
1790 switch (shift)
1791 {
1792 default:
1793 case LSL:
1794 return (value << count);
1795 case LSR:
1796 return (value >> count);
1797 case ASR:
1798 {
1799 int32_t svalue = value;
1800 return (svalue >> count);
1801 }
1802 case ROR:
1803 {
1804 uint32_t top = value >> count;
1805 uint32_t bottom = value << (32 - count);
1806 return (bottom | top);
1807 }
1808 }
1809 }
1810
1811 static inline uint64_t
1812 shifted64 (uint64_t value, Shift shift, uint32_t count)
1813 {
1814 switch (shift)
1815 {
1816 default:
1817 case LSL:
1818 return (value << count);
1819 case LSR:
1820 return (value >> count);
1821 case ASR:
1822 {
1823 int64_t svalue = value;
1824 return (svalue >> count);
1825 }
1826 case ROR:
1827 {
1828 uint64_t top = value >> count;
1829 uint64_t bottom = value << (64 - count);
1830 return (bottom | top);
1831 }
1832 }
1833 }
1834
1835 /* Arithmetic shifted register.
1836 These allow an optional LSL, ASR or LSR to the second source
1837 register with a count up to the register bit count.
1838
1839 N.B register args may not be SP. */
1840
1841 /* 32 bit ADD shifted register. */
1842 static void
1843 add32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1844 {
1845 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1846 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1847 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1848
1849 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1850 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1851 + shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1852 shift, count));
1853 }
1854
1855 /* 64 bit ADD shifted register. */
1856 static void
1857 add64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1858 {
1859 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1860 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1861 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1862
1863 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1864 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1865 + shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1866 shift, count));
1867 }
1868
1869 /* 32 bit ADD shifted register setting flags. */
1870 static void
1871 adds32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1872 {
1873 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1874 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1875 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1876
1877 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1878 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1879 shift, count);
1880
1881 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1882 set_flags_for_add32 (cpu, value1, value2);
1883 }
1884
1885 /* 64 bit ADD shifted register setting flags. */
1886 static void
1887 adds64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1888 {
1889 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1890 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1891 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1892
1893 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1894 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1895 shift, count);
1896
1897 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
1898 set_flags_for_add64 (cpu, value1, value2);
1899 }
1900
1901 /* 32 bit SUB shifted register. */
1902 static void
1903 sub32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1904 {
1905 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1906 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1907 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1908
1909 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1910 aarch64_get_reg_u32 (cpu, rn, NO_SP)
1911 - shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1912 shift, count));
1913 }
1914
1915 /* 64 bit SUB shifted register. */
1916 static void
1917 sub64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1918 {
1919 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1920 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1921 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1922
1923 aarch64_set_reg_u64 (cpu, rd, NO_SP,
1924 aarch64_get_reg_u64 (cpu, rn, NO_SP)
1925 - shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1926 shift, count));
1927 }
1928
1929 /* 32 bit SUB shifted register setting flags. */
1930 static void
1931 subs32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1932 {
1933 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1934 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1935 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1936
1937 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
1938 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
1939 shift, count);
1940
1941 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1942 set_flags_for_sub32 (cpu, value1, value2);
1943 }
1944
1945 /* 64 bit SUB shifted register setting flags. */
1946 static void
1947 subs64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
1948 {
1949 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
1950 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
1951 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
1952
1953 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
1954 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
1955 shift, count);
1956
1957 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
1958 set_flags_for_sub64 (cpu, value1, value2);
1959 }
1960
1961 /* First a couple more helpers to fetch the
1962 relevant source register element either
1963 sign or zero extended as required by the
1964 extension value. */
1965
1966 static uint32_t
1967 extreg32 (sim_cpu *cpu, unsigned int lo, Extension extension)
1968 {
1969 switch (extension)
1970 {
1971 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
1972 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
1973 case UXTW: /* Fall through. */
1974 case UXTX: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
1975 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
1976 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
1977 case SXTW: /* Fall through. */
1978 case SXTX: /* Fall through. */
1979 default: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
1980 }
1981 }
1982
1983 static uint64_t
1984 extreg64 (sim_cpu *cpu, unsigned int lo, Extension extension)
1985 {
1986 switch (extension)
1987 {
1988 case UXTB: return aarch64_get_reg_u8 (cpu, lo, NO_SP);
1989 case UXTH: return aarch64_get_reg_u16 (cpu, lo, NO_SP);
1990 case UXTW: return aarch64_get_reg_u32 (cpu, lo, NO_SP);
1991 case UXTX: return aarch64_get_reg_u64 (cpu, lo, NO_SP);
1992 case SXTB: return aarch64_get_reg_s8 (cpu, lo, NO_SP);
1993 case SXTH: return aarch64_get_reg_s16 (cpu, lo, NO_SP);
1994 case SXTW: return aarch64_get_reg_s32 (cpu, lo, NO_SP);
1995 case SXTX:
1996 default: return aarch64_get_reg_s64 (cpu, lo, NO_SP);
1997 }
1998 }
1999
2000 /* Arithmetic extending register
2001 These allow an optional sign extension of some portion of the
2002 second source register followed by an optional left shift of
2003 between 1 and 4 bits (i.e. a shift of 0-4 bits???)
2004
2005 N.B output (dest) and first input arg (source) may normally be Xn
2006 or SP. However, for flag setting operations dest can only be
2007 Xn. Second input registers are always Xn. */
2008
2009 /* 32 bit ADD extending register. */
2010 static void
2011 add32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2012 {
2013 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2014 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2015 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2016
2017 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2018 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2019 + (extreg32 (cpu, rm, extension) << shift));
2020 }
2021
2022 /* 64 bit ADD extending register.
2023 N.B. This subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2024 static void
2025 add64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2026 {
2027 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2028 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2029 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2030
2031 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2032 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2033 + (extreg64 (cpu, rm, extension) << shift));
2034 }
2035
2036 /* 32 bit ADD extending register setting flags. */
2037 static void
2038 adds32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2039 {
2040 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2041 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2042 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2043
2044 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2045 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2046
2047 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2048 set_flags_for_add32 (cpu, value1, value2);
2049 }
2050
2051 /* 64 bit ADD extending register setting flags */
2052 /* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2053 static void
2054 adds64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2055 {
2056 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2057 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2058 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2059
2060 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2061 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2062
2063 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2);
2064 set_flags_for_add64 (cpu, value1, value2);
2065 }
2066
2067 /* 32 bit SUB extending register. */
2068 static void
2069 sub32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2070 {
2071 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2072 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2073 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2074
2075 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2076 aarch64_get_reg_u32 (cpu, rn, SP_OK)
2077 - (extreg32 (cpu, rm, extension) << shift));
2078 }
2079
2080 /* 64 bit SUB extending register. */
2081 /* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0. */
2082 static void
2083 sub64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2084 {
2085 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2086 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2087 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2088
2089 aarch64_set_reg_u64 (cpu, rd, SP_OK,
2090 aarch64_get_reg_u64 (cpu, rn, SP_OK)
2091 - (extreg64 (cpu, rm, extension) << shift));
2092 }
2093
2094 /* 32 bit SUB extending register setting flags. */
2095 static void
2096 subs32_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2097 {
2098 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2099 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2100 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2101
2102 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, SP_OK);
2103 uint32_t value2 = extreg32 (cpu, rm, extension) << shift;
2104
2105 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2106 set_flags_for_sub32 (cpu, value1, value2);
2107 }
2108
2109 /* 64 bit SUB extending register setting flags */
2110 /* N.B. this subsumes the case with 64 bit source2 and UXTX #n or LSL #0 */
2111 static void
2112 subs64_ext (sim_cpu *cpu, Extension extension, uint32_t shift)
2113 {
2114 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2115 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2116 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2117
2118 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, SP_OK);
2119 uint64_t value2 = extreg64 (cpu, rm, extension) << shift;
2120
2121 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 - value2);
2122 set_flags_for_sub64 (cpu, value1, value2);
2123 }
2124
2125 static void
2126 dexAddSubtractImmediate (sim_cpu *cpu)
2127 {
2128 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2129 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2130 instr[29] = set : 0 ==> no flags, 1 ==> set flags
2131 instr[28,24] = 10001
2132 instr[23,22] = shift : 00 == LSL#0, 01 = LSL#12 1x = UNALLOC
2133 instr[21,10] = uimm12
2134 instr[9,5] = Rn
2135 instr[4,0] = Rd */
2136
2137 /* N.B. the shift is applied at decode before calling the add/sub routine. */
2138 uint32_t shift = uimm (aarch64_get_instr (cpu), 23, 22);
2139 uint32_t imm = uimm (aarch64_get_instr (cpu), 21, 10);
2140 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2141
2142 NYI_assert (28, 24, 0x11);
2143
2144 if (shift > 1)
2145 HALT_UNALLOC;
2146
2147 if (shift)
2148 imm <<= 12;
2149
2150 switch (dispatch)
2151 {
2152 case 0: add32 (cpu, imm); break;
2153 case 1: adds32 (cpu, imm); break;
2154 case 2: sub32 (cpu, imm); break;
2155 case 3: subs32 (cpu, imm); break;
2156 case 4: add64 (cpu, imm); break;
2157 case 5: adds64 (cpu, imm); break;
2158 case 6: sub64 (cpu, imm); break;
2159 case 7: subs64 (cpu, imm); break;
2160 default:
2161 HALT_UNALLOC;
2162 }
2163 }
2164
2165 static void
2166 dexAddSubtractShiftedRegister (sim_cpu *cpu)
2167 {
2168 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2169 instr[30,29] = op : 00 ==> ADD, 01 ==> ADDS, 10 ==> SUB, 11 ==> SUBS
2170 instr[28,24] = 01011
2171 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> UNALLOC
2172 instr[21] = 0
2173 instr[20,16] = Rm
2174 instr[15,10] = count : must be 0xxxxx for 32 bit
2175 instr[9,5] = Rn
2176 instr[4,0] = Rd */
2177
2178 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
2179 /* 32 bit operations must have count[5] = 0
2180 or else we have an UNALLOC. */
2181 uint32_t count = uimm (aarch64_get_instr (cpu), 15, 10);
2182 /* Shift encoded as ROR is unallocated. */
2183 Shift shiftType = shift (aarch64_get_instr (cpu), 22);
2184 /* Dispatch on size:op i.e aarch64_get_instr (cpu)[31,29]. */
2185 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2186
2187 NYI_assert (28, 24, 0x0B);
2188 NYI_assert (21, 21, 0);
2189
2190 if (shiftType == ROR)
2191 HALT_UNALLOC;
2192
2193 if (!size && uimm (count, 5, 5))
2194 HALT_UNALLOC;
2195
2196 switch (dispatch)
2197 {
2198 case 0: add32_shift (cpu, shiftType, count); break;
2199 case 1: adds32_shift (cpu, shiftType, count); break;
2200 case 2: sub32_shift (cpu, shiftType, count); break;
2201 case 3: subs32_shift (cpu, shiftType, count); break;
2202 case 4: add64_shift (cpu, shiftType, count); break;
2203 case 5: adds64_shift (cpu, shiftType, count); break;
2204 case 6: sub64_shift (cpu, shiftType, count); break;
2205 case 7: subs64_shift (cpu, shiftType, count); break;
2206 default:
2207 HALT_UNALLOC;
2208 }
2209 }
2210
2211 static void
2212 dexAddSubtractExtendedRegister (sim_cpu *cpu)
2213 {
2214 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2215 instr[30] = op : 0 ==> ADD, 1 ==> SUB
2216 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2217 instr[28,24] = 01011
2218 instr[23,22] = opt : 0 ==> ok, 1,2,3 ==> UNALLOC
2219 instr[21] = 1
2220 instr[20,16] = Rm
2221 instr[15,13] = option : 000 ==> UXTB, 001 ==> UXTH,
2222 000 ==> LSL|UXTW, 001 ==> UXTZ,
2223 000 ==> SXTB, 001 ==> SXTH,
2224 000 ==> SXTW, 001 ==> SXTX,
2225 instr[12,10] = shift : 0,1,2,3,4 ==> ok, 5,6,7 ==> UNALLOC
2226 instr[9,5] = Rn
2227 instr[4,0] = Rd */
2228
2229 Extension extensionType = extension (aarch64_get_instr (cpu), 13);
2230 uint32_t shift = uimm (aarch64_get_instr (cpu), 12, 10);
2231 /* dispatch on size:op:set? i.e aarch64_get_instr (cpu)[31,29] */
2232 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2233
2234 NYI_assert (28, 24, 0x0B);
2235 NYI_assert (21, 21, 1);
2236
2237 /* Shift may not exceed 4. */
2238 if (shift > 4)
2239 HALT_UNALLOC;
2240
2241 switch (dispatch)
2242 {
2243 case 0: add32_ext (cpu, extensionType, shift); break;
2244 case 1: adds32_ext (cpu, extensionType, shift); break;
2245 case 2: sub32_ext (cpu, extensionType, shift); break;
2246 case 3: subs32_ext (cpu, extensionType, shift); break;
2247 case 4: add64_ext (cpu, extensionType, shift); break;
2248 case 5: adds64_ext (cpu, extensionType, shift); break;
2249 case 6: sub64_ext (cpu, extensionType, shift); break;
2250 case 7: subs64_ext (cpu, extensionType, shift); break;
2251 default: HALT_UNALLOC;
2252 }
2253 }
2254
2255 /* Conditional data processing
2256 Condition register is implicit 3rd source. */
2257
2258 /* 32 bit add with carry. */
2259 /* N.B register args may not be SP. */
2260
2261 static void
2262 adc32 (sim_cpu *cpu)
2263 {
2264 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2265 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2266 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2267
2268 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2269 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2270 + aarch64_get_reg_u32 (cpu, rm, NO_SP)
2271 + IS_SET (C));
2272 }
2273
2274 /* 64 bit add with carry */
2275 static void
2276 adc64 (sim_cpu *cpu)
2277 {
2278 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2279 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2280 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2281
2282 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2283 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2284 + aarch64_get_reg_u64 (cpu, rm, NO_SP)
2285 + IS_SET (C));
2286 }
2287
2288 /* 32 bit add with carry setting flags. */
2289 static void
2290 adcs32 (sim_cpu *cpu)
2291 {
2292 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2293 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2294 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2295
2296 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2297 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2298 uint32_t carry = IS_SET (C);
2299
2300 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2301 set_flags_for_add32 (cpu, value1, value2 + carry);
2302 }
2303
2304 /* 64 bit add with carry setting flags. */
2305 static void
2306 adcs64 (sim_cpu *cpu)
2307 {
2308 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2309 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2310 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2311
2312 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2313 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2314 uint64_t carry = IS_SET (C);
2315
2316 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 + value2 + carry);
2317 set_flags_for_add64 (cpu, value1, value2 + carry);
2318 }
2319
2320 /* 32 bit sub with carry. */
2321 static void
2322 sbc32 (sim_cpu *cpu)
2323 {
2324 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2325 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2326 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2327
2328 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2329 aarch64_get_reg_u32 (cpu, rn, NO_SP)
2330 - aarch64_get_reg_u32 (cpu, rm, NO_SP)
2331 - 1 + IS_SET (C));
2332 }
2333
2334 /* 64 bit sub with carry */
2335 static void
2336 sbc64 (sim_cpu *cpu)
2337 {
2338 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2339 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2340 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2341
2342 aarch64_set_reg_u64 (cpu, rd, NO_SP,
2343 aarch64_get_reg_u64 (cpu, rn, NO_SP)
2344 - aarch64_get_reg_u64 (cpu, rm, NO_SP)
2345 - 1 + IS_SET (C));
2346 }
2347
2348 /* 32 bit sub with carry setting flags */
2349 static void
2350 sbcs32 (sim_cpu *cpu)
2351 {
2352 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2353 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2354 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2355
2356 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
2357 uint32_t value2 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
2358 uint32_t carry = IS_SET (C);
2359 uint32_t result = value1 - value2 + 1 - carry;
2360
2361 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2362 set_flags_for_sub32 (cpu, value1, value2 + 1 - carry);
2363 }
2364
2365 /* 64 bit sub with carry setting flags */
2366 static void
2367 sbcs64 (sim_cpu *cpu)
2368 {
2369 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
2370 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
2371 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2372
2373 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
2374 uint64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
2375 uint64_t carry = IS_SET (C);
2376 uint64_t result = value1 - value2 + 1 - carry;
2377
2378 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
2379 set_flags_for_sub64 (cpu, value1, value2 + 1 - carry);
2380 }
2381
2382 static void
2383 dexAddSubtractWithCarry (sim_cpu *cpu)
2384 {
2385 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2386 instr[30] = op : 0 ==> ADC, 1 ==> SBC
2387 instr[29] = set? : 0 ==> no flags, 1 ==> set flags
2388 instr[28,21] = 1 1010 000
2389 instr[20,16] = Rm
2390 instr[15,10] = op2 : 00000 ==> ok, ow ==> UNALLOC
2391 instr[9,5] = Rn
2392 instr[4,0] = Rd */
2393
2394 uint32_t op2 = uimm (aarch64_get_instr (cpu), 15, 10);
2395 /* Dispatch on size:op:set? i.e aarch64_get_instr (cpu)[31,29] */
2396 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
2397
2398 NYI_assert (28, 21, 0xD0);
2399
2400 if (op2 != 0)
2401 HALT_UNALLOC;
2402
2403 switch (dispatch)
2404 {
2405 case 0: adc32 (cpu); break;
2406 case 1: adcs32 (cpu); break;
2407 case 2: sbc32 (cpu); break;
2408 case 3: sbcs32 (cpu); break;
2409 case 4: adc64 (cpu); break;
2410 case 5: adcs64 (cpu); break;
2411 case 6: sbc64 (cpu); break;
2412 case 7: sbcs64 (cpu); break;
2413 default: HALT_UNALLOC;
2414 }
2415 }
2416
2417 static uint32_t
2418 testConditionCode (sim_cpu *cpu, CondCode cc)
2419 {
2420 /* This should be reduceable to branchless logic
2421 by some careful testing of bits in CC followed
2422 by the requisite masking and combining of bits
2423 from the flag register.
2424
2425 For now we do it with a switch. */
2426 int res;
2427
2428 switch (cc)
2429 {
2430 case EQ: res = IS_SET (Z); break;
2431 case NE: res = IS_CLEAR (Z); break;
2432 case CS: res = IS_SET (C); break;
2433 case CC: res = IS_CLEAR (C); break;
2434 case MI: res = IS_SET (N); break;
2435 case PL: res = IS_CLEAR (N); break;
2436 case VS: res = IS_SET (V); break;
2437 case VC: res = IS_CLEAR (V); break;
2438 case HI: res = IS_SET (C) && IS_CLEAR (Z); break;
2439 case LS: res = IS_CLEAR (C) || IS_SET (Z); break;
2440 case GE: res = IS_SET (N) == IS_SET (V); break;
2441 case LT: res = IS_SET (N) != IS_SET (V); break;
2442 case GT: res = IS_CLEAR (Z) && (IS_SET (N) == IS_SET (V)); break;
2443 case LE: res = IS_SET (Z) || (IS_SET (N) != IS_SET (V)); break;
2444 case AL:
2445 case NV:
2446 default:
2447 res = 1;
2448 break;
2449 }
2450 return res;
2451 }
2452
2453 static void
2454 CondCompare (sim_cpu *cpu) /* aka: ccmp and ccmn */
2455 {
2456 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
2457 instr[30] = compare with positive (0) or negative value (1)
2458 instr[29,21] = 1 1101 0010
2459 instr[20,16] = Rm or const
2460 instr[15,12] = cond
2461 instr[11] = compare reg (0) or const (1)
2462 instr[10] = 0
2463 instr[9,5] = Rn
2464 instr[4] = 0
2465 instr[3,0] = value for CPSR bits if the comparison does not take place. */
2466 signed int negate;
2467 unsigned rm;
2468 unsigned rn;
2469
2470 NYI_assert (29, 21, 0x1d2);
2471 NYI_assert (10, 10, 0);
2472 NYI_assert (4, 4, 0);
2473
2474 if (! testConditionCode (cpu, uimm (aarch64_get_instr (cpu), 15, 12)))
2475 {
2476 aarch64_set_CPSR (cpu, uimm (aarch64_get_instr (cpu), 3, 0));
2477 return;
2478 }
2479
2480 negate = uimm (aarch64_get_instr (cpu), 30, 30) ? -1 : 1;
2481 rm = uimm (aarch64_get_instr (cpu), 20, 16);
2482 rn = uimm (aarch64_get_instr (cpu), 9, 5);
2483
2484 if (uimm (aarch64_get_instr (cpu), 31, 31))
2485 {
2486 if (uimm (aarch64_get_instr (cpu), 11, 11))
2487 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2488 negate * (uint64_t) rm);
2489 else
2490 set_flags_for_sub64 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK),
2491 negate * aarch64_get_reg_u64 (cpu, rm, SP_OK));
2492 }
2493 else
2494 {
2495 if (uimm (aarch64_get_instr (cpu), 11, 11))
2496 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2497 negate * rm);
2498 else
2499 set_flags_for_sub32 (cpu, aarch64_get_reg_u32 (cpu, rn, SP_OK),
2500 negate * aarch64_get_reg_u32 (cpu, rm, SP_OK));
2501 }
2502 }
2503
2504 static void
2505 do_vec_MOV_whole_vector (sim_cpu *cpu)
2506 {
2507 /* MOV Vd.T, Vs.T (alias for ORR Vd.T, Vn.T, Vm.T where Vn == Vm)
2508
2509 instr[31] = 0
2510 instr[30] = half(0)/full(1)
2511 instr[29,21] = 001110101
2512 instr[20,16] = Vs
2513 instr[15,10] = 000111
2514 instr[9,5] = Vs
2515 instr[4,0] = Vd */
2516
2517 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2518 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2519
2520 NYI_assert (29, 21, 0x075);
2521 NYI_assert (15, 10, 0x07);
2522
2523 if (uimm (aarch64_get_instr (cpu), 20, 16) != vs)
2524 HALT_NYI;
2525
2526 if (uimm (aarch64_get_instr (cpu), 30, 30))
2527 aarch64_set_vec_u64 (cpu, vd, 1, aarch64_get_vec_u64 (cpu, vs, 1));
2528
2529 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vs, 0));
2530 }
2531
2532 static void
2533 do_vec_MOV_into_scalar (sim_cpu *cpu)
2534 {
2535 /* instr[31] = 0
2536 instr[30] = word(0)/long(1)
2537 instr[29,21] = 00 1110 000
2538 instr[20,18] = element size and index
2539 instr[17,10] = 00 0011 11
2540 instr[9,5] = V source
2541 instr[4,0] = R dest */
2542
2543 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2544 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
2545
2546 NYI_assert (29, 21, 0x070);
2547 NYI_assert (17, 10, 0x0F);
2548
2549 switch (uimm (aarch64_get_instr (cpu), 20, 18))
2550 {
2551 case 0x2:
2552 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 0));
2553 break;
2554
2555 case 0x6:
2556 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, vs, 1));
2557 break;
2558
2559 case 0x1:
2560 case 0x3:
2561 case 0x5:
2562 case 0x7:
2563 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u32
2564 (cpu, vs, uimm (aarch64_get_instr (cpu), 20, 19)));
2565 break;
2566
2567 default:
2568 HALT_NYI;
2569 }
2570 }
2571
2572 static void
2573 do_vec_INS (sim_cpu *cpu)
2574 {
2575 /* instr[31,21] = 01001110000
2576 instr[20,16] = element size and index
2577 instr[15,10] = 000111
2578 instr[9,5] = W source
2579 instr[4,0] = V dest */
2580
2581 int index;
2582 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
2583 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2584
2585 NYI_assert (31, 21, 0x270);
2586 NYI_assert (15, 10, 0x07);
2587
2588 if (uimm (aarch64_get_instr (cpu), 16, 16))
2589 {
2590 index = uimm (aarch64_get_instr (cpu), 20, 17);
2591 aarch64_set_vec_u8 (cpu, vd, index,
2592 aarch64_get_reg_u8 (cpu, rs, NO_SP));
2593 }
2594 else if (uimm (aarch64_get_instr (cpu), 17, 17))
2595 {
2596 index = uimm (aarch64_get_instr (cpu), 20, 18);
2597 aarch64_set_vec_u16 (cpu, vd, index,
2598 aarch64_get_reg_u16 (cpu, rs, NO_SP));
2599 }
2600 else if (uimm (aarch64_get_instr (cpu), 18, 18))
2601 {
2602 index = uimm (aarch64_get_instr (cpu), 20, 19);
2603 aarch64_set_vec_u32 (cpu, vd, index,
2604 aarch64_get_reg_u32 (cpu, rs, NO_SP));
2605 }
2606 else if (uimm (aarch64_get_instr (cpu), 19, 19))
2607 {
2608 index = uimm (aarch64_get_instr (cpu), 20, 20);
2609 aarch64_set_vec_u64 (cpu, vd, index,
2610 aarch64_get_reg_u64 (cpu, rs, NO_SP));
2611 }
2612 else
2613 HALT_NYI;
2614 }
2615
2616 static void
2617 do_vec_DUP_vector_into_vector (sim_cpu *cpu)
2618 {
2619 /* instr[31] = 0
2620 instr[30] = half(0)/full(1)
2621 instr[29,21] = 00 1110 000
2622 instr[20,16] = element size and index
2623 instr[15,10] = 0000 01
2624 instr[9,5] = V source
2625 instr[4,0] = V dest. */
2626
2627 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
2628 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
2629 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2630 int i, index;
2631
2632 NYI_assert (29, 21, 0x070);
2633 NYI_assert (15, 10, 0x01);
2634
2635 if (uimm (aarch64_get_instr (cpu), 16, 16))
2636 {
2637 index = uimm (aarch64_get_instr (cpu), 20, 17);
2638
2639 for (i = 0; i < (full ? 16 : 8); i++)
2640 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, index));
2641 }
2642 else if (uimm (aarch64_get_instr (cpu), 17, 17))
2643 {
2644 index = uimm (aarch64_get_instr (cpu), 20, 18);
2645
2646 for (i = 0; i < (full ? 8 : 4); i++)
2647 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, index));
2648 }
2649 else if (uimm (aarch64_get_instr (cpu), 18, 18))
2650 {
2651 index = uimm (aarch64_get_instr (cpu), 20, 19);
2652
2653 for (i = 0; i < (full ? 4 : 2); i++)
2654 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, index));
2655 }
2656 else
2657 {
2658 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
2659 HALT_UNALLOC;
2660
2661 if (! full)
2662 HALT_UNALLOC;
2663
2664 index = uimm (aarch64_get_instr (cpu), 20, 20);
2665
2666 for (i = 0; i < 2; i++)
2667 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, index));
2668 }
2669 }
2670
2671 static void
2672 do_vec_TBL (sim_cpu *cpu)
2673 {
2674 /* instr[31] = 0
2675 instr[30] = half(0)/full(1)
2676 instr[29,21] = 00 1110 000
2677 instr[20,16] = Vm
2678 instr[15] = 0
2679 instr[14,13] = vec length
2680 instr[12,10] = 000
2681 instr[9,5] = V start
2682 instr[4,0] = V dest */
2683
2684 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2685 int len = uimm (aarch64_get_instr (cpu), 14, 13) + 1;
2686 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2687 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2688 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2689 unsigned i;
2690
2691 NYI_assert (29, 21, 0x070);
2692 NYI_assert (12, 10, 0);
2693
2694 for (i = 0; i < (full ? 16 : 8); i++)
2695 {
2696 unsigned int selector = aarch64_get_vec_u8 (cpu, vm, i);
2697 uint8_t val;
2698
2699 if (selector < 16)
2700 val = aarch64_get_vec_u8 (cpu, vn, selector);
2701 else if (selector < 32)
2702 val = len < 2 ? 0 : aarch64_get_vec_u8 (cpu, vn + 1, selector - 16);
2703 else if (selector < 48)
2704 val = len < 3 ? 0 : aarch64_get_vec_u8 (cpu, vn + 2, selector - 32);
2705 else if (selector < 64)
2706 val = len < 4 ? 0 : aarch64_get_vec_u8 (cpu, vn + 3, selector - 48);
2707 else
2708 val = 0;
2709
2710 aarch64_set_vec_u8 (cpu, vd, i, val);
2711 }
2712 }
2713
2714 static void
2715 do_vec_TRN (sim_cpu *cpu)
2716 {
2717 /* instr[31] = 0
2718 instr[30] = half(0)/full(1)
2719 instr[29,24] = 00 1110
2720 instr[23,22] = size
2721 instr[21] = 0
2722 instr[20,16] = Vm
2723 instr[15] = 0
2724 instr[14] = TRN1 (0) / TRN2 (1)
2725 instr[13,10] = 1010
2726 instr[9,5] = V source
2727 instr[4,0] = V dest. */
2728
2729 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2730 int second = uimm (aarch64_get_instr (cpu), 14, 14);
2731 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2732 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2733 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2734 unsigned i;
2735
2736 NYI_assert (29, 24, 0x0E);
2737 NYI_assert (13, 10, 0xA);
2738
2739 switch (uimm (aarch64_get_instr (cpu), 23, 22))
2740 {
2741 case 0:
2742 for (i = 0; i < (full ? 8 : 4); i++)
2743 {
2744 aarch64_set_vec_u8
2745 (cpu, vd, i * 2,
2746 aarch64_get_vec_u8 (cpu, second ? vm : vn, i * 2));
2747 aarch64_set_vec_u8
2748 (cpu, vd, 1 * 2 + 1,
2749 aarch64_get_vec_u8 (cpu, second ? vn : vm, i * 2 + 1));
2750 }
2751 break;
2752
2753 case 1:
2754 for (i = 0; i < (full ? 4 : 2); i++)
2755 {
2756 aarch64_set_vec_u16
2757 (cpu, vd, i * 2,
2758 aarch64_get_vec_u16 (cpu, second ? vm : vn, i * 2));
2759 aarch64_set_vec_u16
2760 (cpu, vd, 1 * 2 + 1,
2761 aarch64_get_vec_u16 (cpu, second ? vn : vm, i * 2 + 1));
2762 }
2763 break;
2764
2765 case 2:
2766 aarch64_set_vec_u32
2767 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, second ? vm : vn, 0));
2768 aarch64_set_vec_u32
2769 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, second ? vn : vm, 1));
2770 aarch64_set_vec_u32
2771 (cpu, vd, 2, aarch64_get_vec_u32 (cpu, second ? vm : vn, 2));
2772 aarch64_set_vec_u32
2773 (cpu, vd, 3, aarch64_get_vec_u32 (cpu, second ? vn : vm, 3));
2774 break;
2775
2776 case 3:
2777 if (! full)
2778 HALT_UNALLOC;
2779
2780 aarch64_set_vec_u64 (cpu, vd, 0,
2781 aarch64_get_vec_u64 (cpu, second ? vm : vn, 0));
2782 aarch64_set_vec_u64 (cpu, vd, 1,
2783 aarch64_get_vec_u64 (cpu, second ? vn : vm, 1));
2784 break;
2785
2786 default:
2787 HALT_UNALLOC;
2788 }
2789 }
2790
2791 static void
2792 do_vec_DUP_scalar_into_vector (sim_cpu *cpu)
2793 {
2794 /* instr[31] = 0
2795 instr[30] = 0=> zero top 64-bits, 1=> duplicate into top 64-bits
2796 [must be 1 for 64-bit xfer]
2797 instr[29,20] = 00 1110 0000
2798 instr[19,16] = element size: 0001=> 8-bits, 0010=> 16-bits,
2799 0100=> 32-bits. 1000=>64-bits
2800 instr[15,10] = 0000 11
2801 instr[9,5] = W source
2802 instr[4,0] = V dest. */
2803
2804 unsigned i;
2805 unsigned Vd = uimm (aarch64_get_instr (cpu), 4, 0);
2806 unsigned Rs = uimm (aarch64_get_instr (cpu), 9, 5);
2807 int both = uimm (aarch64_get_instr (cpu), 30, 30);
2808
2809 NYI_assert (29, 20, 0x0E0);
2810 NYI_assert (15, 10, 0x03);
2811
2812 switch (uimm (aarch64_get_instr (cpu), 19, 16))
2813 {
2814 case 1:
2815 for (i = 0; i < (both ? 16 : 8); i++)
2816 aarch64_set_vec_u8 (cpu, Vd, i, aarch64_get_reg_u8 (cpu, Rs, NO_SP));
2817 break;
2818
2819 case 2:
2820 for (i = 0; i < (both ? 8 : 4); i++)
2821 aarch64_set_vec_u16 (cpu, Vd, i, aarch64_get_reg_u16 (cpu, Rs, NO_SP));
2822 break;
2823
2824 case 4:
2825 for (i = 0; i < (both ? 4 : 2); i++)
2826 aarch64_set_vec_u32 (cpu, Vd, i, aarch64_get_reg_u32 (cpu, Rs, NO_SP));
2827 break;
2828
2829 case 8:
2830 if (!both)
2831 HALT_NYI;
2832 aarch64_set_vec_u64 (cpu, Vd, 0, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2833 aarch64_set_vec_u64 (cpu, Vd, 1, aarch64_get_reg_u64 (cpu, Rs, NO_SP));
2834 break;
2835
2836 default:
2837 HALT_NYI;
2838 }
2839 }
2840
2841 static void
2842 do_vec_UZP (sim_cpu *cpu)
2843 {
2844 /* instr[31] = 0
2845 instr[30] = half(0)/full(1)
2846 instr[29,24] = 00 1110
2847 instr[23,22] = size: byte(00), half(01), word (10), long (11)
2848 instr[21] = 0
2849 instr[20,16] = Vm
2850 instr[15] = 0
2851 instr[14] = lower (0) / upper (1)
2852 instr[13,10] = 0110
2853 instr[9,5] = Vn
2854 instr[4,0] = Vd. */
2855
2856 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2857 int upper = uimm (aarch64_get_instr (cpu), 14, 14);
2858
2859 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2860 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2861 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2862
2863 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2864 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2865 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2866 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2867
2868 uint64_t val1 = 0;
2869 uint64_t val2 = 0;
2870
2871 uint64_t input1 = upper ? val_n1 : val_m1;
2872 uint64_t input2 = upper ? val_n2 : val_m2;
2873 unsigned i;
2874
2875 NYI_assert (29, 24, 0x0E);
2876 NYI_assert (21, 21, 0);
2877 NYI_assert (15, 15, 0);
2878 NYI_assert (13, 10, 6);
2879
2880 switch (uimm (aarch64_get_instr (cpu), 23, 23))
2881 {
2882 case 0:
2883 for (i = 0; i < 8; i++)
2884 {
2885 val1 |= (input1 >> (i * 8)) & (0xFFULL << (i * 8));
2886 val2 |= (input2 >> (i * 8)) & (0xFFULL << (i * 8));
2887 }
2888 break;
2889
2890 case 1:
2891 for (i = 0; i < 4; i++)
2892 {
2893 val1 |= (input1 >> (i * 16)) & (0xFFFFULL << (i * 16));
2894 val2 |= (input2 >> (i * 16)) & (0xFFFFULL << (i * 16));
2895 }
2896 break;
2897
2898 case 2:
2899 val1 = ((input1 & 0xFFFFFFFF) | ((input1 >> 32) & 0xFFFFFFFF00000000ULL));
2900 val2 = ((input2 & 0xFFFFFFFF) | ((input2 >> 32) & 0xFFFFFFFF00000000ULL));
2901
2902 case 3:
2903 val1 = input1;
2904 val2 = input2;
2905 break;
2906 }
2907
2908 aarch64_set_vec_u64 (cpu, vd, 0, val1);
2909 if (full)
2910 aarch64_set_vec_u64 (cpu, vd, 1, val2);
2911 }
2912
2913 static void
2914 do_vec_ZIP (sim_cpu *cpu)
2915 {
2916 /* instr[31] = 0
2917 instr[30] = half(0)/full(1)
2918 instr[29,24] = 00 1110
2919 instr[23,22] = size: byte(00), hald(01), word (10), long (11)
2920 instr[21] = 0
2921 instr[20,16] = Vm
2922 instr[15] = 0
2923 instr[14] = lower (0) / upper (1)
2924 instr[13,10] = 1110
2925 instr[9,5] = Vn
2926 instr[4,0] = Vd. */
2927
2928 int full = uimm (aarch64_get_instr (cpu), 30, 30);
2929 int upper = uimm (aarch64_get_instr (cpu), 14, 14);
2930
2931 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
2932 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
2933 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
2934
2935 uint64_t val_m1 = aarch64_get_vec_u64 (cpu, vm, 0);
2936 uint64_t val_m2 = aarch64_get_vec_u64 (cpu, vm, 1);
2937 uint64_t val_n1 = aarch64_get_vec_u64 (cpu, vn, 0);
2938 uint64_t val_n2 = aarch64_get_vec_u64 (cpu, vn, 1);
2939
2940 uint64_t val1 = 0;
2941 uint64_t val2 = 0;
2942
2943 uint64_t input1 = upper ? val_n1 : val_m1;
2944 uint64_t input2 = upper ? val_n2 : val_m2;
2945
2946 NYI_assert (29, 24, 0x0E);
2947 NYI_assert (21, 21, 0);
2948 NYI_assert (15, 15, 0);
2949 NYI_assert (13, 10, 0xE);
2950
2951 switch (uimm (aarch64_get_instr (cpu), 23, 23))
2952 {
2953 case 0:
2954 val1 =
2955 ((input1 << 0) & (0xFF << 0))
2956 | ((input2 << 8) & (0xFF << 8))
2957 | ((input1 << 8) & (0xFF << 16))
2958 | ((input2 << 16) & (0xFF << 24))
2959 | ((input1 << 16) & (0xFFULL << 32))
2960 | ((input2 << 24) & (0xFFULL << 40))
2961 | ((input1 << 24) & (0xFFULL << 48))
2962 | ((input2 << 32) & (0xFFULL << 56));
2963
2964 val2 =
2965 ((input1 >> 32) & (0xFF << 0))
2966 | ((input2 >> 24) & (0xFF << 8))
2967 | ((input1 >> 24) & (0xFF << 16))
2968 | ((input2 >> 16) & (0xFF << 24))
2969 | ((input1 >> 16) & (0xFFULL << 32))
2970 | ((input2 >> 8) & (0xFFULL << 40))
2971 | ((input1 >> 8) & (0xFFULL << 48))
2972 | ((input2 >> 0) & (0xFFULL << 56));
2973 break;
2974
2975 case 1:
2976 val1 =
2977 ((input1 << 0) & (0xFFFF << 0))
2978 | ((input2 << 16) & (0xFFFF << 16))
2979 | ((input1 << 16) & (0xFFFFULL << 32))
2980 | ((input2 << 32) & (0xFFFFULL << 48));
2981
2982 val2 =
2983 ((input1 >> 32) & (0xFFFF << 0))
2984 | ((input2 >> 16) & (0xFFFF << 16))
2985 | ((input1 >> 16) & (0xFFFFULL << 32))
2986 | ((input2 >> 0) & (0xFFFFULL << 48));
2987 break;
2988
2989 case 2:
2990 val1 = (input1 & 0xFFFFFFFFULL) | (input2 << 32);
2991 val2 = (input2 & 0xFFFFFFFFULL) | (input1 << 32);
2992 break;
2993
2994 case 3:
2995 val1 = input1;
2996 val2 = input2;
2997 break;
2998 }
2999
3000 aarch64_set_vec_u64 (cpu, vd, 0, val1);
3001 if (full)
3002 aarch64_set_vec_u64 (cpu, vd, 1, val2);
3003 }
3004
3005 /* Floating point immediates are encoded in 8 bits.
3006 fpimm[7] = sign bit.
3007 fpimm[6:4] = signed exponent.
3008 fpimm[3:0] = fraction (assuming leading 1).
3009 i.e. F = s * 1.f * 2^(e - b). */
3010
3011 static float
3012 fp_immediate_for_encoding_32 (uint32_t imm8)
3013 {
3014 float u;
3015 uint32_t s, e, f, i;
3016
3017 s = (imm8 >> 7) & 0x1;
3018 e = (imm8 >> 4) & 0x7;
3019 f = imm8 & 0xf;
3020
3021 /* The fp value is s * n/16 * 2r where n is 16+e. */
3022 u = (16.0 + f) / 16.0;
3023
3024 /* N.B. exponent is signed. */
3025 if (e < 4)
3026 {
3027 int epos = e;
3028
3029 for (i = 0; i <= epos; i++)
3030 u *= 2.0;
3031 }
3032 else
3033 {
3034 int eneg = 7 - e;
3035
3036 for (i = 0; i < eneg; i++)
3037 u /= 2.0;
3038 }
3039
3040 if (s)
3041 u = - u;
3042
3043 return u;
3044 }
3045
3046 static double
3047 fp_immediate_for_encoding_64 (uint32_t imm8)
3048 {
3049 double u;
3050 uint32_t s, e, f, i;
3051
3052 s = (imm8 >> 7) & 0x1;
3053 e = (imm8 >> 4) & 0x7;
3054 f = imm8 & 0xf;
3055
3056 /* The fp value is s * n/16 * 2r where n is 16+e. */
3057 u = (16.0 + f) / 16.0;
3058
3059 /* N.B. exponent is signed. */
3060 if (e < 4)
3061 {
3062 int epos = e;
3063
3064 for (i = 0; i <= epos; i++)
3065 u *= 2.0;
3066 }
3067 else
3068 {
3069 int eneg = 7 - e;
3070
3071 for (i = 0; i < eneg; i++)
3072 u /= 2.0;
3073 }
3074
3075 if (s)
3076 u = - u;
3077
3078 return u;
3079 }
3080
3081 static void
3082 do_vec_MOV_immediate (sim_cpu *cpu)
3083 {
3084 /* instr[31] = 0
3085 instr[30] = full/half selector
3086 instr[29,19] = 00111100000
3087 instr[18,16] = high 3 bits of uimm8
3088 instr[15,12] = size & shift:
3089 0000 => 32-bit
3090 0010 => 32-bit + LSL#8
3091 0100 => 32-bit + LSL#16
3092 0110 => 32-bit + LSL#24
3093 1010 => 16-bit + LSL#8
3094 1000 => 16-bit
3095 1101 => 32-bit + MSL#16
3096 1100 => 32-bit + MSL#8
3097 1110 => 8-bit
3098 1111 => double
3099 instr[11,10] = 01
3100 instr[9,5] = low 5-bits of uimm8
3101 instr[4,0] = Vd. */
3102
3103 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3104 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3105 unsigned val = uimm (aarch64_get_instr (cpu), 18, 16) << 5
3106 | uimm (aarch64_get_instr (cpu), 9, 5);
3107 unsigned i;
3108
3109 NYI_assert (29, 19, 0x1E0);
3110 NYI_assert (11, 10, 1);
3111
3112 switch (uimm (aarch64_get_instr (cpu), 15, 12))
3113 {
3114 case 0x0: /* 32-bit, no shift. */
3115 case 0x2: /* 32-bit, shift by 8. */
3116 case 0x4: /* 32-bit, shift by 16. */
3117 case 0x6: /* 32-bit, shift by 24. */
3118 val <<= (8 * uimm (aarch64_get_instr (cpu), 14, 13));
3119 for (i = 0; i < (full ? 4 : 2); i++)
3120 aarch64_set_vec_u32 (cpu, vd, i, val);
3121 break;
3122
3123 case 0xa: /* 16-bit, shift by 8. */
3124 val <<= 8;
3125 /* Fall through. */
3126 case 0x8: /* 16-bit, no shift. */
3127 for (i = 0; i < (full ? 8 : 4); i++)
3128 aarch64_set_vec_u16 (cpu, vd, i, val);
3129 /* Fall through. */
3130 case 0xd: /* 32-bit, mask shift by 16. */
3131 val <<= 8;
3132 val |= 0xFF;
3133 /* Fall through. */
3134 case 0xc: /* 32-bit, mask shift by 8. */
3135 val <<= 8;
3136 val |= 0xFF;
3137 for (i = 0; i < (full ? 4 : 2); i++)
3138 aarch64_set_vec_u32 (cpu, vd, i, val);
3139 break;
3140
3141 case 0xe: /* 8-bit, no shift. */
3142 for (i = 0; i < (full ? 16 : 8); i++)
3143 aarch64_set_vec_u8 (cpu, vd, i, val);
3144 break;
3145
3146 case 0xf: /* FMOV Vs.{2|4}S, #fpimm. */
3147 {
3148 float u = fp_immediate_for_encoding_32 (val);
3149 for (i = 0; i < (full ? 4 : 2); i++)
3150 aarch64_set_vec_float (cpu, vd, i, u);
3151 break;
3152 }
3153
3154 default:
3155 HALT_NYI;
3156 }
3157 }
3158
3159 static void
3160 do_vec_MVNI (sim_cpu *cpu)
3161 {
3162 /* instr[31] = 0
3163 instr[30] = full/half selector
3164 instr[29,19] = 10111100000
3165 instr[18,16] = high 3 bits of uimm8
3166 instr[15,12] = selector
3167 instr[11,10] = 01
3168 instr[9,5] = low 5-bits of uimm8
3169 instr[4,0] = Vd. */
3170
3171 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3172 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3173 unsigned val = uimm (aarch64_get_instr (cpu), 18, 16) << 5
3174 | uimm (aarch64_get_instr (cpu), 9, 5);
3175 unsigned i;
3176
3177 NYI_assert (29, 19, 0x5E0);
3178 NYI_assert (11, 10, 1);
3179
3180 switch (uimm (aarch64_get_instr (cpu), 15, 12))
3181 {
3182 case 0x0: /* 32-bit, no shift. */
3183 case 0x2: /* 32-bit, shift by 8. */
3184 case 0x4: /* 32-bit, shift by 16. */
3185 case 0x6: /* 32-bit, shift by 24. */
3186 val <<= (8 * uimm (aarch64_get_instr (cpu), 14, 13));
3187 val = ~ val;
3188 for (i = 0; i < (full ? 4 : 2); i++)
3189 aarch64_set_vec_u32 (cpu, vd, i, val);
3190 return;
3191
3192 case 0xa: /* 16-bit, 8 bit shift. */
3193 val <<= 8;
3194 case 0x8: /* 16-bit, no shift. */
3195 val = ~ val;
3196 for (i = 0; i < (full ? 8 : 4); i++)
3197 aarch64_set_vec_u16 (cpu, vd, i, val);
3198 return;
3199
3200 case 0xd: /* 32-bit, mask shift by 16. */
3201 val <<= 8;
3202 val |= 0xFF;
3203 case 0xc: /* 32-bit, mask shift by 8. */
3204 val <<= 8;
3205 val |= 0xFF;
3206 val = ~ val;
3207 for (i = 0; i < (full ? 4 : 2); i++)
3208 aarch64_set_vec_u32 (cpu, vd, i, val);
3209 return;
3210
3211 case 0xE: /* MOVI Dn, #mask64 */
3212 {
3213 uint64_t mask = 0;
3214
3215 for (i = 0; i < 8; i++)
3216 if (val & (1 << i))
3217 mask |= (0xF << (i * 4));
3218 aarch64_set_vec_u64 (cpu, vd, 0, mask);
3219 aarch64_set_vec_u64 (cpu, vd, 1, 0);
3220 return;
3221 }
3222
3223 case 0xf: /* FMOV Vd.2D, #fpimm. */
3224 {
3225 double u = fp_immediate_for_encoding_64 (val);
3226
3227 if (! full)
3228 HALT_UNALLOC;
3229
3230 aarch64_set_vec_double (cpu, vd, 0, u);
3231 aarch64_set_vec_double (cpu, vd, 1, u);
3232 return;
3233 }
3234
3235 default:
3236 HALT_NYI;
3237 }
3238 }
3239
3240 #define ABS(A) ((A) < 0 ? - (A) : (A))
3241
3242 static void
3243 do_vec_ABS (sim_cpu *cpu)
3244 {
3245 /* instr[31] = 0
3246 instr[30] = half(0)/full(1)
3247 instr[29,24] = 00 1110
3248 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3249 instr[21,10] = 10 0000 1011 10
3250 instr[9,5] = Vn
3251 instr[4.0] = Vd. */
3252
3253 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3254 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3255 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
3256 unsigned i;
3257
3258 NYI_assert (29, 24, 0x0E);
3259 NYI_assert (21, 10, 0x82E);
3260
3261 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3262 {
3263 case 0:
3264 for (i = 0; i < (full ? 16 : 8); i++)
3265 aarch64_set_vec_s8 (cpu, vd, i,
3266 ABS (aarch64_get_vec_s8 (cpu, vn, i)));
3267 break;
3268
3269 case 1:
3270 for (i = 0; i < (full ? 8 : 4); i++)
3271 aarch64_set_vec_s16 (cpu, vd, i,
3272 ABS (aarch64_get_vec_s16 (cpu, vn, i)));
3273 break;
3274
3275 case 2:
3276 for (i = 0; i < (full ? 4 : 2); i++)
3277 aarch64_set_vec_s32 (cpu, vd, i,
3278 ABS (aarch64_get_vec_s32 (cpu, vn, i)));
3279 break;
3280
3281 case 3:
3282 if (! full)
3283 HALT_NYI;
3284 for (i = 0; i < 2; i++)
3285 aarch64_set_vec_s64 (cpu, vd, i,
3286 ABS (aarch64_get_vec_s64 (cpu, vn, i)));
3287 break;
3288 }
3289 }
3290
3291 static void
3292 do_vec_ADDV (sim_cpu *cpu)
3293 {
3294 /* instr[31] = 0
3295 instr[30] = full/half selector
3296 instr[29,24] = 00 1110
3297 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3298 instr[21,10] = 11 0001 1011 10
3299 instr[9,5] = Vm
3300 instr[4.0] = Rd. */
3301
3302 unsigned vm = uimm (aarch64_get_instr (cpu), 9, 5);
3303 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
3304 unsigned i;
3305 uint64_t val = 0;
3306 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3307
3308 NYI_assert (29, 24, 0x0E);
3309 NYI_assert (21, 10, 0xC6E);
3310
3311 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3312 {
3313 case 0:
3314 for (i = 0; i < (full ? 16 : 8); i++)
3315 val += aarch64_get_vec_u8 (cpu, vm, i);
3316 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3317 return;
3318
3319 case 1:
3320 for (i = 0; i < (full ? 8 : 4); i++)
3321 val += aarch64_get_vec_u16 (cpu, vm, i);
3322 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3323 return;
3324
3325 case 2:
3326 for (i = 0; i < (full ? 4 : 2); i++)
3327 val += aarch64_get_vec_u32 (cpu, vm, i);
3328 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3329 return;
3330
3331 case 3:
3332 if (! full)
3333 HALT_UNALLOC;
3334 val = aarch64_get_vec_u64 (cpu, vm, 0);
3335 val += aarch64_get_vec_u64 (cpu, vm, 1);
3336 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
3337 return;
3338
3339 default:
3340 HALT_UNREACHABLE;
3341 }
3342 }
3343
3344 static void
3345 do_vec_ins_2 (sim_cpu *cpu)
3346 {
3347 /* instr[31,21] = 01001110000
3348 instr[20,18] = size & element selector
3349 instr[17,14] = 0000
3350 instr[13] = direction: to vec(0), from vec (1)
3351 instr[12,10] = 111
3352 instr[9,5] = Vm
3353 instr[4,0] = Vd. */
3354
3355 unsigned elem;
3356 unsigned vm = uimm (aarch64_get_instr (cpu), 9, 5);
3357 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3358
3359 NYI_assert (31, 21, 0x270);
3360 NYI_assert (17, 14, 0);
3361 NYI_assert (12, 10, 7);
3362
3363 if (uimm (aarch64_get_instr (cpu), 13, 13) == 1)
3364 {
3365 if (uimm (aarch64_get_instr (cpu), 18, 18) == 1)
3366 {
3367 /* 32-bit moves. */
3368 elem = uimm (aarch64_get_instr (cpu), 20, 19);
3369 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3370 aarch64_get_vec_u32 (cpu, vm, elem));
3371 }
3372 else
3373 {
3374 /* 64-bit moves. */
3375 if (uimm (aarch64_get_instr (cpu), 19, 19) != 1)
3376 HALT_NYI;
3377
3378 elem = uimm (aarch64_get_instr (cpu), 20, 20);
3379 aarch64_set_reg_u64 (cpu, vd, NO_SP,
3380 aarch64_get_vec_u64 (cpu, vm, elem));
3381 }
3382 }
3383 else
3384 {
3385 if (uimm (aarch64_get_instr (cpu), 18, 18) == 1)
3386 {
3387 /* 32-bit moves. */
3388 elem = uimm (aarch64_get_instr (cpu), 20, 19);
3389 aarch64_set_vec_u32 (cpu, vd, elem,
3390 aarch64_get_reg_u32 (cpu, vm, NO_SP));
3391 }
3392 else
3393 {
3394 /* 64-bit moves. */
3395 if (uimm (aarch64_get_instr (cpu), 19, 19) != 1)
3396 HALT_NYI;
3397
3398 elem = uimm (aarch64_get_instr (cpu), 20, 20);
3399 aarch64_set_vec_u64 (cpu, vd, elem,
3400 aarch64_get_reg_u64 (cpu, vm, NO_SP));
3401 }
3402 }
3403 }
3404
3405 static void
3406 do_vec_mull (sim_cpu *cpu)
3407 {
3408 /* instr[31] = 0
3409 instr[30] = lower(0)/upper(1) selector
3410 instr[29] = signed(0)/unsigned(1)
3411 instr[28,24] = 0 1110
3412 instr[23,22] = size: 8-bit (00), 16-bit (01), 32-bit (10)
3413 instr[21] = 1
3414 instr[20,16] = Vm
3415 instr[15,10] = 11 0000
3416 instr[9,5] = Vn
3417 instr[4.0] = Vd. */
3418
3419 int unsign = uimm (aarch64_get_instr (cpu), 29, 29);
3420 int bias = uimm (aarch64_get_instr (cpu), 30, 30);
3421 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3422 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3423 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3424 unsigned i;
3425
3426 NYI_assert (28, 24, 0x0E);
3427 NYI_assert (15, 10, 0x30);
3428
3429 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3430 {
3431 case 0:
3432 if (bias)
3433 bias = 8;
3434 if (unsign)
3435 for (i = 0; i < 8; i++)
3436 aarch64_set_vec_u16 (cpu, vd, i,
3437 aarch64_get_vec_u8 (cpu, vn, i + bias)
3438 * aarch64_get_vec_u8 (cpu, vm, i + bias));
3439 else
3440 for (i = 0; i < 8; i++)
3441 aarch64_set_vec_s16 (cpu, vd, i,
3442 aarch64_get_vec_s8 (cpu, vn, i + bias)
3443 * aarch64_get_vec_s8 (cpu, vm, i + bias));
3444 return;
3445
3446 case 1:
3447 if (bias)
3448 bias = 4;
3449 if (unsign)
3450 for (i = 0; i < 4; i++)
3451 aarch64_set_vec_u32 (cpu, vd, i,
3452 aarch64_get_vec_u16 (cpu, vn, i + bias)
3453 * aarch64_get_vec_u16 (cpu, vm, i + bias));
3454 else
3455 for (i = 0; i < 4; i++)
3456 aarch64_set_vec_s32 (cpu, vd, i,
3457 aarch64_get_vec_s16 (cpu, vn, i + bias)
3458 * aarch64_get_vec_s16 (cpu, vm, i + bias));
3459 return;
3460
3461 case 2:
3462 if (bias)
3463 bias = 2;
3464 if (unsign)
3465 for (i = 0; i < 2; i++)
3466 aarch64_set_vec_u64 (cpu, vd, i,
3467 (uint64_t) aarch64_get_vec_u32 (cpu, vn,
3468 i + bias)
3469 * (uint64_t) aarch64_get_vec_u32 (cpu, vm,
3470 i + bias));
3471 else
3472 for (i = 0; i < 2; i++)
3473 aarch64_set_vec_s64 (cpu, vd, i,
3474 aarch64_get_vec_s32 (cpu, vn, i + bias)
3475 * aarch64_get_vec_s32 (cpu, vm, i + bias));
3476 return;
3477
3478 case 3:
3479 default:
3480 HALT_NYI;
3481 }
3482 }
3483
3484 static void
3485 do_vec_fadd (sim_cpu *cpu)
3486 {
3487 /* instr[31] = 0
3488 instr[30] = half(0)/full(1)
3489 instr[29,24] = 001110
3490 instr[23] = FADD(0)/FSUB(1)
3491 instr[22] = float (0)/double(1)
3492 instr[21] = 1
3493 instr[20,16] = Vm
3494 instr[15,10] = 110101
3495 instr[9,5] = Vn
3496 instr[4.0] = Vd. */
3497
3498 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3499 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3500 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3501 unsigned i;
3502 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3503
3504 NYI_assert (29, 24, 0x0E);
3505 NYI_assert (21, 21, 1);
3506 NYI_assert (15, 10, 0x35);
3507
3508 if (uimm (aarch64_get_instr (cpu), 23, 23))
3509 {
3510 if (uimm (aarch64_get_instr (cpu), 22, 22))
3511 {
3512 if (! full)
3513 HALT_NYI;
3514
3515 for (i = 0; i < 2; i++)
3516 aarch64_set_vec_double (cpu, vd, i,
3517 aarch64_get_vec_double (cpu, vn, i)
3518 - aarch64_get_vec_double (cpu, vm, i));
3519 }
3520 else
3521 {
3522 for (i = 0; i < (full ? 4 : 2); i++)
3523 aarch64_set_vec_float (cpu, vd, i,
3524 aarch64_get_vec_float (cpu, vn, i)
3525 - aarch64_get_vec_float (cpu, vm, i));
3526 }
3527 }
3528 else
3529 {
3530 if (uimm (aarch64_get_instr (cpu), 22, 22))
3531 {
3532 if (! full)
3533 HALT_NYI;
3534
3535 for (i = 0; i < 2; i++)
3536 aarch64_set_vec_double (cpu, vd, i,
3537 aarch64_get_vec_double (cpu, vm, i)
3538 + aarch64_get_vec_double (cpu, vn, i));
3539 }
3540 else
3541 {
3542 for (i = 0; i < (full ? 4 : 2); i++)
3543 aarch64_set_vec_float (cpu, vd, i,
3544 aarch64_get_vec_float (cpu, vm, i)
3545 + aarch64_get_vec_float (cpu, vn, i));
3546 }
3547 }
3548 }
3549
3550 static void
3551 do_vec_add (sim_cpu *cpu)
3552 {
3553 /* instr[31] = 0
3554 instr[30] = full/half selector
3555 instr[29,24] = 001110
3556 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit, 11=> 64-bit
3557 instr[21] = 1
3558 instr[20,16] = Vn
3559 instr[15,10] = 100001
3560 instr[9,5] = Vm
3561 instr[4.0] = Vd. */
3562
3563 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3564 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3565 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3566 unsigned i;
3567 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3568
3569 NYI_assert (29, 24, 0x0E);
3570 NYI_assert (21, 21, 1);
3571 NYI_assert (15, 10, 0x21);
3572
3573 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3574 {
3575 case 0:
3576 for (i = 0; i < (full ? 16 : 8); i++)
3577 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
3578 + aarch64_get_vec_u8 (cpu, vm, i));
3579 return;
3580
3581 case 1:
3582 for (i = 0; i < (full ? 8 : 4); i++)
3583 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
3584 + aarch64_get_vec_u16 (cpu, vm, i));
3585 return;
3586
3587 case 2:
3588 for (i = 0; i < (full ? 4 : 2); i++)
3589 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
3590 + aarch64_get_vec_u32 (cpu, vm, i));
3591 return;
3592
3593 case 3:
3594 if (! full)
3595 HALT_UNALLOC;
3596 aarch64_set_vec_u64 (cpu, vd, 0, aarch64_get_vec_u64 (cpu, vn, 0)
3597 + aarch64_get_vec_u64 (cpu, vm, 0));
3598 aarch64_set_vec_u64 (cpu, vd, 1,
3599 aarch64_get_vec_u64 (cpu, vn, 1)
3600 + aarch64_get_vec_u64 (cpu, vm, 1));
3601 return;
3602
3603 default:
3604 HALT_UNREACHABLE;
3605 }
3606 }
3607
3608 static void
3609 do_vec_mul (sim_cpu *cpu)
3610 {
3611 /* instr[31] = 0
3612 instr[30] = full/half selector
3613 instr[29,24] = 00 1110
3614 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3615 instr[21] = 1
3616 instr[20,16] = Vn
3617 instr[15,10] = 10 0111
3618 instr[9,5] = Vm
3619 instr[4.0] = Vd. */
3620
3621 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3622 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3623 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3624 unsigned i;
3625 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3626
3627 NYI_assert (29, 24, 0x0E);
3628 NYI_assert (21, 21, 1);
3629 NYI_assert (15, 10, 0x27);
3630
3631 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3632 {
3633 case 0:
3634 for (i = 0; i < (full ? 16 : 8); i++)
3635 {
3636 uint16_t val = aarch64_get_vec_u8 (cpu, vn, i);
3637 val *= aarch64_get_vec_u8 (cpu, vm, i);
3638
3639 aarch64_set_vec_u16 (cpu, vd, i, val);
3640 }
3641 return;
3642
3643 case 1:
3644 for (i = 0; i < (full ? 8 : 4); i++)
3645 {
3646 uint32_t val = aarch64_get_vec_u16 (cpu, vn, i);
3647 val *= aarch64_get_vec_u16 (cpu, vm, i);
3648
3649 aarch64_set_vec_u32 (cpu, vd, i, val);
3650 }
3651 return;
3652
3653 case 2:
3654 for (i = 0; i < (full ? 4 : 2); i++)
3655 {
3656 uint64_t val = aarch64_get_vec_u32 (cpu, vn, i);
3657 val *= aarch64_get_vec_u32 (cpu, vm, i);
3658
3659 aarch64_set_vec_u64 (cpu, vd, i, val);
3660 }
3661 return;
3662
3663 default:
3664 case 3:
3665 HALT_UNALLOC;
3666 }
3667 }
3668
3669 static void
3670 do_vec_MLA (sim_cpu *cpu)
3671 {
3672 /* instr[31] = 0
3673 instr[30] = full/half selector
3674 instr[29,24] = 00 1110
3675 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
3676 instr[21] = 1
3677 instr[20,16] = Vn
3678 instr[15,10] = 1001 01
3679 instr[9,5] = Vm
3680 instr[4.0] = Vd. */
3681
3682 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3683 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3684 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3685 unsigned i;
3686 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3687
3688 NYI_assert (29, 24, 0x0E);
3689 NYI_assert (21, 21, 1);
3690 NYI_assert (15, 10, 0x25);
3691
3692 switch (uimm (aarch64_get_instr (cpu), 23, 22))
3693 {
3694 case 0:
3695 for (i = 0; i < (full ? 16 : 8); i++)
3696 {
3697 uint16_t val = aarch64_get_vec_u8 (cpu, vn, i);
3698 val *= aarch64_get_vec_u8 (cpu, vm, i);
3699 val += aarch64_get_vec_u8 (cpu, vd, i);
3700
3701 aarch64_set_vec_u16 (cpu, vd, i, val);
3702 }
3703 return;
3704
3705 case 1:
3706 for (i = 0; i < (full ? 8 : 4); i++)
3707 {
3708 uint32_t val = aarch64_get_vec_u16 (cpu, vn, i);
3709 val *= aarch64_get_vec_u16 (cpu, vm, i);
3710 val += aarch64_get_vec_u16 (cpu, vd, i);
3711
3712 aarch64_set_vec_u32 (cpu, vd, i, val);
3713 }
3714 return;
3715
3716 case 2:
3717 for (i = 0; i < (full ? 4 : 2); i++)
3718 {
3719 uint64_t val = aarch64_get_vec_u32 (cpu, vn, i);
3720 val *= aarch64_get_vec_u32 (cpu, vm, i);
3721 val += aarch64_get_vec_u32 (cpu, vd, i);
3722
3723 aarch64_set_vec_u64 (cpu, vd, i, val);
3724 }
3725 return;
3726
3727 default:
3728 case 3:
3729 HALT_UNALLOC;
3730 }
3731 }
3732
3733 static float
3734 fmaxnm (float a, float b)
3735 {
3736 if (fpclassify (a) == FP_NORMAL)
3737 {
3738 if (fpclassify (b) == FP_NORMAL)
3739 return a > b ? a : b;
3740 return a;
3741 }
3742 else if (fpclassify (b) == FP_NORMAL)
3743 return b;
3744 return a;
3745 }
3746
3747 static float
3748 fminnm (float a, float b)
3749 {
3750 if (fpclassify (a) == FP_NORMAL)
3751 {
3752 if (fpclassify (b) == FP_NORMAL)
3753 return a < b ? a : b;
3754 return a;
3755 }
3756 else if (fpclassify (b) == FP_NORMAL)
3757 return b;
3758 return a;
3759 }
3760
3761 static double
3762 dmaxnm (double a, double b)
3763 {
3764 if (fpclassify (a) == FP_NORMAL)
3765 {
3766 if (fpclassify (b) == FP_NORMAL)
3767 return a > b ? a : b;
3768 return a;
3769 }
3770 else if (fpclassify (b) == FP_NORMAL)
3771 return b;
3772 return a;
3773 }
3774
3775 static double
3776 dminnm (double a, double b)
3777 {
3778 if (fpclassify (a) == FP_NORMAL)
3779 {
3780 if (fpclassify (b) == FP_NORMAL)
3781 return a < b ? a : b;
3782 return a;
3783 }
3784 else if (fpclassify (b) == FP_NORMAL)
3785 return b;
3786 return a;
3787 }
3788
3789 static void
3790 do_vec_FminmaxNMP (sim_cpu *cpu)
3791 {
3792 /* aarch64_get_instr (cpu)[31] = 0
3793 aarch64_get_instr (cpu)[30] = half (0)/full (1)
3794 aarch64_get_instr (cpu)[29,24] = 10 1110
3795 aarch64_get_instr (cpu)[23] = max(0)/min(1)
3796 aarch64_get_instr (cpu)[22] = float (0)/double (1)
3797 aarch64_get_instr (cpu)[21] = 1
3798 aarch64_get_instr (cpu)[20,16] = Vn
3799 aarch64_get_instr (cpu)[15,10] = 1100 01
3800 aarch64_get_instr (cpu)[9,5] = Vm
3801 aarch64_get_instr (cpu)[4.0] = Vd. */
3802
3803 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3804 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3805 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3806 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3807
3808 NYI_assert (29, 24, 0x2E);
3809 NYI_assert (21, 21, 1);
3810 NYI_assert (15, 10, 0x31);
3811
3812 if (uimm (aarch64_get_instr (cpu), 22, 22))
3813 {
3814 double (* fn)(double, double) = uimm (aarch64_get_instr (cpu), 23, 23)
3815 ? dminnm : dmaxnm;
3816
3817 if (! full)
3818 HALT_NYI;
3819 aarch64_set_vec_double (cpu, vd, 0,
3820 fn (aarch64_get_vec_double (cpu, vn, 0),
3821 aarch64_get_vec_double (cpu, vn, 1)));
3822 aarch64_set_vec_double (cpu, vd, 0,
3823 fn (aarch64_get_vec_double (cpu, vm, 0),
3824 aarch64_get_vec_double (cpu, vm, 1)));
3825 }
3826 else
3827 {
3828 float (* fn)(float, float) = uimm (aarch64_get_instr (cpu), 23, 23)
3829 ? fminnm : fmaxnm;
3830
3831 aarch64_set_vec_float (cpu, vd, 0,
3832 fn (aarch64_get_vec_float (cpu, vn, 0),
3833 aarch64_get_vec_float (cpu, vn, 1)));
3834 if (full)
3835 aarch64_set_vec_float (cpu, vd, 1,
3836 fn (aarch64_get_vec_float (cpu, vn, 2),
3837 aarch64_get_vec_float (cpu, vn, 3)));
3838
3839 aarch64_set_vec_float (cpu, vd, (full ? 2 : 1),
3840 fn (aarch64_get_vec_float (cpu, vm, 0),
3841 aarch64_get_vec_float (cpu, vm, 1)));
3842 if (full)
3843 aarch64_set_vec_float (cpu, vd, 3,
3844 fn (aarch64_get_vec_float (cpu, vm, 2),
3845 aarch64_get_vec_float (cpu, vm, 3)));
3846 }
3847 }
3848
3849 static void
3850 do_vec_AND (sim_cpu *cpu)
3851 {
3852 /* instr[31] = 0
3853 instr[30] = half (0)/full (1)
3854 instr[29,21] = 001110001
3855 instr[20,16] = Vm
3856 instr[15,10] = 000111
3857 instr[9,5] = Vn
3858 instr[4.0] = Vd. */
3859
3860 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3861 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3862 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3863 unsigned i;
3864 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3865
3866 NYI_assert (29, 21, 0x071);
3867 NYI_assert (15, 10, 0x07);
3868
3869 for (i = 0; i < (full ? 4 : 2); i++)
3870 aarch64_set_vec_u32 (cpu, vd, i,
3871 aarch64_get_vec_u32 (cpu, vn, i)
3872 & aarch64_get_vec_u32 (cpu, vm, i));
3873 }
3874
3875 static void
3876 do_vec_BSL (sim_cpu *cpu)
3877 {
3878 /* instr[31] = 0
3879 instr[30] = half (0)/full (1)
3880 instr[29,21] = 101110011
3881 instr[20,16] = Vm
3882 instr[15,10] = 000111
3883 instr[9,5] = Vn
3884 instr[4.0] = Vd. */
3885
3886 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3887 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3888 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3889 unsigned i;
3890 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3891
3892 NYI_assert (29, 21, 0x173);
3893 NYI_assert (15, 10, 0x07);
3894
3895 for (i = 0; i < (full ? 16 : 8); i++)
3896 aarch64_set_vec_u8 (cpu, vd, i,
3897 ( aarch64_get_vec_u8 (cpu, vd, i)
3898 & aarch64_get_vec_u8 (cpu, vn, i))
3899 | ((~ aarch64_get_vec_u8 (cpu, vd, i))
3900 & aarch64_get_vec_u8 (cpu, vm, i)));
3901 }
3902
3903 static void
3904 do_vec_EOR (sim_cpu *cpu)
3905 {
3906 /* instr[31] = 0
3907 instr[30] = half (0)/full (1)
3908 instr[29,21] = 10 1110 001
3909 instr[20,16] = Vm
3910 instr[15,10] = 000111
3911 instr[9,5] = Vn
3912 instr[4.0] = Vd. */
3913
3914 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3915 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3916 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3917 unsigned i;
3918 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3919
3920 NYI_assert (29, 21, 0x171);
3921 NYI_assert (15, 10, 0x07);
3922
3923 for (i = 0; i < (full ? 4 : 2); i++)
3924 aarch64_set_vec_u32 (cpu, vd, i,
3925 aarch64_get_vec_u32 (cpu, vn, i)
3926 ^ aarch64_get_vec_u32 (cpu, vm, i));
3927 }
3928
3929 static void
3930 do_vec_bit (sim_cpu *cpu)
3931 {
3932 /* instr[31] = 0
3933 instr[30] = half (0)/full (1)
3934 instr[29,23] = 10 1110 1
3935 instr[22] = BIT (0) / BIF (1)
3936 instr[21] = 1
3937 instr[20,16] = Vm
3938 instr[15,10] = 0001 11
3939 instr[9,5] = Vn
3940 instr[4.0] = Vd. */
3941
3942 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3943 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3944 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3945 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
3946 unsigned test_false = uimm (aarch64_get_instr (cpu), 22, 22);
3947 unsigned i;
3948
3949 NYI_assert (29, 23, 0x5D);
3950 NYI_assert (21, 21, 1);
3951 NYI_assert (15, 10, 0x07);
3952
3953 if (test_false)
3954 {
3955 for (i = 0; i < (full ? 16 : 8); i++)
3956 if (aarch64_get_vec_u32 (cpu, vn, i) == 0)
3957 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
3958 }
3959 else
3960 {
3961 for (i = 0; i < (full ? 16 : 8); i++)
3962 if (aarch64_get_vec_u32 (cpu, vn, i) != 0)
3963 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vm, i));
3964 }
3965 }
3966
3967 static void
3968 do_vec_ORN (sim_cpu *cpu)
3969 {
3970 /* instr[31] = 0
3971 instr[30] = half (0)/full (1)
3972 instr[29,21] = 00 1110 111
3973 instr[20,16] = Vm
3974 instr[15,10] = 00 0111
3975 instr[9,5] = Vn
3976 instr[4.0] = Vd. */
3977
3978 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
3979 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
3980 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
3981 unsigned i;
3982 int full = uimm (aarch64_get_instr (cpu), 30, 30);
3983
3984 NYI_assert (29, 21, 0x077);
3985 NYI_assert (15, 10, 0x07);
3986
3987 for (i = 0; i < (full ? 16 : 8); i++)
3988 aarch64_set_vec_u8 (cpu, vd, i,
3989 aarch64_get_vec_u8 (cpu, vn, i)
3990 | ~ aarch64_get_vec_u8 (cpu, vm, i));
3991 }
3992
3993 static void
3994 do_vec_ORR (sim_cpu *cpu)
3995 {
3996 /* instr[31] = 0
3997 instr[30] = half (0)/full (1)
3998 instr[29,21] = 00 1110 101
3999 instr[20,16] = Vm
4000 instr[15,10] = 0001 11
4001 instr[9,5] = Vn
4002 instr[4.0] = Vd. */
4003
4004 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4005 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4006 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4007 unsigned i;
4008 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4009
4010 NYI_assert (29, 21, 0x075);
4011 NYI_assert (15, 10, 0x07);
4012
4013 for (i = 0; i < (full ? 16 : 8); i++)
4014 aarch64_set_vec_u8 (cpu, vd, i,
4015 aarch64_get_vec_u8 (cpu, vn, i)
4016 | aarch64_get_vec_u8 (cpu, vm, i));
4017 }
4018
4019 static void
4020 do_vec_BIC (sim_cpu *cpu)
4021 {
4022 /* instr[31] = 0
4023 instr[30] = half (0)/full (1)
4024 instr[29,21] = 00 1110 011
4025 instr[20,16] = Vm
4026 instr[15,10] = 00 0111
4027 instr[9,5] = Vn
4028 instr[4.0] = Vd. */
4029
4030 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4031 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4032 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4033 unsigned i;
4034 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4035
4036 NYI_assert (29, 21, 0x073);
4037 NYI_assert (15, 10, 0x07);
4038
4039 for (i = 0; i < (full ? 16 : 8); i++)
4040 aarch64_set_vec_u8 (cpu, vd, i,
4041 aarch64_get_vec_u8 (cpu, vn, i)
4042 & ~ aarch64_get_vec_u8 (cpu, vm, i));
4043 }
4044
4045 static void
4046 do_vec_XTN (sim_cpu *cpu)
4047 {
4048 /* instr[31] = 0
4049 instr[30] = first part (0)/ second part (1)
4050 instr[29,24] = 00 1110
4051 instr[23,22] = size: byte(00), half(01), word (10)
4052 instr[21,10] = 1000 0100 1010
4053 instr[9,5] = Vs
4054 instr[4,0] = Vd. */
4055
4056 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4057 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4058 unsigned bias = uimm (aarch64_get_instr (cpu), 30, 30);
4059 unsigned i;
4060
4061 NYI_assert (29, 24, 0x0E);
4062 NYI_assert (21, 10, 0x84A);
4063
4064 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4065 {
4066 case 0:
4067 if (bias)
4068 for (i = 0; i < 8; i++)
4069 aarch64_set_vec_u8 (cpu, vd, i + 8,
4070 aarch64_get_vec_u16 (cpu, vs, i) >> 8);
4071 else
4072 for (i = 0; i < 8; i++)
4073 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i));
4074 return;
4075
4076 case 1:
4077 if (bias)
4078 for (i = 0; i < 4; i++)
4079 aarch64_set_vec_u16 (cpu, vd, i + 4,
4080 aarch64_get_vec_u32 (cpu, vs, i) >> 16);
4081 else
4082 for (i = 0; i < 4; i++)
4083 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vs, i));
4084 return;
4085
4086 case 2:
4087 if (bias)
4088 for (i = 0; i < 2; i++)
4089 aarch64_set_vec_u32 (cpu, vd, i + 4,
4090 aarch64_get_vec_u64 (cpu, vs, i) >> 32);
4091 else
4092 for (i = 0; i < 2; i++)
4093 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vs, i));
4094 return;
4095
4096 default:
4097 HALT_UNALLOC;
4098 }
4099 }
4100
4101 static void
4102 do_vec_maxv (sim_cpu *cpu)
4103 {
4104 /* instr[31] = 0
4105 instr[30] = half(0)/full(1)
4106 instr[29] = signed (0)/unsigned(1)
4107 instr[28,24] = 0 1110
4108 instr[23,22] = size: byte(00), half(01), word (10)
4109 instr[21] = 1
4110 instr[20,17] = 1 000
4111 instr[16] = max(0)/min(1)
4112 instr[15,10] = 1010 10
4113 instr[9,5] = V source
4114 instr[4.0] = R dest. */
4115
4116 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4117 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
4118 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4119 unsigned i;
4120
4121 NYI_assert (28, 24, 0x0E);
4122 NYI_assert (21, 21, 1);
4123 NYI_assert (20, 17, 8);
4124 NYI_assert (15, 10, 0x2A);
4125
4126 switch ((uimm (aarch64_get_instr (cpu), 29, 29) << 1)
4127 | uimm (aarch64_get_instr (cpu), 16, 16))
4128 {
4129 case 0: /* SMAXV. */
4130 {
4131 int64_t smax;
4132 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4133 {
4134 case 0:
4135 smax = aarch64_get_vec_s8 (cpu, vs, 0);
4136 for (i = 1; i < (full ? 16 : 8); i++)
4137 smax = max (smax, aarch64_get_vec_s8 (cpu, vs, i));
4138 break;
4139 case 1:
4140 smax = aarch64_get_vec_s16 (cpu, vs, 0);
4141 for (i = 1; i < (full ? 8 : 4); i++)
4142 smax = max (smax, aarch64_get_vec_s16 (cpu, vs, i));
4143 break;
4144 case 2:
4145 smax = aarch64_get_vec_s32 (cpu, vs, 0);
4146 for (i = 1; i < (full ? 4 : 2); i++)
4147 smax = max (smax, aarch64_get_vec_s32 (cpu, vs, i));
4148 break;
4149 default:
4150 case 3:
4151 HALT_UNALLOC;
4152 }
4153 aarch64_set_reg_s64 (cpu, rd, NO_SP, smax);
4154 return;
4155 }
4156
4157 case 1: /* SMINV. */
4158 {
4159 int64_t smin;
4160 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4161 {
4162 case 0:
4163 smin = aarch64_get_vec_s8 (cpu, vs, 0);
4164 for (i = 1; i < (full ? 16 : 8); i++)
4165 smin = min (smin, aarch64_get_vec_s8 (cpu, vs, i));
4166 break;
4167 case 1:
4168 smin = aarch64_get_vec_s16 (cpu, vs, 0);
4169 for (i = 1; i < (full ? 8 : 4); i++)
4170 smin = min (smin, aarch64_get_vec_s16 (cpu, vs, i));
4171 break;
4172 case 2:
4173 smin = aarch64_get_vec_s32 (cpu, vs, 0);
4174 for (i = 1; i < (full ? 4 : 2); i++)
4175 smin = min (smin, aarch64_get_vec_s32 (cpu, vs, i));
4176 break;
4177 default:
4178 case 3:
4179 HALT_UNALLOC;
4180 }
4181 aarch64_set_reg_s64 (cpu, rd, NO_SP, smin);
4182 return;
4183 }
4184
4185 case 2: /* UMAXV. */
4186 {
4187 uint64_t umax;
4188 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4189 {
4190 case 0:
4191 umax = aarch64_get_vec_u8 (cpu, vs, 0);
4192 for (i = 1; i < (full ? 16 : 8); i++)
4193 umax = max (umax, aarch64_get_vec_u8 (cpu, vs, i));
4194 break;
4195 case 1:
4196 umax = aarch64_get_vec_u16 (cpu, vs, 0);
4197 for (i = 1; i < (full ? 8 : 4); i++)
4198 umax = max (umax, aarch64_get_vec_u16 (cpu, vs, i));
4199 break;
4200 case 2:
4201 umax = aarch64_get_vec_u32 (cpu, vs, 0);
4202 for (i = 1; i < (full ? 4 : 2); i++)
4203 umax = max (umax, aarch64_get_vec_u32 (cpu, vs, i));
4204 break;
4205 default:
4206 case 3:
4207 HALT_UNALLOC;
4208 }
4209 aarch64_set_reg_u64 (cpu, rd, NO_SP, umax);
4210 return;
4211 }
4212
4213 case 3: /* UMINV. */
4214 {
4215 uint64_t umin;
4216 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4217 {
4218 case 0:
4219 umin = aarch64_get_vec_u8 (cpu, vs, 0);
4220 for (i = 1; i < (full ? 16 : 8); i++)
4221 umin = min (umin, aarch64_get_vec_u8 (cpu, vs, i));
4222 break;
4223 case 1:
4224 umin = aarch64_get_vec_u16 (cpu, vs, 0);
4225 for (i = 1; i < (full ? 8 : 4); i++)
4226 umin = min (umin, aarch64_get_vec_u16 (cpu, vs, i));
4227 break;
4228 case 2:
4229 umin = aarch64_get_vec_u32 (cpu, vs, 0);
4230 for (i = 1; i < (full ? 4 : 2); i++)
4231 umin = min (umin, aarch64_get_vec_u32 (cpu, vs, i));
4232 break;
4233 default:
4234 case 3:
4235 HALT_UNALLOC;
4236 }
4237 aarch64_set_reg_u64 (cpu, rd, NO_SP, umin);
4238 return;
4239 }
4240
4241 default:
4242 HALT_UNALLOC;
4243 }
4244 }
4245
4246 static void
4247 do_vec_fminmaxV (sim_cpu *cpu)
4248 {
4249 /* instr[31,24] = 0110 1110
4250 instr[23] = max(0)/min(1)
4251 instr[22,14] = 011 0000 11
4252 instr[13,12] = nm(00)/normal(11)
4253 instr[11,10] = 10
4254 instr[9,5] = V source
4255 instr[4.0] = R dest. */
4256
4257 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
4258 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
4259 unsigned i;
4260 float res = aarch64_get_vec_float (cpu, vs, 0);
4261
4262 NYI_assert (31, 24, 0x6E);
4263 NYI_assert (22, 14, 0x0C3);
4264 NYI_assert (11, 10, 2);
4265
4266 if (uimm (aarch64_get_instr (cpu), 23, 23))
4267 {
4268 switch (uimm (aarch64_get_instr (cpu), 13, 12))
4269 {
4270 case 0: /* FMNINNMV. */
4271 for (i = 1; i < 4; i++)
4272 res = fminnm (res, aarch64_get_vec_float (cpu, vs, i));
4273 break;
4274
4275 case 3: /* FMINV. */
4276 for (i = 1; i < 4; i++)
4277 res = min (res, aarch64_get_vec_float (cpu, vs, i));
4278 break;
4279
4280 default:
4281 HALT_NYI;
4282 }
4283 }
4284 else
4285 {
4286 switch (uimm (aarch64_get_instr (cpu), 13, 12))
4287 {
4288 case 0: /* FMNAXNMV. */
4289 for (i = 1; i < 4; i++)
4290 res = fmaxnm (res, aarch64_get_vec_float (cpu, vs, i));
4291 break;
4292
4293 case 3: /* FMAXV. */
4294 for (i = 1; i < 4; i++)
4295 res = max (res, aarch64_get_vec_float (cpu, vs, i));
4296 break;
4297
4298 default:
4299 HALT_NYI;
4300 }
4301 }
4302
4303 aarch64_set_FP_float (cpu, rd, res);
4304 }
4305
4306 static void
4307 do_vec_Fminmax (sim_cpu *cpu)
4308 {
4309 /* instr[31] = 0
4310 instr[30] = half(0)/full(1)
4311 instr[29,24] = 00 1110
4312 instr[23] = max(0)/min(1)
4313 instr[22] = float(0)/double(1)
4314 instr[21] = 1
4315 instr[20,16] = Vm
4316 instr[15,14] = 11
4317 instr[13,12] = nm(00)/normal(11)
4318 instr[11,10] = 01
4319 instr[9,5] = Vn
4320 instr[4,0] = Vd. */
4321
4322 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4323 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4324 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4325 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4326 unsigned min = uimm (aarch64_get_instr (cpu), 23, 23);
4327 unsigned i;
4328
4329 NYI_assert (29, 24, 0x0E);
4330 NYI_assert (21, 21, 1);
4331 NYI_assert (15, 14, 3);
4332 NYI_assert (11, 10, 1);
4333
4334 if (uimm (aarch64_get_instr (cpu), 22, 22))
4335 {
4336 double (* func)(double, double);
4337
4338 if (! full)
4339 HALT_NYI;
4340
4341 if (uimm (aarch64_get_instr (cpu), 13, 12) == 0)
4342 func = min ? dminnm : dmaxnm;
4343 else if (uimm (aarch64_get_instr (cpu), 13, 12) == 3)
4344 func = min ? fmin : fmax;
4345 else
4346 HALT_NYI;
4347
4348 for (i = 0; i < 2; i++)
4349 aarch64_set_vec_double (cpu, vd, i,
4350 func (aarch64_get_vec_double (cpu, vn, i),
4351 aarch64_get_vec_double (cpu, vm, i)));
4352 }
4353 else
4354 {
4355 float (* func)(float, float);
4356
4357 if (uimm (aarch64_get_instr (cpu), 13, 12) == 0)
4358 func = min ? fminnm : fmaxnm;
4359 else if (uimm (aarch64_get_instr (cpu), 13, 12) == 3)
4360 func = min ? fminf : fmaxf;
4361 else
4362 HALT_NYI;
4363
4364 for (i = 0; i < (full ? 4 : 2); i++)
4365 aarch64_set_vec_float (cpu, vd, i,
4366 func (aarch64_get_vec_float (cpu, vn, i),
4367 aarch64_get_vec_float (cpu, vm, i)));
4368 }
4369 }
4370
4371 static void
4372 do_vec_SCVTF (sim_cpu *cpu)
4373 {
4374 /* instr[31] = 0
4375 instr[30] = Q
4376 instr[29,23] = 00 1110 0
4377 instr[22] = float(0)/double(1)
4378 instr[21,10] = 10 0001 1101 10
4379 instr[9,5] = Vn
4380 instr[4,0] = Vd. */
4381
4382 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4383 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4384 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4385 unsigned size = uimm (aarch64_get_instr (cpu), 22, 22);
4386 unsigned i;
4387
4388 NYI_assert (29, 23, 0x1C);
4389 NYI_assert (21, 10, 0x876);
4390
4391 if (size)
4392 {
4393 if (! full)
4394 HALT_UNALLOC;
4395
4396 for (i = 0; i < 2; i++)
4397 {
4398 double val = (double) aarch64_get_vec_u64 (cpu, vn, i);
4399 aarch64_set_vec_double (cpu, vd, i, val);
4400 }
4401 }
4402 else
4403 {
4404 for (i = 0; i < (full ? 4 : 2); i++)
4405 {
4406 float val = (float) aarch64_get_vec_u32 (cpu, vn, i);
4407 aarch64_set_vec_float (cpu, vd, i, val);
4408 }
4409 }
4410 }
4411
4412 #define VEC_CMP(SOURCE, CMP) \
4413 do \
4414 { \
4415 switch (size) \
4416 { \
4417 case 0: \
4418 for (i = 0; i < (full ? 16 : 8); i++) \
4419 aarch64_set_vec_u8 (cpu, vd, i, \
4420 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4421 CMP \
4422 aarch64_get_vec_##SOURCE##8 (cpu, vm, i) \
4423 ? -1 : 0); \
4424 return; \
4425 case 1: \
4426 for (i = 0; i < (full ? 8 : 4); i++) \
4427 aarch64_set_vec_u16 (cpu, vd, i, \
4428 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4429 CMP \
4430 aarch64_get_vec_##SOURCE##16 (cpu, vm, i) \
4431 ? -1 : 0); \
4432 return; \
4433 case 2: \
4434 for (i = 0; i < (full ? 4 : 2); i++) \
4435 aarch64_set_vec_u32 (cpu, vd, i, \
4436 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4437 CMP \
4438 aarch64_get_vec_##SOURCE##32 (cpu, vm, i) \
4439 ? -1 : 0); \
4440 return; \
4441 case 3: \
4442 if (! full) \
4443 HALT_UNALLOC; \
4444 for (i = 0; i < 2; i++) \
4445 aarch64_set_vec_u64 (cpu, vd, i, \
4446 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4447 CMP \
4448 aarch64_get_vec_##SOURCE##64 (cpu, vm, i) \
4449 ? -1ULL : 0); \
4450 return; \
4451 default: \
4452 HALT_UNALLOC; \
4453 } \
4454 } \
4455 while (0)
4456
4457 #define VEC_CMP0(SOURCE, CMP) \
4458 do \
4459 { \
4460 switch (size) \
4461 { \
4462 case 0: \
4463 for (i = 0; i < (full ? 16 : 8); i++) \
4464 aarch64_set_vec_u8 (cpu, vd, i, \
4465 aarch64_get_vec_##SOURCE##8 (cpu, vn, i) \
4466 CMP 0 ? -1 : 0); \
4467 return; \
4468 case 1: \
4469 for (i = 0; i < (full ? 8 : 4); i++) \
4470 aarch64_set_vec_u16 (cpu, vd, i, \
4471 aarch64_get_vec_##SOURCE##16 (cpu, vn, i) \
4472 CMP 0 ? -1 : 0); \
4473 return; \
4474 case 2: \
4475 for (i = 0; i < (full ? 4 : 2); i++) \
4476 aarch64_set_vec_u32 (cpu, vd, i, \
4477 aarch64_get_vec_##SOURCE##32 (cpu, vn, i) \
4478 CMP 0 ? -1 : 0); \
4479 return; \
4480 case 3: \
4481 if (! full) \
4482 HALT_UNALLOC; \
4483 for (i = 0; i < 2; i++) \
4484 aarch64_set_vec_u64 (cpu, vd, i, \
4485 aarch64_get_vec_##SOURCE##64 (cpu, vn, i) \
4486 CMP 0 ? -1ULL : 0); \
4487 return; \
4488 default: \
4489 HALT_UNALLOC; \
4490 } \
4491 } \
4492 while (0)
4493
4494 #define VEC_FCMP0(CMP) \
4495 do \
4496 { \
4497 if (vm != 0) \
4498 HALT_NYI; \
4499 if (uimm (aarch64_get_instr (cpu), 22, 22)) \
4500 { \
4501 if (! full) \
4502 HALT_NYI; \
4503 for (i = 0; i < 2; i++) \
4504 aarch64_set_vec_u64 (cpu, vd, i, \
4505 aarch64_get_vec_double (cpu, vn, i) \
4506 CMP 0.0 ? -1 : 0); \
4507 } \
4508 else \
4509 { \
4510 for (i = 0; i < (full ? 4 : 2); i++) \
4511 aarch64_set_vec_u32 (cpu, vd, i, \
4512 aarch64_get_vec_float (cpu, vn, i) \
4513 CMP 0.0 ? -1 : 0); \
4514 } \
4515 return; \
4516 } \
4517 while (0)
4518
4519 #define VEC_FCMP(CMP) \
4520 do \
4521 { \
4522 if (uimm (aarch64_get_instr (cpu), 22, 22)) \
4523 { \
4524 if (! full) \
4525 HALT_NYI; \
4526 for (i = 0; i < 2; i++) \
4527 aarch64_set_vec_u64 (cpu, vd, i, \
4528 aarch64_get_vec_double (cpu, vn, i) \
4529 CMP \
4530 aarch64_get_vec_double (cpu, vm, i) \
4531 ? -1 : 0); \
4532 } \
4533 else \
4534 { \
4535 for (i = 0; i < (full ? 4 : 2); i++) \
4536 aarch64_set_vec_u32 (cpu, vd, i, \
4537 aarch64_get_vec_float (cpu, vn, i) \
4538 CMP \
4539 aarch64_get_vec_float (cpu, vm, i) \
4540 ? -1 : 0); \
4541 } \
4542 return; \
4543 } \
4544 while (0)
4545
4546 static void
4547 do_vec_compare (sim_cpu *cpu)
4548 {
4549 /* instr[31] = 0
4550 instr[30] = half(0)/full(1)
4551 instr[29] = part-of-comparison-type
4552 instr[28,24] = 0 1110
4553 instr[23,22] = size of integer compares: byte(00), half(01), word (10), long (11)
4554 type of float compares: single (-0) / double (-1)
4555 instr[21] = 1
4556 instr[20,16] = Vm or 00000 (compare vs 0)
4557 instr[15,10] = part-of-comparison-type
4558 instr[9,5] = Vn
4559 instr[4.0] = Vd. */
4560
4561 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4562 int size = uimm (aarch64_get_instr (cpu), 23, 22);
4563 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4564 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4565 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4566 unsigned i;
4567
4568 NYI_assert (28, 24, 0x0E);
4569 NYI_assert (21, 21, 1);
4570
4571 if ((uimm (aarch64_get_instr (cpu), 11, 11)
4572 && uimm (aarch64_get_instr (cpu), 14, 14))
4573 || ((uimm (aarch64_get_instr (cpu), 11, 11) == 0
4574 && uimm (aarch64_get_instr (cpu), 10, 10) == 0)))
4575 {
4576 /* A compare vs 0. */
4577 if (vm != 0)
4578 {
4579 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x2A)
4580 do_vec_maxv (cpu);
4581 else if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x32
4582 || uimm (aarch64_get_instr (cpu), 15, 10) == 0x3E)
4583 do_vec_fminmaxV (cpu);
4584 else if (uimm (aarch64_get_instr (cpu), 29, 23) == 0x1C
4585 && uimm (aarch64_get_instr (cpu), 21, 10) == 0x876)
4586 do_vec_SCVTF (cpu);
4587 else
4588 HALT_NYI;
4589 return;
4590 }
4591 }
4592
4593 if (uimm (aarch64_get_instr (cpu), 14, 14))
4594 {
4595 /* A floating point compare. */
4596 unsigned decode = (uimm (aarch64_get_instr (cpu), 29, 29) << 5)
4597 | (uimm (aarch64_get_instr (cpu), 23, 23) << 4)
4598 | uimm (aarch64_get_instr (cpu), 13, 10);
4599
4600 NYI_assert (15, 15, 1);
4601
4602 switch (decode)
4603 {
4604 case /* 0b010010: GT#0 */ 0x12: VEC_FCMP0 (>);
4605 case /* 0b110010: GE#0 */ 0x32: VEC_FCMP0 (>=);
4606 case /* 0b010110: EQ#0 */ 0x16: VEC_FCMP0 (==);
4607 case /* 0b110110: LE#0 */ 0x36: VEC_FCMP0 (<=);
4608 case /* 0b011010: LT#0 */ 0x1A: VEC_FCMP0 (<);
4609 case /* 0b111001: GT */ 0x39: VEC_FCMP (>);
4610 case /* 0b101001: GE */ 0x29: VEC_FCMP (>=);
4611 case /* 0b001001: EQ */ 0x09: VEC_FCMP (==);
4612
4613 default:
4614 HALT_NYI;
4615 }
4616 }
4617 else
4618 {
4619 unsigned decode = (uimm (aarch64_get_instr (cpu), 29, 29) << 6)
4620 | uimm (aarch64_get_instr (cpu), 15, 10);
4621
4622 switch (decode)
4623 {
4624 case 0x0D: /* 0001101 GT */ VEC_CMP (s, > );
4625 case 0x0F: /* 0001111 GE */ VEC_CMP (s, >= );
4626 case 0x22: /* 0100010 GT #0 */ VEC_CMP0 (s, > );
4627 case 0x26: /* 0100110 EQ #0 */ VEC_CMP0 (s, == );
4628 case 0x2A: /* 0101010 LT #0 */ VEC_CMP0 (s, < );
4629 case 0x4D: /* 1001101 HI */ VEC_CMP (u, > );
4630 case 0x4F: /* 1001111 HS */ VEC_CMP (u, >= );
4631 case 0x62: /* 1100010 GE #0 */ VEC_CMP0 (s, >= );
4632 case 0x63: /* 1100011 EQ */ VEC_CMP (u, == );
4633 case 0x66: /* 1100110 LE #0 */ VEC_CMP0 (s, <= );
4634 default:
4635 if (vm == 0)
4636 HALT_NYI;
4637 do_vec_maxv (cpu);
4638 }
4639 }
4640 }
4641
4642 static void
4643 do_vec_SSHL (sim_cpu *cpu)
4644 {
4645 /* instr[31] = 0
4646 instr[30] = first part (0)/ second part (1)
4647 instr[29,24] = 00 1110
4648 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4649 instr[21] = 1
4650 instr[20,16] = Vm
4651 instr[15,10] = 0100 01
4652 instr[9,5] = Vn
4653 instr[4,0] = Vd. */
4654
4655 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4656 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4657 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4658 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4659 unsigned i;
4660
4661 NYI_assert (29, 24, 0x0E);
4662 NYI_assert (21, 21, 1);
4663 NYI_assert (15, 10, 0x11);
4664
4665 /* FIXME: What is a signed shift left in this context ?. */
4666
4667 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4668 {
4669 case 0:
4670 for (i = 0; i < (full ? 16 : 8); i++)
4671 aarch64_set_vec_s8 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vn, i)
4672 << aarch64_get_vec_s8 (cpu, vm, i));
4673 return;
4674
4675 case 1:
4676 for (i = 0; i < (full ? 8 : 4); i++)
4677 aarch64_set_vec_s16 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vn, i)
4678 << aarch64_get_vec_s16 (cpu, vm, i));
4679 return;
4680
4681 case 2:
4682 for (i = 0; i < (full ? 4 : 2); i++)
4683 aarch64_set_vec_s32 (cpu, vd, i, aarch64_get_vec_s32 (cpu, vn, i)
4684 << aarch64_get_vec_s32 (cpu, vm, i));
4685 return;
4686
4687 case 3:
4688 if (! full)
4689 HALT_UNALLOC;
4690 for (i = 0; i < 2; i++)
4691 aarch64_set_vec_s64 (cpu, vd, i, aarch64_get_vec_s64 (cpu, vn, i)
4692 << aarch64_get_vec_s64 (cpu, vm, i));
4693 return;
4694
4695 default:
4696 HALT_NYI;
4697 }
4698 }
4699
4700 static void
4701 do_vec_USHL (sim_cpu *cpu)
4702 {
4703 /* instr[31] = 0
4704 instr[30] = first part (0)/ second part (1)
4705 instr[29,24] = 10 1110
4706 instr[23,22] = size: byte(00), half(01), word (10), long (11)
4707 instr[21] = 1
4708 instr[20,16] = Vm
4709 instr[15,10] = 0100 01
4710 instr[9,5] = Vn
4711 instr[4,0] = Vd */
4712
4713 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
4714 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4715 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4716 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4717 unsigned i;
4718
4719 NYI_assert (29, 24, 0x2E);
4720 NYI_assert (15, 10, 0x11);
4721
4722 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4723 {
4724 case 0:
4725 for (i = 0; i < (full ? 16 : 8); i++)
4726 aarch64_set_vec_u8 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vn, i)
4727 << aarch64_get_vec_u8 (cpu, vm, i));
4728 return;
4729
4730 case 1:
4731 for (i = 0; i < (full ? 8 : 4); i++)
4732 aarch64_set_vec_u16 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vn, i)
4733 << aarch64_get_vec_u16 (cpu, vm, i));
4734 return;
4735
4736 case 2:
4737 for (i = 0; i < (full ? 4 : 2); i++)
4738 aarch64_set_vec_u32 (cpu, vd, i, aarch64_get_vec_u32 (cpu, vn, i)
4739 << aarch64_get_vec_u32 (cpu, vm, i));
4740 return;
4741
4742 case 3:
4743 if (! full)
4744 HALT_UNALLOC;
4745 for (i = 0; i < 2; i++)
4746 aarch64_set_vec_u64 (cpu, vd, i, aarch64_get_vec_u64 (cpu, vn, i)
4747 << aarch64_get_vec_u64 (cpu, vm, i));
4748 return;
4749
4750 default:
4751 HALT_NYI;
4752 }
4753 }
4754
4755 static void
4756 do_vec_FMLA (sim_cpu *cpu)
4757 {
4758 /* instr[31] = 0
4759 instr[30] = full/half selector
4760 instr[29,23] = 0011100
4761 instr[22] = size: 0=>float, 1=>double
4762 instr[21] = 1
4763 instr[20,16] = Vn
4764 instr[15,10] = 1100 11
4765 instr[9,5] = Vm
4766 instr[4.0] = Vd. */
4767
4768 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4769 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4770 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4771 unsigned i;
4772 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4773
4774 NYI_assert (29, 23, 0x1C);
4775 NYI_assert (21, 21, 1);
4776 NYI_assert (15, 10, 0x33);
4777
4778 if (uimm (aarch64_get_instr (cpu), 22, 22))
4779 {
4780 if (! full)
4781 HALT_UNALLOC;
4782 for (i = 0; i < 2; i++)
4783 aarch64_set_vec_double (cpu, vd, i,
4784 aarch64_get_vec_double (cpu, vn, i) *
4785 aarch64_get_vec_double (cpu, vm, i) +
4786 aarch64_get_vec_double (cpu, vd, i));
4787 }
4788 else
4789 {
4790 for (i = 0; i < (full ? 4 : 2); i++)
4791 aarch64_set_vec_float (cpu, vd, i,
4792 aarch64_get_vec_float (cpu, vn, i) *
4793 aarch64_get_vec_float (cpu, vm, i) +
4794 aarch64_get_vec_float (cpu, vd, i));
4795 }
4796 }
4797
4798 static void
4799 do_vec_max (sim_cpu *cpu)
4800 {
4801 /* instr[31] = 0
4802 instr[30] = full/half selector
4803 instr[29] = SMAX (0) / UMAX (1)
4804 instr[28,24] = 0 1110
4805 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4806 instr[21] = 1
4807 instr[20,16] = Vn
4808 instr[15,10] = 0110 01
4809 instr[9,5] = Vm
4810 instr[4.0] = Vd. */
4811
4812 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4813 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4814 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4815 unsigned i;
4816 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4817
4818 NYI_assert (28, 24, 0x0E);
4819 NYI_assert (21, 21, 1);
4820 NYI_assert (15, 10, 0x19);
4821
4822 if (uimm (aarch64_get_instr (cpu), 29, 29))
4823 {
4824 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4825 {
4826 case 0:
4827 for (i = 0; i < (full ? 16 : 8); i++)
4828 aarch64_set_vec_u8 (cpu, vd, i,
4829 aarch64_get_vec_u8 (cpu, vn, i)
4830 > aarch64_get_vec_u8 (cpu, vm, i)
4831 ? aarch64_get_vec_u8 (cpu, vn, i)
4832 : aarch64_get_vec_u8 (cpu, vm, i));
4833 return;
4834
4835 case 1:
4836 for (i = 0; i < (full ? 8 : 4); i++)
4837 aarch64_set_vec_u16 (cpu, vd, i,
4838 aarch64_get_vec_u16 (cpu, vn, i)
4839 > aarch64_get_vec_u16 (cpu, vm, i)
4840 ? aarch64_get_vec_u16 (cpu, vn, i)
4841 : aarch64_get_vec_u16 (cpu, vm, i));
4842 return;
4843
4844 case 2:
4845 for (i = 0; i < (full ? 4 : 2); i++)
4846 aarch64_set_vec_u32 (cpu, vd, i,
4847 aarch64_get_vec_u32 (cpu, vn, i)
4848 > aarch64_get_vec_u32 (cpu, vm, i)
4849 ? aarch64_get_vec_u32 (cpu, vn, i)
4850 : aarch64_get_vec_u32 (cpu, vm, i));
4851 return;
4852
4853 default:
4854 case 3:
4855 HALT_UNALLOC;
4856 }
4857 }
4858 else
4859 {
4860 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4861 {
4862 case 0:
4863 for (i = 0; i < (full ? 16 : 8); i++)
4864 aarch64_set_vec_s8 (cpu, vd, i,
4865 aarch64_get_vec_s8 (cpu, vn, i)
4866 > aarch64_get_vec_s8 (cpu, vm, i)
4867 ? aarch64_get_vec_s8 (cpu, vn, i)
4868 : aarch64_get_vec_s8 (cpu, vm, i));
4869 return;
4870
4871 case 1:
4872 for (i = 0; i < (full ? 8 : 4); i++)
4873 aarch64_set_vec_s16 (cpu, vd, i,
4874 aarch64_get_vec_s16 (cpu, vn, i)
4875 > aarch64_get_vec_s16 (cpu, vm, i)
4876 ? aarch64_get_vec_s16 (cpu, vn, i)
4877 : aarch64_get_vec_s16 (cpu, vm, i));
4878 return;
4879
4880 case 2:
4881 for (i = 0; i < (full ? 4 : 2); i++)
4882 aarch64_set_vec_s32 (cpu, vd, i,
4883 aarch64_get_vec_s32 (cpu, vn, i)
4884 > aarch64_get_vec_s32 (cpu, vm, i)
4885 ? aarch64_get_vec_s32 (cpu, vn, i)
4886 : aarch64_get_vec_s32 (cpu, vm, i));
4887 return;
4888
4889 default:
4890 case 3:
4891 HALT_UNALLOC;
4892 }
4893 }
4894 }
4895
4896 static void
4897 do_vec_min (sim_cpu *cpu)
4898 {
4899 /* instr[31] = 0
4900 instr[30] = full/half selector
4901 instr[29] = SMIN (0) / UMIN (1)
4902 instr[28,24] = 0 1110
4903 instr[23,22] = size: 00=> 8-bit, 01=> 16-bit, 10=> 32-bit
4904 instr[21] = 1
4905 instr[20,16] = Vn
4906 instr[15,10] = 0110 11
4907 instr[9,5] = Vm
4908 instr[4.0] = Vd. */
4909
4910 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
4911 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
4912 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
4913 unsigned i;
4914 int full = uimm (aarch64_get_instr (cpu), 30, 30);
4915
4916 NYI_assert (28, 24, 0x0E);
4917 NYI_assert (21, 21, 1);
4918 NYI_assert (15, 10, 0x1B);
4919
4920 if (uimm (aarch64_get_instr (cpu), 29, 29))
4921 {
4922 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4923 {
4924 case 0:
4925 for (i = 0; i < (full ? 16 : 8); i++)
4926 aarch64_set_vec_u8 (cpu, vd, i,
4927 aarch64_get_vec_u8 (cpu, vn, i)
4928 < aarch64_get_vec_u8 (cpu, vm, i)
4929 ? aarch64_get_vec_u8 (cpu, vn, i)
4930 : aarch64_get_vec_u8 (cpu, vm, i));
4931 return;
4932
4933 case 1:
4934 for (i = 0; i < (full ? 8 : 4); i++)
4935 aarch64_set_vec_u16 (cpu, vd, i,
4936 aarch64_get_vec_u16 (cpu, vn, i)
4937 < aarch64_get_vec_u16 (cpu, vm, i)
4938 ? aarch64_get_vec_u16 (cpu, vn, i)
4939 : aarch64_get_vec_u16 (cpu, vm, i));
4940 return;
4941
4942 case 2:
4943 for (i = 0; i < (full ? 4 : 2); i++)
4944 aarch64_set_vec_u32 (cpu, vd, i,
4945 aarch64_get_vec_u32 (cpu, vn, i)
4946 < aarch64_get_vec_u32 (cpu, vm, i)
4947 ? aarch64_get_vec_u32 (cpu, vn, i)
4948 : aarch64_get_vec_u32 (cpu, vm, i));
4949 return;
4950
4951 default:
4952 case 3:
4953 HALT_UNALLOC;
4954 }
4955 }
4956 else
4957 {
4958 switch (uimm (aarch64_get_instr (cpu), 23, 22))
4959 {
4960 case 0:
4961 for (i = 0; i < (full ? 16 : 8); i++)
4962 aarch64_set_vec_s8 (cpu, vd, i,
4963 aarch64_get_vec_s8 (cpu, vn, i)
4964 < aarch64_get_vec_s8 (cpu, vm, i)
4965 ? aarch64_get_vec_s8 (cpu, vn, i)
4966 : aarch64_get_vec_s8 (cpu, vm, i));
4967 return;
4968
4969 case 1:
4970 for (i = 0; i < (full ? 8 : 4); i++)
4971 aarch64_set_vec_s16 (cpu, vd, i,
4972 aarch64_get_vec_s16 (cpu, vn, i)
4973 < aarch64_get_vec_s16 (cpu, vm, i)
4974 ? aarch64_get_vec_s16 (cpu, vn, i)
4975 : aarch64_get_vec_s16 (cpu, vm, i));
4976 return;
4977
4978 case 2:
4979 for (i = 0; i < (full ? 4 : 2); i++)
4980 aarch64_set_vec_s32 (cpu, vd, i,
4981 aarch64_get_vec_s32 (cpu, vn, i)
4982 < aarch64_get_vec_s32 (cpu, vm, i)
4983 ? aarch64_get_vec_s32 (cpu, vn, i)
4984 : aarch64_get_vec_s32 (cpu, vm, i));
4985 return;
4986
4987 default:
4988 case 3:
4989 HALT_UNALLOC;
4990 }
4991 }
4992 }
4993
4994 static void
4995 do_vec_sub_long (sim_cpu *cpu)
4996 {
4997 /* instr[31] = 0
4998 instr[30] = lower (0) / upper (1)
4999 instr[29] = signed (0) / unsigned (1)
5000 instr[28,24] = 0 1110
5001 instr[23,22] = size: bytes (00), half (01), word (10)
5002 instr[21] = 1
5003 insrt[20,16] = Vm
5004 instr[15,10] = 0010 00
5005 instr[9,5] = Vn
5006 instr[4,0] = V dest. */
5007
5008 unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
5009 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5010 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5011 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5012 unsigned bias = 0;
5013 unsigned i;
5014
5015 NYI_assert (28, 24, 0x0E);
5016 NYI_assert (21, 21, 1);
5017 NYI_assert (15, 10, 0x08);
5018
5019 if (size == 3)
5020 HALT_UNALLOC;
5021
5022 switch (uimm (aarch64_get_instr (cpu), 30, 29))
5023 {
5024 case 2: /* SSUBL2. */
5025 bias = 2;
5026 case 0: /* SSUBL. */
5027 switch (size)
5028 {
5029 case 0:
5030 bias *= 3;
5031 for (i = 0; i < 8; i++)
5032 aarch64_set_vec_s16 (cpu, vd, i,
5033 aarch64_get_vec_s8 (cpu, vn, i + bias)
5034 - aarch64_get_vec_s8 (cpu, vm, i + bias));
5035 break;
5036
5037 case 1:
5038 bias *= 2;
5039 for (i = 0; i < 4; i++)
5040 aarch64_set_vec_s32 (cpu, vd, i,
5041 aarch64_get_vec_s16 (cpu, vn, i + bias)
5042 - aarch64_get_vec_s16 (cpu, vm, i + bias));
5043 break;
5044
5045 case 2:
5046 for (i = 0; i < 2; i++)
5047 aarch64_set_vec_s64 (cpu, vd, i,
5048 aarch64_get_vec_s32 (cpu, vn, i + bias)
5049 - aarch64_get_vec_s32 (cpu, vm, i + bias));
5050 break;
5051
5052 default:
5053 HALT_UNALLOC;
5054 }
5055 break;
5056
5057 case 3: /* USUBL2. */
5058 bias = 2;
5059 case 1: /* USUBL. */
5060 switch (size)
5061 {
5062 case 0:
5063 bias *= 3;
5064 for (i = 0; i < 8; i++)
5065 aarch64_set_vec_u16 (cpu, vd, i,
5066 aarch64_get_vec_u8 (cpu, vn, i + bias)
5067 - aarch64_get_vec_u8 (cpu, vm, i + bias));
5068 break;
5069
5070 case 1:
5071 bias *= 2;
5072 for (i = 0; i < 4; i++)
5073 aarch64_set_vec_u32 (cpu, vd, i,
5074 aarch64_get_vec_u16 (cpu, vn, i + bias)
5075 - aarch64_get_vec_u16 (cpu, vm, i + bias));
5076 break;
5077
5078 case 2:
5079 for (i = 0; i < 2; i++)
5080 aarch64_set_vec_u64 (cpu, vd, i,
5081 aarch64_get_vec_u32 (cpu, vn, i + bias)
5082 - aarch64_get_vec_u32 (cpu, vm, i + bias));
5083 break;
5084
5085 default:
5086 HALT_UNALLOC;
5087 }
5088 break;
5089 }
5090 }
5091
5092 #define DO_ADDP(FN) \
5093 do \
5094 { \
5095 for (i = 0; i < range; i++) \
5096 { \
5097 aarch64_set_vec_##FN (cpu, vd, i, \
5098 aarch64_get_vec_##FN (cpu, vn, i * 2) \
5099 + aarch64_get_vec_##FN (cpu, vn, i * 2 + 1)); \
5100 aarch64_set_vec_##FN (cpu, vd, i + range, \
5101 aarch64_get_vec_##FN (cpu, vm, i * 2) \
5102 + aarch64_get_vec_##FN (cpu, vm, i * 2 + 1)); \
5103 } \
5104 } \
5105 while (0)
5106
5107 static void
5108 do_vec_ADDP (sim_cpu *cpu)
5109 {
5110 /* instr[31] = 0
5111 instr[30] = half(0)/full(1)
5112 instr[29,24] = 00 1110
5113 instr[23,22] = size: bytes (00), half (01), word (10), long (11)
5114 instr[21] = 1
5115 insrt[20,16] = Vm
5116 instr[15,10] = 1011 11
5117 instr[9,5] = Vn
5118 instr[4,0] = V dest. */
5119
5120 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5121 unsigned size = uimm (aarch64_get_instr (cpu), 23, 22);
5122 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5123 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5124 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5125 unsigned i, range;
5126
5127 NYI_assert (29, 24, 0x0E);
5128 NYI_assert (21, 21, 1);
5129 NYI_assert (15, 10, 0x2F);
5130
5131 switch (size)
5132 {
5133 case 0:
5134 range = full ? 8 : 4;
5135 DO_ADDP (u8);
5136 return;
5137
5138 case 1:
5139 range = full ? 4 : 2;
5140 DO_ADDP (u16);
5141 return;
5142
5143 case 2:
5144 range = full ? 2 : 1;
5145 DO_ADDP (u32);
5146 return;
5147
5148 case 3:
5149 if (! full)
5150 HALT_UNALLOC;
5151 range = 1;
5152 DO_ADDP (u64);
5153 return;
5154
5155 default:
5156 HALT_NYI;
5157 }
5158 }
5159
5160 static void
5161 do_vec_UMOV (sim_cpu *cpu)
5162 {
5163 /* instr[31] = 0
5164 instr[30] = 32-bit(0)/64-bit(1)
5165 instr[29,21] = 00 1110 000
5166 insrt[20,16] = size & index
5167 instr[15,10] = 0011 11
5168 instr[9,5] = V source
5169 instr[4,0] = R dest. */
5170
5171 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5172 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
5173 unsigned index;
5174
5175 NYI_assert (29, 21, 0x070);
5176 NYI_assert (15, 10, 0x0F);
5177
5178 if (uimm (aarch64_get_instr (cpu), 16, 16))
5179 {
5180 /* Byte transfer. */
5181 index = uimm (aarch64_get_instr (cpu), 20, 17);
5182 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5183 aarch64_get_vec_u8 (cpu, vs, index));
5184 }
5185 else if (uimm (aarch64_get_instr (cpu), 17, 17))
5186 {
5187 index = uimm (aarch64_get_instr (cpu), 20, 18);
5188 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5189 aarch64_get_vec_u16 (cpu, vs, index));
5190 }
5191 else if (uimm (aarch64_get_instr (cpu), 18, 18))
5192 {
5193 index = uimm (aarch64_get_instr (cpu), 20, 19);
5194 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5195 aarch64_get_vec_u32 (cpu, vs, index));
5196 }
5197 else
5198 {
5199 if (uimm (aarch64_get_instr (cpu), 30, 30) != 1)
5200 HALT_UNALLOC;
5201
5202 index = uimm (aarch64_get_instr (cpu), 20, 20);
5203 aarch64_set_reg_u64 (cpu, rd, NO_SP,
5204 aarch64_get_vec_u64 (cpu, vs, index));
5205 }
5206 }
5207
5208 static void
5209 do_vec_FABS (sim_cpu *cpu)
5210 {
5211 /* instr[31] = 0
5212 instr[30] = half(0)/full(1)
5213 instr[29,23] = 00 1110 1
5214 instr[22] = float(0)/double(1)
5215 instr[21,16] = 10 0000
5216 instr[15,10] = 1111 10
5217 instr[9,5] = Vn
5218 instr[4,0] = Vd. */
5219
5220 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5221 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5222 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5223 unsigned i;
5224
5225 NYI_assert (29, 23, 0x1D);
5226 NYI_assert (21, 10, 0x83E);
5227
5228 if (uimm (aarch64_get_instr (cpu), 22, 22))
5229 {
5230 if (! full)
5231 HALT_NYI;
5232
5233 for (i = 0; i < 2; i++)
5234 aarch64_set_vec_double (cpu, vd, i,
5235 fabs (aarch64_get_vec_double (cpu, vn, i)));
5236 }
5237 else
5238 {
5239 for (i = 0; i < (full ? 4 : 2); i++)
5240 aarch64_set_vec_float (cpu, vd, i,
5241 fabsf (aarch64_get_vec_float (cpu, vn, i)));
5242 }
5243 }
5244
5245 static void
5246 do_vec_FCVTZS (sim_cpu *cpu)
5247 {
5248 /* instr[31] = 0
5249 instr[30] = half (0) / all (1)
5250 instr[29,23] = 00 1110 1
5251 instr[22] = single (0) / double (1)
5252 instr[21,10] = 10 0001 1011 10
5253 instr[9,5] = Rn
5254 instr[4,0] = Rd. */
5255
5256 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
5257 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
5258 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5259 unsigned i;
5260
5261 NYI_assert (31, 31, 0);
5262 NYI_assert (29, 23, 0x1D);
5263 NYI_assert (21, 10, 0x86E);
5264
5265 if (uimm (aarch64_get_instr (cpu), 22, 22))
5266 {
5267 if (! full)
5268 HALT_UNALLOC;
5269
5270 for (i = 0; i < 2; i++)
5271 aarch64_set_vec_s64 (cpu, rd, i,
5272 (int64_t) aarch64_get_vec_double (cpu, rn, i));
5273 }
5274 else
5275 for (i = 0; i < (full ? 4 : 2); i++)
5276 aarch64_set_vec_s32 (cpu, rd, i,
5277 (int32_t) aarch64_get_vec_float (cpu, rn, i));
5278 }
5279
5280 static void
5281 do_vec_op1 (sim_cpu *cpu)
5282 {
5283 /* instr[31] = 0
5284 instr[30] = half/full
5285 instr[29,24] = 00 1110
5286 instr[23,21] = ???
5287 instr[20,16] = Vm
5288 instr[15,10] = sub-opcode
5289 instr[9,5] = Vn
5290 instr[4,0] = Vd */
5291 NYI_assert (29, 24, 0x0E);
5292
5293 if (uimm (aarch64_get_instr (cpu), 21, 21) == 0)
5294 {
5295 if (uimm (aarch64_get_instr (cpu), 23, 22) == 0)
5296 {
5297 if (uimm (aarch64_get_instr (cpu), 30, 30) == 1
5298 && uimm (aarch64_get_instr (cpu), 17, 14) == 0
5299 && uimm (aarch64_get_instr (cpu), 12, 10) == 7)
5300 return do_vec_ins_2 (cpu);
5301
5302 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5303 {
5304 case 0x01: do_vec_DUP_vector_into_vector (cpu); return;
5305 case 0x03: do_vec_DUP_scalar_into_vector (cpu); return;
5306 case 0x07: do_vec_INS (cpu); return;
5307 case 0x0A: do_vec_TRN (cpu); return;
5308
5309 case 0x0F:
5310 if (uimm (aarch64_get_instr (cpu), 17, 16) == 0)
5311 {
5312 do_vec_MOV_into_scalar (cpu);
5313 return;
5314 }
5315 break;
5316
5317 case 0x00:
5318 case 0x08:
5319 case 0x10:
5320 case 0x18:
5321 do_vec_TBL (cpu); return;
5322
5323 case 0x06:
5324 case 0x16:
5325 do_vec_UZP (cpu); return;
5326
5327 case 0x0E:
5328 case 0x1E:
5329 do_vec_ZIP (cpu); return;
5330
5331 default:
5332 HALT_NYI;
5333 }
5334 }
5335
5336 switch (uimm (aarch64_get_instr (cpu), 13, 10))
5337 {
5338 case 0x6: do_vec_UZP (cpu); return;
5339 case 0xE: do_vec_ZIP (cpu); return;
5340 case 0xA: do_vec_TRN (cpu); return;
5341 case 0xF: do_vec_UMOV (cpu); return;
5342 default: HALT_NYI;
5343 }
5344 }
5345
5346 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5347 {
5348 case 0x07:
5349 switch (uimm (aarch64_get_instr (cpu), 23, 21))
5350 {
5351 case 1: do_vec_AND (cpu); return;
5352 case 3: do_vec_BIC (cpu); return;
5353 case 5: do_vec_ORR (cpu); return;
5354 case 7: do_vec_ORN (cpu); return;
5355 default: HALT_NYI;
5356 }
5357
5358 case 0x08: do_vec_sub_long (cpu); return;
5359 case 0x0a: do_vec_XTN (cpu); return;
5360 case 0x11: do_vec_SSHL (cpu); return;
5361 case 0x19: do_vec_max (cpu); return;
5362 case 0x1B: do_vec_min (cpu); return;
5363 case 0x21: do_vec_add (cpu); return;
5364 case 0x25: do_vec_MLA (cpu); return;
5365 case 0x27: do_vec_mul (cpu); return;
5366 case 0x2F: do_vec_ADDP (cpu); return;
5367 case 0x30: do_vec_mull (cpu); return;
5368 case 0x33: do_vec_FMLA (cpu); return;
5369 case 0x35: do_vec_fadd (cpu); return;
5370
5371 case 0x2E:
5372 switch (uimm (aarch64_get_instr (cpu), 20, 16))
5373 {
5374 case 0x00: do_vec_ABS (cpu); return;
5375 case 0x01: do_vec_FCVTZS (cpu); return;
5376 case 0x11: do_vec_ADDV (cpu); return;
5377 default: HALT_NYI;
5378 }
5379
5380 case 0x31:
5381 case 0x3B:
5382 do_vec_Fminmax (cpu); return;
5383
5384 case 0x0D:
5385 case 0x0F:
5386 case 0x22:
5387 case 0x23:
5388 case 0x26:
5389 case 0x2A:
5390 case 0x32:
5391 case 0x36:
5392 case 0x39:
5393 case 0x3A:
5394 do_vec_compare (cpu); return;
5395
5396 case 0x3E:
5397 do_vec_FABS (cpu); return;
5398
5399 default:
5400 HALT_NYI;
5401 }
5402 }
5403
5404 static void
5405 do_vec_xtl (sim_cpu *cpu)
5406 {
5407 /* instr[31] = 0
5408 instr[30,29] = SXTL (00), UXTL (01), SXTL2 (10), UXTL2 (11)
5409 instr[28,22] = 0 1111 00
5410 instr[21,16] = size & shift (USHLL, SSHLL, USHLL2, SSHLL2)
5411 instr[15,10] = 1010 01
5412 instr[9,5] = V source
5413 instr[4,0] = V dest. */
5414
5415 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5416 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5417 unsigned i, shift, bias = 0;
5418
5419 NYI_assert (28, 22, 0x3C);
5420 NYI_assert (15, 10, 0x29);
5421
5422 switch (uimm (aarch64_get_instr (cpu), 30, 29))
5423 {
5424 case 2: /* SXTL2, SSHLL2. */
5425 bias = 2;
5426 case 0: /* SXTL, SSHLL. */
5427 if (uimm (aarch64_get_instr (cpu), 21, 21))
5428 {
5429 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5430 aarch64_set_vec_s64
5431 (cpu, vd, 0, aarch64_get_vec_s32 (cpu, vs, bias) << shift);
5432 aarch64_set_vec_s64
5433 (cpu, vd, 1, aarch64_get_vec_s32 (cpu, vs, bias + 1) << shift);
5434 }
5435 else if (uimm (aarch64_get_instr (cpu), 20, 20))
5436 {
5437 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5438 bias *= 2;
5439 for (i = 0; i < 4; i++)
5440 aarch64_set_vec_s32
5441 (cpu, vd, i, aarch64_get_vec_s16 (cpu, vs, i + bias) << shift);
5442 }
5443 else
5444 {
5445 NYI_assert (19, 19, 1);
5446
5447 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5448 bias *= 3;
5449 for (i = 0; i < 8; i++)
5450 aarch64_set_vec_s16
5451 (cpu, vd, i, aarch64_get_vec_s8 (cpu, vs, i + bias) << shift);
5452 }
5453 return;
5454
5455 case 3: /* UXTL2, USHLL2. */
5456 bias = 2;
5457 case 1: /* UXTL, USHLL. */
5458 if (uimm (aarch64_get_instr (cpu), 21, 21))
5459 {
5460 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5461 aarch64_set_vec_u64
5462 (cpu, vd, 0, aarch64_get_vec_u32 (cpu, vs, bias) << shift);
5463 aarch64_set_vec_u64
5464 (cpu, vd, 1, aarch64_get_vec_u32 (cpu, vs, bias + 1) << shift);
5465 }
5466 else if (uimm (aarch64_get_instr (cpu), 20, 20))
5467 {
5468 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5469 bias *= 2;
5470 for (i = 0; i < 4; i++)
5471 aarch64_set_vec_u32
5472 (cpu, vd, i, aarch64_get_vec_u16 (cpu, vs, i + bias) << shift);
5473 }
5474 else
5475 {
5476 NYI_assert (19, 19, 1);
5477
5478 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5479 bias *= 3;
5480 for (i = 0; i < 8; i++)
5481 aarch64_set_vec_u16
5482 (cpu, vd, i, aarch64_get_vec_u8 (cpu, vs, i + bias) << shift);
5483 }
5484 return;
5485
5486 default:
5487 HALT_NYI;
5488 }
5489 }
5490
5491 static void
5492 do_vec_SHL (sim_cpu *cpu)
5493 {
5494 /* instr [31] = 0
5495 instr [30] = half(0)/full(1)
5496 instr [29,23] = 001 1110
5497 instr [22,16] = size and shift amount
5498 instr [15,10] = 01 0101
5499 instr [9, 5] = Vs
5500 instr [4, 0] = Vd. */
5501
5502 int shift;
5503 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5504 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5505 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5506 unsigned i;
5507
5508 NYI_assert (29, 23, 0x1E);
5509 NYI_assert (15, 10, 0x15);
5510
5511 if (uimm (aarch64_get_instr (cpu), 22, 22))
5512 {
5513 shift = uimm (aarch64_get_instr (cpu), 21, 16) - 1;
5514
5515 if (full == 0)
5516 HALT_UNALLOC;
5517
5518 for (i = 0; i < 2; i++)
5519 {
5520 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5521 aarch64_set_vec_u64 (cpu, vd, i, val << shift);
5522 }
5523
5524 return;
5525 }
5526
5527 if (uimm (aarch64_get_instr (cpu), 21, 21))
5528 {
5529 shift = uimm (aarch64_get_instr (cpu), 20, 16) - 1;
5530
5531 for (i = 0; i < (full ? 4 : 2); i++)
5532 {
5533 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5534 aarch64_set_vec_u32 (cpu, vd, i, val << shift);
5535 }
5536
5537 return;
5538 }
5539
5540 if (uimm (aarch64_get_instr (cpu), 20, 20))
5541 {
5542 shift = uimm (aarch64_get_instr (cpu), 19, 16) - 1;
5543
5544 for (i = 0; i < (full ? 8 : 4); i++)
5545 {
5546 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5547 aarch64_set_vec_u16 (cpu, vd, i, val << shift);
5548 }
5549
5550 return;
5551 }
5552
5553 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
5554 HALT_UNALLOC;
5555
5556 shift = uimm (aarch64_get_instr (cpu), 18, 16) - 1;
5557
5558 for (i = 0; i < (full ? 16 : 8); i++)
5559 {
5560 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5561 aarch64_set_vec_u8 (cpu, vd, i, val << shift);
5562 }
5563 }
5564
5565 static void
5566 do_vec_SSHR_USHR (sim_cpu *cpu)
5567 {
5568 /* instr [31] = 0
5569 instr [30] = half(0)/full(1)
5570 instr [29] = signed(0)/unsigned(1)
5571 instr [28,23] = 01 1110
5572 instr [22,16] = size and shift amount
5573 instr [15,10] = 0000 01
5574 instr [9, 5] = Vs
5575 instr [4, 0] = Vd. */
5576
5577 int shift;
5578 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5579 int sign = uimm (aarch64_get_instr (cpu), 29, 29);
5580 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5581 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5582 unsigned i;
5583
5584 NYI_assert (28, 23, 0x1E);
5585 NYI_assert (15, 10, 0x01);
5586
5587 if (uimm (aarch64_get_instr (cpu), 22, 22))
5588 {
5589 shift = uimm (aarch64_get_instr (cpu), 21, 16);
5590
5591 if (full == 0)
5592 HALT_UNALLOC;
5593
5594 if (sign)
5595 for (i = 0; i < 2; i++)
5596 {
5597 int64_t val = aarch64_get_vec_s64 (cpu, vs, i);
5598 aarch64_set_vec_s64 (cpu, vd, i, val >> shift);
5599 }
5600 else
5601 for (i = 0; i < 2; i++)
5602 {
5603 uint64_t val = aarch64_get_vec_u64 (cpu, vs, i);
5604 aarch64_set_vec_u64 (cpu, vd, i, val >> shift);
5605 }
5606
5607 return;
5608 }
5609
5610 if (uimm (aarch64_get_instr (cpu), 21, 21))
5611 {
5612 shift = uimm (aarch64_get_instr (cpu), 20, 16);
5613
5614 if (sign)
5615 for (i = 0; i < (full ? 4 : 2); i++)
5616 {
5617 int32_t val = aarch64_get_vec_s32 (cpu, vs, i);
5618 aarch64_set_vec_s32 (cpu, vd, i, val >> shift);
5619 }
5620 else
5621 for (i = 0; i < (full ? 4 : 2); i++)
5622 {
5623 uint32_t val = aarch64_get_vec_u32 (cpu, vs, i);
5624 aarch64_set_vec_u32 (cpu, vd, i, val >> shift);
5625 }
5626
5627 return;
5628 }
5629
5630 if (uimm (aarch64_get_instr (cpu), 20, 20))
5631 {
5632 shift = uimm (aarch64_get_instr (cpu), 19, 16);
5633
5634 if (sign)
5635 for (i = 0; i < (full ? 8 : 4); i++)
5636 {
5637 int16_t val = aarch64_get_vec_s16 (cpu, vs, i);
5638 aarch64_set_vec_s16 (cpu, vd, i, val >> shift);
5639 }
5640 else
5641 for (i = 0; i < (full ? 8 : 4); i++)
5642 {
5643 uint16_t val = aarch64_get_vec_u16 (cpu, vs, i);
5644 aarch64_set_vec_u16 (cpu, vd, i, val >> shift);
5645 }
5646
5647 return;
5648 }
5649
5650 if (uimm (aarch64_get_instr (cpu), 19, 19) == 0)
5651 HALT_UNALLOC;
5652
5653 shift = uimm (aarch64_get_instr (cpu), 18, 16);
5654
5655 if (sign)
5656 for (i = 0; i < (full ? 16 : 8); i++)
5657 {
5658 int8_t val = aarch64_get_vec_s8 (cpu, vs, i);
5659 aarch64_set_vec_s8 (cpu, vd, i, val >> shift);
5660 }
5661 else
5662 for (i = 0; i < (full ? 16 : 8); i++)
5663 {
5664 uint8_t val = aarch64_get_vec_u8 (cpu, vs, i);
5665 aarch64_set_vec_u8 (cpu, vd, i, val >> shift);
5666 }
5667 }
5668
5669 static void
5670 do_vec_op2 (sim_cpu *cpu)
5671 {
5672 /* instr[31] = 0
5673 instr[30] = half/full
5674 instr[29,24] = 00 1111
5675 instr[23] = ?
5676 instr[22,16] = element size & index
5677 instr[15,10] = sub-opcode
5678 instr[9,5] = Vm
5679 instr[4.0] = Vd */
5680
5681 NYI_assert (29, 24, 0x0F);
5682
5683 if (uimm (aarch64_get_instr (cpu), 23, 23) != 0)
5684 HALT_NYI;
5685
5686 switch (uimm (aarch64_get_instr (cpu), 15, 10))
5687 {
5688 case 0x01: do_vec_SSHR_USHR (cpu); return;
5689 case 0x15: do_vec_SHL (cpu); return;
5690 case 0x29: do_vec_xtl (cpu); return;
5691 default: HALT_NYI;
5692 }
5693 }
5694
5695 static void
5696 do_vec_neg (sim_cpu *cpu)
5697 {
5698 /* instr[31] = 0
5699 instr[30] = full(1)/half(0)
5700 instr[29,24] = 10 1110
5701 instr[23,22] = size: byte(00), half (01), word (10), long (11)
5702 instr[21,10] = 1000 0010 1110
5703 instr[9,5] = Vs
5704 instr[4,0] = Vd */
5705
5706 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5707 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5708 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5709 unsigned i;
5710
5711 NYI_assert (29, 24, 0x2E);
5712 NYI_assert (21, 10, 0x82E);
5713
5714 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5715 {
5716 case 0:
5717 for (i = 0; i < (full ? 16 : 8); i++)
5718 aarch64_set_vec_s8 (cpu, vd, i, - aarch64_get_vec_s8 (cpu, vs, i));
5719 return;
5720
5721 case 1:
5722 for (i = 0; i < (full ? 8 : 4); i++)
5723 aarch64_set_vec_s16 (cpu, vd, i, - aarch64_get_vec_s16 (cpu, vs, i));
5724 return;
5725
5726 case 2:
5727 for (i = 0; i < (full ? 4 : 2); i++)
5728 aarch64_set_vec_s32 (cpu, vd, i, - aarch64_get_vec_s32 (cpu, vs, i));
5729 return;
5730
5731 case 3:
5732 if (! full)
5733 HALT_NYI;
5734 for (i = 0; i < 2; i++)
5735 aarch64_set_vec_s64 (cpu, vd, i, - aarch64_get_vec_s64 (cpu, vs, i));
5736 return;
5737
5738 default:
5739 HALT_UNREACHABLE;
5740 }
5741 }
5742
5743 static void
5744 do_vec_sqrt (sim_cpu *cpu)
5745 {
5746 /* instr[31] = 0
5747 instr[30] = full(1)/half(0)
5748 instr[29,23] = 101 1101
5749 instr[22] = single(0)/double(1)
5750 instr[21,10] = 1000 0111 1110
5751 instr[9,5] = Vs
5752 instr[4,0] = Vd. */
5753
5754 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5755 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5756 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5757 unsigned i;
5758
5759 NYI_assert (29, 23, 0x5B);
5760 NYI_assert (21, 10, 0x87E);
5761
5762 if (uimm (aarch64_get_instr (cpu), 22, 22) == 0)
5763 for (i = 0; i < (full ? 4 : 2); i++)
5764 aarch64_set_vec_float (cpu, vd, i,
5765 sqrtf (aarch64_get_vec_float (cpu, vs, i)));
5766 else
5767 for (i = 0; i < 2; i++)
5768 aarch64_set_vec_double (cpu, vd, i,
5769 sqrt (aarch64_get_vec_double (cpu, vs, i)));
5770 }
5771
5772 static void
5773 do_vec_mls_indexed (sim_cpu *cpu)
5774 {
5775 /* instr[31] = 0
5776 instr[30] = half(0)/full(1)
5777 instr[29,24] = 10 1111
5778 instr[23,22] = 16-bit(01)/32-bit(10)
5779 instr[21,20+11] = index (if 16-bit)
5780 instr[21+11] = index (if 32-bit)
5781 instr[20,16] = Vm
5782 instr[15,12] = 0100
5783 instr[11] = part of index
5784 instr[10] = 0
5785 instr[9,5] = Vs
5786 instr[4,0] = Vd. */
5787
5788 int full = uimm (aarch64_get_instr (cpu), 30, 30);
5789 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
5790 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5791 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5792 unsigned i;
5793
5794 NYI_assert (15, 12, 4);
5795 NYI_assert (10, 10, 0);
5796
5797 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5798 {
5799 case 1:
5800 {
5801 unsigned elem;
5802 uint32_t val;
5803
5804 if (vm > 15)
5805 HALT_NYI;
5806
5807 elem = (uimm (aarch64_get_instr (cpu), 21, 20) << 1)
5808 | uimm (aarch64_get_instr (cpu), 11, 11);
5809 val = aarch64_get_vec_u16 (cpu, vm, elem);
5810
5811 for (i = 0; i < (full ? 8 : 4); i++)
5812 aarch64_set_vec_u32 (cpu, vd, i,
5813 aarch64_get_vec_u32 (cpu, vd, i) -
5814 (aarch64_get_vec_u32 (cpu, vs, i) * val));
5815 return;
5816 }
5817
5818 case 2:
5819 {
5820 unsigned elem = (uimm (aarch64_get_instr (cpu), 21, 21) << 1)
5821 | uimm (aarch64_get_instr (cpu), 11, 11);
5822 uint64_t val = aarch64_get_vec_u32 (cpu, vm, elem);
5823
5824 for (i = 0; i < (full ? 4 : 2); i++)
5825 aarch64_set_vec_u64 (cpu, vd, i,
5826 aarch64_get_vec_u64 (cpu, vd, i) -
5827 (aarch64_get_vec_u64 (cpu, vs, i) * val));
5828 return;
5829 }
5830
5831 case 0:
5832 case 3:
5833 default:
5834 HALT_NYI;
5835 }
5836 }
5837
5838 static void
5839 do_vec_SUB (sim_cpu *cpu)
5840 {
5841 /* instr [31] = 0
5842 instr [30] = half(0)/full(1)
5843 instr [29,24] = 10 1110
5844 instr [23,22] = size: byte(00, half(01), word (10), long (11)
5845 instr [21] = 1
5846 instr [20,16] = Vm
5847 instr [15,10] = 10 0001
5848 instr [9, 5] = Vn
5849 instr [4, 0] = Vd. */
5850
5851 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5852 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5853 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5854 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5855 unsigned i;
5856
5857 NYI_assert (29, 24, 0x2E);
5858 NYI_assert (21, 21, 1);
5859 NYI_assert (15, 10, 0x21);
5860
5861 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5862 {
5863 case 0:
5864 for (i = 0; i < (full ? 16 : 8); i++)
5865 aarch64_set_vec_s8 (cpu, vd, i,
5866 aarch64_get_vec_s8 (cpu, vn, i)
5867 - aarch64_get_vec_s8 (cpu, vm, i));
5868 return;
5869
5870 case 1:
5871 for (i = 0; i < (full ? 8 : 4); i++)
5872 aarch64_set_vec_s16 (cpu, vd, i,
5873 aarch64_get_vec_s16 (cpu, vn, i)
5874 - aarch64_get_vec_s16 (cpu, vm, i));
5875 return;
5876
5877 case 2:
5878 for (i = 0; i < (full ? 4 : 2); i++)
5879 aarch64_set_vec_s32 (cpu, vd, i,
5880 aarch64_get_vec_s32 (cpu, vn, i)
5881 - aarch64_get_vec_s32 (cpu, vm, i));
5882 return;
5883
5884 case 3:
5885 if (full == 0)
5886 HALT_UNALLOC;
5887
5888 for (i = 0; i < 2; i++)
5889 aarch64_set_vec_s64 (cpu, vd, i,
5890 aarch64_get_vec_s64 (cpu, vn, i)
5891 - aarch64_get_vec_s64 (cpu, vm, i));
5892 return;
5893
5894 default:
5895 HALT_UNREACHABLE;
5896 }
5897 }
5898
5899 static void
5900 do_vec_MLS (sim_cpu *cpu)
5901 {
5902 /* instr [31] = 0
5903 instr [30] = half(0)/full(1)
5904 instr [29,24] = 10 1110
5905 instr [23,22] = size: byte(00, half(01), word (10)
5906 instr [21] = 1
5907 instr [20,16] = Vm
5908 instr [15,10] = 10 0101
5909 instr [9, 5] = Vn
5910 instr [4, 0] = Vd. */
5911
5912 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5913 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5914 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5915 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5916 unsigned i;
5917
5918 NYI_assert (29, 24, 0x2E);
5919 NYI_assert (21, 21, 1);
5920 NYI_assert (15, 10, 0x25);
5921
5922 switch (uimm (aarch64_get_instr (cpu), 23, 22))
5923 {
5924 case 0:
5925 for (i = 0; i < (full ? 16 : 8); i++)
5926 aarch64_set_vec_u8 (cpu, vd, i,
5927 (aarch64_get_vec_u8 (cpu, vn, i)
5928 * aarch64_get_vec_u8 (cpu, vm, i))
5929 - aarch64_get_vec_u8 (cpu, vd, i));
5930 return;
5931
5932 case 1:
5933 for (i = 0; i < (full ? 8 : 4); i++)
5934 aarch64_set_vec_u16 (cpu, vd, i,
5935 (aarch64_get_vec_u16 (cpu, vn, i)
5936 * aarch64_get_vec_u16 (cpu, vm, i))
5937 - aarch64_get_vec_u16 (cpu, vd, i));
5938 return;
5939
5940 case 2:
5941 for (i = 0; i < (full ? 4 : 2); i++)
5942 aarch64_set_vec_u32 (cpu, vd, i,
5943 (aarch64_get_vec_u32 (cpu, vn, i)
5944 * aarch64_get_vec_u32 (cpu, vm, i))
5945 - aarch64_get_vec_u32 (cpu, vd, i));
5946 return;
5947
5948 default:
5949 HALT_UNALLOC;
5950 }
5951 }
5952
5953 static void
5954 do_vec_FDIV (sim_cpu *cpu)
5955 {
5956 /* instr [31] = 0
5957 instr [30] = half(0)/full(1)
5958 instr [29,23] = 10 1110 0
5959 instr [22] = float()/double(1)
5960 instr [21] = 1
5961 instr [20,16] = Vm
5962 instr [15,10] = 1111 11
5963 instr [9, 5] = Vn
5964 instr [4, 0] = Vd. */
5965
5966 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
5967 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
5968 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
5969 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
5970 unsigned i;
5971
5972 NYI_assert (29, 23, 0x5C);
5973 NYI_assert (21, 21, 1);
5974 NYI_assert (15, 10, 0x3F);
5975
5976 if (uimm (aarch64_get_instr (cpu), 22, 22))
5977 {
5978 if (! full)
5979 HALT_UNALLOC;
5980
5981 for (i = 0; i < 2; i++)
5982 aarch64_set_vec_double (cpu, vd, i,
5983 aarch64_get_vec_double (cpu, vn, i)
5984 / aarch64_get_vec_double (cpu, vm, i));
5985 }
5986 else
5987 for (i = 0; i < (full ? 4 : 2); i++)
5988 aarch64_set_vec_float (cpu, vd, i,
5989 aarch64_get_vec_float (cpu, vn, i)
5990 / aarch64_get_vec_float (cpu, vm, i));
5991 }
5992
5993 static void
5994 do_vec_FMUL (sim_cpu *cpu)
5995 {
5996 /* instr [31] = 0
5997 instr [30] = half(0)/full(1)
5998 instr [29,23] = 10 1110 0
5999 instr [22] = float(0)/double(1)
6000 instr [21] = 1
6001 instr [20,16] = Vm
6002 instr [15,10] = 1101 11
6003 instr [9, 5] = Vn
6004 instr [4, 0] = Vd. */
6005
6006 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6007 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6008 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6009 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6010 unsigned i;
6011
6012 NYI_assert (29, 23, 0x5C);
6013 NYI_assert (21, 21, 1);
6014 NYI_assert (15, 10, 0x37);
6015
6016 if (uimm (aarch64_get_instr (cpu), 22, 22))
6017 {
6018 if (! full)
6019 HALT_UNALLOC;
6020
6021 for (i = 0; i < 2; i++)
6022 aarch64_set_vec_double (cpu, vd, i,
6023 aarch64_get_vec_double (cpu, vn, i)
6024 * aarch64_get_vec_double (cpu, vm, i));
6025 }
6026 else
6027 for (i = 0; i < (full ? 4 : 2); i++)
6028 aarch64_set_vec_float (cpu, vd, i,
6029 aarch64_get_vec_float (cpu, vn, i)
6030 * aarch64_get_vec_float (cpu, vm, i));
6031 }
6032
6033 static void
6034 do_vec_FADDP (sim_cpu *cpu)
6035 {
6036 /* instr [31] = 0
6037 instr [30] = half(0)/full(1)
6038 instr [29,23] = 10 1110 0
6039 instr [22] = float(0)/double(1)
6040 instr [21] = 1
6041 instr [20,16] = Vm
6042 instr [15,10] = 1101 01
6043 instr [9, 5] = Vn
6044 instr [4, 0] = Vd. */
6045
6046 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6047 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
6048 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6049 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6050
6051 NYI_assert (29, 23, 0x5C);
6052 NYI_assert (21, 21, 1);
6053 NYI_assert (15, 10, 0x35);
6054
6055 if (uimm (aarch64_get_instr (cpu), 22, 22))
6056 {
6057 if (! full)
6058 HALT_UNALLOC;
6059
6060 aarch64_set_vec_double (cpu, vd, 0, aarch64_get_vec_double (cpu, vn, 0)
6061 + aarch64_get_vec_double (cpu, vn, 1));
6062 aarch64_set_vec_double (cpu, vd, 1, aarch64_get_vec_double (cpu, vm, 0)
6063 + aarch64_get_vec_double (cpu, vm, 1));
6064 }
6065 else
6066 {
6067 aarch64_set_vec_float (cpu, vd, 0, aarch64_get_vec_float (cpu, vn, 0)
6068 + aarch64_get_vec_float (cpu, vn, 1));
6069 if (full)
6070 aarch64_set_vec_float (cpu, vd, 1, aarch64_get_vec_float (cpu, vn, 2)
6071 + aarch64_get_vec_float (cpu, vn, 3));
6072 aarch64_set_vec_float (cpu, vd, full ? 2 : 1,
6073 aarch64_get_vec_float (cpu, vm, 0)
6074 + aarch64_get_vec_float (cpu, vm, 1));
6075 if (full)
6076 aarch64_set_vec_float (cpu, vd, 3,
6077 aarch64_get_vec_float (cpu, vm, 2)
6078 + aarch64_get_vec_float (cpu, vm, 3));
6079 }
6080 }
6081
6082 static void
6083 do_vec_FSQRT (sim_cpu *cpu)
6084 {
6085 /* instr[31] = 0
6086 instr[30] = half(0)/full(1)
6087 instr[29,23] = 10 1110 1
6088 instr[22] = single(0)/double(1)
6089 instr[21,10] = 10 0001 1111 10
6090 instr[9,5] = Vsrc
6091 instr[4,0] = Vdest. */
6092
6093 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6094 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6095 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6096 int i;
6097
6098 NYI_assert (29, 23, 0x5D);
6099 NYI_assert (21, 10, 0x87E);
6100
6101 if (uimm (aarch64_get_instr (cpu), 22, 22))
6102 {
6103 if (! full)
6104 HALT_UNALLOC;
6105
6106 for (i = 0; i < 2; i++)
6107 aarch64_set_vec_double (cpu, vd, i,
6108 sqrt (aarch64_get_vec_double (cpu, vn, i)));
6109 }
6110 else
6111 {
6112 for (i = 0; i < (full ? 4 : 2); i++)
6113 aarch64_set_vec_float (cpu, vd, i,
6114 sqrtf (aarch64_get_vec_float (cpu, vn, i)));
6115 }
6116 }
6117
6118 static void
6119 do_vec_FNEG (sim_cpu *cpu)
6120 {
6121 /* instr[31] = 0
6122 instr[30] = half (0)/full (1)
6123 instr[29,23] = 10 1110 1
6124 instr[22] = single (0)/double (1)
6125 instr[21,10] = 10 0000 1111 10
6126 instr[9,5] = Vsrc
6127 instr[4,0] = Vdest. */
6128
6129 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6130 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6131 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
6132 int i;
6133
6134 NYI_assert (29, 23, 0x5D);
6135 NYI_assert (21, 10, 0x83E);
6136
6137 if (uimm (aarch64_get_instr (cpu), 22, 22))
6138 {
6139 if (! full)
6140 HALT_UNALLOC;
6141
6142 for (i = 0; i < 2; i++)
6143 aarch64_set_vec_double (cpu, vd, i,
6144 - aarch64_get_vec_double (cpu, vn, i));
6145 }
6146 else
6147 {
6148 for (i = 0; i < (full ? 4 : 2); i++)
6149 aarch64_set_vec_float (cpu, vd, i,
6150 - aarch64_get_vec_float (cpu, vn, i));
6151 }
6152 }
6153
6154 static void
6155 do_vec_NOT (sim_cpu *cpu)
6156 {
6157 /* instr[31] = 0
6158 instr[30] = half (0)/full (1)
6159 instr[29,21] = 10 1110 001
6160 instr[20,16] = 0 0000
6161 instr[15,10] = 0101 10
6162 instr[9,5] = Vn
6163 instr[4.0] = Vd. */
6164
6165 unsigned vn = uimm (aarch64_get_instr (cpu), 9, 5);
6166 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6167 unsigned i;
6168 int full = uimm (aarch64_get_instr (cpu), 30, 30);
6169
6170 NYI_assert (29, 10, 0xB8816);
6171
6172 for (i = 0; i < (full ? 16 : 8); i++)
6173 aarch64_set_vec_u8 (cpu, vd, i, ~ aarch64_get_vec_u8 (cpu, vn, i));
6174 }
6175
6176 static void
6177 do_vec_MOV_element (sim_cpu *cpu)
6178 {
6179 /* instr[31,21] = 0110 1110 000
6180 instr[20,16] = size & dest index
6181 instr[15] = 0
6182 instr[14,11] = source index
6183 instr[10] = 1
6184 instr[9,5] = Vs
6185 instr[4.0] = Vd. */
6186
6187 unsigned vs = uimm (aarch64_get_instr (cpu), 9, 5);
6188 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
6189 unsigned src_index;
6190 unsigned dst_index;
6191
6192 NYI_assert (31, 21, 0x370);
6193 NYI_assert (15, 15, 0);
6194 NYI_assert (10, 10, 1);
6195
6196 if (uimm (aarch64_get_instr (cpu), 16, 16))
6197 {
6198 /* Move a byte. */
6199 src_index = uimm (aarch64_get_instr (cpu), 14, 11);
6200 dst_index = uimm (aarch64_get_instr (cpu), 20, 17);
6201 aarch64_set_vec_u8 (cpu, vd, dst_index,
6202 aarch64_get_vec_u8 (cpu, vs, src_index));
6203 }
6204 else if (uimm (aarch64_get_instr (cpu), 17, 17))
6205 {
6206 /* Move 16-bits. */
6207 NYI_assert (11, 11, 0);
6208 src_index = uimm (aarch64_get_instr (cpu), 14, 12);
6209 dst_index = uimm (aarch64_get_instr (cpu), 20, 18);
6210 aarch64_set_vec_u16 (cpu, vd, dst_index,
6211 aarch64_get_vec_u16 (cpu, vs, src_index));
6212 }
6213 else if (uimm (aarch64_get_instr (cpu), 18, 18))
6214 {
6215 /* Move 32-bits. */
6216 NYI_assert (12, 11, 0);
6217 src_index = uimm (aarch64_get_instr (cpu), 14, 13);
6218 dst_index = uimm (aarch64_get_instr (cpu), 20, 19);
6219 aarch64_set_vec_u32 (cpu, vd, dst_index,
6220 aarch64_get_vec_u32 (cpu, vs, src_index));
6221 }
6222 else
6223 {
6224 NYI_assert (19, 19, 1);
6225 NYI_assert (13, 11, 0);
6226 src_index = uimm (aarch64_get_instr (cpu), 14, 14);
6227 dst_index = uimm (aarch64_get_instr (cpu), 20, 20);
6228 aarch64_set_vec_u64 (cpu, vd, dst_index,
6229 aarch64_get_vec_u64 (cpu, vs, src_index));
6230 }
6231 }
6232
6233 static void
6234 dexAdvSIMD0 (sim_cpu *cpu)
6235 {
6236 /* instr [28,25] = 0 111. */
6237 if ( uimm (aarch64_get_instr (cpu), 15, 10) == 0x07
6238 && (uimm (aarch64_get_instr (cpu), 9, 5) ==
6239 uimm (aarch64_get_instr (cpu), 20, 16)))
6240 {
6241 if (uimm (aarch64_get_instr (cpu), 31, 21) == 0x075
6242 || uimm (aarch64_get_instr (cpu), 31, 21) == 0x275)
6243 {
6244 do_vec_MOV_whole_vector (cpu);
6245 return;
6246 }
6247 }
6248
6249 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x1E0)
6250 {
6251 do_vec_MOV_immediate (cpu);
6252 return;
6253 }
6254
6255 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x5E0)
6256 {
6257 do_vec_MVNI (cpu);
6258 return;
6259 }
6260
6261 if (uimm (aarch64_get_instr (cpu), 29, 19) == 0x1C0
6262 || uimm (aarch64_get_instr (cpu), 29, 19) == 0x1C1)
6263 {
6264 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x03)
6265 {
6266 do_vec_DUP_scalar_into_vector (cpu);
6267 return;
6268 }
6269 }
6270
6271 switch (uimm (aarch64_get_instr (cpu), 29, 24))
6272 {
6273 case 0x0E: do_vec_op1 (cpu); return;
6274 case 0x0F: do_vec_op2 (cpu); return;
6275
6276 case 0x2f:
6277 switch (uimm (aarch64_get_instr (cpu), 15, 10))
6278 {
6279 case 0x01: do_vec_SSHR_USHR (cpu); return;
6280 case 0x10:
6281 case 0x12: do_vec_mls_indexed (cpu); return;
6282 case 0x29: do_vec_xtl (cpu); return;
6283 default:
6284 HALT_NYI;
6285 }
6286
6287 case 0x2E:
6288 if (uimm (aarch64_get_instr (cpu), 21, 21) == 1)
6289 {
6290 switch (uimm (aarch64_get_instr (cpu), 15, 10))
6291 {
6292 case 0x07:
6293 switch (uimm (aarch64_get_instr (cpu), 23, 22))
6294 {
6295 case 0: do_vec_EOR (cpu); return;
6296 case 1: do_vec_BSL (cpu); return;
6297 case 2:
6298 case 3: do_vec_bit (cpu); return;
6299 }
6300 break;
6301
6302 case 0x08: do_vec_sub_long (cpu); return;
6303 case 0x11: do_vec_USHL (cpu); return;
6304 case 0x16: do_vec_NOT (cpu); return;
6305 case 0x19: do_vec_max (cpu); return;
6306 case 0x1B: do_vec_min (cpu); return;
6307 case 0x21: do_vec_SUB (cpu); return;
6308 case 0x25: do_vec_MLS (cpu); return;
6309 case 0x31: do_vec_FminmaxNMP (cpu); return;
6310 case 0x35: do_vec_FADDP (cpu); return;
6311 case 0x37: do_vec_FMUL (cpu); return;
6312 case 0x3F: do_vec_FDIV (cpu); return;
6313
6314 case 0x3E:
6315 switch (uimm (aarch64_get_instr (cpu), 20, 16))
6316 {
6317 case 0x00: do_vec_FNEG (cpu); return;
6318 case 0x01: do_vec_FSQRT (cpu); return;
6319 default: HALT_NYI;
6320 }
6321
6322 case 0x0D:
6323 case 0x0F:
6324 case 0x22:
6325 case 0x23:
6326 case 0x26:
6327 case 0x2A:
6328 case 0x32:
6329 case 0x36:
6330 case 0x39:
6331 case 0x3A:
6332 do_vec_compare (cpu); return;
6333
6334 default: break;
6335 }
6336 }
6337
6338 if (uimm (aarch64_get_instr (cpu), 31, 21) == 0x370)
6339 {
6340 do_vec_MOV_element (cpu);
6341 return;
6342 }
6343
6344 switch (uimm (aarch64_get_instr (cpu), 21, 10))
6345 {
6346 case 0x82E: do_vec_neg (cpu); return;
6347 case 0x87E: do_vec_sqrt (cpu); return;
6348 default:
6349 if (uimm (aarch64_get_instr (cpu), 15, 10) == 0x30)
6350 {
6351 do_vec_mull (cpu);
6352 return;
6353 }
6354 break;
6355 }
6356 break;
6357
6358 default:
6359 break;
6360 }
6361
6362 HALT_NYI;
6363 }
6364
6365 /* 3 sources. */
6366
6367 /* Float multiply add. */
6368 static void
6369 fmadds (sim_cpu *cpu)
6370 {
6371 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6372 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6373 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6374 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6375
6376 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6377 + aarch64_get_FP_float (cpu, sn)
6378 * aarch64_get_FP_float (cpu, sm));
6379 }
6380
6381 /* Double multiply add. */
6382 static void
6383 fmaddd (sim_cpu *cpu)
6384 {
6385 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6386 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6387 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6388 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6389
6390 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6391 + aarch64_get_FP_double (cpu, sn)
6392 * aarch64_get_FP_double (cpu, sm));
6393 }
6394
6395 /* Float multiply subtract. */
6396 static void
6397 fmsubs (sim_cpu *cpu)
6398 {
6399 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6400 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6401 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6402 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6403
6404 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sa)
6405 - aarch64_get_FP_float (cpu, sn)
6406 * aarch64_get_FP_float (cpu, sm));
6407 }
6408
6409 /* Double multiply subtract. */
6410 static void
6411 fmsubd (sim_cpu *cpu)
6412 {
6413 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6414 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6415 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6416 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6417
6418 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sa)
6419 - aarch64_get_FP_double (cpu, sn)
6420 * aarch64_get_FP_double (cpu, sm));
6421 }
6422
6423 /* Float negative multiply add. */
6424 static void
6425 fnmadds (sim_cpu *cpu)
6426 {
6427 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6428 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6429 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6430 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6431
6432 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6433 + (- aarch64_get_FP_float (cpu, sn))
6434 * aarch64_get_FP_float (cpu, sm));
6435 }
6436
6437 /* Double negative multiply add. */
6438 static void
6439 fnmaddd (sim_cpu *cpu)
6440 {
6441 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6442 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6443 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6444 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6445
6446 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6447 + (- aarch64_get_FP_double (cpu, sn))
6448 * aarch64_get_FP_double (cpu, sm));
6449 }
6450
6451 /* Float negative multiply subtract. */
6452 static void
6453 fnmsubs (sim_cpu *cpu)
6454 {
6455 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6456 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6457 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6458 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6459
6460 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sa)
6461 + aarch64_get_FP_float (cpu, sn)
6462 * aarch64_get_FP_float (cpu, sm));
6463 }
6464
6465 /* Double negative multiply subtract. */
6466 static void
6467 fnmsubd (sim_cpu *cpu)
6468 {
6469 unsigned sa = uimm (aarch64_get_instr (cpu), 14, 10);
6470 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6471 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6472 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6473
6474 aarch64_set_FP_double (cpu, sd, - aarch64_get_FP_double (cpu, sa)
6475 + aarch64_get_FP_double (cpu, sn)
6476 * aarch64_get_FP_double (cpu, sm));
6477 }
6478
6479 static void
6480 dexSimpleFPDataProc3Source (sim_cpu *cpu)
6481 {
6482 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
6483 instr[30] = 0
6484 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
6485 instr[28,25] = 1111
6486 instr[24] = 1
6487 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
6488 instr[21] ==> o1 : 0 ==> unnegated, 1 ==> negated
6489 instr[15] ==> o2 : 0 ==> ADD, 1 ==> SUB */
6490
6491 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
6492 | uimm (aarch64_get_instr (cpu), 29, 29);
6493 /* dispatch on combined type:o1:o2. */
6494 uint32_t dispatch = (uimm (aarch64_get_instr (cpu), 23, 21) << 1)
6495 | uimm (aarch64_get_instr (cpu), 15, 15);
6496
6497 if (M_S != 0)
6498 HALT_UNALLOC;
6499
6500 switch (dispatch)
6501 {
6502 case 0: fmadds (cpu); return;
6503 case 1: fmsubs (cpu); return;
6504 case 2: fnmadds (cpu); return;
6505 case 3: fnmsubs (cpu); return;
6506 case 4: fmaddd (cpu); return;
6507 case 5: fmsubd (cpu); return;
6508 case 6: fnmaddd (cpu); return;
6509 case 7: fnmsubd (cpu); return;
6510 default:
6511 /* type > 1 is currently unallocated. */
6512 HALT_UNALLOC;
6513 }
6514 }
6515
6516 static void
6517 dexSimpleFPFixedConvert (sim_cpu *cpu)
6518 {
6519 HALT_NYI;
6520 }
6521
6522 static void
6523 dexSimpleFPCondCompare (sim_cpu *cpu)
6524 {
6525 HALT_NYI;
6526 }
6527
6528 /* 2 sources. */
6529
6530 /* Float add. */
6531 static void
6532 fadds (sim_cpu *cpu)
6533 {
6534 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6535 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6536 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6537
6538 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6539 + aarch64_get_FP_float (cpu, sm));
6540 }
6541
6542 /* Double add. */
6543 static void
6544 faddd (sim_cpu *cpu)
6545 {
6546 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6547 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6548 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6549
6550 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6551 + aarch64_get_FP_double (cpu, sm));
6552 }
6553
6554 /* Float divide. */
6555 static void
6556 fdivs (sim_cpu *cpu)
6557 {
6558 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6559 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6560 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6561
6562 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6563 / aarch64_get_FP_float (cpu, sm));
6564 }
6565
6566 /* Double divide. */
6567 static void
6568 fdivd (sim_cpu *cpu)
6569 {
6570 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6571 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6572 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6573
6574 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6575 / aarch64_get_FP_double (cpu, sm));
6576 }
6577
6578 /* Float multiply. */
6579 static void
6580 fmuls (sim_cpu *cpu)
6581 {
6582 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6583 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6584 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6585
6586 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6587 * aarch64_get_FP_float (cpu, sm));
6588 }
6589
6590 /* Double multiply. */
6591 static void
6592 fmuld (sim_cpu *cpu)
6593 {
6594 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6595 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6596 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6597
6598 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6599 * aarch64_get_FP_double (cpu, sm));
6600 }
6601
6602 /* Float negate and multiply. */
6603 static void
6604 fnmuls (sim_cpu *cpu)
6605 {
6606 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6607 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6608 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6609
6610 aarch64_set_FP_float (cpu, sd, - (aarch64_get_FP_float (cpu, sn)
6611 * aarch64_get_FP_float (cpu, sm)));
6612 }
6613
6614 /* Double negate and multiply. */
6615 static void
6616 fnmuld (sim_cpu *cpu)
6617 {
6618 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6619 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6620 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6621
6622 aarch64_set_FP_double (cpu, sd, - (aarch64_get_FP_double (cpu, sn)
6623 * aarch64_get_FP_double (cpu, sm)));
6624 }
6625
6626 /* Float subtract. */
6627 static void
6628 fsubs (sim_cpu *cpu)
6629 {
6630 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6631 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6632 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6633
6634 aarch64_set_FP_float (cpu, sd, aarch64_get_FP_float (cpu, sn)
6635 - aarch64_get_FP_float (cpu, sm));
6636 }
6637
6638 /* Double subtract. */
6639 static void
6640 fsubd (sim_cpu *cpu)
6641 {
6642 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6643 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6644 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6645
6646 aarch64_set_FP_double (cpu, sd, aarch64_get_FP_double (cpu, sn)
6647 - aarch64_get_FP_double (cpu, sm));
6648 }
6649
6650 static void
6651 do_FMINNM (sim_cpu *cpu)
6652 {
6653 /* instr[31,23] = 0 0011 1100
6654 instr[22] = float(0)/double(1)
6655 instr[21] = 1
6656 instr[20,16] = Sm
6657 instr[15,10] = 01 1110
6658 instr[9,5] = Sn
6659 instr[4,0] = Cpu */
6660
6661 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6662 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6663 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6664
6665 NYI_assert (31, 23, 0x03C);
6666 NYI_assert (15, 10, 0x1E);
6667
6668 if (uimm (aarch64_get_instr (cpu), 22, 22))
6669 aarch64_set_FP_double (cpu, sd,
6670 dminnm (aarch64_get_FP_double (cpu, sn),
6671 aarch64_get_FP_double (cpu, sm)));
6672 else
6673 aarch64_set_FP_float (cpu, sd,
6674 fminnm (aarch64_get_FP_float (cpu, sn),
6675 aarch64_get_FP_float (cpu, sm)));
6676 }
6677
6678 static void
6679 do_FMAXNM (sim_cpu *cpu)
6680 {
6681 /* instr[31,23] = 0 0011 1100
6682 instr[22] = float(0)/double(1)
6683 instr[21] = 1
6684 instr[20,16] = Sm
6685 instr[15,10] = 01 1010
6686 instr[9,5] = Sn
6687 instr[4,0] = Cpu */
6688
6689 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6690 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6691 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6692
6693 NYI_assert (31, 23, 0x03C);
6694 NYI_assert (15, 10, 0x1A);
6695
6696 if (uimm (aarch64_get_instr (cpu), 22, 22))
6697 aarch64_set_FP_double (cpu, sd,
6698 dmaxnm (aarch64_get_FP_double (cpu, sn),
6699 aarch64_get_FP_double (cpu, sm)));
6700 else
6701 aarch64_set_FP_float (cpu, sd,
6702 fmaxnm (aarch64_get_FP_float (cpu, sn),
6703 aarch64_get_FP_float (cpu, sm)));
6704 }
6705
6706 static void
6707 dexSimpleFPDataProc2Source (sim_cpu *cpu)
6708 {
6709 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
6710 instr[30] = 0
6711 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
6712 instr[28,25] = 1111
6713 instr[24] = 0
6714 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
6715 instr[21] = 1
6716 instr[20,16] = Vm
6717 instr[15,12] ==> opcode : 0000 ==> FMUL, 0001 ==> FDIV
6718 0010 ==> FADD, 0011 ==> FSUB,
6719 0100 ==> FMAX, 0101 ==> FMIN
6720 0110 ==> FMAXNM, 0111 ==> FMINNM
6721 1000 ==> FNMUL, ow ==> UNALLOC
6722 instr[11,10] = 10
6723 instr[9,5] = Vn
6724 instr[4,0] = Vd */
6725
6726 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
6727 | uimm (aarch64_get_instr (cpu), 29, 29);
6728 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
6729 /* Dispatch on opcode. */
6730 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 15, 12);
6731
6732 if (type > 1)
6733 HALT_UNALLOC;
6734
6735 if (M_S != 0)
6736 HALT_UNALLOC;
6737
6738 if (type)
6739 switch (dispatch)
6740 {
6741 case 0: fmuld (cpu); return;
6742 case 1: fdivd (cpu); return;
6743 case 2: faddd (cpu); return;
6744 case 3: fsubd (cpu); return;
6745 case 6: do_FMAXNM (cpu); return;
6746 case 7: do_FMINNM (cpu); return;
6747 case 8: fnmuld (cpu); return;
6748
6749 /* Have not yet implemented fmax and fmin. */
6750 case 4:
6751 case 5:
6752 HALT_NYI;
6753
6754 default:
6755 HALT_UNALLOC;
6756 }
6757 else /* type == 0 => floats. */
6758 switch (dispatch)
6759 {
6760 case 0: fmuls (cpu); return;
6761 case 1: fdivs (cpu); return;
6762 case 2: fadds (cpu); return;
6763 case 3: fsubs (cpu); return;
6764 case 6: do_FMAXNM (cpu); return;
6765 case 7: do_FMINNM (cpu); return;
6766 case 8: fnmuls (cpu); return;
6767
6768 case 4:
6769 case 5:
6770 HALT_NYI;
6771
6772 default:
6773 HALT_UNALLOC;
6774 }
6775 }
6776
6777 static void
6778 dexSimpleFPCondSelect (sim_cpu *cpu)
6779 {
6780 /* FCSEL
6781 instr[31,23] = 0 0011 1100
6782 instr[22] = 0=>single 1=>double
6783 instr[21] = 1
6784 instr[20,16] = Sm
6785 instr[15,12] = cond
6786 instr[11,10] = 11
6787 instr[9,5] = Sn
6788 instr[4,0] = Cpu */
6789 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
6790 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
6791 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
6792 uint32_t set = testConditionCode (cpu, uimm (aarch64_get_instr (cpu), 15, 12));
6793
6794 NYI_assert (31, 23, 0x03C);
6795 NYI_assert (11, 10, 0x3);
6796
6797 if (uimm (aarch64_get_instr (cpu), 22, 22))
6798 aarch64_set_FP_double (cpu, sd, set ? sn : sm);
6799 else
6800 aarch64_set_FP_float (cpu, sd, set ? sn : sm);
6801 }
6802
6803 /* Store 32 bit unscaled signed 9 bit. */
6804 static void
6805 fsturs (sim_cpu *cpu, int32_t offset)
6806 {
6807 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6808 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6809
6810 aarch64_set_mem_float (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
6811 aarch64_get_FP_float (cpu, rn));
6812 }
6813
6814 /* Store 64 bit unscaled signed 9 bit. */
6815 static void
6816 fsturd (sim_cpu *cpu, int32_t offset)
6817 {
6818 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6819 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6820
6821 aarch64_set_mem_double (cpu, aarch64_get_reg_u64 (cpu, st, 1) + offset,
6822 aarch64_get_FP_double (cpu, rn));
6823 }
6824
6825 /* Store 128 bit unscaled signed 9 bit. */
6826 static void
6827 fsturq (sim_cpu *cpu, int32_t offset)
6828 {
6829 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6830 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6831 FRegister a;
6832
6833 aarch64_get_FP_long_double (cpu, rn, & a);
6834 aarch64_set_mem_long_double (cpu,
6835 aarch64_get_reg_u64 (cpu, st, 1)
6836 + offset, a);
6837 }
6838
6839 /* TODO FP move register. */
6840
6841 /* 32 bit fp to fp move register. */
6842 static void
6843 ffmovs (sim_cpu *cpu)
6844 {
6845 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6846 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6847
6848 aarch64_set_FP_float (cpu, st, aarch64_get_FP_float (cpu, rn));
6849 }
6850
6851 /* 64 bit fp to fp move register. */
6852 static void
6853 ffmovd (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_double (cpu, st, aarch64_get_FP_double (cpu, rn));
6859 }
6860
6861 /* 32 bit GReg to Vec move register. */
6862 static void
6863 fgmovs (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_vec_u32 (cpu, st, 0, aarch64_get_reg_u32 (cpu, rn, NO_SP));
6869 }
6870
6871 /* 64 bit g to fp move register. */
6872 static void
6873 fgmovd (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_u64 (cpu, st, 0, aarch64_get_reg_u64 (cpu, rn, NO_SP));
6879 }
6880
6881 /* 32 bit fp to g move register. */
6882 static void
6883 gfmovs (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_reg_u64 (cpu, st, NO_SP, aarch64_get_vec_u32 (cpu, rn, 0));
6889 }
6890
6891 /* 64 bit fp to g move register. */
6892 static void
6893 gfmovd (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_u64 (cpu, rn, 0));
6899 }
6900
6901 /* FP move immediate
6902
6903 These install an immediate 8 bit value in the target register
6904 where the 8 bits comprise 1 sign bit, 4 bits of fraction and a 3
6905 bit exponent. */
6906
6907 static void
6908 fmovs (sim_cpu *cpu)
6909 {
6910 unsigned int sd = uimm (aarch64_get_instr (cpu), 4, 0);
6911 uint32_t imm = uimm (aarch64_get_instr (cpu), 20, 13);
6912 float f = fp_immediate_for_encoding_32 (imm);
6913
6914 aarch64_set_FP_float (cpu, sd, f);
6915 }
6916
6917 static void
6918 fmovd (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 double d = fp_immediate_for_encoding_64 (imm);
6923
6924 aarch64_set_FP_double (cpu, sd, d);
6925 }
6926
6927 static void
6928 dexSimpleFPImmediate (sim_cpu *cpu)
6929 {
6930 /* instr[31,23] == 00111100
6931 instr[22] == type : single(0)/double(1)
6932 instr[21] == 1
6933 instr[20,13] == imm8
6934 instr[12,10] == 100
6935 instr[9,5] == imm5 : 00000 ==> PK, ow ==> UNALLOC
6936 instr[4,0] == Rd */
6937 uint32_t imm5 = uimm (aarch64_get_instr (cpu), 9, 5);
6938
6939 NYI_assert (31, 23, 0x3C);
6940
6941 if (imm5 != 0)
6942 HALT_UNALLOC;
6943
6944 if (uimm (aarch64_get_instr (cpu), 22, 22))
6945 fmovd (cpu);
6946 else
6947 fmovs (cpu);
6948 }
6949
6950 /* TODO specific decode and execute for group Load Store. */
6951
6952 /* TODO FP load/store single register (unscaled offset). */
6953
6954 /* TODO load 8 bit unscaled signed 9 bit. */
6955 /* TODO load 16 bit unscaled signed 9 bit. */
6956
6957 /* Load 32 bit unscaled signed 9 bit. */
6958 static void
6959 fldurs (sim_cpu *cpu, int32_t offset)
6960 {
6961 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6962 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6963
6964 aarch64_set_FP_float (cpu, st, aarch64_get_mem_float
6965 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
6966 }
6967
6968 /* Load 64 bit unscaled signed 9 bit. */
6969 static void
6970 fldurd (sim_cpu *cpu, int32_t offset)
6971 {
6972 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6973 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6974
6975 aarch64_set_FP_double (cpu, st, aarch64_get_mem_double
6976 (cpu, aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset));
6977 }
6978
6979 /* Load 128 bit unscaled signed 9 bit. */
6980 static void
6981 fldurq (sim_cpu *cpu, int32_t offset)
6982 {
6983 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
6984 unsigned int st = uimm (aarch64_get_instr (cpu), 4, 0);
6985 FRegister a;
6986 uint64_t addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
6987
6988 aarch64_get_mem_long_double (cpu, addr, & a);
6989 aarch64_set_FP_long_double (cpu, st, a);
6990 }
6991
6992 /* TODO store 8 bit unscaled signed 9 bit. */
6993 /* TODO store 16 bit unscaled signed 9 bit. */
6994
6995
6996 /* 1 source. */
6997
6998 /* Float absolute value. */
6999 static void
7000 fabss (sim_cpu *cpu)
7001 {
7002 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7003 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7004 float value = aarch64_get_FP_float (cpu, sn);
7005
7006 aarch64_set_FP_float (cpu, sd, fabsf (value));
7007 }
7008
7009 /* Double absolute value. */
7010 static void
7011 fabcpu (sim_cpu *cpu)
7012 {
7013 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7014 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7015 double value = aarch64_get_FP_double (cpu, sn);
7016
7017 aarch64_set_FP_double (cpu, sd, fabs (value));
7018 }
7019
7020 /* Float negative value. */
7021 static void
7022 fnegs (sim_cpu *cpu)
7023 {
7024 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7025 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7026
7027 aarch64_set_FP_float (cpu, sd, - aarch64_get_FP_float (cpu, sn));
7028 }
7029
7030 /* Double negative value. */
7031 static void
7032 fnegd (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_double (cpu, sd, - aarch64_get_FP_double (cpu, sn));
7038 }
7039
7040 /* Float square root. */
7041 static void
7042 fsqrts (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_float (cpu, sd, sqrt (aarch64_get_FP_float (cpu, sn)));
7048 }
7049
7050 /* Double square root. */
7051 static void
7052 fsqrtd (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_double (cpu, sd,
7058 sqrt (aarch64_get_FP_double (cpu, sn)));
7059 }
7060
7061 /* Convert double to float. */
7062 static void
7063 fcvtds (sim_cpu *cpu)
7064 {
7065 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7066 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7067
7068 aarch64_set_FP_float (cpu, sd, (float) aarch64_get_FP_double (cpu, sn));
7069 }
7070
7071 /* Convert float to double. */
7072 static void
7073 fcvtcpu (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_double (cpu, sd, (double) aarch64_get_FP_float (cpu, sn));
7079 }
7080
7081 static void
7082 do_FRINT (sim_cpu *cpu)
7083 {
7084 /* instr[31,23] = 0001 1110 0
7085 instr[22] = single(0)/double(1)
7086 instr[21,18] = 1001
7087 instr[17,15] = rounding mode
7088 instr[14,10] = 10000
7089 instr[9,5] = source
7090 instr[4,0] = dest */
7091
7092 float val;
7093 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7094 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7095 unsigned int rmode = uimm (aarch64_get_instr (cpu), 17, 15);
7096
7097 NYI_assert (31, 23, 0x03C);
7098 NYI_assert (21, 18, 0x9);
7099 NYI_assert (14, 10, 0x10);
7100
7101 if (rmode == 6 || rmode == 7)
7102 /* FIXME: Add support for rmode == 6 exactness check. */
7103 rmode = uimm (aarch64_get_FPSR (cpu), 23, 22);
7104
7105 if (uimm (aarch64_get_instr (cpu), 22, 22))
7106 {
7107 double val = aarch64_get_FP_double (cpu, rs);
7108
7109 switch (rmode)
7110 {
7111 case 0: /* mode N: nearest or even. */
7112 {
7113 double rval = round (val);
7114
7115 if (val - rval == 0.5)
7116 {
7117 if (((rval / 2.0) * 2.0) != rval)
7118 rval += 1.0;
7119 }
7120
7121 aarch64_set_FP_double (cpu, rd, round (val));
7122 return;
7123 }
7124
7125 case 1: /* mode P: towards +inf. */
7126 if (val < 0.0)
7127 aarch64_set_FP_double (cpu, rd, trunc (val));
7128 else
7129 aarch64_set_FP_double (cpu, rd, round (val));
7130 return;
7131
7132 case 2: /* mode M: towards -inf. */
7133 if (val < 0.0)
7134 aarch64_set_FP_double (cpu, rd, round (val));
7135 else
7136 aarch64_set_FP_double (cpu, rd, trunc (val));
7137 return;
7138
7139 case 3: /* mode Z: towards 0. */
7140 aarch64_set_FP_double (cpu, rd, trunc (val));
7141 return;
7142
7143 case 4: /* mode A: away from 0. */
7144 aarch64_set_FP_double (cpu, rd, round (val));
7145 return;
7146
7147 case 6: /* mode X: use FPCR with exactness check. */
7148 case 7: /* mode I: use FPCR mode. */
7149 HALT_NYI;
7150
7151 default:
7152 HALT_UNALLOC;
7153 }
7154 }
7155
7156 val = aarch64_get_FP_float (cpu, rs);
7157
7158 switch (rmode)
7159 {
7160 case 0: /* mode N: nearest or even. */
7161 {
7162 float rval = roundf (val);
7163
7164 if (val - rval == 0.5)
7165 {
7166 if (((rval / 2.0) * 2.0) != rval)
7167 rval += 1.0;
7168 }
7169
7170 aarch64_set_FP_float (cpu, rd, rval);
7171 return;
7172 }
7173
7174 case 1: /* mode P: towards +inf. */
7175 if (val < 0.0)
7176 aarch64_set_FP_float (cpu, rd, truncf (val));
7177 else
7178 aarch64_set_FP_float (cpu, rd, roundf (val));
7179 return;
7180
7181 case 2: /* mode M: towards -inf. */
7182 if (val < 0.0)
7183 aarch64_set_FP_float (cpu, rd, truncf (val));
7184 else
7185 aarch64_set_FP_float (cpu, rd, roundf (val));
7186 return;
7187
7188 case 3: /* mode Z: towards 0. */
7189 aarch64_set_FP_float (cpu, rd, truncf (val));
7190 return;
7191
7192 case 4: /* mode A: away from 0. */
7193 aarch64_set_FP_float (cpu, rd, roundf (val));
7194 return;
7195
7196 case 6: /* mode X: use FPCR with exactness check. */
7197 case 7: /* mode I: use FPCR mode. */
7198 HALT_NYI;
7199
7200 default:
7201 HALT_UNALLOC;
7202 }
7203 }
7204
7205 static void
7206 dexSimpleFPDataProc1Source (sim_cpu *cpu)
7207 {
7208 /* instr[31] ==> M : 0 ==> OK, 1 ==> UNALLOC
7209 instr[30] = 0
7210 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7211 instr[28,25] = 1111
7212 instr[24] = 0
7213 instr[23,22] ==> type : 00 ==> source is single,
7214 01 ==> source is double
7215 10 ==> UNALLOC
7216 11 ==> UNALLOC or source is half
7217 instr[21] = 1
7218 instr[20,15] ==> opcode : with type 00 or 01
7219 000000 ==> FMOV, 000001 ==> FABS,
7220 000010 ==> FNEG, 000011 ==> FSQRT,
7221 000100 ==> UNALLOC, 000101 ==> FCVT,(to single/double)
7222 000110 ==> UNALLOC, 000111 ==> FCVT (to half)
7223 001000 ==> FRINTN, 001001 ==> FRINTP,
7224 001010 ==> FRINTM, 001011 ==> FRINTZ,
7225 001100 ==> FRINTA, 001101 ==> UNALLOC
7226 001110 ==> FRINTX, 001111 ==> FRINTI
7227 with type 11
7228 000100 ==> FCVT (half-to-single)
7229 000101 ==> FCVT (half-to-double)
7230 instr[14,10] = 10000. */
7231
7232 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
7233 | uimm (aarch64_get_instr (cpu), 29, 29);
7234 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
7235 uint32_t opcode = uimm (aarch64_get_instr (cpu), 20, 15);
7236
7237 if (M_S != 0)
7238 HALT_UNALLOC;
7239
7240 if (type == 3)
7241 {
7242 if (opcode == 4 || opcode == 5)
7243 HALT_NYI;
7244 else
7245 HALT_UNALLOC;
7246 }
7247
7248 if (type == 2)
7249 HALT_UNALLOC;
7250
7251 switch (opcode)
7252 {
7253 case 0:
7254 if (type)
7255 ffmovd (cpu);
7256 else
7257 ffmovs (cpu);
7258 return;
7259
7260 case 1:
7261 if (type)
7262 fabcpu (cpu);
7263 else
7264 fabss (cpu);
7265 return;
7266
7267 case 2:
7268 if (type)
7269 fnegd (cpu);
7270 else
7271 fnegs (cpu);
7272 return;
7273
7274 case 3:
7275 if (type)
7276 fsqrtd (cpu);
7277 else
7278 fsqrts (cpu);
7279 return;
7280
7281 case 4:
7282 if (type)
7283 fcvtds (cpu);
7284 else
7285 HALT_UNALLOC;
7286 return;
7287
7288 case 5:
7289 if (type)
7290 HALT_UNALLOC;
7291 fcvtcpu (cpu);
7292 return;
7293
7294 case 8: /* FRINTN etc. */
7295 case 9:
7296 case 10:
7297 case 11:
7298 case 12:
7299 case 14:
7300 case 15:
7301 do_FRINT (cpu);
7302 return;
7303
7304 case 7: /* FCVT double/single to half precision. */
7305 case 13:
7306 HALT_NYI;
7307
7308 default:
7309 HALT_UNALLOC;
7310 }
7311 }
7312
7313 /* 32 bit signed int to float. */
7314 static void
7315 scvtf32 (sim_cpu *cpu)
7316 {
7317 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7318 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7319
7320 aarch64_set_FP_float
7321 (cpu, sd, (float) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7322 }
7323
7324 /* signed int to float. */
7325 static void
7326 scvtf (sim_cpu *cpu)
7327 {
7328 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7329 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7330
7331 aarch64_set_FP_float
7332 (cpu, sd, (float) aarch64_get_reg_s64 (cpu, rn, NO_SP));
7333 }
7334
7335 /* 32 bit signed int to double. */
7336 static void
7337 scvtd32 (sim_cpu *cpu)
7338 {
7339 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7340 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7341
7342 aarch64_set_FP_double
7343 (cpu, sd, (double) aarch64_get_reg_s32 (cpu, rn, NO_SP));
7344 }
7345
7346 /* signed int to double. */
7347 static void
7348 scvtd (sim_cpu *cpu)
7349 {
7350 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7351 unsigned sd = uimm (aarch64_get_instr (cpu), 4, 0);
7352
7353 aarch64_set_FP_double
7354 (cpu, sd, (double) aarch64_get_reg_s64 (cpu, rn, NO_SP));
7355 }
7356
7357 static const float FLOAT_INT_MAX = (float) INT_MAX;
7358 static const float FLOAT_INT_MIN = (float) INT_MIN;
7359 static const double DOUBLE_INT_MAX = (double) INT_MAX;
7360 static const double DOUBLE_INT_MIN = (double) INT_MIN;
7361 static const float FLOAT_LONG_MAX = (float) LONG_MAX;
7362 static const float FLOAT_LONG_MIN = (float) LONG_MIN;
7363 static const double DOUBLE_LONG_MAX = (double) LONG_MAX;
7364 static const double DOUBLE_LONG_MIN = (double) LONG_MIN;
7365
7366 /* Check for FP exception conditions:
7367 NaN raises IO
7368 Infinity raises IO
7369 Out of Range raises IO and IX and saturates value
7370 Denormal raises ID and IX and sets to zero. */
7371 #define RAISE_EXCEPTIONS(F, VALUE, FTYPE, ITYPE) \
7372 do \
7373 { \
7374 switch (fpclassify (F)) \
7375 { \
7376 case FP_INFINITE: \
7377 case FP_NAN: \
7378 aarch64_set_FPSR (cpu, IO); \
7379 if (signbit (F)) \
7380 VALUE = ITYPE##_MAX; \
7381 else \
7382 VALUE = ITYPE##_MIN; \
7383 break; \
7384 \
7385 case FP_NORMAL: \
7386 if (F >= FTYPE##_##ITYPE##_MAX) \
7387 { \
7388 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7389 VALUE = ITYPE##_MAX; \
7390 } \
7391 else if (F <= FTYPE##_##ITYPE##_MIN) \
7392 { \
7393 aarch64_set_FPSR_bits (cpu, IO | IX, IO | IX); \
7394 VALUE = ITYPE##_MIN; \
7395 } \
7396 break; \
7397 \
7398 case FP_SUBNORMAL: \
7399 aarch64_set_FPSR_bits (cpu, IO | IX | ID, IX | ID); \
7400 VALUE = 0; \
7401 break; \
7402 \
7403 default: \
7404 case FP_ZERO: \
7405 VALUE = 0; \
7406 break; \
7407 } \
7408 } \
7409 while (0)
7410
7411 /* 32 bit convert float to signed int truncate towards zero. */
7412 static void
7413 fcvtszs32 (sim_cpu *cpu)
7414 {
7415 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7416 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7417 /* TODO : check that this rounds toward zero. */
7418 float f = aarch64_get_FP_float (cpu, sn);
7419 int32_t value = (int32_t) f;
7420
7421 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
7422
7423 /* Avoid sign extension to 64 bit. */
7424 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7425 }
7426
7427 /* 64 bit convert float to signed int truncate towards zero. */
7428 static void
7429 fcvtszs (sim_cpu *cpu)
7430 {
7431 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7432 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7433 float f = aarch64_get_FP_float (cpu, sn);
7434 int64_t value = (int64_t) f;
7435
7436 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
7437
7438 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7439 }
7440
7441 /* 32 bit convert double to signed int truncate towards zero. */
7442 static void
7443 fcvtszd32 (sim_cpu *cpu)
7444 {
7445 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7446 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7447 /* TODO : check that this rounds toward zero. */
7448 double d = aarch64_get_FP_double (cpu, sn);
7449 int32_t value = (int32_t) d;
7450
7451 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
7452
7453 /* Avoid sign extension to 64 bit. */
7454 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
7455 }
7456
7457 /* 64 bit convert double to signed int truncate towards zero. */
7458 static void
7459 fcvtszd (sim_cpu *cpu)
7460 {
7461 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7462 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7463 /* TODO : check that this rounds toward zero. */
7464 double d = aarch64_get_FP_double (cpu, sn);
7465 int64_t value;
7466
7467 value = (int64_t) d;
7468
7469 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7470
7471 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
7472 }
7473
7474 static void
7475 do_fcvtzu (sim_cpu *cpu)
7476 {
7477 /* instr[31] = size: 32-bit (0), 64-bit (1)
7478 instr[30,23] = 00111100
7479 instr[22] = type: single (0)/ double (1)
7480 instr[21] = enable (0)/disable(1) precision
7481 instr[20,16] = 11001
7482 instr[15,10] = precision
7483 instr[9,5] = Rs
7484 instr[4,0] = Rd. */
7485
7486 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7487 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7488
7489 NYI_assert (30, 23, 0x3C);
7490 NYI_assert (20, 16, 0x19);
7491
7492 if (uimm (aarch64_get_instr (cpu), 21, 21) != 1)
7493 /* Convert to fixed point. */
7494 HALT_NYI;
7495
7496 if (uimm (aarch64_get_instr (cpu), 31, 31))
7497 {
7498 /* Convert to unsigned 64-bit integer. */
7499 if (uimm (aarch64_get_instr (cpu), 22, 22))
7500 {
7501 double d = aarch64_get_FP_double (cpu, rs);
7502 uint64_t value = (uint64_t) d;
7503
7504 /* Do not raise an exception if we have reached ULONG_MAX. */
7505 if (value != (1UL << 63))
7506 RAISE_EXCEPTIONS (d, value, DOUBLE, LONG);
7507
7508 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7509 }
7510 else
7511 {
7512 float f = aarch64_get_FP_float (cpu, rs);
7513 uint64_t value = (uint64_t) f;
7514
7515 /* Do not raise an exception if we have reached ULONG_MAX. */
7516 if (value != (1UL << 63))
7517 RAISE_EXCEPTIONS (f, value, FLOAT, LONG);
7518
7519 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7520 }
7521 }
7522 else
7523 {
7524 uint32_t value;
7525
7526 /* Convert to unsigned 32-bit integer. */
7527 if (uimm (aarch64_get_instr (cpu), 22, 22))
7528 {
7529 double d = aarch64_get_FP_double (cpu, rs);
7530
7531 value = (uint32_t) d;
7532 /* Do not raise an exception if we have reached UINT_MAX. */
7533 if (value != (1UL << 31))
7534 RAISE_EXCEPTIONS (d, value, DOUBLE, INT);
7535 }
7536 else
7537 {
7538 float f = aarch64_get_FP_float (cpu, rs);
7539
7540 value = (uint32_t) f;
7541 /* Do not raise an exception if we have reached UINT_MAX. */
7542 if (value != (1UL << 31))
7543 RAISE_EXCEPTIONS (f, value, FLOAT, INT);
7544 }
7545
7546 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
7547 }
7548 }
7549
7550 static void
7551 do_UCVTF (sim_cpu *cpu)
7552 {
7553 /* instr[31] = size: 32-bit (0), 64-bit (1)
7554 instr[30,23] = 001 1110 0
7555 instr[22] = type: single (0)/ double (1)
7556 instr[21] = enable (0)/disable(1) precision
7557 instr[20,16] = 0 0011
7558 instr[15,10] = precision
7559 instr[9,5] = Rs
7560 instr[4,0] = Rd. */
7561
7562 unsigned rs = uimm (aarch64_get_instr (cpu), 9, 5);
7563 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7564
7565 NYI_assert (30, 23, 0x3C);
7566 NYI_assert (20, 16, 0x03);
7567
7568 if (uimm (aarch64_get_instr (cpu), 21, 21) != 1)
7569 HALT_NYI;
7570
7571 /* FIXME: Add exception raising. */
7572 if (uimm (aarch64_get_instr (cpu), 31, 31))
7573 {
7574 uint64_t value = aarch64_get_reg_u64 (cpu, rs, NO_SP);
7575
7576 if (uimm (aarch64_get_instr (cpu), 22, 22))
7577 aarch64_set_FP_double (cpu, rd, (double) value);
7578 else
7579 aarch64_set_FP_float (cpu, rd, (float) value);
7580 }
7581 else
7582 {
7583 uint32_t value = aarch64_get_reg_u32 (cpu, rs, NO_SP);
7584
7585 if (uimm (aarch64_get_instr (cpu), 22, 22))
7586 aarch64_set_FP_double (cpu, rd, (double) value);
7587 else
7588 aarch64_set_FP_float (cpu, rd, (float) value);
7589 }
7590 }
7591
7592 static void
7593 float_vector_move (sim_cpu *cpu)
7594 {
7595 /* instr[31,17] == 100 1111 0101 0111
7596 instr[16] ==> direction 0=> to GR, 1=> from GR
7597 instr[15,10] => ???
7598 instr[9,5] ==> source
7599 instr[4,0] ==> dest. */
7600
7601 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7602 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7603
7604 NYI_assert (31, 17, 0x4F57);
7605
7606 if (uimm (aarch64_get_instr (cpu), 15, 10) != 0)
7607 HALT_UNALLOC;
7608
7609 if (uimm (aarch64_get_instr (cpu), 16, 16))
7610 aarch64_set_vec_u64 (cpu, rd, 1, aarch64_get_reg_u64 (cpu, rn, NO_SP));
7611 else
7612 aarch64_set_reg_u64 (cpu, rd, NO_SP, aarch64_get_vec_u64 (cpu, rn, 1));
7613 }
7614
7615 static void
7616 dexSimpleFPIntegerConvert (sim_cpu *cpu)
7617 {
7618 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
7619 instr[30 = 0
7620 instr[29] = S : 0 ==> OK, 1 ==> UNALLOC
7621 instr[28,25] = 1111
7622 instr[24] = 0
7623 instr[23,22] = type : 00 ==> single, 01 ==> double, 1x ==> UNALLOC
7624 instr[21] = 1
7625 instr[20,19] = rmode
7626 instr[18,16] = opcode
7627 instr[15,10] = 10 0000 */
7628
7629 uint32_t rmode_opcode;
7630 uint32_t size_type;
7631 uint32_t type;
7632 uint32_t size;
7633 uint32_t S;
7634
7635 if (uimm (aarch64_get_instr (cpu), 31, 17) == 0x4F57)
7636 {
7637 float_vector_move (cpu);
7638 return;
7639 }
7640
7641 size = uimm (aarch64_get_instr (cpu), 31, 31);
7642 S = uimm (aarch64_get_instr (cpu), 29, 29);
7643 if (S != 0)
7644 HALT_UNALLOC;
7645
7646 type = uimm (aarch64_get_instr (cpu), 23, 22);
7647 if (type > 1)
7648 HALT_UNALLOC;
7649
7650 rmode_opcode = uimm (aarch64_get_instr (cpu), 20, 16);
7651 size_type = (size << 1) | type; /* 0==32f, 1==32d, 2==64f, 3==64d. */
7652
7653 switch (rmode_opcode)
7654 {
7655 case 2: /* SCVTF. */
7656 switch (size_type)
7657 {
7658 case 0: scvtf32 (cpu); return;
7659 case 1: scvtd32 (cpu); return;
7660 case 2: scvtf (cpu); return;
7661 case 3: scvtd (cpu); return;
7662 default:
7663 HALT_UNREACHABLE;
7664 }
7665
7666 case 6: /* FMOV GR, Vec. */
7667 switch (size_type)
7668 {
7669 case 0: gfmovs (cpu); return;
7670 case 3: gfmovd (cpu); return;
7671 default: HALT_UNALLOC;
7672 }
7673
7674 case 7: /* FMOV vec, GR. */
7675 switch (size_type)
7676 {
7677 case 0: fgmovs (cpu); return;
7678 case 3: fgmovd (cpu); return;
7679 default: HALT_UNALLOC;
7680 }
7681
7682 case 24: /* FCVTZS. */
7683 switch (size_type)
7684 {
7685 case 0: fcvtszs32 (cpu); return;
7686 case 1: fcvtszd32 (cpu); return;
7687 case 2: fcvtszs (cpu); return;
7688 case 3: fcvtszd (cpu); return;
7689 default: HALT_UNREACHABLE;
7690 }
7691
7692 case 25: do_fcvtzu (cpu); return;
7693 case 3: do_UCVTF (cpu); return;
7694
7695 case 0: /* FCVTNS. */
7696 case 1: /* FCVTNU. */
7697 case 4: /* FCVTAS. */
7698 case 5: /* FCVTAU. */
7699 case 8: /* FCVPTS. */
7700 case 9: /* FCVTPU. */
7701 case 16: /* FCVTMS. */
7702 case 17: /* FCVTMU. */
7703 default:
7704 HALT_NYI;
7705 }
7706 }
7707
7708 static void
7709 set_flags_for_float_compare (sim_cpu *cpu, float fvalue1, float fvalue2)
7710 {
7711 uint32_t flags;
7712
7713 if (isnan (fvalue1) || isnan (fvalue2))
7714 flags = C|V;
7715 else
7716 {
7717 float result = fvalue1 - fvalue2;
7718
7719 if (result == 0.0)
7720 flags = Z|C;
7721 else if (result < 0)
7722 flags = N;
7723 else /* (result > 0). */
7724 flags = C;
7725 }
7726
7727 aarch64_set_CPSR (cpu, flags);
7728 }
7729
7730 static void
7731 fcmps (sim_cpu *cpu)
7732 {
7733 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7734 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7735
7736 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7737 float fvalue2 = aarch64_get_FP_float (cpu, sm);
7738
7739 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
7740 }
7741
7742 /* Float compare to zero -- Invalid Operation exception
7743 only on signaling NaNs. */
7744 static void
7745 fcmpzs (sim_cpu *cpu)
7746 {
7747 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7748 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7749
7750 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
7751 }
7752
7753 /* Float compare -- Invalid Operation exception on all NaNs. */
7754 static void
7755 fcmpes (sim_cpu *cpu)
7756 {
7757 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7758 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7759
7760 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7761 float fvalue2 = aarch64_get_FP_float (cpu, sm);
7762
7763 set_flags_for_float_compare (cpu, fvalue1, fvalue2);
7764 }
7765
7766 /* Float compare to zero -- Invalid Operation exception on all NaNs. */
7767 static void
7768 fcmpzes (sim_cpu *cpu)
7769 {
7770 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7771 float fvalue1 = aarch64_get_FP_float (cpu, sn);
7772
7773 set_flags_for_float_compare (cpu, fvalue1, 0.0f);
7774 }
7775
7776 static void
7777 set_flags_for_double_compare (sim_cpu *cpu, double dval1, double dval2)
7778 {
7779 uint32_t flags;
7780
7781 if (isnan (dval1) || isnan (dval2))
7782 flags = C|V;
7783 else
7784 {
7785 double result = dval1 - dval2;
7786
7787 if (result == 0.0)
7788 flags = Z|C;
7789 else if (result < 0)
7790 flags = N;
7791 else /* (result > 0). */
7792 flags = C;
7793 }
7794
7795 aarch64_set_CPSR (cpu, flags);
7796 }
7797
7798 /* Double compare -- Invalid Operation exception only on signaling NaNs. */
7799 static void
7800 fcmpd (sim_cpu *cpu)
7801 {
7802 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7803 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7804
7805 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7806 double dvalue2 = aarch64_get_FP_double (cpu, sm);
7807
7808 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
7809 }
7810
7811 /* Double compare to zero -- Invalid Operation exception
7812 only on signaling NaNs. */
7813 static void
7814 fcmpzd (sim_cpu *cpu)
7815 {
7816 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7817 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7818
7819 set_flags_for_double_compare (cpu, dvalue1, 0.0);
7820 }
7821
7822 /* Double compare -- Invalid Operation exception on all NaNs. */
7823 static void
7824 fcmped (sim_cpu *cpu)
7825 {
7826 unsigned sm = uimm (aarch64_get_instr (cpu), 20, 16);
7827 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7828
7829 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7830 double dvalue2 = aarch64_get_FP_double (cpu, sm);
7831
7832 set_flags_for_double_compare (cpu, dvalue1, dvalue2);
7833 }
7834
7835 /* Double compare to zero -- Invalid Operation exception on all NaNs. */
7836 static void
7837 fcmpzed (sim_cpu *cpu)
7838 {
7839 unsigned sn = uimm (aarch64_get_instr (cpu), 9, 5);
7840 double dvalue1 = aarch64_get_FP_double (cpu, sn);
7841
7842 set_flags_for_double_compare (cpu, dvalue1, 0.0);
7843 }
7844
7845 static void
7846 dexSimpleFPCompare (sim_cpu *cpu)
7847 {
7848 /* assert instr[28,25] == 1111
7849 instr[30:24:21:13,10] = 0011000
7850 instr[31] = M : 0 ==> OK, 1 ==> UNALLOC
7851 instr[29] ==> S : 0 ==> OK, 1 ==> UNALLOC
7852 instr[23,22] ==> type : 0 ==> single, 01 ==> double, 1x ==> UNALLOC
7853 instr[15,14] ==> op : 00 ==> OK, ow ==> UNALLOC
7854 instr[4,0] ==> opcode2 : 00000 ==> FCMP, 10000 ==> FCMPE,
7855 01000 ==> FCMPZ, 11000 ==> FCMPEZ,
7856 ow ==> UNALLOC */
7857 uint32_t dispatch;
7858 uint32_t M_S = (uimm (aarch64_get_instr (cpu), 31, 31) << 1)
7859 | uimm (aarch64_get_instr (cpu), 29, 29);
7860 uint32_t type = uimm (aarch64_get_instr (cpu), 23, 22);
7861 uint32_t op = uimm (aarch64_get_instr (cpu), 15, 14);
7862 uint32_t op2_2_0 = uimm (aarch64_get_instr (cpu), 2, 0);
7863
7864 if (op2_2_0 != 0)
7865 HALT_UNALLOC;
7866
7867 if (M_S != 0)
7868 HALT_UNALLOC;
7869
7870 if (type > 1)
7871 HALT_UNALLOC;
7872
7873 if (op != 0)
7874 HALT_UNALLOC;
7875
7876 /* dispatch on type and top 2 bits of opcode. */
7877 dispatch = (type << 2) | uimm (aarch64_get_instr (cpu), 4, 3);
7878
7879 switch (dispatch)
7880 {
7881 case 0: fcmps (cpu); return;
7882 case 1: fcmpzs (cpu); return;
7883 case 2: fcmpes (cpu); return;
7884 case 3: fcmpzes (cpu); return;
7885 case 4: fcmpd (cpu); return;
7886 case 5: fcmpzd (cpu); return;
7887 case 6: fcmped (cpu); return;
7888 case 7: fcmpzed (cpu); return;
7889 default: HALT_UNREACHABLE;
7890 }
7891 }
7892
7893 static void
7894 do_scalar_FADDP (sim_cpu *cpu)
7895 {
7896 /* instr [31,23] = 011111100
7897 instr [22] = single(0)/double(1)
7898 instr [21,10] = 1100 0011 0110
7899 instr [9,5] = Fn
7900 instr [4,0] = Fd. */
7901
7902 unsigned Fn = uimm (aarch64_get_instr (cpu), 9, 5);
7903 unsigned Fd = uimm (aarch64_get_instr (cpu), 4, 0);
7904
7905 NYI_assert (31, 23, 0x0FC);
7906 NYI_assert (21, 10, 0xC36);
7907
7908 if (uimm (aarch64_get_instr (cpu), 22, 22))
7909 {
7910 double val1 = aarch64_get_vec_double (cpu, Fn, 0);
7911 double val2 = aarch64_get_vec_double (cpu, Fn, 1);
7912
7913 aarch64_set_FP_double (cpu, Fd, val1 + val2);
7914 }
7915 else
7916 {
7917 float val1 = aarch64_get_vec_float (cpu, Fn, 0);
7918 float val2 = aarch64_get_vec_float (cpu, Fn, 1);
7919
7920 aarch64_set_FP_float (cpu, Fd, val1 + val2);
7921 }
7922 }
7923
7924 /* Floating point absolute difference. */
7925
7926 static void
7927 do_scalar_FABD (sim_cpu *cpu)
7928 {
7929 /* instr [31,23] = 0111 1110 1
7930 instr [22] = float(0)/double(1)
7931 instr [21] = 1
7932 instr [20,16] = Rm
7933 instr [15,10] = 1101 01
7934 instr [9, 5] = Rn
7935 instr [4, 0] = Rd. */
7936
7937 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
7938 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7939 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7940
7941 NYI_assert (31, 23, 0x0FD);
7942 NYI_assert (21, 21, 1);
7943 NYI_assert (15, 10, 0x35);
7944
7945 if (uimm (aarch64_get_instr (cpu), 22, 22))
7946 aarch64_set_FP_double (cpu, rd,
7947 fabs (aarch64_get_FP_double (cpu, rn)
7948 - aarch64_get_FP_double (cpu, rm)));
7949 else
7950 aarch64_set_FP_float (cpu, rd,
7951 fabsf (aarch64_get_FP_float (cpu, rn)
7952 - aarch64_get_FP_float (cpu, rm)));
7953 }
7954
7955 static void
7956 do_scalar_CMGT (sim_cpu *cpu)
7957 {
7958 /* instr [31,21] = 0101 1110 111
7959 instr [20,16] = Rm
7960 instr [15,10] = 00 1101
7961 instr [9, 5] = Rn
7962 instr [4, 0] = Rd. */
7963
7964 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
7965 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7966 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7967
7968 NYI_assert (31, 21, 0x2F7);
7969 NYI_assert (15, 10, 0x0D);
7970
7971 aarch64_set_vec_u64 (cpu, rd, 0,
7972 aarch64_get_vec_u64 (cpu, rn, 0) >
7973 aarch64_get_vec_u64 (cpu, rm, 0) ? -1L : 0L);
7974 }
7975
7976 static void
7977 do_scalar_USHR (sim_cpu *cpu)
7978 {
7979 /* instr [31,23] = 0111 1111 0
7980 instr [22,16] = shift amount
7981 instr [15,10] = 0000 01
7982 instr [9, 5] = Rn
7983 instr [4, 0] = Rd. */
7984
7985 unsigned amount = 128 - uimm (aarch64_get_instr (cpu), 22, 16);
7986 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
7987 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
7988
7989 NYI_assert (31, 23, 0x0FE);
7990 NYI_assert (15, 10, 0x01);
7991
7992 aarch64_set_vec_u64 (cpu, rd, 0,
7993 aarch64_get_vec_u64 (cpu, rn, 0) >> amount);
7994 }
7995
7996 static void
7997 do_scalar_SHL (sim_cpu *cpu)
7998 {
7999 /* instr [31,23] = 0111 1101 0
8000 instr [22,16] = shift amount
8001 instr [15,10] = 0101 01
8002 instr [9, 5] = Rn
8003 instr [4, 0] = Rd. */
8004
8005 unsigned amount = uimm (aarch64_get_instr (cpu), 22, 16) - 64;
8006 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8007 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8008
8009 NYI_assert (31, 23, 0x0BE);
8010 NYI_assert (15, 10, 0x15);
8011
8012 if (uimm (aarch64_get_instr (cpu), 22, 22) == 0)
8013 HALT_UNALLOC;
8014
8015 aarch64_set_vec_u64 (cpu, rd, 0,
8016 aarch64_get_vec_u64 (cpu, rn, 0) << amount);
8017 }
8018
8019 /* FCMEQ FCMGT FCMGE. */
8020 static void
8021 do_scalar_FCM (sim_cpu *cpu)
8022 {
8023 /* instr [31,30] = 01
8024 instr [29] = U
8025 instr [28,24] = 1 1110
8026 instr [23] = E
8027 instr [22] = size
8028 instr [21] = 1
8029 instr [20,16] = Rm
8030 instr [15,12] = 1110
8031 instr [11] = AC
8032 instr [10] = 1
8033 instr [9, 5] = Rn
8034 instr [4, 0] = Rd. */
8035
8036 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8037 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8038 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8039 unsigned EUac = (uimm (aarch64_get_instr (cpu), 23, 23) << 2)
8040 | (uimm (aarch64_get_instr (cpu), 29, 29) << 1)
8041 | uimm (aarch64_get_instr (cpu), 11, 11);
8042 unsigned result;
8043 float val1;
8044 float val2;
8045
8046 NYI_assert (31, 30, 1);
8047 NYI_assert (28, 24, 0x1E);
8048 NYI_assert (21, 21, 1);
8049 NYI_assert (15, 12, 0xE);
8050 NYI_assert (10, 10, 1);
8051
8052 if (uimm (aarch64_get_instr (cpu), 22, 22))
8053 {
8054 double val1 = aarch64_get_FP_double (cpu, rn);
8055 double val2 = aarch64_get_FP_double (cpu, rm);
8056
8057 switch (EUac)
8058 {
8059 case 0: /* 000 */
8060 result = val1 == val2;
8061 break;
8062
8063 case 3: /* 011 */
8064 val1 = fabs (val1);
8065 val2 = fabs (val2);
8066 /* Fall through. */
8067 case 2: /* 010 */
8068 result = val1 >= val2;
8069 break;
8070
8071 case 7: /* 111 */
8072 val1 = fabs (val1);
8073 val2 = fabs (val2);
8074 /* Fall through. */
8075 case 6: /* 110 */
8076 result = val1 > val2;
8077 break;
8078
8079 default:
8080 HALT_UNALLOC;
8081 }
8082
8083 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8084 return;
8085 }
8086
8087 val1 = aarch64_get_FP_float (cpu, rn);
8088 val2 = aarch64_get_FP_float (cpu, rm);
8089
8090 switch (EUac)
8091 {
8092 case 0: /* 000 */
8093 result = val1 == val2;
8094 break;
8095
8096 case 3: /* 011 */
8097 val1 = fabsf (val1);
8098 val2 = fabsf (val2);
8099 /* Fall through. */
8100 case 2: /* 010 */
8101 result = val1 >= val2;
8102 break;
8103
8104 case 7: /* 111 */
8105 val1 = fabsf (val1);
8106 val2 = fabsf (val2);
8107 /* Fall through. */
8108 case 6: /* 110 */
8109 result = val1 > val2;
8110 break;
8111
8112 default:
8113 HALT_UNALLOC;
8114 }
8115
8116 aarch64_set_vec_u32 (cpu, rd, 0, result ? -1 : 0);
8117 }
8118
8119 /* An alias of DUP. */
8120 static void
8121 do_scalar_MOV (sim_cpu *cpu)
8122 {
8123 /* instr [31,21] = 0101 1110 000
8124 instr [20,16] = imm5
8125 instr [15,10] = 0000 01
8126 instr [9, 5] = Rn
8127 instr [4, 0] = Rd. */
8128
8129 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8130 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8131 unsigned index;
8132
8133 NYI_assert (31, 21, 0x2F0);
8134 NYI_assert (15, 10, 0x01);
8135
8136 if (uimm (aarch64_get_instr (cpu), 16, 16))
8137 {
8138 /* 8-bit. */
8139 index = uimm (aarch64_get_instr (cpu), 20, 17);
8140 aarch64_set_vec_u8
8141 (cpu, rd, 0, aarch64_get_vec_u8 (cpu, rn, index));
8142 }
8143 else if (uimm (aarch64_get_instr (cpu), 17, 17))
8144 {
8145 /* 16-bit. */
8146 index = uimm (aarch64_get_instr (cpu), 20, 18);
8147 aarch64_set_vec_u16
8148 (cpu, rd, 0, aarch64_get_vec_u16 (cpu, rn, index));
8149 }
8150 else if (uimm (aarch64_get_instr (cpu), 18, 18))
8151 {
8152 /* 32-bit. */
8153 index = uimm (aarch64_get_instr (cpu), 20, 19);
8154 aarch64_set_vec_u32
8155 (cpu, rd, 0, aarch64_get_vec_u32 (cpu, rn, index));
8156 }
8157 else if (uimm (aarch64_get_instr (cpu), 19, 19))
8158 {
8159 /* 64-bit. */
8160 index = uimm (aarch64_get_instr (cpu), 20, 20);
8161 aarch64_set_vec_u64
8162 (cpu, rd, 0, aarch64_get_vec_u64 (cpu, rn, index));
8163 }
8164 else
8165 HALT_UNALLOC;
8166 }
8167
8168 static void
8169 do_double_add (sim_cpu *cpu)
8170 {
8171 /* instr [28,25] = 1111. */
8172 unsigned Fd;
8173 unsigned Fm;
8174 unsigned Fn;
8175 double val1;
8176 double val2;
8177
8178 switch (uimm (aarch64_get_instr (cpu), 31, 23))
8179 {
8180 case 0xBC:
8181 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8182 {
8183 case 0x01: do_scalar_MOV (cpu); return;
8184 case 0x39: do_scalar_FCM (cpu); return;
8185 case 0x3B: do_scalar_FCM (cpu); return;
8186 }
8187 break;
8188
8189 case 0xBE: do_scalar_SHL (cpu); return;
8190
8191 case 0xFC:
8192 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8193 {
8194 case 0x36: do_scalar_FADDP (cpu); return;
8195 case 0x39: do_scalar_FCM (cpu); return;
8196 case 0x3B: do_scalar_FCM (cpu); return;
8197 }
8198 break;
8199
8200 case 0xFD:
8201 switch (uimm (aarch64_get_instr (cpu), 15, 10))
8202 {
8203 case 0x0D: do_scalar_CMGT (cpu); return;
8204 case 0x35: do_scalar_FABD (cpu); return;
8205 case 0x39: do_scalar_FCM (cpu); return;
8206 case 0x3B: do_scalar_FCM (cpu); return;
8207 default:
8208 HALT_NYI;
8209 }
8210
8211 case 0xFE: do_scalar_USHR (cpu); return;
8212 default:
8213 break;
8214 }
8215
8216 /* instr [31,21] = 0101 1110 111
8217 instr [20,16] = Fn
8218 instr [15,10] = 1000 01
8219 instr [9,5] = Fm
8220 instr [4,0] = Fd. */
8221 if (uimm (aarch64_get_instr (cpu), 31, 21) != 0x2F7
8222 || uimm (aarch64_get_instr (cpu), 15, 10) != 0x21)
8223 HALT_NYI;
8224
8225 Fd = uimm (aarch64_get_instr (cpu), 4, 0);
8226 Fm = uimm (aarch64_get_instr (cpu), 9, 5);
8227 Fn = uimm (aarch64_get_instr (cpu), 20, 16);
8228
8229 val1 = aarch64_get_FP_double (cpu, Fm);
8230 val2 = aarch64_get_FP_double (cpu, Fn);
8231
8232 aarch64_set_FP_double (cpu, Fd, val1 + val2);
8233 }
8234
8235 static void
8236 dexAdvSIMD1 (sim_cpu *cpu)
8237 {
8238 /* instr [28,25] = 1 111. */
8239
8240 /* we are currently only interested in the basic
8241 scalar fp routines which all have bit 30 = 0. */
8242 if (uimm (aarch64_get_instr (cpu), 30, 30))
8243 do_double_add (cpu);
8244
8245 /* instr[24] is set for FP data processing 3-source and clear for
8246 all other basic scalar fp instruction groups. */
8247 else if (uimm (aarch64_get_instr (cpu), 24, 24))
8248 dexSimpleFPDataProc3Source (cpu);
8249
8250 /* instr[21] is clear for floating <-> fixed conversions and set for
8251 all other basic scalar fp instruction groups. */
8252 else if (!uimm (aarch64_get_instr (cpu), 21, 21))
8253 dexSimpleFPFixedConvert (cpu);
8254
8255 /* instr[11,10] : 01 ==> cond compare, 10 ==> Data Proc 2 Source
8256 11 ==> cond select, 00 ==> other. */
8257 else
8258 switch (uimm (aarch64_get_instr (cpu), 11, 10))
8259 {
8260 case 1: dexSimpleFPCondCompare (cpu); return;
8261 case 2: dexSimpleFPDataProc2Source (cpu); return;
8262 case 3: dexSimpleFPCondSelect (cpu); return;
8263
8264 default:
8265 /* Now an ordered cascade of tests.
8266 FP immediate has aarch64_get_instr (cpu)[12] == 1.
8267 FP compare has aarch64_get_instr (cpu)[13] == 1.
8268 FP Data Proc 1 Source has aarch64_get_instr (cpu)[14] == 1.
8269 FP floating <--> integer conversions has aarch64_get_instr (cpu)[15] == 0. */
8270 if (uimm (aarch64_get_instr (cpu), 12, 12))
8271 dexSimpleFPImmediate (cpu);
8272
8273 else if (uimm (aarch64_get_instr (cpu), 13, 13))
8274 dexSimpleFPCompare (cpu);
8275
8276 else if (uimm (aarch64_get_instr (cpu), 14, 14))
8277 dexSimpleFPDataProc1Source (cpu);
8278
8279 else if (!uimm (aarch64_get_instr (cpu), 15, 15))
8280 dexSimpleFPIntegerConvert (cpu);
8281
8282 else
8283 /* If we get here then instr[15] == 1 which means UNALLOC. */
8284 HALT_UNALLOC;
8285 }
8286 }
8287
8288 /* PC relative addressing. */
8289
8290 static void
8291 pcadr (sim_cpu *cpu)
8292 {
8293 /* instr[31] = op : 0 ==> ADR, 1 ==> ADRP
8294 instr[30,29] = immlo
8295 instr[23,5] = immhi. */
8296 uint64_t address;
8297 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8298 uint32_t isPage = uimm (aarch64_get_instr (cpu), 31, 31);
8299 union { int64_t u64; uint64_t s64; } imm;
8300 uint64_t offset;
8301
8302 imm.s64 = simm64 (aarch64_get_instr (cpu), 23, 5);
8303 offset = imm.u64;
8304 offset = (offset << 2) | uimm (aarch64_get_instr (cpu), 30, 29);
8305
8306 address = aarch64_get_PC (cpu);
8307
8308 if (isPage)
8309 {
8310 offset <<= 12;
8311 address &= ~0xfff;
8312 }
8313
8314 aarch64_set_reg_u64 (cpu, rd, NO_SP, address + offset);
8315 }
8316
8317 /* Specific decode and execute for group Data Processing Immediate. */
8318
8319 static void
8320 dexPCRelAddressing (sim_cpu *cpu)
8321 {
8322 /* assert instr[28,24] = 10000. */
8323 pcadr (cpu);
8324 }
8325
8326 /* Immediate logical.
8327 The bimm32/64 argument is constructed by replicating a 2, 4, 8,
8328 16, 32 or 64 bit sequence pulled out at decode and possibly
8329 inverting it..
8330
8331 N.B. the output register (dest) can normally be Xn or SP
8332 the exception occurs for flag setting instructions which may
8333 only use Xn for the output (dest). The input register can
8334 never be SP. */
8335
8336 /* 32 bit and immediate. */
8337 static void
8338 and32 (sim_cpu *cpu, uint32_t bimm)
8339 {
8340 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8341 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8342
8343 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8344 aarch64_get_reg_u32 (cpu, rn, NO_SP) & bimm);
8345 }
8346
8347 /* 64 bit and immediate. */
8348 static void
8349 and64 (sim_cpu *cpu, uint64_t bimm)
8350 {
8351 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8352 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8353
8354 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8355 aarch64_get_reg_u64 (cpu, rn, NO_SP) & bimm);
8356 }
8357
8358 /* 32 bit and immediate set flags. */
8359 static void
8360 ands32 (sim_cpu *cpu, uint32_t bimm)
8361 {
8362 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8363 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8364
8365 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8366 uint32_t value2 = bimm;
8367
8368 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8369 set_flags_for_binop32 (cpu, value1 & value2);
8370 }
8371
8372 /* 64 bit and immediate set flags. */
8373 static void
8374 ands64 (sim_cpu *cpu, uint64_t bimm)
8375 {
8376 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8377 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8378
8379 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8380 uint64_t value2 = bimm;
8381
8382 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8383 set_flags_for_binop64 (cpu, value1 & value2);
8384 }
8385
8386 /* 32 bit exclusive or immediate. */
8387 static void
8388 eor32 (sim_cpu *cpu, uint32_t bimm)
8389 {
8390 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8391 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8392
8393 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8394 aarch64_get_reg_u32 (cpu, rn, NO_SP) ^ bimm);
8395 }
8396
8397 /* 64 bit exclusive or immediate. */
8398 static void
8399 eor64 (sim_cpu *cpu, uint64_t bimm)
8400 {
8401 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8402 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8403
8404 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8405 aarch64_get_reg_u64 (cpu, rn, NO_SP) ^ bimm);
8406 }
8407
8408 /* 32 bit or immediate. */
8409 static void
8410 orr32 (sim_cpu *cpu, uint32_t bimm)
8411 {
8412 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8413 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8414
8415 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8416 aarch64_get_reg_u32 (cpu, rn, NO_SP) | bimm);
8417 }
8418
8419 /* 64 bit or immediate. */
8420 static void
8421 orr64 (sim_cpu *cpu, uint64_t bimm)
8422 {
8423 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8424 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8425
8426 aarch64_set_reg_u64 (cpu, rd, SP_OK,
8427 aarch64_get_reg_u64 (cpu, rn, NO_SP) | bimm);
8428 }
8429
8430 /* Logical shifted register.
8431 These allow an optional LSL, ASR, LSR or ROR to the second source
8432 register with a count up to the register bit count.
8433 N.B register args may not be SP. */
8434
8435 /* 32 bit AND shifted register. */
8436 static void
8437 and32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8438 {
8439 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8440 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8441 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8442
8443 aarch64_set_reg_u64
8444 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8445 & shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8446 }
8447
8448 /* 64 bit AND shifted register. */
8449 static void
8450 and64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8451 {
8452 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8453 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8454 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8455
8456 aarch64_set_reg_u64
8457 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8458 & shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8459 }
8460
8461 /* 32 bit AND shifted register setting flags. */
8462 static void
8463 ands32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8464 {
8465 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8466 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8467 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8468
8469 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8470 uint32_t value2 = shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
8471 shift, count);
8472
8473 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8474 set_flags_for_binop32 (cpu, value1 & value2);
8475 }
8476
8477 /* 64 bit AND shifted register setting flags. */
8478 static void
8479 ands64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8480 {
8481 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8482 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8483 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8484
8485 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8486 uint64_t value2 = shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
8487 shift, count);
8488
8489 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8490 set_flags_for_binop64 (cpu, value1 & value2);
8491 }
8492
8493 /* 32 bit BIC shifted register. */
8494 static void
8495 bic32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8496 {
8497 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8498 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8499 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8500
8501 aarch64_set_reg_u64
8502 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8503 & ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8504 }
8505
8506 /* 64 bit BIC shifted register. */
8507 static void
8508 bic64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8509 {
8510 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8511 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8512 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8513
8514 aarch64_set_reg_u64
8515 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8516 & ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8517 }
8518
8519 /* 32 bit BIC shifted register setting flags. */
8520 static void
8521 bics32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8522 {
8523 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8524 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8525 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8526
8527 uint32_t value1 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8528 uint32_t value2 = ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP),
8529 shift, count);
8530
8531 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8532 set_flags_for_binop32 (cpu, value1 & value2);
8533 }
8534
8535 /* 64 bit BIC shifted register setting flags. */
8536 static void
8537 bics64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8538 {
8539 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8540 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8541 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8542
8543 uint64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8544 uint64_t value2 = ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP),
8545 shift, count);
8546
8547 aarch64_set_reg_u64 (cpu, rd, NO_SP, value1 & value2);
8548 set_flags_for_binop64 (cpu, value1 & value2);
8549 }
8550
8551 /* 32 bit EON shifted register. */
8552 static void
8553 eon32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8554 {
8555 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8556 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8557 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8558
8559 aarch64_set_reg_u64
8560 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8561 ^ ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8562 }
8563
8564 /* 64 bit EON shifted register. */
8565 static void
8566 eon64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8567 {
8568 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8569 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8570 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8571
8572 aarch64_set_reg_u64
8573 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8574 ^ ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8575 }
8576
8577 /* 32 bit EOR shifted register. */
8578 static void
8579 eor32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8580 {
8581 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8582 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8583 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8584
8585 aarch64_set_reg_u64
8586 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8587 ^ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8588 }
8589
8590 /* 64 bit EOR shifted register. */
8591 static void
8592 eor64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8593 {
8594 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8595 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8596 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8597
8598 aarch64_set_reg_u64
8599 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8600 ^ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8601 }
8602
8603 /* 32 bit ORR shifted register. */
8604 static void
8605 orr32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8606 {
8607 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8608 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8609 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8610
8611 aarch64_set_reg_u64
8612 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8613 | shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8614 }
8615
8616 /* 64 bit ORR shifted register. */
8617 static void
8618 orr64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8619 {
8620 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8621 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8622 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8623
8624 aarch64_set_reg_u64
8625 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8626 | shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8627 }
8628
8629 /* 32 bit ORN shifted register. */
8630 static void
8631 orn32_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8632 {
8633 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8634 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8635 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8636
8637 aarch64_set_reg_u64
8638 (cpu, rd, NO_SP, aarch64_get_reg_u32 (cpu, rn, NO_SP)
8639 | ~ shifted32 (aarch64_get_reg_u32 (cpu, rm, NO_SP), shift, count));
8640 }
8641
8642 /* 64 bit ORN shifted register. */
8643 static void
8644 orn64_shift (sim_cpu *cpu, Shift shift, uint32_t count)
8645 {
8646 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
8647 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8648 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8649
8650 aarch64_set_reg_u64
8651 (cpu, rd, NO_SP, aarch64_get_reg_u64 (cpu, rn, NO_SP)
8652 | ~ shifted64 (aarch64_get_reg_u64 (cpu, rm, NO_SP), shift, count));
8653 }
8654
8655 static void
8656 dexLogicalImmediate (sim_cpu *cpu)
8657 {
8658 /* assert instr[28,23] = 1001000
8659 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8660 instr[30,29] = op : 0 ==> AND, 1 ==> ORR, 2 ==> EOR, 3 ==> ANDS
8661 instr[22] = N : used to construct immediate mask
8662 instr[21,16] = immr
8663 instr[15,10] = imms
8664 instr[9,5] = Rn
8665 instr[4,0] = Rd */
8666
8667 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
8668 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
8669 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
8670 /* uint32_t immr = uimm (aarch64_get_instr (cpu), 21, 16);. */
8671 /* uint32_t imms = uimm (aarch64_get_instr (cpu), 15, 10);. */
8672 uint32_t index = uimm (aarch64_get_instr (cpu), 22, 10);
8673 uint64_t bimm64 = LITable [index];
8674 uint32_t dispatch = uimm (aarch64_get_instr (cpu), 30, 29);
8675
8676 if (~size & N)
8677 HALT_UNALLOC;
8678
8679 if (!bimm64)
8680 HALT_UNALLOC;
8681
8682 if (size == 0)
8683 {
8684 uint32_t bimm = (uint32_t) bimm64;
8685
8686 switch (dispatch)
8687 {
8688 case 0: and32 (cpu, bimm); return;
8689 case 1: orr32 (cpu, bimm); return;
8690 case 2: eor32 (cpu, bimm); return;
8691 case 3: ands32 (cpu, bimm); return;
8692 }
8693 }
8694 else
8695 {
8696 switch (dispatch)
8697 {
8698 case 0: and64 (cpu, bimm64); return;
8699 case 1: orr64 (cpu, bimm64); return;
8700 case 2: eor64 (cpu, bimm64); return;
8701 case 3: ands64 (cpu, bimm64); return;
8702 }
8703 }
8704 HALT_UNALLOC;
8705 }
8706
8707 /* Immediate move.
8708 The uimm argument is a 16 bit value to be inserted into the
8709 target register the pos argument locates the 16 bit word in the
8710 dest register i.e. it is in {0, 1} for 32 bit and {0, 1, 2,
8711 3} for 64 bit.
8712 N.B register arg may not be SP so it should be.
8713 accessed using the setGZRegisterXXX accessors. */
8714
8715 /* 32 bit move 16 bit immediate zero remaining shorts. */
8716 static void
8717 movz32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8718 {
8719 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8720
8721 aarch64_set_reg_u64 (cpu, rd, NO_SP, val << (pos * 16));
8722 }
8723
8724 /* 64 bit move 16 bit immediate zero remaining shorts. */
8725 static void
8726 movz64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8727 {
8728 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8729
8730 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((uint64_t) val) << (pos * 16));
8731 }
8732
8733 /* 32 bit move 16 bit immediate negated. */
8734 static void
8735 movn32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8736 {
8737 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8738
8739 aarch64_set_reg_u64 (cpu, rd, NO_SP, ((val << (pos * 16)) ^ 0xffffffffU));
8740 }
8741
8742 /* 64 bit move 16 bit immediate negated. */
8743 static void
8744 movn64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8745 {
8746 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8747
8748 aarch64_set_reg_u64
8749 (cpu, rd, NO_SP, ((((uint64_t) val) << (pos * 16))
8750 ^ 0xffffffffffffffffULL));
8751 }
8752
8753 /* 32 bit move 16 bit immediate keep remaining shorts. */
8754 static void
8755 movk32 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8756 {
8757 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8758 uint32_t current = aarch64_get_reg_u32 (cpu, rd, NO_SP);
8759 uint32_t value = val << (pos * 16);
8760 uint32_t mask = ~(0xffffU << (pos * 16));
8761
8762 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
8763 }
8764
8765 /* 64 bit move 16 it immediate keep remaining shorts. */
8766 static void
8767 movk64 (sim_cpu *cpu, uint32_t val, uint32_t pos)
8768 {
8769 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
8770 uint64_t current = aarch64_get_reg_u64 (cpu, rd, NO_SP);
8771 uint64_t value = (uint64_t) val << (pos * 16);
8772 uint64_t mask = ~(0xffffULL << (pos * 16));
8773
8774 aarch64_set_reg_u64 (cpu, rd, NO_SP, (value | (current & mask)));
8775 }
8776
8777 static void
8778 dexMoveWideImmediate (sim_cpu *cpu)
8779 {
8780 /* assert instr[28:23] = 100101
8781 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
8782 instr[30,29] = op : 0 ==> MOVN, 1 ==> UNALLOC, 2 ==> MOVZ, 3 ==> MOVK
8783 instr[22,21] = shift : 00 == LSL#0, 01 = LSL#16, 10 = LSL#32, 11 = LSL#48
8784 instr[20,5] = uimm16
8785 instr[4,0] = Rd */
8786
8787 /* N.B. the (multiple of 16) shift is applied by the called routine,
8788 we just pass the multiplier. */
8789
8790 uint32_t imm;
8791 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
8792 uint32_t op = uimm (aarch64_get_instr (cpu), 30, 29);
8793 uint32_t shift = uimm (aarch64_get_instr (cpu), 22, 21);
8794
8795 /* 32 bit can only shift 0 or 1 lot of 16.
8796 anything else is an unallocated instruction. */
8797 if (size == 0 && (shift > 1))
8798 HALT_UNALLOC;
8799
8800 if (op == 1)
8801 HALT_UNALLOC;
8802
8803 imm = uimm (aarch64_get_instr (cpu), 20, 5);
8804
8805 if (size == 0)
8806 {
8807 if (op == 0)
8808 movn32 (cpu, imm, shift);
8809 else if (op == 2)
8810 movz32 (cpu, imm, shift);
8811 else
8812 movk32 (cpu, imm, shift);
8813 }
8814 else
8815 {
8816 if (op == 0)
8817 movn64 (cpu, imm, shift);
8818 else if (op == 2)
8819 movz64 (cpu, imm, shift);
8820 else
8821 movk64 (cpu, imm, shift);
8822 }
8823 }
8824
8825 /* Bitfield operations.
8826 These take a pair of bit positions r and s which are in {0..31}
8827 or {0..63} depending on the instruction word size.
8828 N.B register args may not be SP. */
8829
8830 /* OK, we start with ubfm which just needs to pick
8831 some bits out of source zero the rest and write
8832 the result to dest. Just need two logical shifts. */
8833
8834 /* 32 bit bitfield move, left and right of affected zeroed
8835 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8836 static void
8837 ubfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8838 {
8839 unsigned rd;
8840 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8841 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8842
8843 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
8844 if (r <= s)
8845 {
8846 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
8847 We want only bits s:xxx:r at the bottom of the word
8848 so we LSL bit s up to bit 31 i.e. by 31 - s
8849 and then we LSR to bring bit 31 down to bit s - r
8850 i.e. by 31 + r - s. */
8851 value <<= 31 - s;
8852 value >>= 31 + r - s;
8853 }
8854 else
8855 {
8856 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0
8857 We want only bits s:xxx:0 starting at it 31-(r-1)
8858 so we LSL bit s up to bit 31 i.e. by 31 - s
8859 and then we LSL to bring bit 31 down to 31-(r-1)+s
8860 i.e. by r - (s + 1). */
8861 value <<= 31 - s;
8862 value >>= r - (s + 1);
8863 }
8864
8865 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8866 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8867 }
8868
8869 /* 64 bit bitfield move, left and right of affected zeroed
8870 if r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
8871 static void
8872 ubfm (sim_cpu *cpu, uint32_t r, uint32_t s)
8873 {
8874 unsigned rd;
8875 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8876 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
8877
8878 if (r <= s)
8879 {
8880 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
8881 We want only bits s:xxx:r at the bottom of the word.
8882 So we LSL bit s up to bit 63 i.e. by 63 - s
8883 and then we LSR to bring bit 63 down to bit s - r
8884 i.e. by 63 + r - s. */
8885 value <<= 63 - s;
8886 value >>= 63 + r - s;
8887 }
8888 else
8889 {
8890 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0.
8891 We want only bits s:xxx:0 starting at it 63-(r-1).
8892 So we LSL bit s up to bit 63 i.e. by 63 - s
8893 and then we LSL to bring bit 63 down to 63-(r-1)+s
8894 i.e. by r - (s + 1). */
8895 value <<= 63 - s;
8896 value >>= r - (s + 1);
8897 }
8898
8899 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8900 aarch64_set_reg_u64 (cpu, rd, NO_SP, value);
8901 }
8902
8903 /* The signed versions need to insert sign bits
8904 on the left of the inserted bit field. so we do
8905 much the same as the unsigned version except we
8906 use an arithmetic shift right -- this just means
8907 we need to operate on signed values. */
8908
8909 /* 32 bit bitfield move, left of affected sign-extended, right zeroed. */
8910 /* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8911 static void
8912 sbfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8913 {
8914 unsigned rd;
8915 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8916 /* as per ubfm32 but use an ASR instead of an LSR. */
8917 int32_t value = aarch64_get_reg_s32 (cpu, rn, NO_SP);
8918
8919 if (r <= s)
8920 {
8921 value <<= 31 - s;
8922 value >>= 31 + r - s;
8923 }
8924 else
8925 {
8926 value <<= 31 - s;
8927 value >>= r - (s + 1);
8928 }
8929
8930 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8931 aarch64_set_reg_u64 (cpu, rd, NO_SP, (uint32_t) value);
8932 }
8933
8934 /* 64 bit bitfield move, left of affected sign-extended, right zeroed. */
8935 /* If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
8936 static void
8937 sbfm (sim_cpu *cpu, uint32_t r, uint32_t s)
8938 {
8939 unsigned rd;
8940 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8941 /* acpu per ubfm but use an ASR instead of an LSR. */
8942 int64_t value = aarch64_get_reg_s64 (cpu, rn, NO_SP);
8943
8944 if (r <= s)
8945 {
8946 value <<= 63 - s;
8947 value >>= 63 + r - s;
8948 }
8949 else
8950 {
8951 value <<= 63 - s;
8952 value >>= r - (s + 1);
8953 }
8954
8955 rd = uimm (aarch64_get_instr (cpu), 4, 0);
8956 aarch64_set_reg_s64 (cpu, rd, NO_SP, value);
8957 }
8958
8959 /* Finally, these versions leave non-affected bits
8960 as is. so we need to generate the bits as per
8961 ubfm and also generate a mask to pick the
8962 bits from the original and computed values. */
8963
8964 /* 32 bit bitfield move, non-affected bits left as is.
8965 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<32+s-r,32-r> = Wn<s:0>. */
8966 static void
8967 bfm32 (sim_cpu *cpu, uint32_t r, uint32_t s)
8968 {
8969 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
8970 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
8971 uint32_t mask = -1;
8972 unsigned rd;
8973 uint32_t value2;
8974
8975 /* Pick either s+1-r or s+1 consecutive bits out of the original word. */
8976 if (r <= s)
8977 {
8978 /* 31:...:s:xxx:r:...:0 ==> 31:...:s-r:xxx:0.
8979 We want only bits s:xxx:r at the bottom of the word
8980 so we LSL bit s up to bit 31 i.e. by 31 - s
8981 and then we LSR to bring bit 31 down to bit s - r
8982 i.e. by 31 + r - s. */
8983 value <<= 31 - s;
8984 value >>= 31 + r - s;
8985 /* the mask must include the same bits. */
8986 mask <<= 31 - s;
8987 mask >>= 31 + r - s;
8988 }
8989 else
8990 {
8991 /* 31:...:s:xxx:0 ==> 31:...:31-(r-1)+s:xxx:31-(r-1):...:0.
8992 We want only bits s:xxx:0 starting at it 31-(r-1)
8993 so we LSL bit s up to bit 31 i.e. by 31 - s
8994 and then we LSL to bring bit 31 down to 31-(r-1)+s
8995 i.e. by r - (s + 1). */
8996 value <<= 31 - s;
8997 value >>= r - (s + 1);
8998 /* The mask must include the same bits. */
8999 mask <<= 31 - s;
9000 mask >>= r - (s + 1);
9001 }
9002
9003 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9004 value2 = aarch64_get_reg_u32 (cpu, rd, NO_SP);
9005
9006 value2 &= ~mask;
9007 value2 |= value;
9008
9009 aarch64_set_reg_u64
9010 (cpu, rd, NO_SP, (aarch64_get_reg_u32 (cpu, rd, NO_SP) & ~mask) | value);
9011 }
9012
9013 /* 64 bit bitfield move, non-affected bits left as is.
9014 If r <= s Wd<s-r:0> = Wn<s:r> else Wd<64+s-r,64-r> = Wn<s:0>. */
9015 static void
9016 bfm (sim_cpu *cpu, uint32_t r, uint32_t s)
9017 {
9018 unsigned rd;
9019 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9020 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
9021 uint64_t mask = 0xffffffffffffffffULL;
9022
9023 if (r <= s)
9024 {
9025 /* 63:...:s:xxx:r:...:0 ==> 63:...:s-r:xxx:0.
9026 We want only bits s:xxx:r at the bottom of the word
9027 so we LSL bit s up to bit 63 i.e. by 63 - s
9028 and then we LSR to bring bit 63 down to bit s - r
9029 i.e. by 63 + r - s. */
9030 value <<= 63 - s;
9031 value >>= 63 + r - s;
9032 /* The mask must include the same bits. */
9033 mask <<= 63 - s;
9034 mask >>= 63 + r - s;
9035 }
9036 else
9037 {
9038 /* 63:...:s:xxx:0 ==> 63:...:63-(r-1)+s:xxx:63-(r-1):...:0
9039 We want only bits s:xxx:0 starting at it 63-(r-1)
9040 so we LSL bit s up to bit 63 i.e. by 63 - s
9041 and then we LSL to bring bit 63 down to 63-(r-1)+s
9042 i.e. by r - (s + 1). */
9043 value <<= 63 - s;
9044 value >>= r - (s + 1);
9045 /* The mask must include the same bits. */
9046 mask <<= 63 - s;
9047 mask >>= r - (s + 1);
9048 }
9049
9050 rd = uimm (aarch64_get_instr (cpu), 4, 0);
9051 aarch64_set_reg_u64
9052 (cpu, rd, NO_SP, (aarch64_get_reg_u64 (cpu, rd, NO_SP) & ~mask) | value);
9053 }
9054
9055 static void
9056 dexBitfieldImmediate (sim_cpu *cpu)
9057 {
9058 /* assert instr[28:23] = 100110
9059 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9060 instr[30,29] = op : 0 ==> SBFM, 1 ==> BFM, 2 ==> UBFM, 3 ==> UNALLOC
9061 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit ow UNALLOC
9062 instr[21,16] = immr : 0xxxxx for 32 bit, xxxxxx for 64 bit
9063 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9064 instr[9,5] = Rn
9065 instr[4,0] = Rd */
9066
9067 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9068 uint32_t dispatch;
9069 uint32_t imms;
9070 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
9071 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
9072 /* 32 bit operations must have immr[5] = 0 and imms[5] = 0. */
9073 /* or else we have an UNALLOC. */
9074 uint32_t immr = uimm (aarch64_get_instr (cpu), 21, 16);
9075
9076 if (~size & N)
9077 HALT_UNALLOC;
9078
9079 if (!size && uimm (immr, 5, 5))
9080 HALT_UNALLOC;
9081
9082 imms = uimm (aarch64_get_instr (cpu), 15, 10);
9083 if (!size && uimm (imms, 5, 5))
9084 HALT_UNALLOC;
9085
9086 /* Switch on combined size and op. */
9087 dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
9088 switch (dispatch)
9089 {
9090 case 0: sbfm32 (cpu, immr, imms); return;
9091 case 1: bfm32 (cpu, immr, imms); return;
9092 case 2: ubfm32 (cpu, immr, imms); return;
9093 case 4: sbfm (cpu, immr, imms); return;
9094 case 5: bfm (cpu, immr, imms); return;
9095 case 6: ubfm (cpu, immr, imms); return;
9096 default: HALT_UNALLOC;
9097 }
9098 }
9099
9100 static void
9101 do_EXTR_32 (sim_cpu *cpu)
9102 {
9103 /* instr[31:21] = 00010011100
9104 instr[20,16] = Rm
9105 instr[15,10] = imms : 0xxxxx for 32 bit
9106 instr[9,5] = Rn
9107 instr[4,0] = Rd */
9108 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9109 unsigned imms = uimm (aarch64_get_instr (cpu), 15, 10) & 31;
9110 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9111 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
9112 uint64_t val1;
9113 uint64_t val2;
9114
9115 val1 = aarch64_get_reg_u32 (cpu, rm, NO_SP);
9116 val1 >>= imms;
9117 val2 = aarch64_get_reg_u32 (cpu, rn, NO_SP);
9118 val2 <<= (32 - imms);
9119
9120 aarch64_set_reg_u64 (cpu, rd, NO_SP, val1 | val2);
9121 }
9122
9123 static void
9124 do_EXTR_64 (sim_cpu *cpu)
9125 {
9126 /* instr[31:21] = 10010011100
9127 instr[20,16] = Rm
9128 instr[15,10] = imms
9129 instr[9,5] = Rn
9130 instr[4,0] = Rd */
9131 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9132 unsigned imms = uimm (aarch64_get_instr (cpu), 15, 10) & 63;
9133 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9134 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
9135 uint64_t val;
9136
9137 val = aarch64_get_reg_u64 (cpu, rm, NO_SP);
9138 val >>= imms;
9139 val |= (aarch64_get_reg_u64 (cpu, rn, NO_SP) << (64 - imms));
9140
9141 aarch64_set_reg_u64 (cpu, rd, NO_SP, val);
9142 }
9143
9144 static void
9145 dexExtractImmediate (sim_cpu *cpu)
9146 {
9147 /* assert instr[28:23] = 100111
9148 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
9149 instr[30,29] = op21 : 0 ==> EXTR, 1,2,3 ==> UNALLOC
9150 instr[22] = N : must be 0 for 32 bit, 1 for 64 bit or UNALLOC
9151 instr[21] = op0 : must be 0 or UNALLOC
9152 instr[20,16] = Rm
9153 instr[15,10] = imms : 0xxxxx for 32 bit, xxxxxx for 64 bit
9154 instr[9,5] = Rn
9155 instr[4,0] = Rd */
9156
9157 /* 32 bit operations must have N = 0 or else we have an UNALLOC. */
9158 /* 64 bit operations must have N = 1 or else we have an UNALLOC. */
9159 uint32_t dispatch;
9160 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
9161 uint32_t N = uimm (aarch64_get_instr (cpu), 22, 22);
9162 /* 32 bit operations must have imms[5] = 0
9163 or else we have an UNALLOC. */
9164 uint32_t imms = uimm (aarch64_get_instr (cpu), 15, 10);
9165
9166 if (size ^ N)
9167 HALT_UNALLOC;
9168
9169 if (!size && uimm (imms, 5, 5))
9170 HALT_UNALLOC;
9171
9172 /* Switch on combined size and op. */
9173 dispatch = uimm (aarch64_get_instr (cpu), 31, 29);
9174
9175 if (dispatch == 0)
9176 do_EXTR_32 (cpu);
9177
9178 else if (dispatch == 4)
9179 do_EXTR_64 (cpu);
9180
9181 else if (dispatch == 1)
9182 HALT_NYI;
9183 else
9184 HALT_UNALLOC;
9185 }
9186
9187 static void
9188 dexDPImm (sim_cpu *cpu)
9189 {
9190 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
9191 assert group == GROUP_DPIMM_1000 || grpoup == GROUP_DPIMM_1001
9192 bits [25,23] of a DPImm are the secondary dispatch vector. */
9193 uint32_t group2 = dispatchDPImm (aarch64_get_instr (cpu));
9194
9195 switch (group2)
9196 {
9197 case DPIMM_PCADR_000:
9198 case DPIMM_PCADR_001:
9199 dexPCRelAddressing (cpu);
9200 return;
9201
9202 case DPIMM_ADDSUB_010:
9203 case DPIMM_ADDSUB_011:
9204 dexAddSubtractImmediate (cpu);
9205 return;
9206
9207 case DPIMM_LOG_100:
9208 dexLogicalImmediate (cpu);
9209 return;
9210
9211 case DPIMM_MOV_101:
9212 dexMoveWideImmediate (cpu);
9213 return;
9214
9215 case DPIMM_BITF_110:
9216 dexBitfieldImmediate (cpu);
9217 return;
9218
9219 case DPIMM_EXTR_111:
9220 dexExtractImmediate (cpu);
9221 return;
9222
9223 default:
9224 /* Should never reach here. */
9225 HALT_NYI;
9226 }
9227 }
9228
9229 static void
9230 dexLoadUnscaledImmediate (sim_cpu *cpu)
9231 {
9232 /* instr[29,24] == 111_00
9233 instr[21] == 0
9234 instr[11,10] == 00
9235 instr[31,30] = size
9236 instr[26] = V
9237 instr[23,22] = opc
9238 instr[20,12] = simm9
9239 instr[9,5] = rn may be SP. */
9240 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9241 uint32_t V = uimm (aarch64_get_instr (cpu), 26, 26);
9242 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9243 | uimm (aarch64_get_instr (cpu), 23, 22));
9244 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
9245
9246 if (!V)
9247 {
9248 /* GReg operations. */
9249 switch (dispatch)
9250 {
9251 case 0: sturb (cpu, imm); return;
9252 case 1: ldurb32 (cpu, imm); return;
9253 case 2: ldursb64 (cpu, imm); return;
9254 case 3: ldursb32 (cpu, imm); return;
9255 case 4: sturh (cpu, imm); return;
9256 case 5: ldurh32 (cpu, imm); return;
9257 case 6: ldursh64 (cpu, imm); return;
9258 case 7: ldursh32 (cpu, imm); return;
9259 case 8: stur32 (cpu, imm); return;
9260 case 9: ldur32 (cpu, imm); return;
9261 case 10: ldursw (cpu, imm); return;
9262 case 12: stur64 (cpu, imm); return;
9263 case 13: ldur64 (cpu, imm); return;
9264
9265 case 14:
9266 /* PRFUM NYI. */
9267 HALT_NYI;
9268
9269 default:
9270 case 11:
9271 case 15:
9272 HALT_UNALLOC;
9273 }
9274 }
9275
9276 /* FReg operations. */
9277 switch (dispatch)
9278 {
9279 case 2: fsturq (cpu, imm); return;
9280 case 3: fldurq (cpu, imm); return;
9281 case 8: fsturs (cpu, imm); return;
9282 case 9: fldurs (cpu, imm); return;
9283 case 12: fsturd (cpu, imm); return;
9284 case 13: fldurd (cpu, imm); return;
9285
9286 case 0: /* STUR 8 bit FP. */
9287 case 1: /* LDUR 8 bit FP. */
9288 case 4: /* STUR 16 bit FP. */
9289 case 5: /* LDUR 8 bit FP. */
9290 HALT_NYI;
9291
9292 default:
9293 case 6:
9294 case 7:
9295 case 10:
9296 case 11:
9297 case 14:
9298 case 15:
9299 HALT_UNALLOC;
9300 }
9301 }
9302
9303 /* N.B. A preliminary note regarding all the ldrs<x>32
9304 instructions
9305
9306 The signed value loaded by these instructions is cast to unsigned
9307 before being assigned to aarch64_get_reg_u64 (cpu, N) i.e. to the
9308 64 bit element of the GReg union. this performs a 32 bit sign extension
9309 (as required) but avoids 64 bit sign extension, thus ensuring that the
9310 top half of the register word is zero. this is what the spec demands
9311 when a 32 bit load occurs. */
9312
9313 /* 32 bit load sign-extended byte scaled unsigned 12 bit. */
9314 static void
9315 ldrsb32_abs (sim_cpu *cpu, uint32_t offset)
9316 {
9317 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9318 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9319
9320 /* The target register may not be SP but the source may be
9321 there is no scaling required for a byte load. */
9322 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset;
9323 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9324 (int64_t) aarch64_get_mem_s8 (cpu, address));
9325 }
9326
9327 /* 32 bit load sign-extended byte scaled or unscaled zero-
9328 or sign-extended 32-bit register offset. */
9329 static void
9330 ldrsb32_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9331 {
9332 unsigned int rm = uimm (aarch64_get_instr (cpu), 20, 16);
9333 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9334 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9335
9336 /* rn may reference SP, rm and rt must reference ZR. */
9337
9338 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9339 int64_t displacement = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9340 extension);
9341
9342 /* There is no scaling required for a byte load. */
9343 aarch64_set_reg_u64
9344 (cpu, rt, NO_SP, (int64_t) aarch64_get_mem_s8 (cpu, address
9345 + displacement));
9346 }
9347
9348 /* 32 bit load sign-extended byte unscaled signed 9 bit with
9349 pre- or post-writeback. */
9350 static void
9351 ldrsb32_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9352 {
9353 uint64_t address;
9354 unsigned int rn = uimm (aarch64_get_instr (cpu), 9, 5);
9355 unsigned int rt = uimm (aarch64_get_instr (cpu), 4, 0);
9356
9357 if (rn == rt && wb != NoWriteBack)
9358 HALT_UNALLOC;
9359
9360 address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9361
9362 if (wb == Pre)
9363 address += offset;
9364
9365 aarch64_set_reg_u64 (cpu, rt, NO_SP,
9366 (int64_t) aarch64_get_mem_s8 (cpu, address));
9367
9368 if (wb == Post)
9369 address += offset;
9370
9371 if (wb != NoWriteBack)
9372 aarch64_set_reg_u64 (cpu, rn, NO_SP, address);
9373 }
9374
9375 /* 8 bit store scaled. */
9376 static void
9377 fstrb_abs (sim_cpu *cpu, uint32_t offset)
9378 {
9379 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9380 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9381
9382 aarch64_set_mem_u8 (cpu,
9383 aarch64_get_reg_u64 (cpu, rn, SP_OK) + offset,
9384 aarch64_get_vec_u8 (cpu, st, 0));
9385 }
9386
9387 /* 8 bit store scaled or unscaled zero- or
9388 sign-extended 8-bit register offset. */
9389 static void
9390 fstrb_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9391 {
9392 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9393 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9394 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9395
9396 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9397 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9398 extension);
9399 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9400
9401 aarch64_set_mem_u8
9402 (cpu, address + displacement, aarch64_get_vec_u8 (cpu, st, 0));
9403 }
9404
9405 /* 16 bit store scaled. */
9406 static void
9407 fstrh_abs (sim_cpu *cpu, uint32_t offset)
9408 {
9409 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9410 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9411
9412 aarch64_set_mem_u16
9413 (cpu,
9414 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 16),
9415 aarch64_get_vec_u16 (cpu, st, 0));
9416 }
9417
9418 /* 16 bit store scaled or unscaled zero-
9419 or sign-extended 16-bit register offset. */
9420 static void
9421 fstrh_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9422 {
9423 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9424 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9425 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9426
9427 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9428 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9429 extension);
9430 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9431
9432 aarch64_set_mem_u16
9433 (cpu, address + displacement, aarch64_get_vec_u16 (cpu, st, 0));
9434 }
9435
9436 /* 32 bit store scaled unsigned 12 bit. */
9437 static void
9438 fstrs_abs (sim_cpu *cpu, uint32_t offset)
9439 {
9440 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9441 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9442
9443 aarch64_set_mem_float
9444 (cpu,
9445 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 32),
9446 aarch64_get_FP_float (cpu, st));
9447 }
9448
9449 /* 32 bit store unscaled signed 9 bit with pre- or post-writeback. */
9450 static void
9451 fstrs_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9452 {
9453 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9454 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9455
9456 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9457
9458 if (wb != Post)
9459 address += offset;
9460
9461 aarch64_set_mem_float (cpu, address, aarch64_get_FP_float (cpu, st));
9462
9463 if (wb == Post)
9464 address += offset;
9465
9466 if (wb != NoWriteBack)
9467 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9468 }
9469
9470 /* 32 bit store scaled or unscaled zero-
9471 or sign-extended 32-bit register offset. */
9472 static void
9473 fstrs_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9474 {
9475 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9476 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9477 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9478
9479 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9480 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9481 extension);
9482 uint64_t displacement = OPT_SCALE (extended, 32, scaling);
9483
9484 aarch64_set_mem_float
9485 (cpu, address + displacement, aarch64_get_FP_float (cpu, st));
9486 }
9487
9488 /* 64 bit store scaled unsigned 12 bit. */
9489 static void
9490 fstrd_abs (sim_cpu *cpu, uint32_t offset)
9491 {
9492 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9493 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9494
9495 aarch64_set_mem_double
9496 (cpu,
9497 aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 64),
9498 aarch64_get_FP_double (cpu, st));
9499 }
9500
9501 /* 64 bit store unscaled signed 9 bit with pre- or post-writeback. */
9502 static void
9503 fstrd_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9504 {
9505 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9506 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9507
9508 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9509
9510 if (wb != Post)
9511 address += offset;
9512
9513 aarch64_set_mem_double (cpu, address, aarch64_get_FP_double (cpu, st));
9514
9515 if (wb == Post)
9516 address += offset;
9517
9518 if (wb != NoWriteBack)
9519 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9520 }
9521
9522 /* 64 bit store scaled or unscaled zero-
9523 or sign-extended 32-bit register offset. */
9524 static void
9525 fstrd_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9526 {
9527 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9528 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9529 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9530
9531 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9532 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9533 extension);
9534 uint64_t displacement = OPT_SCALE (extended, 64, scaling);
9535
9536 aarch64_set_mem_double
9537 (cpu, address + displacement, aarch64_get_FP_double (cpu, st));
9538 }
9539
9540 /* 128 bit store scaled unsigned 12 bit. */
9541 static void
9542 fstrq_abs (sim_cpu *cpu, uint32_t offset)
9543 {
9544 FRegister a;
9545 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9546 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9547 uint64_t addr;
9548
9549 aarch64_get_FP_long_double (cpu, st, & a);
9550
9551 addr = aarch64_get_reg_u64 (cpu, rn, SP_OK) + SCALE (offset, 128);
9552 aarch64_set_mem_long_double (cpu, addr, a);
9553 }
9554
9555 /* 128 bit store unscaled signed 9 bit with pre- or post-writeback. */
9556 static void
9557 fstrq_wb (sim_cpu *cpu, int32_t offset, WriteBack wb)
9558 {
9559 FRegister a;
9560 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9561 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9562 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9563
9564 if (wb != Post)
9565 address += offset;
9566
9567 aarch64_get_FP_long_double (cpu, st, & a);
9568 aarch64_set_mem_long_double (cpu, address, a);
9569
9570 if (wb == Post)
9571 address += offset;
9572
9573 if (wb != NoWriteBack)
9574 aarch64_set_reg_u64 (cpu, rn, SP_OK, address);
9575 }
9576
9577 /* 128 bit store scaled or unscaled zero-
9578 or sign-extended 32-bit register offset. */
9579 static void
9580 fstrq_scale_ext (sim_cpu *cpu, Scaling scaling, Extension extension)
9581 {
9582 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
9583 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
9584 unsigned st = uimm (aarch64_get_instr (cpu), 4, 0);
9585
9586 uint64_t address = aarch64_get_reg_u64 (cpu, rn, SP_OK);
9587 int64_t extended = extend (aarch64_get_reg_u32 (cpu, rm, NO_SP),
9588 extension);
9589 uint64_t displacement = OPT_SCALE (extended, 128, scaling);
9590
9591 FRegister a;
9592
9593 aarch64_get_FP_long_double (cpu, st, & a);
9594 aarch64_set_mem_long_double (cpu, address + displacement, a);
9595 }
9596
9597 static void
9598 dexLoadImmediatePrePost (sim_cpu *cpu)
9599 {
9600 /* instr[29,24] == 111_00
9601 instr[21] == 0
9602 instr[11,10] == 00
9603 instr[31,30] = size
9604 instr[26] = V
9605 instr[23,22] = opc
9606 instr[20,12] = simm9
9607 instr[11] = wb : 0 ==> Post, 1 ==> Pre
9608 instr[9,5] = rn may be SP. */
9609 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9610 uint32_t V = uimm (aarch64_get_instr (cpu), 26, 26);
9611 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9612 | uimm (aarch64_get_instr (cpu), 23, 22));
9613 int32_t imm = simm32 (aarch64_get_instr (cpu), 20, 12);
9614 WriteBack wb = writeback (aarch64_get_instr (cpu), 11);
9615
9616 if (!V)
9617 {
9618 /* GReg operations. */
9619 switch (dispatch)
9620 {
9621 case 0: strb_wb (cpu, imm, wb); return;
9622 case 1: ldrb32_wb (cpu, imm, wb); return;
9623 case 2: ldrsb_wb (cpu, imm, wb); return;
9624 case 3: ldrsb32_wb (cpu, imm, wb); return;
9625 case 4: strh_wb (cpu, imm, wb); return;
9626 case 5: ldrh32_wb (cpu, imm, wb); return;
9627 case 6: ldrsh64_wb (cpu, imm, wb); return;
9628 case 7: ldrsh32_wb (cpu, imm, wb); return;
9629 case 8: str32_wb (cpu, imm, wb); return;
9630 case 9: ldr32_wb (cpu, imm, wb); return;
9631 case 10: ldrsw_wb (cpu, imm, wb); return;
9632 case 12: str_wb (cpu, imm, wb); return;
9633 case 13: ldr_wb (cpu, imm, wb); return;
9634
9635 default:
9636 case 11:
9637 case 14:
9638 case 15:
9639 HALT_UNALLOC;
9640 }
9641 }
9642
9643 /* FReg operations. */
9644 switch (dispatch)
9645 {
9646 case 2: fstrq_wb (cpu, imm, wb); return;
9647 case 3: fldrq_wb (cpu, imm, wb); return;
9648 case 8: fstrs_wb (cpu, imm, wb); return;
9649 case 9: fldrs_wb (cpu, imm, wb); return;
9650 case 12: fstrd_wb (cpu, imm, wb); return;
9651 case 13: fldrd_wb (cpu, imm, wb); return;
9652
9653 case 0: /* STUR 8 bit FP. */
9654 case 1: /* LDUR 8 bit FP. */
9655 case 4: /* STUR 16 bit FP. */
9656 case 5: /* LDUR 8 bit FP. */
9657 HALT_NYI;
9658
9659 default:
9660 case 6:
9661 case 7:
9662 case 10:
9663 case 11:
9664 case 14:
9665 case 15:
9666 HALT_UNALLOC;
9667 }
9668 }
9669
9670 static void
9671 dexLoadRegisterOffset (sim_cpu *cpu)
9672 {
9673 /* instr[31,30] = size
9674 instr[29,27] = 111
9675 instr[26] = V
9676 instr[25,24] = 00
9677 instr[23,22] = opc
9678 instr[21] = 1
9679 instr[20,16] = rm
9680 instr[15,13] = option : 010 ==> UXTW, 011 ==> UXTX/LSL,
9681 110 ==> SXTW, 111 ==> SXTX,
9682 ow ==> RESERVED
9683 instr[12] = scaled
9684 instr[11,10] = 10
9685 instr[9,5] = rn
9686 instr[4,0] = rt. */
9687
9688 uint32_t V = uimm (aarch64_get_instr (cpu), 26,26);
9689 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9690 | uimm (aarch64_get_instr (cpu), 23, 22));
9691 Scaling scale = scaling (aarch64_get_instr (cpu), 12);
9692 Extension extensionType = extension (aarch64_get_instr (cpu), 13);
9693
9694 /* Check for illegal extension types. */
9695 if (uimm (extensionType, 1, 1) == 0)
9696 HALT_UNALLOC;
9697
9698 if (extensionType == UXTX || extensionType == SXTX)
9699 extensionType = NoExtension;
9700
9701 if (!V)
9702 {
9703 /* GReg operations. */
9704 switch (dispatch)
9705 {
9706 case 0: strb_scale_ext (cpu, scale, extensionType); return;
9707 case 1: ldrb32_scale_ext (cpu, scale, extensionType); return;
9708 case 2: ldrsb_scale_ext (cpu, scale, extensionType); return;
9709 case 3: ldrsb32_scale_ext (cpu, scale, extensionType); return;
9710 case 4: strh_scale_ext (cpu, scale, extensionType); return;
9711 case 5: ldrh32_scale_ext (cpu, scale, extensionType); return;
9712 case 6: ldrsh_scale_ext (cpu, scale, extensionType); return;
9713 case 7: ldrsh32_scale_ext (cpu, scale, extensionType); return;
9714 case 8: str32_scale_ext (cpu, scale, extensionType); return;
9715 case 9: ldr32_scale_ext (cpu, scale, extensionType); return;
9716 case 10: ldrsw_scale_ext (cpu, scale, extensionType); return;
9717 case 12: str_scale_ext (cpu, scale, extensionType); return;
9718 case 13: ldr_scale_ext (cpu, scale, extensionType); return;
9719 case 14: prfm_scale_ext (cpu, scale, extensionType); return;
9720
9721 default:
9722 case 11:
9723 case 15:
9724 HALT_UNALLOC;
9725 }
9726 }
9727
9728 /* FReg operations. */
9729 switch (dispatch)
9730 {
9731 case 1: /* LDUR 8 bit FP. */
9732 HALT_NYI;
9733 case 3: fldrq_scale_ext (cpu, scale, extensionType); return;
9734 case 5: /* LDUR 8 bit FP. */
9735 HALT_NYI;
9736 case 9: fldrs_scale_ext (cpu, scale, extensionType); return;
9737 case 13: fldrd_scale_ext (cpu, scale, extensionType); return;
9738
9739 case 0: fstrb_scale_ext (cpu, scale, extensionType); return;
9740 case 2: fstrq_scale_ext (cpu, scale, extensionType); return;
9741 case 4: fstrh_scale_ext (cpu, scale, extensionType); return;
9742 case 8: fstrs_scale_ext (cpu, scale, extensionType); return;
9743 case 12: fstrd_scale_ext (cpu, scale, extensionType); return;
9744
9745 default:
9746 case 6:
9747 case 7:
9748 case 10:
9749 case 11:
9750 case 14:
9751 case 15:
9752 HALT_UNALLOC;
9753 }
9754 }
9755
9756 static void
9757 dexLoadUnsignedImmediate (sim_cpu *cpu)
9758 {
9759 /* assert instr[29,24] == 111_01
9760 instr[31,30] = size
9761 instr[26] = V
9762 instr[23,22] = opc
9763 instr[21,10] = uimm12 : unsigned immediate offset
9764 instr[9,5] = rn may be SP. */
9765 /* unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0); */
9766 uint32_t V = uimm (aarch64_get_instr (cpu), 26,26);
9767 uint32_t dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 30) << 2)
9768 | uimm (aarch64_get_instr (cpu), 23, 22));
9769 uint32_t imm = uimm (aarch64_get_instr (cpu), 21, 10);
9770
9771 if (!V)
9772 {
9773 /* GReg operations. */
9774 switch (dispatch)
9775 {
9776 case 0: strb_abs (cpu, imm); return;
9777 case 1: ldrb32_abs (cpu, imm); return;
9778 case 2: ldrsb_abs (cpu, imm); return;
9779 case 3: ldrsb32_abs (cpu, imm); return;
9780 case 4: strh_abs (cpu, imm); return;
9781 case 5: ldrh32_abs (cpu, imm); return;
9782 case 6: ldrsh_abs (cpu, imm); return;
9783 case 7: ldrsh32_abs (cpu, imm); return;
9784 case 8: str32_abs (cpu, imm); return;
9785 case 9: ldr32_abs (cpu, imm); return;
9786 case 10: ldrsw_abs (cpu, imm); return;
9787 case 12: str_abs (cpu, imm); return;
9788 case 13: ldr_abs (cpu, imm); return;
9789 case 14: prfm_abs (cpu, imm); return;
9790
9791 default:
9792 case 11:
9793 case 15:
9794 HALT_UNALLOC;
9795 }
9796 }
9797
9798 /* FReg operations. */
9799 switch (dispatch)
9800 {
9801 case 3: fldrq_abs (cpu, imm); return;
9802 case 9: fldrs_abs (cpu, imm); return;
9803 case 13: fldrd_abs (cpu, imm); return;
9804
9805 case 0: fstrb_abs (cpu, imm); return;
9806 case 2: fstrq_abs (cpu, imm); return;
9807 case 4: fstrh_abs (cpu, imm); return;
9808 case 8: fstrs_abs (cpu, imm); return;
9809 case 12: fstrd_abs (cpu, imm); return;
9810
9811 case 1: /* LDR 8 bit FP. */
9812 case 5: /* LDR 8 bit FP. */
9813 HALT_NYI;
9814
9815 default:
9816 case 6:
9817 case 7:
9818 case 10:
9819 case 11:
9820 case 14:
9821 case 15:
9822 HALT_UNALLOC;
9823 }
9824 }
9825
9826 static void
9827 dexLoadExclusive (sim_cpu *cpu)
9828 {
9829 /* assert instr[29:24] = 001000;
9830 instr[31,30] = size
9831 instr[23] = 0 if exclusive
9832 instr[22] = L : 1 if load, 0 if store
9833 instr[21] = 1 if pair
9834 instr[20,16] = Rs
9835 instr[15] = o0 : 1 if ordered
9836 instr[14,10] = Rt2
9837 instr[9,5] = Rn
9838 instr[4.0] = Rt. */
9839
9840 switch (uimm (aarch64_get_instr (cpu), 22, 21))
9841 {
9842 case 2: ldxr (cpu); return;
9843 case 0: stxr (cpu); return;
9844 default: HALT_NYI;
9845 }
9846 }
9847
9848 static void
9849 dexLoadOther (sim_cpu *cpu)
9850 {
9851 uint32_t dispatch;
9852
9853 /* instr[29,25] = 111_0
9854 instr[24] == 0 ==> dispatch, 1 ==> ldst reg unsigned immediate
9855 instr[21:11,10] is the secondary dispatch. */
9856 if (uimm (aarch64_get_instr (cpu), 24, 24))
9857 {
9858 dexLoadUnsignedImmediate (cpu);
9859 return;
9860 }
9861
9862 dispatch = ( (uimm (aarch64_get_instr (cpu), 21, 21) << 2)
9863 | uimm (aarch64_get_instr (cpu), 11, 10));
9864 switch (dispatch)
9865 {
9866 case 0: dexLoadUnscaledImmediate (cpu); return;
9867 case 1: dexLoadImmediatePrePost (cpu); return;
9868 case 3: dexLoadImmediatePrePost (cpu); return;
9869 case 6: dexLoadRegisterOffset (cpu); return;
9870
9871 default:
9872 case 2:
9873 case 4:
9874 case 5:
9875 case 7:
9876 HALT_NYI;
9877 }
9878 }
9879
9880 static void
9881 store_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9882 {
9883 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9884 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9885 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9886 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9887
9888 if ((rn == rd || rm == rd) && wb != NoWriteBack)
9889 HALT_UNALLOC; /* ??? */
9890
9891 offset <<= 2;
9892
9893 if (wb != Post)
9894 address += offset;
9895
9896 aarch64_set_mem_u32 (cpu, address,
9897 aarch64_get_reg_u32 (cpu, rm, NO_SP));
9898 aarch64_set_mem_u32 (cpu, address + 4,
9899 aarch64_get_reg_u32 (cpu, rn, NO_SP));
9900
9901 if (wb == Post)
9902 address += offset;
9903
9904 if (wb != NoWriteBack)
9905 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9906 }
9907
9908 static void
9909 store_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9910 {
9911 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9912 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9913 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9914 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9915
9916 if ((rn == rd || rm == rd) && wb != NoWriteBack)
9917 HALT_UNALLOC; /* ??? */
9918
9919 offset <<= 3;
9920
9921 if (wb != Post)
9922 address += offset;
9923
9924 aarch64_set_mem_u64 (cpu, address,
9925 aarch64_get_reg_u64 (cpu, rm, SP_OK));
9926 aarch64_set_mem_u64 (cpu, address + 8,
9927 aarch64_get_reg_u64 (cpu, rn, SP_OK));
9928
9929 if (wb == Post)
9930 address += offset;
9931
9932 if (wb != NoWriteBack)
9933 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9934 }
9935
9936 static void
9937 load_pair_u32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9938 {
9939 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9940 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9941 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9942 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9943
9944 /* treat this as unalloc to make sure we don't do it. */
9945 if (rn == rm)
9946 HALT_UNALLOC;
9947
9948 offset <<= 2;
9949
9950 if (wb != Post)
9951 address += offset;
9952
9953 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u32 (cpu, address));
9954 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u32 (cpu, address + 4));
9955
9956 if (wb == Post)
9957 address += offset;
9958
9959 if (wb != NoWriteBack)
9960 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9961 }
9962
9963 static void
9964 load_pair_s32 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9965 {
9966 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9967 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9968 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9969 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9970
9971 /* Treat this as unalloc to make sure we don't do it. */
9972 if (rn == rm)
9973 HALT_UNALLOC;
9974
9975 offset <<= 2;
9976
9977 if (wb != Post)
9978 address += offset;
9979
9980 aarch64_set_reg_s64 (cpu, rm, SP_OK, aarch64_get_mem_s32 (cpu, address));
9981 aarch64_set_reg_s64 (cpu, rn, SP_OK, aarch64_get_mem_s32 (cpu, address + 4));
9982
9983 if (wb == Post)
9984 address += offset;
9985
9986 if (wb != NoWriteBack)
9987 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
9988 }
9989
9990 static void
9991 load_pair_u64 (sim_cpu *cpu, int32_t offset, WriteBack wb)
9992 {
9993 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
9994 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
9995 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
9996 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
9997
9998 /* Treat this as unalloc to make sure we don't do it. */
9999 if (rn == rm)
10000 HALT_UNALLOC;
10001
10002 offset <<= 3;
10003
10004 if (wb != Post)
10005 address += offset;
10006
10007 aarch64_set_reg_u64 (cpu, rm, SP_OK, aarch64_get_mem_u64 (cpu, address));
10008 aarch64_set_reg_u64 (cpu, rn, SP_OK, aarch64_get_mem_u64 (cpu, address + 8));
10009
10010 if (wb == Post)
10011 address += offset;
10012
10013 if (wb != NoWriteBack)
10014 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10015 }
10016
10017 static void
10018 dex_load_store_pair_gr (sim_cpu *cpu)
10019 {
10020 /* instr[31,30] = size (10=> 64-bit, 01=> signed 32-bit, 00=> 32-bit)
10021 instr[29,25] = instruction encoding: 101_0
10022 instr[26] = V : 1 if fp 0 if gp
10023 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10024 instr[22] = load/store (1=> load)
10025 instr[21,15] = signed, scaled, offset
10026 instr[14,10] = Rn
10027 instr[ 9, 5] = Rd
10028 instr[ 4, 0] = Rm. */
10029
10030 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 3)
10031 | uimm (aarch64_get_instr (cpu), 24, 22));
10032 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10033
10034 switch (dispatch)
10035 {
10036 case 2: store_pair_u32 (cpu, offset, Post); return;
10037 case 3: load_pair_u32 (cpu, offset, Post); return;
10038 case 4: store_pair_u32 (cpu, offset, NoWriteBack); return;
10039 case 5: load_pair_u32 (cpu, offset, NoWriteBack); return;
10040 case 6: store_pair_u32 (cpu, offset, Pre); return;
10041 case 7: load_pair_u32 (cpu, offset, Pre); return;
10042
10043 case 11: load_pair_s32 (cpu, offset, Post); return;
10044 case 13: load_pair_s32 (cpu, offset, NoWriteBack); return;
10045 case 15: load_pair_s32 (cpu, offset, Pre); return;
10046
10047 case 18: store_pair_u64 (cpu, offset, Post); return;
10048 case 19: load_pair_u64 (cpu, offset, Post); return;
10049 case 20: store_pair_u64 (cpu, offset, NoWriteBack); return;
10050 case 21: load_pair_u64 (cpu, offset, NoWriteBack); return;
10051 case 22: store_pair_u64 (cpu, offset, Pre); return;
10052 case 23: load_pair_u64 (cpu, offset, Pre); return;
10053
10054 default:
10055 HALT_UNALLOC;
10056 }
10057 }
10058
10059 static void
10060 store_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10061 {
10062 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10063 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10064 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10065 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10066
10067 offset <<= 2;
10068
10069 if (wb != Post)
10070 address += offset;
10071
10072 aarch64_set_mem_float (cpu, address, aarch64_get_FP_float (cpu, rm));
10073 aarch64_set_mem_float (cpu, address + 4, aarch64_get_FP_float (cpu, rn));
10074
10075 if (wb == Post)
10076 address += offset;
10077
10078 if (wb != NoWriteBack)
10079 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10080 }
10081
10082 static void
10083 store_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10084 {
10085 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10086 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10087 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10088 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10089
10090 offset <<= 3;
10091
10092 if (wb != Post)
10093 address += offset;
10094
10095 aarch64_set_mem_double (cpu, address, aarch64_get_FP_double (cpu, rm));
10096 aarch64_set_mem_double (cpu, address + 8, aarch64_get_FP_double (cpu, rn));
10097
10098 if (wb == Post)
10099 address += offset;
10100
10101 if (wb != NoWriteBack)
10102 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10103 }
10104
10105 static void
10106 store_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10107 {
10108 FRegister a;
10109 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10110 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10111 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10112 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10113
10114 offset <<= 4;
10115
10116 if (wb != Post)
10117 address += offset;
10118
10119 aarch64_get_FP_long_double (cpu, rm, & a);
10120 aarch64_set_mem_long_double (cpu, address, a);
10121 aarch64_get_FP_long_double (cpu, rn, & a);
10122 aarch64_set_mem_long_double (cpu, address + 16, a);
10123
10124 if (wb == Post)
10125 address += offset;
10126
10127 if (wb != NoWriteBack)
10128 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10129 }
10130
10131 static void
10132 load_pair_float (sim_cpu *cpu, int32_t offset, WriteBack wb)
10133 {
10134 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10135 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10136 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10137 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10138
10139 if (rm == rn)
10140 HALT_UNALLOC;
10141
10142 offset <<= 2;
10143
10144 if (wb != Post)
10145 address += offset;
10146
10147 aarch64_set_FP_float (cpu, rm, aarch64_get_mem_float (cpu, address));
10148 aarch64_set_FP_float (cpu, rn, aarch64_get_mem_float (cpu, address + 4));
10149
10150 if (wb == Post)
10151 address += offset;
10152
10153 if (wb != NoWriteBack)
10154 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10155 }
10156
10157 static void
10158 load_pair_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10159 {
10160 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10161 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10162 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10163 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10164
10165 if (rm == rn)
10166 HALT_UNALLOC;
10167
10168 offset <<= 3;
10169
10170 if (wb != Post)
10171 address += offset;
10172
10173 aarch64_set_FP_double (cpu, rm, aarch64_get_mem_double (cpu, address));
10174 aarch64_set_FP_double (cpu, rn, aarch64_get_mem_double (cpu, address + 8));
10175
10176 if (wb == Post)
10177 address += offset;
10178
10179 if (wb != NoWriteBack)
10180 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10181 }
10182
10183 static void
10184 load_pair_long_double (sim_cpu *cpu, int32_t offset, WriteBack wb)
10185 {
10186 FRegister a;
10187 unsigned rn = uimm (aarch64_get_instr (cpu), 14, 10);
10188 unsigned rd = uimm (aarch64_get_instr (cpu), 9, 5);
10189 unsigned rm = uimm (aarch64_get_instr (cpu), 4, 0);
10190 uint64_t address = aarch64_get_reg_u64 (cpu, rd, SP_OK);
10191
10192 if (rm == rn)
10193 HALT_UNALLOC;
10194
10195 offset <<= 4;
10196
10197 if (wb != Post)
10198 address += offset;
10199
10200 aarch64_get_mem_long_double (cpu, address, & a);
10201 aarch64_set_FP_long_double (cpu, rm, a);
10202 aarch64_get_mem_long_double (cpu, address + 16, & a);
10203 aarch64_set_FP_long_double (cpu, rn, a);
10204
10205 if (wb == Post)
10206 address += offset;
10207
10208 if (wb != NoWriteBack)
10209 aarch64_set_reg_u64 (cpu, rd, SP_OK, address);
10210 }
10211
10212 static void
10213 dex_load_store_pair_fp (sim_cpu *cpu)
10214 {
10215 /* instr[31,30] = size (10=> 128-bit, 01=> 64-bit, 00=> 32-bit)
10216 instr[29,25] = instruction encoding
10217 instr[24,23] = addressing mode (10=> offset, 01=> post, 11=> pre)
10218 instr[22] = load/store (1=> load)
10219 instr[21,15] = signed, scaled, offset
10220 instr[14,10] = Rn
10221 instr[ 9, 5] = Rd
10222 instr[ 4, 0] = Rm */
10223
10224 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 3)
10225 | uimm (aarch64_get_instr (cpu), 24, 22));
10226 int32_t offset = simm32 (aarch64_get_instr (cpu), 21, 15);
10227
10228 switch (dispatch)
10229 {
10230 case 2: store_pair_float (cpu, offset, Post); return;
10231 case 3: load_pair_float (cpu, offset, Post); return;
10232 case 4: store_pair_float (cpu, offset, NoWriteBack); return;
10233 case 5: load_pair_float (cpu, offset, NoWriteBack); return;
10234 case 6: store_pair_float (cpu, offset, Pre); return;
10235 case 7: load_pair_float (cpu, offset, Pre); return;
10236
10237 case 10: store_pair_double (cpu, offset, Post); return;
10238 case 11: load_pair_double (cpu, offset, Post); return;
10239 case 12: store_pair_double (cpu, offset, NoWriteBack); return;
10240 case 13: load_pair_double (cpu, offset, NoWriteBack); return;
10241 case 14: store_pair_double (cpu, offset, Pre); return;
10242 case 15: load_pair_double (cpu, offset, Pre); return;
10243
10244 case 18: store_pair_long_double (cpu, offset, Post); return;
10245 case 19: load_pair_long_double (cpu, offset, Post); return;
10246 case 20: store_pair_long_double (cpu, offset, NoWriteBack); return;
10247 case 21: load_pair_long_double (cpu, offset, NoWriteBack); return;
10248 case 22: store_pair_long_double (cpu, offset, Pre); return;
10249 case 23: load_pair_long_double (cpu, offset, Pre); return;
10250
10251 default:
10252 HALT_UNALLOC;
10253 }
10254 }
10255
10256 static inline unsigned
10257 vec_reg (unsigned v, unsigned o)
10258 {
10259 return (v + o) & 0x3F;
10260 }
10261
10262 /* Load multiple N-element structures to N consecutive registers. */
10263 static void
10264 vec_load (sim_cpu *cpu, uint64_t address, unsigned N)
10265 {
10266 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10267 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10268 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10269 unsigned i;
10270
10271 switch (size)
10272 {
10273 case 0: /* 8-bit operations. */
10274 if (all)
10275 for (i = 0; i < (16 * N); i++)
10276 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15,
10277 aarch64_get_mem_u8 (cpu, address + i));
10278 else
10279 for (i = 0; i < (8 * N); i++)
10280 aarch64_set_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7,
10281 aarch64_get_mem_u8 (cpu, address + i));
10282 return;
10283
10284 case 1: /* 16-bit operations. */
10285 if (all)
10286 for (i = 0; i < (8 * N); i++)
10287 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7,
10288 aarch64_get_mem_u16 (cpu, address + i * 2));
10289 else
10290 for (i = 0; i < (4 * N); i++)
10291 aarch64_set_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3,
10292 aarch64_get_mem_u16 (cpu, address + i * 2));
10293 return;
10294
10295 case 2: /* 32-bit operations. */
10296 if (all)
10297 for (i = 0; i < (4 * N); i++)
10298 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3,
10299 aarch64_get_mem_u32 (cpu, address + i * 4));
10300 else
10301 for (i = 0; i < (2 * N); i++)
10302 aarch64_set_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1,
10303 aarch64_get_mem_u32 (cpu, address + i * 4));
10304 return;
10305
10306 case 3: /* 64-bit operations. */
10307 if (all)
10308 for (i = 0; i < (2 * N); i++)
10309 aarch64_set_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1,
10310 aarch64_get_mem_u64 (cpu, address + i * 8));
10311 else
10312 for (i = 0; i < N; i++)
10313 aarch64_set_vec_u64 (cpu, vec_reg (vd, i), 0,
10314 aarch64_get_mem_u64 (cpu, address + i * 8));
10315 return;
10316
10317 default:
10318 HALT_UNREACHABLE;
10319 }
10320 }
10321
10322 /* LD4: load multiple 4-element to four consecutive registers. */
10323 static void
10324 LD4 (sim_cpu *cpu, uint64_t address)
10325 {
10326 vec_load (cpu, address, 4);
10327 }
10328
10329 /* LD3: load multiple 3-element structures to three consecutive registers. */
10330 static void
10331 LD3 (sim_cpu *cpu, uint64_t address)
10332 {
10333 vec_load (cpu, address, 3);
10334 }
10335
10336 /* LD2: load multiple 2-element structures to two consecutive registers. */
10337 static void
10338 LD2 (sim_cpu *cpu, uint64_t address)
10339 {
10340 vec_load (cpu, address, 2);
10341 }
10342
10343 /* Load multiple 1-element structures into one register. */
10344 static void
10345 LD1_1 (sim_cpu *cpu, uint64_t address)
10346 {
10347 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10348 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10349 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10350 unsigned i;
10351
10352 switch (size)
10353 {
10354 case 0:
10355 /* LD1 {Vd.16b}, addr, #16 */
10356 /* LD1 {Vd.8b}, addr, #8 */
10357 for (i = 0; i < (all ? 16 : 8); i++)
10358 aarch64_set_vec_u8 (cpu, vd, i,
10359 aarch64_get_mem_u8 (cpu, address + i));
10360 return;
10361
10362 case 1:
10363 /* LD1 {Vd.8h}, addr, #16 */
10364 /* LD1 {Vd.4h}, addr, #8 */
10365 for (i = 0; i < (all ? 8 : 4); i++)
10366 aarch64_set_vec_u16 (cpu, vd, i,
10367 aarch64_get_mem_u16 (cpu, address + i * 2));
10368 return;
10369
10370 case 2:
10371 /* LD1 {Vd.4s}, addr, #16 */
10372 /* LD1 {Vd.2s}, addr, #8 */
10373 for (i = 0; i < (all ? 4 : 2); i++)
10374 aarch64_set_vec_u32 (cpu, vd, i,
10375 aarch64_get_mem_u32 (cpu, address + i * 4));
10376 return;
10377
10378 case 3:
10379 /* LD1 {Vd.2d}, addr, #16 */
10380 /* LD1 {Vd.1d}, addr, #8 */
10381 for (i = 0; i < (all ? 2 : 1); i++)
10382 aarch64_set_vec_u64 (cpu, vd, i,
10383 aarch64_get_mem_u64 (cpu, address + i * 8));
10384 return;
10385
10386 default:
10387 HALT_UNREACHABLE;
10388 }
10389 }
10390
10391 /* Load multiple 1-element structures into two registers. */
10392 static void
10393 LD1_2 (sim_cpu *cpu, uint64_t address)
10394 {
10395 /* FIXME: This algorithm is *exactly* the same as the LD2 version.
10396 So why have two different instructions ? There must be something
10397 wrong somewhere. */
10398 vec_load (cpu, address, 2);
10399 }
10400
10401 /* Load multiple 1-element structures into three registers. */
10402 static void
10403 LD1_3 (sim_cpu *cpu, uint64_t address)
10404 {
10405 /* FIXME: This algorithm is *exactly* the same as the LD3 version.
10406 So why have two different instructions ? There must be something
10407 wrong somewhere. */
10408 vec_load (cpu, address, 3);
10409 }
10410
10411 /* Load multiple 1-element structures into four registers. */
10412 static void
10413 LD1_4 (sim_cpu *cpu, uint64_t address)
10414 {
10415 /* FIXME: This algorithm is *exactly* the same as the LD4 version.
10416 So why have two different instructions ? There must be something
10417 wrong somewhere. */
10418 vec_load (cpu, address, 4);
10419 }
10420
10421 /* Store multiple N-element structures to N consecutive registers. */
10422 static void
10423 vec_store (sim_cpu *cpu, uint64_t address, unsigned N)
10424 {
10425 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10426 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10427 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10428 unsigned i;
10429
10430 switch (size)
10431 {
10432 case 0: /* 8-bit operations. */
10433 if (all)
10434 for (i = 0; i < (16 * N); i++)
10435 aarch64_set_mem_u8
10436 (cpu, address + i,
10437 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 4), i & 15));
10438 else
10439 for (i = 0; i < (8 * N); i++)
10440 aarch64_set_mem_u8
10441 (cpu, address + i,
10442 aarch64_get_vec_u8 (cpu, vec_reg (vd, i >> 3), i & 7));
10443 return;
10444
10445 case 1: /* 16-bit operations. */
10446 if (all)
10447 for (i = 0; i < (8 * N); i++)
10448 aarch64_set_mem_u16
10449 (cpu, address + i * 2,
10450 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 3), i & 7));
10451 else
10452 for (i = 0; i < (4 * N); i++)
10453 aarch64_set_mem_u16
10454 (cpu, address + i * 2,
10455 aarch64_get_vec_u16 (cpu, vec_reg (vd, i >> 2), i & 3));
10456 return;
10457
10458 case 2: /* 32-bit operations. */
10459 if (all)
10460 for (i = 0; i < (4 * N); i++)
10461 aarch64_set_mem_u32
10462 (cpu, address + i * 4,
10463 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 2), i & 3));
10464 else
10465 for (i = 0; i < (2 * N); i++)
10466 aarch64_set_mem_u32
10467 (cpu, address + i * 4,
10468 aarch64_get_vec_u32 (cpu, vec_reg (vd, i >> 1), i & 1));
10469 return;
10470
10471 case 3: /* 64-bit operations. */
10472 if (all)
10473 for (i = 0; i < (2 * N); i++)
10474 aarch64_set_mem_u64
10475 (cpu, address + i * 8,
10476 aarch64_get_vec_u64 (cpu, vec_reg (vd, i >> 1), i & 1));
10477 else
10478 for (i = 0; i < N; i++)
10479 aarch64_set_mem_u64
10480 (cpu, address + i * 8,
10481 aarch64_get_vec_u64 (cpu, vec_reg (vd, i), 0));
10482 return;
10483
10484 default:
10485 HALT_UNREACHABLE;
10486 }
10487 }
10488
10489 /* Store multiple 4-element structure to four consecutive registers. */
10490 static void
10491 ST4 (sim_cpu *cpu, uint64_t address)
10492 {
10493 vec_store (cpu, address, 4);
10494 }
10495
10496 /* Store multiple 3-element structures to three consecutive registers. */
10497 static void
10498 ST3 (sim_cpu *cpu, uint64_t address)
10499 {
10500 vec_store (cpu, address, 3);
10501 }
10502
10503 /* Store multiple 2-element structures to two consecutive registers. */
10504 static void
10505 ST2 (sim_cpu *cpu, uint64_t address)
10506 {
10507 vec_store (cpu, address, 2);
10508 }
10509
10510 /* Store multiple 1-element structures into one register. */
10511 static void
10512 ST1_1 (sim_cpu *cpu, uint64_t address)
10513 {
10514 int all = uimm (aarch64_get_instr (cpu), 30, 30);
10515 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10516 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10517 unsigned i;
10518
10519 switch (size)
10520 {
10521 case 0:
10522 for (i = 0; i < (all ? 16 : 8); i++)
10523 aarch64_set_mem_u8 (cpu, address + i,
10524 aarch64_get_vec_u8 (cpu, vd, i));
10525 return;
10526
10527 case 1:
10528 for (i = 0; i < (all ? 8 : 4); i++)
10529 aarch64_set_mem_u16 (cpu, address + i * 2,
10530 aarch64_get_vec_u16 (cpu, vd, i));
10531 return;
10532
10533 case 2:
10534 for (i = 0; i < (all ? 4 : 2); i++)
10535 aarch64_set_mem_u32 (cpu, address + i * 4,
10536 aarch64_get_vec_u32 (cpu, vd, i));
10537 return;
10538
10539 case 3:
10540 for (i = 0; i < (all ? 2 : 1); i++)
10541 aarch64_set_mem_u64 (cpu, address + i * 8,
10542 aarch64_get_vec_u64 (cpu, vd, i));
10543 return;
10544
10545 default:
10546 HALT_UNREACHABLE;
10547 }
10548 }
10549
10550 /* Store multiple 1-element structures into two registers. */
10551 static void
10552 ST1_2 (sim_cpu *cpu, uint64_t address)
10553 {
10554 /* FIXME: This algorithm is *exactly* the same as the ST2 version.
10555 So why have two different instructions ? There must be
10556 something wrong somewhere. */
10557 vec_store (cpu, address, 2);
10558 }
10559
10560 /* Store multiple 1-element structures into three registers. */
10561 static void
10562 ST1_3 (sim_cpu *cpu, uint64_t address)
10563 {
10564 /* FIXME: This algorithm is *exactly* the same as the ST3 version.
10565 So why have two different instructions ? There must be
10566 something wrong somewhere. */
10567 vec_store (cpu, address, 3);
10568 }
10569
10570 /* Store multiple 1-element structures into four registers. */
10571 static void
10572 ST1_4 (sim_cpu *cpu, uint64_t address)
10573 {
10574 /* FIXME: This algorithm is *exactly* the same as the ST4 version.
10575 So why have two different instructions ? There must be
10576 something wrong somewhere. */
10577 vec_store (cpu, address, 4);
10578 }
10579
10580 static void
10581 do_vec_LDnR (sim_cpu *cpu, uint64_t address)
10582 {
10583 /* instr[31] = 0
10584 instr[30] = element selector 0=>half, 1=>all elements
10585 instr[29,24] = 00 1101
10586 instr[23] = 0=>simple, 1=>post
10587 instr[22] = 1
10588 instr[21] = width: LD1R-or-LD3R (0) / LD2R-or-LD4R (1)
10589 instr[20,16] = 0 0000 (simple), Vinc (reg-post-inc, no SP),
10590 11111 (immediate post inc)
10591 instr[15,14] = 11
10592 instr[13] = width: LD1R-or-LD2R (0) / LD3R-or-LD4R (1)
10593 instr[12] = 0
10594 instr[11,10] = element size 00=> byte(b), 01=> half(h),
10595 10=> word(s), 11=> double(d)
10596 instr[9,5] = address
10597 instr[4,0] = Vd */
10598
10599 unsigned full = uimm (aarch64_get_instr (cpu), 30, 30);
10600 unsigned vd = uimm (aarch64_get_instr (cpu), 4, 0);
10601 unsigned size = uimm (aarch64_get_instr (cpu), 11, 10);
10602 int i;
10603
10604 NYI_assert (29, 24, 0x0D);
10605 NYI_assert (22, 22, 1);
10606 NYI_assert (15, 14, 3);
10607 NYI_assert (12, 12, 0);
10608
10609 switch ((uimm (aarch64_get_instr (cpu), 13, 13) << 1)
10610 | uimm (aarch64_get_instr (cpu), 21, 21))
10611 {
10612 case 0: /* LD1R. */
10613 switch (size)
10614 {
10615 case 0:
10616 {
10617 uint8_t val = aarch64_get_mem_u8 (cpu, address);
10618 for (i = 0; i < (full ? 16 : 8); i++)
10619 aarch64_set_vec_u8 (cpu, vd, i, val);
10620 break;
10621 }
10622
10623 case 1:
10624 {
10625 uint16_t val = aarch64_get_mem_u16 (cpu, address);
10626 for (i = 0; i < (full ? 8 : 4); i++)
10627 aarch64_set_vec_u16 (cpu, vd, i, val);
10628 break;
10629 }
10630
10631 case 2:
10632 {
10633 uint32_t val = aarch64_get_mem_u32 (cpu, address);
10634 for (i = 0; i < (full ? 4 : 2); i++)
10635 aarch64_set_vec_u32 (cpu, vd, i, val);
10636 break;
10637 }
10638
10639 case 3:
10640 {
10641 uint64_t val = aarch64_get_mem_u64 (cpu, address);
10642 for (i = 0; i < (full ? 2 : 1); i++)
10643 aarch64_set_vec_u64 (cpu, vd, i, val);
10644 break;
10645 }
10646
10647 default:
10648 HALT_UNALLOC;
10649 }
10650 break;
10651
10652 case 1: /* LD2R. */
10653 switch (size)
10654 {
10655 case 0:
10656 {
10657 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10658 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10659
10660 for (i = 0; i < (full ? 16 : 8); i++)
10661 {
10662 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10663 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10664 }
10665 break;
10666 }
10667
10668 case 1:
10669 {
10670 uint16_t val1 = aarch64_get_mem_u16 (cpu, address);
10671 uint16_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10672
10673 for (i = 0; i < (full ? 8 : 4); i++)
10674 {
10675 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10676 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10677 }
10678 break;
10679 }
10680
10681 case 2:
10682 {
10683 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10684 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10685
10686 for (i = 0; i < (full ? 4 : 2); i++)
10687 {
10688 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10689 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10690 }
10691 break;
10692 }
10693
10694 case 3:
10695 {
10696 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10697 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10698
10699 for (i = 0; i < (full ? 2 : 1); i++)
10700 {
10701 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10702 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10703 }
10704 break;
10705 }
10706
10707 default:
10708 HALT_UNALLOC;
10709 }
10710 break;
10711
10712 case 2: /* LD3R. */
10713 switch (size)
10714 {
10715 case 0:
10716 {
10717 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10718 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10719 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
10720
10721 for (i = 0; i < (full ? 16 : 8); i++)
10722 {
10723 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10724 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10725 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
10726 }
10727 }
10728 break;
10729
10730 case 1:
10731 {
10732 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
10733 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10734 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
10735
10736 for (i = 0; i < (full ? 8 : 4); i++)
10737 {
10738 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10739 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10740 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
10741 }
10742 }
10743 break;
10744
10745 case 2:
10746 {
10747 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10748 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10749 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
10750
10751 for (i = 0; i < (full ? 4 : 2); i++)
10752 {
10753 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10754 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10755 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
10756 }
10757 }
10758 break;
10759
10760 case 3:
10761 {
10762 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10763 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10764 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
10765
10766 for (i = 0; i < (full ? 2 : 1); i++)
10767 {
10768 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10769 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10770 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
10771 }
10772 }
10773 break;
10774
10775 default:
10776 HALT_UNALLOC;
10777 }
10778 break;
10779
10780 case 3: /* LD4R. */
10781 switch (size)
10782 {
10783 case 0:
10784 {
10785 uint8_t val1 = aarch64_get_mem_u8 (cpu, address);
10786 uint8_t val2 = aarch64_get_mem_u8 (cpu, address + 1);
10787 uint8_t val3 = aarch64_get_mem_u8 (cpu, address + 2);
10788 uint8_t val4 = aarch64_get_mem_u8 (cpu, address + 3);
10789
10790 for (i = 0; i < (full ? 16 : 8); i++)
10791 {
10792 aarch64_set_vec_u8 (cpu, vd, 0, val1);
10793 aarch64_set_vec_u8 (cpu, vd + 1, 0, val2);
10794 aarch64_set_vec_u8 (cpu, vd + 2, 0, val3);
10795 aarch64_set_vec_u8 (cpu, vd + 3, 0, val4);
10796 }
10797 }
10798 break;
10799
10800 case 1:
10801 {
10802 uint32_t val1 = aarch64_get_mem_u16 (cpu, address);
10803 uint32_t val2 = aarch64_get_mem_u16 (cpu, address + 2);
10804 uint32_t val3 = aarch64_get_mem_u16 (cpu, address + 4);
10805 uint32_t val4 = aarch64_get_mem_u16 (cpu, address + 6);
10806
10807 for (i = 0; i < (full ? 8 : 4); i++)
10808 {
10809 aarch64_set_vec_u16 (cpu, vd, 0, val1);
10810 aarch64_set_vec_u16 (cpu, vd + 1, 0, val2);
10811 aarch64_set_vec_u16 (cpu, vd + 2, 0, val3);
10812 aarch64_set_vec_u16 (cpu, vd + 3, 0, val4);
10813 }
10814 }
10815 break;
10816
10817 case 2:
10818 {
10819 uint32_t val1 = aarch64_get_mem_u32 (cpu, address);
10820 uint32_t val2 = aarch64_get_mem_u32 (cpu, address + 4);
10821 uint32_t val3 = aarch64_get_mem_u32 (cpu, address + 8);
10822 uint32_t val4 = aarch64_get_mem_u32 (cpu, address + 12);
10823
10824 for (i = 0; i < (full ? 4 : 2); i++)
10825 {
10826 aarch64_set_vec_u32 (cpu, vd, 0, val1);
10827 aarch64_set_vec_u32 (cpu, vd + 1, 0, val2);
10828 aarch64_set_vec_u32 (cpu, vd + 2, 0, val3);
10829 aarch64_set_vec_u32 (cpu, vd + 3, 0, val4);
10830 }
10831 }
10832 break;
10833
10834 case 3:
10835 {
10836 uint64_t val1 = aarch64_get_mem_u64 (cpu, address);
10837 uint64_t val2 = aarch64_get_mem_u64 (cpu, address + 8);
10838 uint64_t val3 = aarch64_get_mem_u64 (cpu, address + 16);
10839 uint64_t val4 = aarch64_get_mem_u64 (cpu, address + 24);
10840
10841 for (i = 0; i < (full ? 2 : 1); i++)
10842 {
10843 aarch64_set_vec_u64 (cpu, vd, 0, val1);
10844 aarch64_set_vec_u64 (cpu, vd + 1, 0, val2);
10845 aarch64_set_vec_u64 (cpu, vd + 2, 0, val3);
10846 aarch64_set_vec_u64 (cpu, vd + 3, 0, val4);
10847 }
10848 }
10849 break;
10850
10851 default:
10852 HALT_UNALLOC;
10853 }
10854 break;
10855
10856 default:
10857 HALT_UNALLOC;
10858 }
10859 }
10860
10861 static void
10862 do_vec_load_store (sim_cpu *cpu)
10863 {
10864 /* {LD|ST}<N> {Vd..Vd+N}, vaddr
10865
10866 instr[31] = 0
10867 instr[30] = element selector 0=>half, 1=>all elements
10868 instr[29,25] = 00110
10869 instr[24] = ?
10870 instr[23] = 0=>simple, 1=>post
10871 instr[22] = 0=>store, 1=>load
10872 instr[21] = 0 (LDn) / small(0)-large(1) selector (LDnR)
10873 instr[20,16] = 00000 (simple), Vinc (reg-post-inc, no SP),
10874 11111 (immediate post inc)
10875 instr[15,12] = elements and destinations. eg for load:
10876 0000=>LD4 => load multiple 4-element to
10877 four consecutive registers
10878 0100=>LD3 => load multiple 3-element to
10879 three consecutive registers
10880 1000=>LD2 => load multiple 2-element to
10881 two consecutive registers
10882 0010=>LD1 => load multiple 1-element to
10883 four consecutive registers
10884 0110=>LD1 => load multiple 1-element to
10885 three consecutive registers
10886 1010=>LD1 => load multiple 1-element to
10887 two consecutive registers
10888 0111=>LD1 => load multiple 1-element to
10889 one register
10890 1100=>LDR1,LDR2
10891 1110=>LDR3,LDR4
10892 instr[11,10] = element size 00=> byte(b), 01=> half(h),
10893 10=> word(s), 11=> double(d)
10894 instr[9,5] = Vn, can be SP
10895 instr[4,0] = Vd */
10896
10897 int post;
10898 int load;
10899 unsigned vn;
10900 uint64_t address;
10901 int type;
10902
10903 if (uimm (aarch64_get_instr (cpu), 31, 31) != 0
10904 || uimm (aarch64_get_instr (cpu), 29, 25) != 0x06)
10905 HALT_NYI;
10906
10907 type = uimm (aarch64_get_instr (cpu), 15, 12);
10908 if (type != 0xE && type != 0xE && uimm (aarch64_get_instr (cpu), 21, 21) != 0)
10909 HALT_NYI;
10910
10911 post = uimm (aarch64_get_instr (cpu), 23, 23);
10912 load = uimm (aarch64_get_instr (cpu), 22, 22);
10913 vn = uimm (aarch64_get_instr (cpu), 9, 5);
10914 address = aarch64_get_reg_u64 (cpu, vn, SP_OK);
10915
10916 if (post)
10917 {
10918 unsigned vm = uimm (aarch64_get_instr (cpu), 20, 16);
10919
10920 if (vm == R31)
10921 {
10922 unsigned sizeof_operation;
10923
10924 switch (type)
10925 {
10926 case 0: sizeof_operation = 32; break;
10927 case 4: sizeof_operation = 24; break;
10928 case 8: sizeof_operation = 16; break;
10929
10930 case 0xC:
10931 sizeof_operation = uimm (aarch64_get_instr (cpu), 21, 21) ? 2 : 1;
10932 sizeof_operation <<= uimm (aarch64_get_instr (cpu), 11, 10);
10933 break;
10934
10935 case 0xE:
10936 sizeof_operation = uimm (aarch64_get_instr (cpu), 21, 21) ? 8 : 4;
10937 sizeof_operation <<= uimm (aarch64_get_instr (cpu), 11, 10);
10938 break;
10939
10940 case 2:
10941 case 6:
10942 case 10:
10943 case 7:
10944 sizeof_operation = 2 << uimm (aarch64_get_instr (cpu), 11, 10);
10945 break;
10946
10947 default:
10948 HALT_UNALLOC;
10949 }
10950
10951 if (uimm (aarch64_get_instr (cpu), 30, 30))
10952 sizeof_operation *= 2;
10953
10954 aarch64_set_reg_u64 (cpu, vn, SP_OK, address + sizeof_operation);
10955 }
10956 else
10957 aarch64_set_reg_u64 (cpu, vn, SP_OK,
10958 address + aarch64_get_reg_u64 (cpu, vm, NO_SP));
10959 }
10960 else
10961 {
10962 NYI_assert (20, 16, 0);
10963 }
10964
10965 if (load)
10966 {
10967 switch (type)
10968 {
10969 case 0: LD4 (cpu, address); return;
10970 case 4: LD3 (cpu, address); return;
10971 case 8: LD2 (cpu, address); return;
10972 case 2: LD1_4 (cpu, address); return;
10973 case 6: LD1_3 (cpu, address); return;
10974 case 10: LD1_2 (cpu, address); return;
10975 case 7: LD1_1 (cpu, address); return;
10976
10977 case 0xE:
10978 case 0xC: do_vec_LDnR (cpu, address); return;
10979
10980 default:
10981 HALT_NYI;
10982 }
10983 }
10984
10985 /* Stores. */
10986 switch (type)
10987 {
10988 case 0: ST4 (cpu, address); return;
10989 case 4: ST3 (cpu, address); return;
10990 case 8: ST2 (cpu, address); return;
10991 case 2: ST1_4 (cpu, address); return;
10992 case 6: ST1_3 (cpu, address); return;
10993 case 10: ST1_2 (cpu, address); return;
10994 case 7: ST1_1 (cpu, address); return;
10995 default:
10996 HALT_NYI;
10997 }
10998 }
10999
11000 static void
11001 dexLdSt (sim_cpu *cpu)
11002 {
11003 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
11004 assert group == GROUP_LDST_0100 || group == GROUP_LDST_0110 ||
11005 group == GROUP_LDST_1100 || group == GROUP_LDST_1110
11006 bits [29,28:26] of a LS are the secondary dispatch vector. */
11007 uint32_t group2 = dispatchLS (aarch64_get_instr (cpu));
11008
11009 switch (group2)
11010 {
11011 case LS_EXCL_000:
11012 dexLoadExclusive (cpu); return;
11013
11014 case LS_LIT_010:
11015 case LS_LIT_011:
11016 dexLoadLiteral (cpu); return;
11017
11018 case LS_OTHER_110:
11019 case LS_OTHER_111:
11020 dexLoadOther (cpu); return;
11021
11022 case LS_ADVSIMD_001:
11023 do_vec_load_store (cpu); return;
11024
11025 case LS_PAIR_100:
11026 dex_load_store_pair_gr (cpu); return;
11027
11028 case LS_PAIR_101:
11029 dex_load_store_pair_fp (cpu); return;
11030
11031 default:
11032 /* Should never reach here. */
11033 HALT_NYI;
11034 }
11035 }
11036
11037 /* Specific decode and execute for group Data Processing Register. */
11038
11039 static void
11040 dexLogicalShiftedRegister (sim_cpu *cpu)
11041 {
11042 /* assert instr[28:24] = 01010
11043 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11044 instr[30,29:21] = op,N : 000 ==> AND, 001 ==> BIC,
11045 010 ==> ORR, 011 ==> ORN
11046 100 ==> EOR, 101 ==> EON,
11047 110 ==> ANDS, 111 ==> BICS
11048 instr[23,22] = shift : 0 ==> LSL, 1 ==> LSR, 2 ==> ASR, 3 ==> ROR
11049 instr[15,10] = count : must be 0xxxxx for 32 bit
11050 instr[9,5] = Rn
11051 instr[4,0] = Rd */
11052
11053 /* unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16); */
11054 uint32_t dispatch;
11055 Shift shiftType;
11056 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
11057
11058 /* 32 bit operations must have count[5] = 0. */
11059 /* or else we have an UNALLOC. */
11060 uint32_t count = uimm (aarch64_get_instr (cpu), 15, 10);
11061
11062 if (!size && uimm (count, 5, 5))
11063 HALT_UNALLOC;
11064
11065 shiftType = shift (aarch64_get_instr (cpu), 22);
11066
11067 /* dispatch on size:op:N i.e aarch64_get_instr (cpu)[31,29:21]. */
11068 dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 29) << 1)
11069 | uimm (aarch64_get_instr (cpu), 21, 21));
11070
11071 switch (dispatch)
11072 {
11073 case 0: and32_shift (cpu, shiftType, count); return;
11074 case 1: bic32_shift (cpu, shiftType, count); return;
11075 case 2: orr32_shift (cpu, shiftType, count); return;
11076 case 3: orn32_shift (cpu, shiftType, count); return;
11077 case 4: eor32_shift (cpu, shiftType, count); return;
11078 case 5: eon32_shift (cpu, shiftType, count); return;
11079 case 6: ands32_shift (cpu, shiftType, count); return;
11080 case 7: bics32_shift (cpu, shiftType, count); return;
11081 case 8: and64_shift (cpu, shiftType, count); return;
11082 case 9: bic64_shift (cpu, shiftType, count); return;
11083 case 10:orr64_shift (cpu, shiftType, count); return;
11084 case 11:orn64_shift (cpu, shiftType, count); return;
11085 case 12:eor64_shift (cpu, shiftType, count); return;
11086 case 13:eon64_shift (cpu, shiftType, count); return;
11087 case 14:ands64_shift (cpu, shiftType, count); return;
11088 case 15:bics64_shift (cpu, shiftType, count); return;
11089 default: HALT_UNALLOC;
11090 }
11091 }
11092
11093 /* 32 bit conditional select. */
11094 static void
11095 csel32 (sim_cpu *cpu, CondCode cc)
11096 {
11097 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11098 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11099 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11100
11101 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11102 testConditionCode (cpu, cc)
11103 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11104 : aarch64_get_reg_u32 (cpu, rm, NO_SP));
11105 }
11106
11107 /* 64 bit conditional select. */
11108 static void
11109 csel64 (sim_cpu *cpu, CondCode cc)
11110 {
11111 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11112 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11113 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11114
11115 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11116 testConditionCode (cpu, cc)
11117 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11118 : aarch64_get_reg_u64 (cpu, rm, NO_SP));
11119 }
11120
11121 /* 32 bit conditional increment. */
11122 static void
11123 csinc32 (sim_cpu *cpu, CondCode cc)
11124 {
11125 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11126 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11127 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11128
11129 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11130 testConditionCode (cpu, cc)
11131 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11132 : aarch64_get_reg_u32 (cpu, rm, NO_SP) + 1);
11133 }
11134
11135 /* 64 bit conditional increment. */
11136 static void
11137 csinc64 (sim_cpu *cpu, CondCode cc)
11138 {
11139 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11140 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11141 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11142
11143 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11144 testConditionCode (cpu, cc)
11145 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11146 : aarch64_get_reg_u64 (cpu, rm, NO_SP) + 1);
11147 }
11148
11149 /* 32 bit conditional invert. */
11150 static void
11151 csinv32 (sim_cpu *cpu, CondCode cc)
11152 {
11153 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11154 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11155 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11156
11157 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11158 testConditionCode (cpu, cc)
11159 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11160 : ~ aarch64_get_reg_u32 (cpu, rm, NO_SP));
11161 }
11162
11163 /* 64 bit conditional invert. */
11164 static void
11165 csinv64 (sim_cpu *cpu, CondCode cc)
11166 {
11167 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11168 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11169 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11170
11171 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11172 testConditionCode (cpu, cc)
11173 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11174 : ~ aarch64_get_reg_u64 (cpu, rm, NO_SP));
11175 }
11176
11177 /* 32 bit conditional negate. */
11178 static void
11179 csneg32 (sim_cpu *cpu, CondCode cc)
11180 {
11181 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11182 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11183 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11184
11185 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11186 testConditionCode (cpu, cc)
11187 ? aarch64_get_reg_u32 (cpu, rn, NO_SP)
11188 : - aarch64_get_reg_u32 (cpu, rm, NO_SP));
11189 }
11190
11191 /* 64 bit conditional negate. */
11192 static void
11193 csneg64 (sim_cpu *cpu, CondCode cc)
11194 {
11195 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11196 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11197 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11198
11199 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11200 testConditionCode (cpu, cc)
11201 ? aarch64_get_reg_u64 (cpu, rn, NO_SP)
11202 : - aarch64_get_reg_u64 (cpu, rm, NO_SP));
11203 }
11204
11205 static void
11206 dexCondSelect (sim_cpu *cpu)
11207 {
11208 /* assert instr[28,21] = 11011011
11209 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11210 instr[30:11,10] = op : 000 ==> CSEL, 001 ==> CSINC,
11211 100 ==> CSINV, 101 ==> CSNEG,
11212 _1_ ==> UNALLOC
11213 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11214 instr[15,12] = cond
11215 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC */
11216
11217 CondCode cc;
11218 uint32_t dispatch;
11219 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11220 uint32_t op2 = uimm (aarch64_get_instr (cpu), 11, 10);
11221
11222 if (S == 1)
11223 HALT_UNALLOC;
11224
11225 if (op2 & 0x2)
11226 HALT_UNALLOC;
11227
11228 cc = condcode (aarch64_get_instr (cpu), 12);
11229 dispatch = ((uimm (aarch64_get_instr (cpu), 31, 30) << 1) | op2);
11230
11231 switch (dispatch)
11232 {
11233 case 0: csel32 (cpu, cc); return;
11234 case 1: csinc32 (cpu, cc); return;
11235 case 2: csinv32 (cpu, cc); return;
11236 case 3: csneg32 (cpu, cc); return;
11237 case 4: csel64 (cpu, cc); return;
11238 case 5: csinc64 (cpu, cc); return;
11239 case 6: csinv64 (cpu, cc); return;
11240 case 7: csneg64 (cpu, cc); return;
11241 default: HALT_UNALLOC;
11242 }
11243 }
11244
11245 /* Some helpers for counting leading 1 or 0 bits. */
11246
11247 /* Counts the number of leading bits which are the same
11248 in a 32 bit value in the range 1 to 32. */
11249 static uint32_t
11250 leading32 (uint32_t value)
11251 {
11252 int32_t mask= 0xffff0000;
11253 uint32_t count= 16; /* Counts number of bits set in mask. */
11254 uint32_t lo = 1; /* Lower bound for number of sign bits. */
11255 uint32_t hi = 32; /* Upper bound for number of sign bits. */
11256
11257 while (lo + 1 < hi)
11258 {
11259 int32_t test = (value & mask);
11260
11261 if (test == 0 || test == mask)
11262 {
11263 lo = count;
11264 count = (lo + hi) / 2;
11265 mask >>= (count - lo);
11266 }
11267 else
11268 {
11269 hi = count;
11270 count = (lo + hi) / 2;
11271 mask <<= hi - count;
11272 }
11273 }
11274
11275 if (lo != hi)
11276 {
11277 int32_t test;
11278
11279 mask >>= 1;
11280 test = (value & mask);
11281
11282 if (test == 0 || test == mask)
11283 count = hi;
11284 else
11285 count = lo;
11286 }
11287
11288 return count;
11289 }
11290
11291 /* Counts the number of leading bits which are the same
11292 in a 64 bit value in the range 1 to 64. */
11293 static uint64_t
11294 leading64 (uint64_t value)
11295 {
11296 int64_t mask= 0xffffffff00000000LL;
11297 uint64_t count = 32; /* Counts number of bits set in mask. */
11298 uint64_t lo = 1; /* Lower bound for number of sign bits. */
11299 uint64_t hi = 64; /* Upper bound for number of sign bits. */
11300
11301 while (lo + 1 < hi)
11302 {
11303 int64_t test = (value & mask);
11304
11305 if (test == 0 || test == mask)
11306 {
11307 lo = count;
11308 count = (lo + hi) / 2;
11309 mask >>= (count - lo);
11310 }
11311 else
11312 {
11313 hi = count;
11314 count = (lo + hi) / 2;
11315 mask <<= hi - count;
11316 }
11317 }
11318
11319 if (lo != hi)
11320 {
11321 int64_t test;
11322
11323 mask >>= 1;
11324 test = (value & mask);
11325
11326 if (test == 0 || test == mask)
11327 count = hi;
11328 else
11329 count = lo;
11330 }
11331
11332 return count;
11333 }
11334
11335 /* Bit operations. */
11336 /* N.B register args may not be SP. */
11337
11338 /* 32 bit count leading sign bits. */
11339 static void
11340 cls32 (sim_cpu *cpu)
11341 {
11342 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11343 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11344
11345 /* N.B. the result needs to exclude the leading bit. */
11346 aarch64_set_reg_u64
11347 (cpu, rd, NO_SP, leading32 (aarch64_get_reg_u32 (cpu, rn, NO_SP)) - 1);
11348 }
11349
11350 /* 64 bit count leading sign bits. */
11351 static void
11352 cls64 (sim_cpu *cpu)
11353 {
11354 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11355 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11356
11357 /* N.B. the result needs to exclude the leading bit. */
11358 aarch64_set_reg_u64
11359 (cpu, rd, NO_SP, leading64 (aarch64_get_reg_u64 (cpu, rn, NO_SP)) - 1);
11360 }
11361
11362 /* 32 bit count leading zero bits. */
11363 static void
11364 clz32 (sim_cpu *cpu)
11365 {
11366 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11367 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11368 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11369
11370 /* if the sign (top) bit is set then the count is 0. */
11371 if (pick32 (value, 31, 31))
11372 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11373 else
11374 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading32 (value));
11375 }
11376
11377 /* 64 bit count leading zero bits. */
11378 static void
11379 clz64 (sim_cpu *cpu)
11380 {
11381 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11382 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11383 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11384
11385 /* if the sign (top) bit is set then the count is 0. */
11386 if (pick64 (value, 63, 63))
11387 aarch64_set_reg_u64 (cpu, rd, NO_SP, 0L);
11388 else
11389 aarch64_set_reg_u64 (cpu, rd, NO_SP, leading64 (value));
11390 }
11391
11392 /* 32 bit reverse bits. */
11393 static void
11394 rbit32 (sim_cpu *cpu)
11395 {
11396 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11397 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11398 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11399 uint32_t result = 0;
11400 int i;
11401
11402 for (i = 0; i < 32; i++)
11403 {
11404 result <<= 1;
11405 result |= (value & 1);
11406 value >>= 1;
11407 }
11408 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11409 }
11410
11411 /* 64 bit reverse bits. */
11412 static void
11413 rbit64 (sim_cpu *cpu)
11414 {
11415 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11416 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11417 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11418 uint64_t result = 0;
11419 int i;
11420
11421 for (i = 0; i < 64; i++)
11422 {
11423 result <<= 1;
11424 result |= (value & 1L);
11425 value >>= 1;
11426 }
11427 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11428 }
11429
11430 /* 32 bit reverse bytes. */
11431 static void
11432 rev32 (sim_cpu *cpu)
11433 {
11434 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11435 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11436 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11437 uint32_t result = 0;
11438 int i;
11439
11440 for (i = 0; i < 4; i++)
11441 {
11442 result <<= 8;
11443 result |= (value & 0xff);
11444 value >>= 8;
11445 }
11446 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11447 }
11448
11449 /* 64 bit reverse bytes. */
11450 static void
11451 rev64 (sim_cpu *cpu)
11452 {
11453 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11454 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11455 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11456 uint64_t result = 0;
11457 int i;
11458
11459 for (i = 0; i < 8; i++)
11460 {
11461 result <<= 8;
11462 result |= (value & 0xffULL);
11463 value >>= 8;
11464 }
11465 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11466 }
11467
11468 /* 32 bit reverse shorts. */
11469 /* N.B.this reverses the order of the bytes in each half word. */
11470 static void
11471 revh32 (sim_cpu *cpu)
11472 {
11473 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11474 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11475 uint32_t value = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11476 uint32_t result = 0;
11477 int i;
11478
11479 for (i = 0; i < 2; i++)
11480 {
11481 result <<= 8;
11482 result |= (value & 0x00ff00ff);
11483 value >>= 8;
11484 }
11485 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11486 }
11487
11488 /* 64 bit reverse shorts. */
11489 /* N.B.this reverses the order of the bytes in each half word. */
11490 static void
11491 revh64 (sim_cpu *cpu)
11492 {
11493 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11494 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11495 uint64_t value = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11496 uint64_t result = 0;
11497 int i;
11498
11499 for (i = 0; i < 2; i++)
11500 {
11501 result <<= 8;
11502 result |= (value & 0x00ff00ff00ff00ffULL);
11503 value >>= 8;
11504 }
11505 aarch64_set_reg_u64 (cpu, rd, NO_SP, result);
11506 }
11507
11508 static void
11509 dexDataProc1Source (sim_cpu *cpu)
11510 {
11511 /* assert instr[30] == 1
11512 aarch64_get_instr (cpu)[28,21] == 111010110
11513 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11514 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11515 instr[20,16] = opcode2 : 00000 ==> ok, ow ==> UNALLOC
11516 instr[15,10] = opcode : 000000 ==> RBIT, 000001 ==> REV16,
11517 000010 ==> REV, 000011 ==> UNALLOC
11518 000100 ==> CLZ, 000101 ==> CLS
11519 ow ==> UNALLOC
11520 instr[9,5] = rn : may not be SP
11521 instr[4,0] = rd : may not be SP. */
11522
11523 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11524 uint32_t opcode2 = uimm (aarch64_get_instr (cpu), 20, 16);
11525 uint32_t opcode = uimm (aarch64_get_instr (cpu), 15, 10);
11526 uint32_t dispatch = ((uimm (aarch64_get_instr (cpu), 31, 31) << 3) | opcode);
11527
11528 if (S == 1)
11529 HALT_UNALLOC;
11530
11531 if (opcode2 != 0)
11532 HALT_UNALLOC;
11533
11534 if (opcode & 0x38)
11535 HALT_UNALLOC;
11536
11537 switch (dispatch)
11538 {
11539 case 0: rbit32 (cpu); return;
11540 case 1: revh32 (cpu); return;
11541 case 2: rev32 (cpu); return;
11542 case 4: clz32 (cpu); return;
11543 case 5: cls32 (cpu); return;
11544 case 8: rbit64 (cpu); return;
11545 case 9: revh64 (cpu); return;
11546 case 10:rev32 (cpu); return;
11547 case 11:rev64 (cpu); return;
11548 case 12:clz64 (cpu); return;
11549 case 13:cls64 (cpu); return;
11550 default: HALT_UNALLOC;
11551 }
11552 }
11553
11554 /* Variable shift.
11555 Shifts by count supplied in register.
11556 N.B register args may not be SP.
11557 These all use the shifted auxiliary function for
11558 simplicity and clarity. Writing the actual shift
11559 inline would avoid a branch and so be faster but
11560 would also necessitate getting signs right. */
11561
11562 /* 32 bit arithmetic shift right. */
11563 static void
11564 asrv32 (sim_cpu *cpu)
11565 {
11566 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11567 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11568 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11569
11570 aarch64_set_reg_u64
11571 (cpu, rd, NO_SP,
11572 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ASR,
11573 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11574 }
11575
11576 /* 64 bit arithmetic shift right. */
11577 static void
11578 asrv64 (sim_cpu *cpu)
11579 {
11580 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11581 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11582 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11583
11584 aarch64_set_reg_u64
11585 (cpu, rd, NO_SP,
11586 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ASR,
11587 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11588 }
11589
11590 /* 32 bit logical shift left. */
11591 static void
11592 lslv32 (sim_cpu *cpu)
11593 {
11594 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11595 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11596 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11597
11598 aarch64_set_reg_u64
11599 (cpu, rd, NO_SP,
11600 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSL,
11601 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11602 }
11603
11604 /* 64 bit arithmetic shift left. */
11605 static void
11606 lslv64 (sim_cpu *cpu)
11607 {
11608 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11609 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11610 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11611
11612 aarch64_set_reg_u64
11613 (cpu, rd, NO_SP,
11614 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSL,
11615 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11616 }
11617
11618 /* 32 bit logical shift right. */
11619 static void
11620 lsrv32 (sim_cpu *cpu)
11621 {
11622 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11623 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11624 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11625
11626 aarch64_set_reg_u64
11627 (cpu, rd, NO_SP,
11628 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), LSR,
11629 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11630 }
11631
11632 /* 64 bit logical shift right. */
11633 static void
11634 lsrv64 (sim_cpu *cpu)
11635 {
11636 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11637 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11638 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11639
11640 aarch64_set_reg_u64
11641 (cpu, rd, NO_SP,
11642 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), LSR,
11643 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11644 }
11645
11646 /* 32 bit rotate right. */
11647 static void
11648 rorv32 (sim_cpu *cpu)
11649 {
11650 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11651 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11652 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11653
11654 aarch64_set_reg_u64
11655 (cpu, rd, NO_SP,
11656 shifted32 (aarch64_get_reg_u32 (cpu, rn, NO_SP), ROR,
11657 (aarch64_get_reg_u32 (cpu, rm, NO_SP) & 0x1f)));
11658 }
11659
11660 /* 64 bit rotate right. */
11661 static void
11662 rorv64 (sim_cpu *cpu)
11663 {
11664 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11665 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11666 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11667
11668 aarch64_set_reg_u64
11669 (cpu, rd, NO_SP,
11670 shifted64 (aarch64_get_reg_u64 (cpu, rn, NO_SP), ROR,
11671 (aarch64_get_reg_u64 (cpu, rm, NO_SP) & 0x3f)));
11672 }
11673
11674
11675 /* divide. */
11676
11677 /* 32 bit signed divide. */
11678 static void
11679 cpuiv32 (sim_cpu *cpu)
11680 {
11681 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11682 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11683 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11684 /* N.B. the pseudo-code does the divide using 64 bit data. */
11685 /* TODO : check that this rounds towards zero as required. */
11686 int64_t dividend = aarch64_get_reg_s32 (cpu, rn, NO_SP);
11687 int64_t divisor = aarch64_get_reg_s32 (cpu, rm, NO_SP);
11688
11689 aarch64_set_reg_s64 (cpu, rd, NO_SP,
11690 divisor ? ((int32_t) (dividend / divisor)) : 0);
11691 }
11692
11693 /* 64 bit signed divide. */
11694 static void
11695 cpuiv64 (sim_cpu *cpu)
11696 {
11697 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11698 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11699 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11700
11701 /* TODO : check that this rounds towards zero as required. */
11702 int64_t divisor = aarch64_get_reg_s64 (cpu, rm, NO_SP);
11703
11704 aarch64_set_reg_s64
11705 (cpu, rd, NO_SP,
11706 divisor ? (aarch64_get_reg_s64 (cpu, rn, NO_SP) / divisor) : 0);
11707 }
11708
11709 /* 32 bit unsigned divide. */
11710 static void
11711 udiv32 (sim_cpu *cpu)
11712 {
11713 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11714 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11715 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11716
11717 /* N.B. the pseudo-code does the divide using 64 bit data. */
11718 uint64_t dividend = aarch64_get_reg_u32 (cpu, rn, NO_SP);
11719 uint64_t divisor = aarch64_get_reg_u32 (cpu, rm, NO_SP);
11720
11721 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11722 divisor ? (uint32_t) (dividend / divisor) : 0);
11723 }
11724
11725 /* 64 bit unsigned divide. */
11726 static void
11727 udiv64 (sim_cpu *cpu)
11728 {
11729 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11730 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11731 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11732
11733 /* TODO : check that this rounds towards zero as required. */
11734 uint64_t divisor = aarch64_get_reg_u64 (cpu, rm, NO_SP);
11735
11736 aarch64_set_reg_u64
11737 (cpu, rd, NO_SP,
11738 divisor ? (aarch64_get_reg_u64 (cpu, rn, NO_SP) / divisor) : 0);
11739 }
11740
11741 static void
11742 dexDataProc2Source (sim_cpu *cpu)
11743 {
11744 /* assert instr[30] == 0
11745 instr[28,21] == 11010110
11746 instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit
11747 instr[29] = S : 0 ==> ok, 1 ==> UNALLOC
11748 instr[15,10] = opcode : 000010 ==> UDIV, 000011 ==> CPUIV,
11749 001000 ==> LSLV, 001001 ==> LSRV
11750 001010 ==> ASRV, 001011 ==> RORV
11751 ow ==> UNALLOC. */
11752
11753 uint32_t dispatch;
11754 uint32_t S = uimm (aarch64_get_instr (cpu), 29, 29);
11755 uint32_t opcode = uimm (aarch64_get_instr (cpu), 15, 10);
11756
11757 if (S == 1)
11758 HALT_UNALLOC;
11759
11760 if (opcode & 0x34)
11761 HALT_UNALLOC;
11762
11763 dispatch = ( (uimm (aarch64_get_instr (cpu), 31, 31) << 3)
11764 | (uimm (opcode, 3, 3) << 2)
11765 | uimm (opcode, 1, 0));
11766 switch (dispatch)
11767 {
11768 case 2: udiv32 (cpu); return;
11769 case 3: cpuiv32 (cpu); return;
11770 case 4: lslv32 (cpu); return;
11771 case 5: lsrv32 (cpu); return;
11772 case 6: asrv32 (cpu); return;
11773 case 7: rorv32 (cpu); return;
11774 case 10: udiv64 (cpu); return;
11775 case 11: cpuiv64 (cpu); return;
11776 case 12: lslv64 (cpu); return;
11777 case 13: lsrv64 (cpu); return;
11778 case 14: asrv64 (cpu); return;
11779 case 15: rorv64 (cpu); return;
11780 default: HALT_UNALLOC;
11781 }
11782 }
11783
11784
11785 /* Multiply. */
11786
11787 /* 32 bit multiply and add. */
11788 static void
11789 madd32 (sim_cpu *cpu)
11790 {
11791 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11792 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11793 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11794 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11795
11796 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11797 aarch64_get_reg_u32 (cpu, ra, NO_SP)
11798 + aarch64_get_reg_u32 (cpu, rn, NO_SP)
11799 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
11800 }
11801
11802 /* 64 bit multiply and add. */
11803 static void
11804 madd64 (sim_cpu *cpu)
11805 {
11806 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11807 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11808 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11809 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11810
11811 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11812 aarch64_get_reg_u64 (cpu, ra, NO_SP)
11813 + aarch64_get_reg_u64 (cpu, rn, NO_SP)
11814 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
11815 }
11816
11817 /* 32 bit multiply and sub. */
11818 static void
11819 msub32 (sim_cpu *cpu)
11820 {
11821 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11822 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11823 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11824 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11825
11826 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11827 aarch64_get_reg_u32 (cpu, ra, NO_SP)
11828 - aarch64_get_reg_u32 (cpu, rn, NO_SP)
11829 * aarch64_get_reg_u32 (cpu, rm, NO_SP));
11830 }
11831
11832 /* 64 bit multiply and sub. */
11833 static void
11834 msub64 (sim_cpu *cpu)
11835 {
11836 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11837 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11838 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11839 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11840
11841 aarch64_set_reg_u64 (cpu, rd, NO_SP,
11842 aarch64_get_reg_u64 (cpu, ra, NO_SP)
11843 - aarch64_get_reg_u64 (cpu, rn, NO_SP)
11844 * aarch64_get_reg_u64 (cpu, rm, NO_SP));
11845 }
11846
11847 /* Signed multiply add long -- source, source2 : 32 bit, source3 : 64 bit. */
11848 static void
11849 smaddl (sim_cpu *cpu)
11850 {
11851 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11852 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11853 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11854 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11855
11856 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
11857 obtain a 64 bit product. */
11858 aarch64_set_reg_s64
11859 (cpu, rd, NO_SP,
11860 aarch64_get_reg_s64 (cpu, ra, NO_SP)
11861 + ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
11862 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
11863 }
11864
11865 /* Signed multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
11866 static void
11867 smsubl (sim_cpu *cpu)
11868 {
11869 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11870 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
11871 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11872 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11873
11874 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
11875 obtain a 64 bit product. */
11876 aarch64_set_reg_s64
11877 (cpu, rd, NO_SP,
11878 aarch64_get_reg_s64 (cpu, ra, NO_SP)
11879 - ((int64_t) aarch64_get_reg_s32 (cpu, rn, NO_SP))
11880 * ((int64_t) aarch64_get_reg_s32 (cpu, rm, NO_SP)));
11881 }
11882
11883 /* Integer Multiply/Divide. */
11884
11885 /* First some macros and a helper function. */
11886 /* Macros to test or access elements of 64 bit words. */
11887
11888 /* Mask used to access lo 32 bits of 64 bit unsigned int. */
11889 #define LOW_WORD_MASK ((1ULL << 32) - 1)
11890 /* Return the lo 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
11891 #define lowWordToU64(_value_u64) ((_value_u64) & LOW_WORD_MASK)
11892 /* Return the hi 32 bit word of a 64 bit unsigned int as a 64 bit unsigned int. */
11893 #define highWordToU64(_value_u64) ((_value_u64) >> 32)
11894
11895 /* Offset of sign bit in 64 bit signed integger. */
11896 #define SIGN_SHIFT_U64 63
11897 /* The sign bit itself -- also identifies the minimum negative int value. */
11898 #define SIGN_BIT_U64 (1UL << SIGN_SHIFT_U64)
11899 /* Return true if a 64 bit signed int presented as an unsigned int is the
11900 most negative value. */
11901 #define isMinimumU64(_value_u64) ((_value_u64) == SIGN_BIT_U64)
11902 /* Return true (non-zero) if a 64 bit signed int presented as an unsigned
11903 int has its sign bit set to false. */
11904 #define isSignSetU64(_value_u64) ((_value_u64) & SIGN_BIT_U64)
11905 /* Return 1L or -1L according to whether a 64 bit signed int presented as
11906 an unsigned int has its sign bit set or not. */
11907 #define signOfU64(_value_u64) (1L + (((value_u64) >> SIGN_SHIFT_U64) * -2L)
11908 /* Clear the sign bit of a 64 bit signed int presented as an unsigned int. */
11909 #define clearSignU64(_value_u64) ((_value_u64) &= ~SIGN_BIT_U64)
11910
11911 /* Multiply two 64 bit ints and return.
11912 the hi 64 bits of the 128 bit product. */
11913
11914 static uint64_t
11915 mul64hi (uint64_t value1, uint64_t value2)
11916 {
11917 uint64_t resultmid1;
11918 uint64_t result;
11919 uint64_t value1_lo = lowWordToU64 (value1);
11920 uint64_t value1_hi = highWordToU64 (value1) ;
11921 uint64_t value2_lo = lowWordToU64 (value2);
11922 uint64_t value2_hi = highWordToU64 (value2);
11923
11924 /* Cross-multiply and collect results. */
11925
11926 uint64_t xproductlo = value1_lo * value2_lo;
11927 uint64_t xproductmid1 = value1_lo * value2_hi;
11928 uint64_t xproductmid2 = value1_hi * value2_lo;
11929 uint64_t xproducthi = value1_hi * value2_hi;
11930 uint64_t carry = 0;
11931 /* Start accumulating 64 bit results. */
11932 /* Drop bottom half of lowest cross-product. */
11933 uint64_t resultmid = xproductlo >> 32;
11934 /* Add in middle products. */
11935 resultmid = resultmid + xproductmid1;
11936
11937 /* Check for overflow. */
11938 if (resultmid < xproductmid1)
11939 /* Carry over 1 into top cross-product. */
11940 carry++;
11941
11942 resultmid1 = resultmid + xproductmid2;
11943
11944 /* Check for overflow. */
11945 if (resultmid1 < xproductmid2)
11946 /* Carry over 1 into top cross-product. */
11947 carry++;
11948
11949 /* Drop lowest 32 bits of middle cross-product. */
11950 result = resultmid1 >> 32;
11951
11952 /* Add top cross-product plus and any carry. */
11953 result += xproducthi + carry;
11954
11955 return result;
11956 }
11957
11958 /* Signed multiply high, source, source2 :
11959 64 bit, dest <-- high 64-bit of result. */
11960 static void
11961 smulh (sim_cpu *cpu)
11962 {
11963 uint64_t uresult;
11964 int64_t result;
11965 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
11966 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
11967 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
11968 GReg ra = greg (aarch64_get_instr (cpu), 10);
11969 int64_t value1 = aarch64_get_reg_u64 (cpu, rn, NO_SP);
11970 int64_t value2 = aarch64_get_reg_u64 (cpu, rm, NO_SP);
11971 uint64_t uvalue1;
11972 uint64_t uvalue2;
11973 int64_t signum = 1;
11974
11975 if (ra != R31)
11976 HALT_UNALLOC;
11977
11978 /* Convert to unsigned and use the unsigned mul64hi routine
11979 the fix the sign up afterwards. */
11980 if (value1 < 0)
11981 {
11982 signum *= -1L;
11983 uvalue1 = -value1;
11984 }
11985 else
11986 {
11987 uvalue1 = value1;
11988 }
11989
11990 if (value2 < 0)
11991 {
11992 signum *= -1L;
11993 uvalue2 = -value2;
11994 }
11995 else
11996 {
11997 uvalue2 = value2;
11998 }
11999
12000 uresult = mul64hi (uvalue1, uvalue2);
12001 result = uresult;
12002 result *= signum;
12003
12004 aarch64_set_reg_s64 (cpu, rd, NO_SP, result);
12005 }
12006
12007 /* Unsigned multiply add long -- source, source2 :
12008 32 bit, source3 : 64 bit. */
12009 static void
12010 umaddl (sim_cpu *cpu)
12011 {
12012 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12013 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
12014 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12015 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12016
12017 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12018 obtain a 64 bit product. */
12019 aarch64_set_reg_u64
12020 (cpu, rd, NO_SP,
12021 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12022 + ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12023 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12024 }
12025
12026 /* Unsigned multiply sub long -- source, source2 : 32 bit, source3 : 64 bit. */
12027 static void
12028 umsubl (sim_cpu *cpu)
12029 {
12030 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12031 unsigned ra = uimm (aarch64_get_instr (cpu), 14, 10);
12032 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12033 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12034
12035 /* N.B. we need to multiply the signed 32 bit values in rn, rm to
12036 obtain a 64 bit product. */
12037 aarch64_set_reg_u64
12038 (cpu, rd, NO_SP,
12039 aarch64_get_reg_u64 (cpu, ra, NO_SP)
12040 - ((uint64_t) aarch64_get_reg_u32 (cpu, rn, NO_SP))
12041 * ((uint64_t) aarch64_get_reg_u32 (cpu, rm, NO_SP)));
12042 }
12043
12044 /* Unsigned multiply high, source, source2 :
12045 64 bit, dest <-- high 64-bit of result. */
12046 static void
12047 umulh (sim_cpu *cpu)
12048 {
12049 unsigned rm = uimm (aarch64_get_instr (cpu), 20, 16);
12050 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12051 unsigned rd = uimm (aarch64_get_instr (cpu), 4, 0);
12052 GReg ra = greg (aarch64_get_instr (cpu), 10);
12053
12054 if (ra != R31)
12055 HALT_UNALLOC;
12056
12057 aarch64_set_reg_u64 (cpu, rd, NO_SP,
12058 mul64hi (aarch64_get_reg_u64 (cpu, rn, NO_SP),
12059 aarch64_get_reg_u64 (cpu, rm, NO_SP)));
12060 }
12061
12062 static void
12063 dexDataProc3Source (sim_cpu *cpu)
12064 {
12065 /* assert instr[28,24] == 11011. */
12066 /* instr[31] = size : 0 ==> 32 bit, 1 ==> 64 bit (for rd at least)
12067 instr[30,29] = op54 : 00 ==> ok, ow ==> UNALLOC
12068 instr[23,21] = op31 : 111 ==> UNALLOC, o2 ==> ok
12069 instr[15] = o0 : 0/1 ==> ok
12070 instr[23,21:15] ==> op : 0000 ==> MADD, 0001 ==> MSUB, (32/64 bit)
12071 0010 ==> SMADDL, 0011 ==> SMSUBL, (64 bit only)
12072 0100 ==> SMULH, (64 bit only)
12073 1010 ==> UMADDL, 1011 ==> UNSUBL, (64 bit only)
12074 1100 ==> UMULH (64 bit only)
12075 ow ==> UNALLOC. */
12076
12077 uint32_t dispatch;
12078 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
12079 uint32_t op54 = uimm (aarch64_get_instr (cpu), 30, 29);
12080 uint32_t op31 = uimm (aarch64_get_instr (cpu), 23, 21);
12081 uint32_t o0 = uimm (aarch64_get_instr (cpu), 15, 15);
12082
12083 if (op54 != 0)
12084 HALT_UNALLOC;
12085
12086 if (size == 0)
12087 {
12088 if (op31 != 0)
12089 HALT_UNALLOC;
12090
12091 if (o0 == 0)
12092 madd32 (cpu);
12093 else
12094 msub32 (cpu);
12095 return;
12096 }
12097
12098 dispatch = (op31 << 1) | o0;
12099
12100 switch (dispatch)
12101 {
12102 case 0: madd64 (cpu); return;
12103 case 1: msub64 (cpu); return;
12104 case 2: smaddl (cpu); return;
12105 case 3: smsubl (cpu); return;
12106 case 4: smulh (cpu); return;
12107 case 10: umaddl (cpu); return;
12108 case 11: umsubl (cpu); return;
12109 case 12: umulh (cpu); return;
12110 default: HALT_UNALLOC;
12111 }
12112 }
12113
12114 static void
12115 dexDPReg (sim_cpu *cpu)
12116 {
12117 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12118 assert group == GROUP_DPREG_0101 || group == GROUP_DPREG_1101
12119 bits [28:24:21] of a DPReg are the secondary dispatch vector. */
12120 uint32_t group2 = dispatchDPReg (aarch64_get_instr (cpu));
12121
12122 switch (group2)
12123 {
12124 case DPREG_LOG_000:
12125 case DPREG_LOG_001:
12126 dexLogicalShiftedRegister (cpu); return;
12127
12128 case DPREG_ADDSHF_010:
12129 dexAddSubtractShiftedRegister (cpu); return;
12130
12131 case DPREG_ADDEXT_011:
12132 dexAddSubtractExtendedRegister (cpu); return;
12133
12134 case DPREG_ADDCOND_100:
12135 {
12136 /* This set bundles a variety of different operations. */
12137 /* Check for. */
12138 /* 1) add/sub w carry. */
12139 uint32_t mask1 = 0x1FE00000U;
12140 uint32_t val1 = 0x1A000000U;
12141 /* 2) cond compare register/immediate. */
12142 uint32_t mask2 = 0x1FE00000U;
12143 uint32_t val2 = 0x1A400000U;
12144 /* 3) cond select. */
12145 uint32_t mask3 = 0x1FE00000U;
12146 uint32_t val3 = 0x1A800000U;
12147 /* 4) data proc 1/2 source. */
12148 uint32_t mask4 = 0x1FE00000U;
12149 uint32_t val4 = 0x1AC00000U;
12150
12151 if ((aarch64_get_instr (cpu) & mask1) == val1)
12152 dexAddSubtractWithCarry (cpu);
12153
12154 else if ((aarch64_get_instr (cpu) & mask2) == val2)
12155 CondCompare (cpu);
12156
12157 else if ((aarch64_get_instr (cpu) & mask3) == val3)
12158 dexCondSelect (cpu);
12159
12160 else if ((aarch64_get_instr (cpu) & mask4) == val4)
12161 {
12162 /* Bit 30 is clear for data proc 2 source
12163 and set for data proc 1 source. */
12164 if (aarch64_get_instr (cpu) & (1U << 30))
12165 dexDataProc1Source (cpu);
12166 else
12167 dexDataProc2Source (cpu);
12168 }
12169
12170 else
12171 /* Should not reach here. */
12172 HALT_NYI;
12173
12174 return;
12175 }
12176
12177 case DPREG_3SRC_110:
12178 dexDataProc3Source (cpu); return;
12179
12180 case DPREG_UNALLOC_101:
12181 HALT_UNALLOC;
12182
12183 case DPREG_3SRC_111:
12184 dexDataProc3Source (cpu); return;
12185
12186 default:
12187 /* Should never reach here. */
12188 HALT_NYI;
12189 }
12190 }
12191
12192 /* Unconditional Branch immediate.
12193 Offset is a PC-relative byte offset in the range +/- 128MiB.
12194 The offset is assumed to be raw from the decode i.e. the
12195 simulator is expected to scale them from word offsets to byte. */
12196
12197 /* Unconditional branch. */
12198 static void
12199 buc (sim_cpu *cpu, int32_t offset)
12200 {
12201 aarch64_set_next_PC_by_offset (cpu, offset);
12202 }
12203
12204 static unsigned stack_depth = 0;
12205
12206 /* Unconditional branch and link -- writes return PC to LR. */
12207 static void
12208 bl (sim_cpu *cpu, int32_t offset)
12209 {
12210 aarch64_save_LR (cpu);
12211 aarch64_set_next_PC_by_offset (cpu, offset);
12212
12213 if (TRACE_BRANCH_P (cpu))
12214 {
12215 ++ stack_depth;
12216 TRACE_BRANCH (cpu,
12217 " %*scall %" PRIx64 " [%s]"
12218 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12219 stack_depth, " ", aarch64_get_next_PC (cpu),
12220 aarch64_get_func (aarch64_get_next_PC (cpu)),
12221 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12222 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12223 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12224 );
12225 }
12226 }
12227
12228 /* Unconditional Branch register.
12229 Branch/return address is in source register. */
12230
12231 /* Unconditional branch. */
12232 static void
12233 br (sim_cpu *cpu)
12234 {
12235 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12236 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12237 }
12238
12239 /* Unconditional branch and link -- writes return PC to LR. */
12240 static void
12241 blr (sim_cpu *cpu)
12242 {
12243 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12244
12245 /* The pseudo code in the spec says we update LR before fetching.
12246 the value from the rn. */
12247 aarch64_save_LR (cpu);
12248 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12249
12250 if (TRACE_BRANCH_P (cpu))
12251 {
12252 ++ stack_depth;
12253 TRACE_BRANCH (cpu,
12254 " %*scall %" PRIx64 " [%s]"
12255 " [args: %" PRIx64 " %" PRIx64 " %" PRIx64 "]",
12256 stack_depth, " ", aarch64_get_next_PC (cpu),
12257 aarch64_get_func (aarch64_get_next_PC (cpu)),
12258 aarch64_get_reg_u64 (cpu, 0, NO_SP),
12259 aarch64_get_reg_u64 (cpu, 1, NO_SP),
12260 aarch64_get_reg_u64 (cpu, 2, NO_SP)
12261 );
12262 }
12263 }
12264
12265 /* Return -- assembler will default source to LR this is functionally
12266 equivalent to br but, presumably, unlike br it side effects the
12267 branch predictor. */
12268 static void
12269 ret (sim_cpu *cpu)
12270 {
12271 unsigned rn = uimm (aarch64_get_instr (cpu), 9, 5);
12272 aarch64_set_next_PC (cpu, aarch64_get_reg_u64 (cpu, rn, NO_SP));
12273
12274 if (TRACE_BRANCH_P (cpu))
12275 {
12276 TRACE_BRANCH (cpu,
12277 " %*sreturn [result: %" PRIx64 "]",
12278 stack_depth, " ", aarch64_get_reg_u64 (cpu, 0, NO_SP));
12279 -- stack_depth;
12280 }
12281 }
12282
12283 /* NOP -- we implement this and call it from the decode in case we
12284 want to intercept it later. */
12285
12286 static void
12287 nop (sim_cpu *cpu)
12288 {
12289 }
12290
12291 /* Data synchronization barrier. */
12292
12293 static void
12294 dsb (sim_cpu *cpu)
12295 {
12296 }
12297
12298 /* Data memory barrier. */
12299
12300 static void
12301 dmb (sim_cpu *cpu)
12302 {
12303 }
12304
12305 /* Instruction synchronization barrier. */
12306
12307 static void
12308 isb (sim_cpu *cpu)
12309 {
12310 }
12311
12312 static void
12313 dexBranchImmediate (sim_cpu *cpu)
12314 {
12315 /* assert instr[30,26] == 00101
12316 instr[31] ==> 0 == B, 1 == BL
12317 instr[25,0] == imm26 branch offset counted in words. */
12318
12319 uint32_t top = uimm (aarch64_get_instr (cpu), 31, 31);
12320 /* We have a 26 byte signed word offset which we need to pass to the
12321 execute routine as a signed byte offset. */
12322 int32_t offset = simm32 (aarch64_get_instr (cpu), 25, 0) << 2;
12323
12324 if (top)
12325 bl (cpu, offset);
12326 else
12327 buc (cpu, offset);
12328 }
12329
12330 /* Control Flow. */
12331
12332 /* Conditional branch
12333
12334 Offset is a PC-relative byte offset in the range +/- 1MiB pos is
12335 a bit position in the range 0 .. 63
12336
12337 cc is a CondCode enum value as pulled out of the decode
12338
12339 N.B. any offset register (source) can only be Xn or Wn. */
12340
12341 static void
12342 bcc (sim_cpu *cpu, int32_t offset, CondCode cc)
12343 {
12344 /* the test returns TRUE if CC is met. */
12345 if (testConditionCode (cpu, cc))
12346 aarch64_set_next_PC_by_offset (cpu, offset);
12347 }
12348
12349 /* 32 bit branch on register non-zero. */
12350 static void
12351 cbnz32 (sim_cpu *cpu, int32_t offset)
12352 {
12353 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12354
12355 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) != 0)
12356 aarch64_set_next_PC_by_offset (cpu, offset);
12357 }
12358
12359 /* 64 bit branch on register zero. */
12360 static void
12361 cbnz (sim_cpu *cpu, int32_t offset)
12362 {
12363 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12364
12365 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) != 0)
12366 aarch64_set_next_PC_by_offset (cpu, offset);
12367 }
12368
12369 /* 32 bit branch on register non-zero. */
12370 static void
12371 cbz32 (sim_cpu *cpu, int32_t offset)
12372 {
12373 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12374
12375 if (aarch64_get_reg_u32 (cpu, rt, NO_SP) == 0)
12376 aarch64_set_next_PC_by_offset (cpu, offset);
12377 }
12378
12379 /* 64 bit branch on register zero. */
12380 static void
12381 cbz (sim_cpu *cpu, int32_t offset)
12382 {
12383 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12384
12385 if (aarch64_get_reg_u64 (cpu, rt, NO_SP) == 0)
12386 aarch64_set_next_PC_by_offset (cpu, offset);
12387 }
12388
12389 /* Branch on register bit test non-zero -- one size fits all. */
12390 static void
12391 tbnz (sim_cpu *cpu, uint32_t pos, 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) & (1 << pos))
12396 aarch64_set_next_PC_by_offset (cpu, offset);
12397 }
12398
12399 /* branch on register bit test zero -- one size fits all. */
12400 static void
12401 tbz (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 static void
12410 dexCompareBranchImmediate (sim_cpu *cpu)
12411 {
12412 /* instr[30,25] = 01 1010
12413 instr[31] = size : 0 ==> 32, 1 ==> 64
12414 instr[24] = op : 0 ==> CBZ, 1 ==> CBNZ
12415 instr[23,5] = simm19 branch offset counted in words
12416 instr[4,0] = rt */
12417
12418 uint32_t size = uimm (aarch64_get_instr (cpu), 31, 31);
12419 uint32_t op = uimm (aarch64_get_instr (cpu), 24, 24);
12420 int32_t offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
12421
12422 if (size == 0)
12423 {
12424 if (op == 0)
12425 cbz32 (cpu, offset);
12426 else
12427 cbnz32 (cpu, offset);
12428 }
12429 else
12430 {
12431 if (op == 0)
12432 cbz (cpu, offset);
12433 else
12434 cbnz (cpu, offset);
12435 }
12436 }
12437
12438 static void
12439 dexTestBranchImmediate (sim_cpu *cpu)
12440 {
12441 /* instr[31] = b5 : bit 5 of test bit idx
12442 instr[30,25] = 01 1011
12443 instr[24] = op : 0 ==> TBZ, 1 == TBNZ
12444 instr[23,19] = b40 : bits 4 to 0 of test bit idx
12445 instr[18,5] = simm14 : signed offset counted in words
12446 instr[4,0] = uimm5 */
12447
12448 uint32_t pos = ((uimm (aarch64_get_instr (cpu), 31, 31) << 4)
12449 | uimm (aarch64_get_instr (cpu), 23,19));
12450 int32_t offset = simm32 (aarch64_get_instr (cpu), 18, 5) << 2;
12451
12452 NYI_assert (30, 25, 0x1b);
12453
12454 if (uimm (aarch64_get_instr (cpu), 24, 24) == 0)
12455 tbz (cpu, pos, offset);
12456 else
12457 tbnz (cpu, pos, offset);
12458 }
12459
12460 static void
12461 dexCondBranchImmediate (sim_cpu *cpu)
12462 {
12463 /* instr[31,25] = 010 1010
12464 instr[24] = op1; op => 00 ==> B.cond
12465 instr[23,5] = simm19 : signed offset counted in words
12466 instr[4] = op0
12467 instr[3,0] = cond */
12468
12469 int32_t offset;
12470 CondCode cc;
12471 uint32_t op = ((uimm (aarch64_get_instr (cpu), 24, 24) << 1)
12472 | uimm (aarch64_get_instr (cpu), 4, 4));
12473
12474 NYI_assert (31, 25, 0x2a);
12475
12476 if (op != 0)
12477 HALT_UNALLOC;
12478
12479 offset = simm32 (aarch64_get_instr (cpu), 23, 5) << 2;
12480 cc = condcode (aarch64_get_instr (cpu), 0);
12481
12482 bcc (cpu, offset, cc);
12483 }
12484
12485 static void
12486 dexBranchRegister (sim_cpu *cpu)
12487 {
12488 /* instr[31,25] = 110 1011
12489 instr[24,21] = op : 0 ==> BR, 1 => BLR, 2 => RET, 3 => ERET, 4 => DRPS
12490 instr[20,16] = op2 : must be 11111
12491 instr[15,10] = op3 : must be 000000
12492 instr[4,0] = op2 : must be 11111. */
12493
12494 uint32_t op = uimm (aarch64_get_instr (cpu), 24, 21);
12495 uint32_t op2 = uimm (aarch64_get_instr (cpu), 20, 16);
12496 uint32_t op3 = uimm (aarch64_get_instr (cpu), 15, 10);
12497 uint32_t op4 = uimm (aarch64_get_instr (cpu), 4, 0);
12498
12499 NYI_assert (31, 25, 0x6b);
12500
12501 if (op2 != 0x1F || op3 != 0 || op4 != 0)
12502 HALT_UNALLOC;
12503
12504 if (op == 0)
12505 br (cpu);
12506
12507 else if (op == 1)
12508 blr (cpu);
12509
12510 else if (op == 2)
12511 ret (cpu);
12512
12513 else
12514 {
12515 /* ERET and DRPS accept 0b11111 for rn = aarch64_get_instr (cpu)[4,0]. */
12516 /* anything else is unallocated. */
12517 uint32_t rn = greg (aarch64_get_instr (cpu), 0);
12518
12519 if (rn != 0x1f)
12520 HALT_UNALLOC;
12521
12522 if (op == 4 || op == 5)
12523 HALT_NYI;
12524
12525 HALT_UNALLOC;
12526 }
12527 }
12528
12529 /* FIXME: We should get the Angel SWI values from ../../libgloss/aarch64/svc.h
12530 but this may not be available. So instead we define the values we need
12531 here. */
12532 #define AngelSVC_Reason_Open 0x01
12533 #define AngelSVC_Reason_Close 0x02
12534 #define AngelSVC_Reason_Write 0x05
12535 #define AngelSVC_Reason_Read 0x06
12536 #define AngelSVC_Reason_IsTTY 0x09
12537 #define AngelSVC_Reason_Seek 0x0A
12538 #define AngelSVC_Reason_FLen 0x0C
12539 #define AngelSVC_Reason_Remove 0x0E
12540 #define AngelSVC_Reason_Rename 0x0F
12541 #define AngelSVC_Reason_Clock 0x10
12542 #define AngelSVC_Reason_Time 0x11
12543 #define AngelSVC_Reason_System 0x12
12544 #define AngelSVC_Reason_Errno 0x13
12545 #define AngelSVC_Reason_GetCmdLine 0x15
12546 #define AngelSVC_Reason_HeapInfo 0x16
12547 #define AngelSVC_Reason_ReportException 0x18
12548 #define AngelSVC_Reason_Elapsed 0x30
12549
12550
12551 static void
12552 handle_halt (sim_cpu *cpu, uint32_t val)
12553 {
12554 uint64_t result = 0;
12555
12556 if (val != 0xf000)
12557 {
12558 TRACE_SYSCALL (cpu, " HLT [0x%x]", val);
12559 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12560 sim_stopped, SIM_SIGTRAP);
12561 }
12562
12563 /* We have encountered an Angel SVC call. See if we can process it. */
12564 switch (aarch64_get_reg_u32 (cpu, 0, NO_SP))
12565 {
12566 case AngelSVC_Reason_HeapInfo:
12567 {
12568 /* Get the values. */
12569 uint64_t stack_top = aarch64_get_stack_start (cpu);
12570 uint64_t heap_base = aarch64_get_heap_start (cpu);
12571
12572 /* Get the pointer */
12573 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12574 ptr = aarch64_get_mem_u64 (cpu, ptr);
12575
12576 /* Fill in the memory block. */
12577 /* Start addr of heap. */
12578 aarch64_set_mem_u64 (cpu, ptr + 0, heap_base);
12579 /* End addr of heap. */
12580 aarch64_set_mem_u64 (cpu, ptr + 8, stack_top);
12581 /* Lowest stack addr. */
12582 aarch64_set_mem_u64 (cpu, ptr + 16, heap_base);
12583 /* Initial stack addr. */
12584 aarch64_set_mem_u64 (cpu, ptr + 24, stack_top);
12585
12586 TRACE_SYSCALL (cpu, " AngelSVC: Get Heap Info");
12587 }
12588 break;
12589
12590 case AngelSVC_Reason_Open:
12591 {
12592 /* Get the pointer */
12593 /* uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);. */
12594 /* FIXME: For now we just assume that we will only be asked
12595 to open the standard file descriptors. */
12596 static int fd = 0;
12597 result = fd ++;
12598
12599 TRACE_SYSCALL (cpu, " AngelSVC: Open file %d", fd - 1);
12600 }
12601 break;
12602
12603 case AngelSVC_Reason_Close:
12604 {
12605 uint64_t fh = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12606 TRACE_SYSCALL (cpu, " AngelSVC: Close file %d", (int) fh);
12607 result = 0;
12608 }
12609 break;
12610
12611 case AngelSVC_Reason_Errno:
12612 result = 0;
12613 TRACE_SYSCALL (cpu, " AngelSVC: Get Errno");
12614 break;
12615
12616 case AngelSVC_Reason_Clock:
12617 result =
12618 #ifdef CLOCKS_PER_SEC
12619 (CLOCKS_PER_SEC >= 100)
12620 ? (clock () / (CLOCKS_PER_SEC / 100))
12621 : ((clock () * 100) / CLOCKS_PER_SEC)
12622 #else
12623 /* Presume unix... clock() returns microseconds. */
12624 (clock () / 10000)
12625 #endif
12626 ;
12627 TRACE_SYSCALL (cpu, " AngelSVC: Get Clock");
12628 break;
12629
12630 case AngelSVC_Reason_GetCmdLine:
12631 {
12632 /* Get the pointer */
12633 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12634 ptr = aarch64_get_mem_u64 (cpu, ptr);
12635
12636 /* FIXME: No command line for now. */
12637 aarch64_set_mem_u64 (cpu, ptr, 0);
12638 TRACE_SYSCALL (cpu, " AngelSVC: Get Command Line");
12639 }
12640 break;
12641
12642 case AngelSVC_Reason_IsTTY:
12643 result = 1;
12644 TRACE_SYSCALL (cpu, " AngelSVC: IsTTY ?");
12645 break;
12646
12647 case AngelSVC_Reason_Write:
12648 {
12649 /* Get the pointer */
12650 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12651 /* Get the write control block. */
12652 uint64_t fd = aarch64_get_mem_u64 (cpu, ptr);
12653 uint64_t buf = aarch64_get_mem_u64 (cpu, ptr + 8);
12654 uint64_t len = aarch64_get_mem_u64 (cpu, ptr + 16);
12655
12656 TRACE_SYSCALL (cpu, "write of %" PRIx64 " bytes from %"
12657 PRIx64 " on descriptor %" PRIx64,
12658 len, buf, fd);
12659
12660 if (len > 1280)
12661 {
12662 TRACE_SYSCALL (cpu,
12663 " AngelSVC: Write: Suspiciously long write: %ld",
12664 (long) len);
12665 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12666 sim_stopped, SIM_SIGBUS);
12667 }
12668 else if (fd == 1)
12669 {
12670 printf ("%.*s", (int) len, aarch64_get_mem_ptr (cpu, buf));
12671 }
12672 else if (fd == 2)
12673 {
12674 TRACE (cpu, 0, "\n");
12675 sim_io_eprintf (CPU_STATE (cpu), "%.*s",
12676 (int) len, aarch64_get_mem_ptr (cpu, buf));
12677 TRACE (cpu, 0, "\n");
12678 }
12679 else
12680 {
12681 TRACE_SYSCALL (cpu,
12682 " AngelSVC: Write: Unexpected file handle: %d",
12683 (int) fd);
12684 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12685 sim_stopped, SIM_SIGABRT);
12686 }
12687 }
12688 break;
12689
12690 case AngelSVC_Reason_ReportException:
12691 {
12692 /* Get the pointer */
12693 uint64_t ptr = aarch64_get_reg_u64 (cpu, 1, SP_OK);
12694 /*ptr = aarch64_get_mem_u64 (cpu, ptr);. */
12695 uint64_t type = aarch64_get_mem_u64 (cpu, ptr);
12696 uint64_t state = aarch64_get_mem_u64 (cpu, ptr + 8);
12697
12698 TRACE_SYSCALL (cpu,
12699 "Angel Exception: type 0x%" PRIx64 " state %" PRIx64,
12700 type, state);
12701
12702 if (type == 0x20026)
12703 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12704 sim_exited, state);
12705 else
12706 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12707 sim_stopped, SIM_SIGINT);
12708 }
12709 break;
12710
12711 case AngelSVC_Reason_Read:
12712 case AngelSVC_Reason_FLen:
12713 case AngelSVC_Reason_Seek:
12714 case AngelSVC_Reason_Remove:
12715 case AngelSVC_Reason_Time:
12716 case AngelSVC_Reason_System:
12717 case AngelSVC_Reason_Rename:
12718 case AngelSVC_Reason_Elapsed:
12719 default:
12720 TRACE_SYSCALL (cpu, " HLT [Unknown angel %x]",
12721 aarch64_get_reg_u32 (cpu, 0, NO_SP));
12722 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12723 sim_stopped, SIM_SIGTRAP);
12724 }
12725
12726 aarch64_set_reg_u64 (cpu, 0, NO_SP, result);
12727 }
12728
12729 static void
12730 dexExcpnGen (sim_cpu *cpu)
12731 {
12732 /* instr[31:24] = 11010100
12733 instr[23,21] = opc : 000 ==> GEN EXCPN, 001 ==> BRK
12734 010 ==> HLT, 101 ==> DBG GEN EXCPN
12735 instr[20,5] = imm16
12736 instr[4,2] = opc2 000 ==> OK, ow ==> UNALLOC
12737 instr[1,0] = LL : discriminates opc */
12738
12739 uint32_t opc = uimm (aarch64_get_instr (cpu), 23, 21);
12740 uint32_t imm16 = uimm (aarch64_get_instr (cpu), 20, 5);
12741 uint32_t opc2 = uimm (aarch64_get_instr (cpu), 4, 2);
12742 uint32_t LL;
12743
12744 NYI_assert (31, 24, 0xd4);
12745
12746 if (opc2 != 0)
12747 HALT_UNALLOC;
12748
12749 LL = uimm (aarch64_get_instr (cpu), 1, 0);
12750
12751 /* We only implement HLT and BRK for now. */
12752 if (opc == 1 && LL == 0)
12753 {
12754 TRACE_EVENTS (cpu, " BRK [0x%x]", imm16);
12755 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
12756 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
12757 }
12758
12759 if (opc == 2 && LL == 0)
12760 handle_halt (cpu, imm16);
12761
12762 else if (opc == 0 || opc == 5)
12763 HALT_NYI;
12764
12765 else
12766 HALT_UNALLOC;
12767 }
12768
12769 /* Stub for accessing system registers.
12770 We implement support for the DCZID register since this is used
12771 by the C library's memset function. */
12772
12773 static uint64_t
12774 system_get (sim_cpu *cpu, unsigned op0, unsigned op1, unsigned crn,
12775 unsigned crm, unsigned op2)
12776 {
12777 if (crn == 0 && op1 == 3 && crm == 0 && op2 == 7)
12778 /* DCZID_EL0 - the Data Cache Zero ID register.
12779 We do not support DC ZVA at the moment, so
12780 we return a value with the disable bit set. */
12781 return ((uint64_t) 1) << 4;
12782
12783 HALT_NYI;
12784 }
12785
12786 static void
12787 do_mrs (sim_cpu *cpu)
12788 {
12789 /* instr[31:20] = 1101 01010 0011
12790 instr[19] = op0
12791 instr[18,16] = op1
12792 instr[15,12] = CRn
12793 instr[11,8] = CRm
12794 instr[7,5] = op2
12795 instr[4,0] = Rt */
12796 unsigned sys_op0 = uimm (aarch64_get_instr (cpu), 19, 19) + 2;
12797 unsigned sys_op1 = uimm (aarch64_get_instr (cpu), 18, 16);
12798 unsigned sys_crn = uimm (aarch64_get_instr (cpu), 15, 12);
12799 unsigned sys_crm = uimm (aarch64_get_instr (cpu), 11, 8);
12800 unsigned sys_op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12801 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12802
12803 aarch64_set_reg_u64 (cpu, rt, NO_SP,
12804 system_get (cpu, sys_op0, sys_op1, sys_crn, sys_crm, sys_op2));
12805 }
12806
12807 static void
12808 dexSystem (sim_cpu *cpu)
12809 {
12810 /* instr[31:22] = 1101 01010 0
12811 instr[21] = L
12812 instr[20,19] = op0
12813 instr[18,16] = op1
12814 instr[15,12] = CRn
12815 instr[11,8] = CRm
12816 instr[7,5] = op2
12817 instr[4,0] = uimm5 */
12818
12819 /* We are interested in HINT, DSB, DMB and ISB
12820
12821 Hint #0 encodes NOOP (this is the only hint we care about)
12822 L == 0, op0 == 0, op1 = 011, CRn = 0010, Rt = 11111,
12823 CRm op2 != 0000 000 OR CRm op2 == 0000 000 || CRm op > 0000 101
12824
12825 DSB, DMB, ISB are data store barrier, data memory barrier and
12826 instruction store barrier, respectively, where
12827
12828 L == 0, op0 == 0, op1 = 011, CRn = 0011, Rt = 11111,
12829 op2 : DSB ==> 100, DMB ==> 101, ISB ==> 110
12830 CRm<3:2> ==> domain, CRm<1:0> ==> types,
12831 domain : 00 ==> OuterShareable, 01 ==> Nonshareable,
12832 10 ==> InerShareable, 11 ==> FullSystem
12833 types : 01 ==> Reads, 10 ==> Writes,
12834 11 ==> All, 00 ==> All (domain == FullSystem). */
12835
12836 unsigned rt = uimm (aarch64_get_instr (cpu), 4, 0);
12837 uint32_t l_op0_op1_crn = uimm (aarch64_get_instr (cpu), 21, 12);
12838
12839 NYI_assert (31, 22, 0x354);
12840
12841 switch (l_op0_op1_crn)
12842 {
12843 case 0x032:
12844 if (rt == 0x1F)
12845 {
12846 /* NOP has CRm != 0000 OR. */
12847 /* (CRm == 0000 AND (op2 == 000 OR op2 > 101)). */
12848 uint32_t crm = uimm (aarch64_get_instr (cpu), 11, 8);
12849 uint32_t op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12850
12851 if (crm != 0 || (op2 == 0 || op2 > 5))
12852 {
12853 /* Actually call nop method so we can reimplement it later. */
12854 nop (cpu);
12855 return;
12856 }
12857 }
12858 HALT_NYI;
12859
12860 case 0x033:
12861 {
12862 uint32_t op2 = uimm (aarch64_get_instr (cpu), 7, 5);
12863
12864 switch (op2)
12865 {
12866 case 2: HALT_NYI;
12867 case 4: dsb (cpu); return;
12868 case 5: dmb (cpu); return;
12869 case 6: isb (cpu); return;
12870 case 7:
12871 default: HALT_UNALLOC;
12872 }
12873 }
12874
12875 case 0x3B0:
12876 /* MRS Wt, sys-reg. */
12877 do_mrs (cpu);
12878 return;
12879
12880 case 0x3B4:
12881 case 0x3BD:
12882 /* MRS Xt, sys-reg. */
12883 do_mrs (cpu);
12884 return;
12885
12886 case 0x0B7:
12887 /* DC <type>, x<n>. */
12888 HALT_NYI;
12889 return;
12890
12891 default:
12892 /* if (uimm (aarch64_get_instr (cpu), 21, 20) == 0x1)
12893 MRS Xt, sys-reg. */
12894 HALT_NYI;
12895 return;
12896 }
12897 }
12898
12899 static void
12900 dexBr (sim_cpu *cpu)
12901 {
12902 /* uint32_t group = dispatchGroup (aarch64_get_instr (cpu));
12903 assert group == GROUP_BREXSYS_1010 || group == GROUP_BREXSYS_1011
12904 bits [31,29] of a BrExSys are the secondary dispatch vector. */
12905 uint32_t group2 = dispatchBrExSys (aarch64_get_instr (cpu));
12906
12907 switch (group2)
12908 {
12909 case BR_IMM_000:
12910 return dexBranchImmediate (cpu);
12911
12912 case BR_IMMCMP_001:
12913 /* Compare has bit 25 clear while test has it set. */
12914 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12915 dexCompareBranchImmediate (cpu);
12916 else
12917 dexTestBranchImmediate (cpu);
12918 return;
12919
12920 case BR_IMMCOND_010:
12921 /* This is a conditional branch if bit 25 is clear otherwise
12922 unallocated. */
12923 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12924 dexCondBranchImmediate (cpu);
12925 else
12926 HALT_UNALLOC;
12927 return;
12928
12929 case BR_UNALLOC_011:
12930 HALT_UNALLOC;
12931
12932 case BR_IMM_100:
12933 dexBranchImmediate (cpu);
12934 return;
12935
12936 case BR_IMMCMP_101:
12937 /* Compare has bit 25 clear while test has it set. */
12938 if (!uimm (aarch64_get_instr (cpu), 25, 25))
12939 dexCompareBranchImmediate (cpu);
12940 else
12941 dexTestBranchImmediate (cpu);
12942 return;
12943
12944 case BR_REG_110:
12945 /* Unconditional branch reg has bit 25 set. */
12946 if (uimm (aarch64_get_instr (cpu), 25, 25))
12947 dexBranchRegister (cpu);
12948
12949 /* This includes both Excpn Gen, System and unalloc operations.
12950 We need to decode the Excpn Gen operation BRK so we can plant
12951 debugger entry points.
12952 Excpn Gen operations have aarch64_get_instr (cpu)[24] = 0.
12953 we need to decode at least one of the System operations NOP
12954 which is an alias for HINT #0.
12955 System operations have aarch64_get_instr (cpu)[24,22] = 100. */
12956 else if (uimm (aarch64_get_instr (cpu), 24, 24) == 0)
12957 dexExcpnGen (cpu);
12958
12959 else if (uimm (aarch64_get_instr (cpu), 24, 22) == 4)
12960 dexSystem (cpu);
12961
12962 else
12963 HALT_UNALLOC;
12964
12965 return;
12966
12967 case BR_UNALLOC_111:
12968 HALT_UNALLOC;
12969
12970 default:
12971 /* Should never reach here. */
12972 HALT_NYI;
12973 }
12974 }
12975
12976 static void
12977 aarch64_decode_and_execute (sim_cpu *cpu, uint64_t pc)
12978 {
12979 /* We need to check if gdb wants an in here. */
12980 /* checkBreak (cpu);. */
12981
12982 uint64_t group = dispatchGroup (aarch64_get_instr (cpu));
12983
12984 switch (group)
12985 {
12986 case GROUP_PSEUDO_0000: dexPseudo (cpu); break;
12987 case GROUP_LDST_0100: dexLdSt (cpu); break;
12988 case GROUP_DPREG_0101: dexDPReg (cpu); break;
12989 case GROUP_LDST_0110: dexLdSt (cpu); break;
12990 case GROUP_ADVSIMD_0111: dexAdvSIMD0 (cpu); break;
12991 case GROUP_DPIMM_1000: dexDPImm (cpu); break;
12992 case GROUP_DPIMM_1001: dexDPImm (cpu); break;
12993 case GROUP_BREXSYS_1010: dexBr (cpu); break;
12994 case GROUP_BREXSYS_1011: dexBr (cpu); break;
12995 case GROUP_LDST_1100: dexLdSt (cpu); break;
12996 case GROUP_DPREG_1101: dexDPReg (cpu); break;
12997 case GROUP_LDST_1110: dexLdSt (cpu); break;
12998 case GROUP_ADVSIMD_1111: dexAdvSIMD1 (cpu); break;
12999
13000 case GROUP_UNALLOC_0001:
13001 case GROUP_UNALLOC_0010:
13002 case GROUP_UNALLOC_0011:
13003 HALT_UNALLOC;
13004
13005 default:
13006 /* Should never reach here. */
13007 HALT_NYI;
13008 }
13009 }
13010
13011 static bfd_boolean
13012 aarch64_step (sim_cpu *cpu)
13013 {
13014 uint64_t pc = aarch64_get_PC (cpu);
13015
13016 if (pc == TOP_LEVEL_RETURN_PC)
13017 return FALSE;
13018
13019 aarch64_set_next_PC (cpu, pc + 4);
13020 aarch64_get_instr (cpu) = aarch64_get_mem_u32 (cpu, pc);
13021
13022 TRACE_INSN (cpu, " pc = %" PRIx64 " instr = %x", pc,
13023 aarch64_get_instr (cpu));
13024 TRACE_DISASM (cpu, pc);
13025
13026 aarch64_decode_and_execute (cpu, pc);
13027
13028 return TRUE;
13029 }
13030
13031 void
13032 aarch64_run (SIM_DESC sd)
13033 {
13034 sim_cpu *cpu = STATE_CPU (sd, 0);
13035
13036 while (aarch64_step (cpu))
13037 aarch64_update_PC (cpu);
13038
13039 sim_engine_halt (sd, NULL, NULL, aarch64_get_PC (cpu),
13040 sim_exited, aarch64_get_reg_s32 (cpu, R0, SP_OK));
13041 }
13042
13043 void
13044 aarch64_init (sim_cpu *cpu, uint64_t pc)
13045 {
13046 uint64_t sp = aarch64_get_stack_start (cpu);
13047
13048 /* Install SP, FP and PC and set LR to -20
13049 so we can detect a top-level return. */
13050 aarch64_set_reg_u64 (cpu, SP, SP_OK, sp);
13051 aarch64_set_reg_u64 (cpu, FP, SP_OK, sp);
13052 aarch64_set_reg_u64 (cpu, LR, SP_OK, TOP_LEVEL_RETURN_PC);
13053 aarch64_set_next_PC (cpu, pc);
13054 aarch64_update_PC (cpu);
13055 aarch64_init_LIT_table ();
13056 }