sim: drop --enable-sim-cflags option
[external/binutils.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 }