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