1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include "qemu/osdep.h"
20
21#include "translate.h"
22#include "translate-a64.h"
23#include "qemu/log.h"
24#include "disas/disas.h"
25#include "arm_ldst.h"
26#include "semihosting/semihost.h"
27#include "cpregs.h"
28
29static TCGv_i64 cpu_X[32];
30static TCGv_i64 cpu_pc;
31
32
33static TCGv_i64 cpu_exclusive_high;
34
35static const char *regnames[] = {
36 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
37 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
38 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
39 "x24", "x25", "x26", "x27", "x28", "x29", "lr", "sp"
40};
41
42enum a64_shift_type {
43 A64_SHIFT_TYPE_LSL = 0,
44 A64_SHIFT_TYPE_LSR = 1,
45 A64_SHIFT_TYPE_ASR = 2,
46 A64_SHIFT_TYPE_ROR = 3
47};
48
49
50
51
52
53
54
55
56
57
58static int uimm_scaled(DisasContext *s, int x)
59{
60 unsigned imm = x >> 3;
61 unsigned scale = extract32(x, 0, 3);
62 return imm << scale;
63}
64
65
66static int scale_by_log2_tag_granule(DisasContext *s, int x)
67{
68 return x << LOG2_TAG_GRANULE;
69}
70
71
72
73
74
75#include "decode-sme-fa64.c.inc"
76#include "decode-a64.c.inc"
77
78
79
80
81typedef void AArch64DecodeFn(DisasContext *s, uint32_t insn);
82
83typedef struct AArch64DecodeTable {
84 uint32_t pattern;
85 uint32_t mask;
86 AArch64DecodeFn *disas_fn;
87} AArch64DecodeTable;
88
89
90void a64_translate_init(void)
91{
92 int i;
93
94 cpu_pc = tcg_global_mem_new_i64(cpu_env,
95 offsetof(CPUARMState, pc),
96 "pc");
97 for (i = 0; i < 32; i++) {
98 cpu_X[i] = tcg_global_mem_new_i64(cpu_env,
99 offsetof(CPUARMState, xregs[i]),
100 regnames[i]);
101 }
102
103 cpu_exclusive_high = tcg_global_mem_new_i64(cpu_env,
104 offsetof(CPUARMState, exclusive_high), "exclusive_high");
105}
106
107
108
109
110static int get_a64_user_mem_index(DisasContext *s)
111{
112
113
114
115
116 ARMMMUIdx useridx = s->mmu_idx;
117
118 if (s->unpriv) {
119
120
121
122
123
124 switch (useridx) {
125 case ARMMMUIdx_E10_1:
126 case ARMMMUIdx_E10_1_PAN:
127 useridx = ARMMMUIdx_E10_0;
128 break;
129 case ARMMMUIdx_E20_2:
130 case ARMMMUIdx_E20_2_PAN:
131 useridx = ARMMMUIdx_E20_0;
132 break;
133 default:
134 g_assert_not_reached();
135 }
136 }
137 return arm_to_core_mmu_idx(useridx);
138}
139
140static void set_btype_raw(int val)
141{
142 tcg_gen_st_i32(tcg_constant_i32(val), cpu_env,
143 offsetof(CPUARMState, btype));
144}
145
146static void set_btype(DisasContext *s, int val)
147{
148
149 tcg_debug_assert(val >= 1 && val <= 3);
150 set_btype_raw(val);
151 s->btype = -1;
152}
153
154static void reset_btype(DisasContext *s)
155{
156 if (s->btype != 0) {
157 set_btype_raw(0);
158 s->btype = 0;
159 }
160}
161
162static void gen_pc_plus_diff(DisasContext *s, TCGv_i64 dest, target_long diff)
163{
164 assert(s->pc_save != -1);
165 if (tb_cflags(s->base.tb) & CF_PCREL) {
166 tcg_gen_addi_i64(dest, cpu_pc, (s->pc_curr - s->pc_save) + diff);
167 } else {
168 tcg_gen_movi_i64(dest, s->pc_curr + diff);
169 }
170}
171
172void gen_a64_update_pc(DisasContext *s, target_long diff)
173{
174 gen_pc_plus_diff(s, cpu_pc, diff);
175 s->pc_save = s->pc_curr + diff;
176}
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191static void gen_top_byte_ignore(DisasContext *s, TCGv_i64 dst,
192 TCGv_i64 src, int tbi)
193{
194 if (tbi == 0) {
195
196 tcg_gen_mov_i64(dst, src);
197 } else if (!regime_has_2_ranges(s->mmu_idx)) {
198
199 tcg_gen_extract_i64(dst, src, 0, 56);
200 } else {
201
202 tcg_gen_sextract_i64(dst, src, 0, 56);
203
204 switch (tbi) {
205 case 1:
206
207 tcg_gen_and_i64(dst, dst, src);
208 break;
209 case 2:
210
211 tcg_gen_or_i64(dst, dst, src);
212 break;
213 case 3:
214
215 break;
216 default:
217 g_assert_not_reached();
218 }
219 }
220}
221
222static void gen_a64_set_pc(DisasContext *s, TCGv_i64 src)
223{
224
225
226
227
228 gen_top_byte_ignore(s, cpu_pc, src, s->tbii);
229 s->pc_save = -1;
230}
231
232
233
234
235
236
237
238
239
240
241
242
243
244TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr)
245{
246 TCGv_i64 clean = tcg_temp_new_i64();
247#ifdef CONFIG_USER_ONLY
248 gen_top_byte_ignore(s, clean, addr, s->tbid);
249#else
250 tcg_gen_mov_i64(clean, addr);
251#endif
252 return clean;
253}
254
255
256static void gen_address_with_allocation_tag0(TCGv_i64 dst, TCGv_i64 src)
257{
258 tcg_gen_andi_i64(dst, src, ~MAKE_64BIT_MASK(56, 4));
259}
260
261static void gen_probe_access(DisasContext *s, TCGv_i64 ptr,
262 MMUAccessType acc, int log2_size)
263{
264 gen_helper_probe_access(cpu_env, ptr,
265 tcg_constant_i32(acc),
266 tcg_constant_i32(get_mem_index(s)),
267 tcg_constant_i32(1 << log2_size));
268}
269
270
271
272
273
274
275
276static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr,
277 bool is_write, bool tag_checked,
278 MemOp memop, bool is_unpriv,
279 int core_idx)
280{
281 if (tag_checked && s->mte_active[is_unpriv]) {
282 TCGv_i64 ret;
283 int desc = 0;
284
285 desc = FIELD_DP32(desc, MTEDESC, MIDX, core_idx);
286 desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid);
287 desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma);
288 desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write);
289 desc = FIELD_DP32(desc, MTEDESC, ALIGN, get_alignment_bits(memop));
290 desc = FIELD_DP32(desc, MTEDESC, SIZEM1, memop_size(memop) - 1);
291
292 ret = tcg_temp_new_i64();
293 gen_helper_mte_check(ret, cpu_env, tcg_constant_i32(desc), addr);
294
295 return ret;
296 }
297 return clean_data_tbi(s, addr);
298}
299
300TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write,
301 bool tag_checked, MemOp memop)
302{
303 return gen_mte_check1_mmuidx(s, addr, is_write, tag_checked, memop,
304 false, get_mem_index(s));
305}
306
307
308
309
310TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write,
311 bool tag_checked, int total_size, MemOp single_mop)
312{
313 if (tag_checked && s->mte_active[0]) {
314 TCGv_i64 ret;
315 int desc = 0;
316
317 desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s));
318 desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid);
319 desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma);
320 desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write);
321 desc = FIELD_DP32(desc, MTEDESC, ALIGN, get_alignment_bits(single_mop));
322 desc = FIELD_DP32(desc, MTEDESC, SIZEM1, total_size - 1);
323
324 ret = tcg_temp_new_i64();
325 gen_helper_mte_check(ret, cpu_env, tcg_constant_i32(desc), addr);
326
327 return ret;
328 }
329 return clean_data_tbi(s, addr);
330}
331
332
333
334
335
336
337
338static void check_lse2_align(DisasContext *s, int rn, int imm,
339 bool is_write, MemOp mop)
340{
341 TCGv_i32 tmp;
342 TCGv_i64 addr;
343 TCGLabel *over_label;
344 MMUAccessType type;
345 int mmu_idx;
346
347 tmp = tcg_temp_new_i32();
348 tcg_gen_extrl_i64_i32(tmp, cpu_reg_sp(s, rn));
349 tcg_gen_addi_i32(tmp, tmp, imm & 15);
350 tcg_gen_andi_i32(tmp, tmp, 15);
351 tcg_gen_addi_i32(tmp, tmp, memop_size(mop));
352
353 over_label = gen_new_label();
354 tcg_gen_brcondi_i32(TCG_COND_LEU, tmp, 16, over_label);
355
356 addr = tcg_temp_new_i64();
357 tcg_gen_addi_i64(addr, cpu_reg_sp(s, rn), imm);
358
359 type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD,
360 mmu_idx = get_mem_index(s);
361 gen_helper_unaligned_access(cpu_env, addr, tcg_constant_i32(type),
362 tcg_constant_i32(mmu_idx));
363
364 gen_set_label(over_label);
365
366}
367
368
369static MemOp check_atomic_align(DisasContext *s, int rn, MemOp mop)
370{
371 MemOp size = mop & MO_SIZE;
372
373 if (size == MO_8) {
374 return mop;
375 }
376
377
378
379
380
381
382 if (size == MO_128) {
383 return finalize_memop_atom(s, MO_128 | MO_ALIGN,
384 MO_ATOM_IFALIGN_PAIR);
385 }
386 if (dc_isar_feature(aa64_lse2, s)) {
387 check_lse2_align(s, rn, 0, true, mop);
388 } else {
389 mop |= MO_ALIGN;
390 }
391 return finalize_memop(s, mop);
392}
393
394
395static MemOp check_ordered_align(DisasContext *s, int rn, int imm,
396 bool is_write, MemOp mop)
397{
398 MemOp size = mop & MO_SIZE;
399
400 if (size == MO_8) {
401 return mop;
402 }
403 if (size == MO_128) {
404 return finalize_memop_atom(s, MO_128 | MO_ALIGN,
405 MO_ATOM_IFALIGN_PAIR);
406 }
407 if (!dc_isar_feature(aa64_lse2, s)) {
408 mop |= MO_ALIGN;
409 } else if (!s->naa) {
410 check_lse2_align(s, rn, imm, is_write, mop);
411 }
412 return finalize_memop(s, mop);
413}
414
415typedef struct DisasCompare64 {
416 TCGCond cond;
417 TCGv_i64 value;
418} DisasCompare64;
419
420static void a64_test_cc(DisasCompare64 *c64, int cc)
421{
422 DisasCompare c32;
423
424 arm_test_cc(&c32, cc);
425
426
427
428
429
430 c64->cond = c32.cond;
431 c64->value = tcg_temp_new_i64();
432 tcg_gen_ext_i32_i64(c64->value, c32.value);
433}
434
435static void gen_rebuild_hflags(DisasContext *s)
436{
437 gen_helper_rebuild_hflags_a64(cpu_env, tcg_constant_i32(s->current_el));
438}
439
440static void gen_exception_internal(int excp)
441{
442 assert(excp_is_internal(excp));
443 gen_helper_exception_internal(cpu_env, tcg_constant_i32(excp));
444}
445
446static void gen_exception_internal_insn(DisasContext *s, int excp)
447{
448 gen_a64_update_pc(s, 0);
449 gen_exception_internal(excp);
450 s->base.is_jmp = DISAS_NORETURN;
451}
452
453static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syndrome)
454{
455 gen_a64_update_pc(s, 0);
456 gen_helper_exception_bkpt_insn(cpu_env, tcg_constant_i32(syndrome));
457 s->base.is_jmp = DISAS_NORETURN;
458}
459
460static void gen_step_complete_exception(DisasContext *s)
461{
462
463
464
465
466
467
468
469
470
471 gen_ss_advance(s);
472 gen_swstep_exception(s, 1, s->is_ldex);
473 s->base.is_jmp = DISAS_NORETURN;
474}
475
476static inline bool use_goto_tb(DisasContext *s, uint64_t dest)
477{
478 if (s->ss_active) {
479 return false;
480 }
481 return translator_use_goto_tb(&s->base, dest);
482}
483
484static void gen_goto_tb(DisasContext *s, int n, int64_t diff)
485{
486 if (use_goto_tb(s, s->pc_curr + diff)) {
487
488
489
490
491
492
493
494
495 if (tb_cflags(s->base.tb) & CF_PCREL) {
496 gen_a64_update_pc(s, diff);
497 tcg_gen_goto_tb(n);
498 } else {
499 tcg_gen_goto_tb(n);
500 gen_a64_update_pc(s, diff);
501 }
502 tcg_gen_exit_tb(s->base.tb, n);
503 s->base.is_jmp = DISAS_NORETURN;
504 } else {
505 gen_a64_update_pc(s, diff);
506 if (s->ss_active) {
507 gen_step_complete_exception(s);
508 } else {
509 tcg_gen_lookup_and_goto_ptr();
510 s->base.is_jmp = DISAS_NORETURN;
511 }
512 }
513}
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530TCGv_i64 cpu_reg(DisasContext *s, int reg)
531{
532 if (reg == 31) {
533 TCGv_i64 t = tcg_temp_new_i64();
534 tcg_gen_movi_i64(t, 0);
535 return t;
536 } else {
537 return cpu_X[reg];
538 }
539}
540
541
542TCGv_i64 cpu_reg_sp(DisasContext *s, int reg)
543{
544 return cpu_X[reg];
545}
546
547
548
549
550
551TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
552{
553 TCGv_i64 v = tcg_temp_new_i64();
554 if (reg != 31) {
555 if (sf) {
556 tcg_gen_mov_i64(v, cpu_X[reg]);
557 } else {
558 tcg_gen_ext32u_i64(v, cpu_X[reg]);
559 }
560 } else {
561 tcg_gen_movi_i64(v, 0);
562 }
563 return v;
564}
565
566TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
567{
568 TCGv_i64 v = tcg_temp_new_i64();
569 if (sf) {
570 tcg_gen_mov_i64(v, cpu_X[reg]);
571 } else {
572 tcg_gen_ext32u_i64(v, cpu_X[reg]);
573 }
574 return v;
575}
576
577
578
579
580
581
582static inline int fp_reg_offset(DisasContext *s, int regno, MemOp size)
583{
584 return vec_reg_offset(s, regno, 0, size);
585}
586
587
588static inline int fp_reg_hi_offset(DisasContext *s, int regno)
589{
590 return vec_reg_offset(s, regno, 1, MO_64);
591}
592
593
594
595
596
597
598
599static TCGv_i64 read_fp_dreg(DisasContext *s, int reg)
600{
601 TCGv_i64 v = tcg_temp_new_i64();
602
603 tcg_gen_ld_i64(v, cpu_env, fp_reg_offset(s, reg, MO_64));
604 return v;
605}
606
607static TCGv_i32 read_fp_sreg(DisasContext *s, int reg)
608{
609 TCGv_i32 v = tcg_temp_new_i32();
610
611 tcg_gen_ld_i32(v, cpu_env, fp_reg_offset(s, reg, MO_32));
612 return v;
613}
614
615static TCGv_i32 read_fp_hreg(DisasContext *s, int reg)
616{
617 TCGv_i32 v = tcg_temp_new_i32();
618
619 tcg_gen_ld16u_i32(v, cpu_env, fp_reg_offset(s, reg, MO_16));
620 return v;
621}
622
623
624
625
626static void clear_vec_high(DisasContext *s, bool is_q, int rd)
627{
628 unsigned ofs = fp_reg_offset(s, rd, MO_64);
629 unsigned vsz = vec_full_reg_size(s);
630
631
632 tcg_gen_gvec_mov(MO_64, ofs, ofs, is_q ? 16 : 8, vsz);
633}
634
635void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v)
636{
637 unsigned ofs = fp_reg_offset(s, reg, MO_64);
638
639 tcg_gen_st_i64(v, cpu_env, ofs);
640 clear_vec_high(s, false, reg);
641}
642
643static void write_fp_sreg(DisasContext *s, int reg, TCGv_i32 v)
644{
645 TCGv_i64 tmp = tcg_temp_new_i64();
646
647 tcg_gen_extu_i32_i64(tmp, v);
648 write_fp_dreg(s, reg, tmp);
649}
650
651
652static void gen_gvec_fn2(DisasContext *s, bool is_q, int rd, int rn,
653 GVecGen2Fn *gvec_fn, int vece)
654{
655 gvec_fn(vece, vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn),
656 is_q ? 16 : 8, vec_full_reg_size(s));
657}
658
659
660
661
662static void gen_gvec_fn2i(DisasContext *s, bool is_q, int rd, int rn,
663 int64_t imm, GVecGen2iFn *gvec_fn, int vece)
664{
665 gvec_fn(vece, vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn),
666 imm, is_q ? 16 : 8, vec_full_reg_size(s));
667}
668
669
670static void gen_gvec_fn3(DisasContext *s, bool is_q, int rd, int rn, int rm,
671 GVecGen3Fn *gvec_fn, int vece)
672{
673 gvec_fn(vece, vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn),
674 vec_full_reg_offset(s, rm), is_q ? 16 : 8, vec_full_reg_size(s));
675}
676
677
678static void gen_gvec_fn4(DisasContext *s, bool is_q, int rd, int rn, int rm,
679 int rx, GVecGen4Fn *gvec_fn, int vece)
680{
681 gvec_fn(vece, vec_full_reg_offset(s, rd), vec_full_reg_offset(s, rn),
682 vec_full_reg_offset(s, rm), vec_full_reg_offset(s, rx),
683 is_q ? 16 : 8, vec_full_reg_size(s));
684}
685
686
687static void gen_gvec_op2_ool(DisasContext *s, bool is_q, int rd,
688 int rn, int data, gen_helper_gvec_2 *fn)
689{
690 tcg_gen_gvec_2_ool(vec_full_reg_offset(s, rd),
691 vec_full_reg_offset(s, rn),
692 is_q ? 16 : 8, vec_full_reg_size(s), data, fn);
693}
694
695
696static void gen_gvec_op3_ool(DisasContext *s, bool is_q, int rd,
697 int rn, int rm, int data, gen_helper_gvec_3 *fn)
698{
699 tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd),
700 vec_full_reg_offset(s, rn),
701 vec_full_reg_offset(s, rm),
702 is_q ? 16 : 8, vec_full_reg_size(s), data, fn);
703}
704
705
706
707
708static void gen_gvec_op3_fpst(DisasContext *s, bool is_q, int rd, int rn,
709 int rm, bool is_fp16, int data,
710 gen_helper_gvec_3_ptr *fn)
711{
712 TCGv_ptr fpst = fpstatus_ptr(is_fp16 ? FPST_FPCR_F16 : FPST_FPCR);
713 tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd),
714 vec_full_reg_offset(s, rn),
715 vec_full_reg_offset(s, rm), fpst,
716 is_q ? 16 : 8, vec_full_reg_size(s), data, fn);
717}
718
719
720static void gen_gvec_op3_qc(DisasContext *s, bool is_q, int rd, int rn,
721 int rm, gen_helper_gvec_3_ptr *fn)
722{
723 TCGv_ptr qc_ptr = tcg_temp_new_ptr();
724
725 tcg_gen_addi_ptr(qc_ptr, cpu_env, offsetof(CPUARMState, vfp.qc));
726 tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd),
727 vec_full_reg_offset(s, rn),
728 vec_full_reg_offset(s, rm), qc_ptr,
729 is_q ? 16 : 8, vec_full_reg_size(s), 0, fn);
730}
731
732
733static void gen_gvec_op4_ool(DisasContext *s, bool is_q, int rd, int rn,
734 int rm, int ra, int data, gen_helper_gvec_4 *fn)
735{
736 tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd),
737 vec_full_reg_offset(s, rn),
738 vec_full_reg_offset(s, rm),
739 vec_full_reg_offset(s, ra),
740 is_q ? 16 : 8, vec_full_reg_size(s), data, fn);
741}
742
743
744
745
746
747static void gen_gvec_op4_fpst(DisasContext *s, bool is_q, int rd, int rn,
748 int rm, int ra, bool is_fp16, int data,
749 gen_helper_gvec_4_ptr *fn)
750{
751 TCGv_ptr fpst = fpstatus_ptr(is_fp16 ? FPST_FPCR_F16 : FPST_FPCR);
752 tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, rd),
753 vec_full_reg_offset(s, rn),
754 vec_full_reg_offset(s, rm),
755 vec_full_reg_offset(s, ra), fpst,
756 is_q ? 16 : 8, vec_full_reg_size(s), data, fn);
757}
758
759
760
761
762static inline void gen_set_NZ64(TCGv_i64 result)
763{
764 tcg_gen_extr_i64_i32(cpu_ZF, cpu_NF, result);
765 tcg_gen_or_i32(cpu_ZF, cpu_ZF, cpu_NF);
766}
767
768
769static inline void gen_logic_CC(int sf, TCGv_i64 result)
770{
771 if (sf) {
772 gen_set_NZ64(result);
773 } else {
774 tcg_gen_extrl_i64_i32(cpu_ZF, result);
775 tcg_gen_mov_i32(cpu_NF, cpu_ZF);
776 }
777 tcg_gen_movi_i32(cpu_CF, 0);
778 tcg_gen_movi_i32(cpu_VF, 0);
779}
780
781
782static void gen_add64_CC(TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
783{
784 TCGv_i64 result, flag, tmp;
785 result = tcg_temp_new_i64();
786 flag = tcg_temp_new_i64();
787 tmp = tcg_temp_new_i64();
788
789 tcg_gen_movi_i64(tmp, 0);
790 tcg_gen_add2_i64(result, flag, t0, tmp, t1, tmp);
791
792 tcg_gen_extrl_i64_i32(cpu_CF, flag);
793
794 gen_set_NZ64(result);
795
796 tcg_gen_xor_i64(flag, result, t0);
797 tcg_gen_xor_i64(tmp, t0, t1);
798 tcg_gen_andc_i64(flag, flag, tmp);
799 tcg_gen_extrh_i64_i32(cpu_VF, flag);
800
801 tcg_gen_mov_i64(dest, result);
802}
803
804static void gen_add32_CC(TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
805{
806 TCGv_i32 t0_32 = tcg_temp_new_i32();
807 TCGv_i32 t1_32 = tcg_temp_new_i32();
808 TCGv_i32 tmp = tcg_temp_new_i32();
809
810 tcg_gen_movi_i32(tmp, 0);
811 tcg_gen_extrl_i64_i32(t0_32, t0);
812 tcg_gen_extrl_i64_i32(t1_32, t1);
813 tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, t1_32, tmp);
814 tcg_gen_mov_i32(cpu_ZF, cpu_NF);
815 tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
816 tcg_gen_xor_i32(tmp, t0_32, t1_32);
817 tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
818 tcg_gen_extu_i32_i64(dest, cpu_NF);
819}
820
821static void gen_add_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
822{
823 if (sf) {
824 gen_add64_CC(dest, t0, t1);
825 } else {
826 gen_add32_CC(dest, t0, t1);
827 }
828}
829
830
831static void gen_sub64_CC(TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
832{
833
834 TCGv_i64 result, flag, tmp;
835
836 result = tcg_temp_new_i64();
837 flag = tcg_temp_new_i64();
838 tcg_gen_sub_i64(result, t0, t1);
839
840 gen_set_NZ64(result);
841
842 tcg_gen_setcond_i64(TCG_COND_GEU, flag, t0, t1);
843 tcg_gen_extrl_i64_i32(cpu_CF, flag);
844
845 tcg_gen_xor_i64(flag, result, t0);
846 tmp = tcg_temp_new_i64();
847 tcg_gen_xor_i64(tmp, t0, t1);
848 tcg_gen_and_i64(flag, flag, tmp);
849 tcg_gen_extrh_i64_i32(cpu_VF, flag);
850 tcg_gen_mov_i64(dest, result);
851}
852
853static void gen_sub32_CC(TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
854{
855
856 TCGv_i32 t0_32 = tcg_temp_new_i32();
857 TCGv_i32 t1_32 = tcg_temp_new_i32();
858 TCGv_i32 tmp;
859
860 tcg_gen_extrl_i64_i32(t0_32, t0);
861 tcg_gen_extrl_i64_i32(t1_32, t1);
862 tcg_gen_sub_i32(cpu_NF, t0_32, t1_32);
863 tcg_gen_mov_i32(cpu_ZF, cpu_NF);
864 tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0_32, t1_32);
865 tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
866 tmp = tcg_temp_new_i32();
867 tcg_gen_xor_i32(tmp, t0_32, t1_32);
868 tcg_gen_and_i32(cpu_VF, cpu_VF, tmp);
869 tcg_gen_extu_i32_i64(dest, cpu_NF);
870}
871
872static void gen_sub_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
873{
874 if (sf) {
875 gen_sub64_CC(dest, t0, t1);
876 } else {
877 gen_sub32_CC(dest, t0, t1);
878 }
879}
880
881
882static void gen_adc(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
883{
884 TCGv_i64 flag = tcg_temp_new_i64();
885 tcg_gen_extu_i32_i64(flag, cpu_CF);
886 tcg_gen_add_i64(dest, t0, t1);
887 tcg_gen_add_i64(dest, dest, flag);
888
889 if (!sf) {
890 tcg_gen_ext32u_i64(dest, dest);
891 }
892}
893
894
895static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
896{
897 if (sf) {
898 TCGv_i64 result = tcg_temp_new_i64();
899 TCGv_i64 cf_64 = tcg_temp_new_i64();
900 TCGv_i64 vf_64 = tcg_temp_new_i64();
901 TCGv_i64 tmp = tcg_temp_new_i64();
902 TCGv_i64 zero = tcg_constant_i64(0);
903
904 tcg_gen_extu_i32_i64(cf_64, cpu_CF);
905 tcg_gen_add2_i64(result, cf_64, t0, zero, cf_64, zero);
906 tcg_gen_add2_i64(result, cf_64, result, cf_64, t1, zero);
907 tcg_gen_extrl_i64_i32(cpu_CF, cf_64);
908 gen_set_NZ64(result);
909
910 tcg_gen_xor_i64(vf_64, result, t0);
911 tcg_gen_xor_i64(tmp, t0, t1);
912 tcg_gen_andc_i64(vf_64, vf_64, tmp);
913 tcg_gen_extrh_i64_i32(cpu_VF, vf_64);
914
915 tcg_gen_mov_i64(dest, result);
916 } else {
917 TCGv_i32 t0_32 = tcg_temp_new_i32();
918 TCGv_i32 t1_32 = tcg_temp_new_i32();
919 TCGv_i32 tmp = tcg_temp_new_i32();
920 TCGv_i32 zero = tcg_constant_i32(0);
921
922 tcg_gen_extrl_i64_i32(t0_32, t0);
923 tcg_gen_extrl_i64_i32(t1_32, t1);
924 tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, zero, cpu_CF, zero);
925 tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1_32, zero);
926
927 tcg_gen_mov_i32(cpu_ZF, cpu_NF);
928 tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
929 tcg_gen_xor_i32(tmp, t0_32, t1_32);
930 tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
931 tcg_gen_extu_i32_i64(dest, cpu_NF);
932 }
933}
934
935
936
937
938
939
940
941
942static void do_gpr_st_memidx(DisasContext *s, TCGv_i64 source,
943 TCGv_i64 tcg_addr, MemOp memop, int memidx,
944 bool iss_valid,
945 unsigned int iss_srt,
946 bool iss_sf, bool iss_ar)
947{
948 tcg_gen_qemu_st_i64(source, tcg_addr, memidx, memop);
949
950 if (iss_valid) {
951 uint32_t syn;
952
953 syn = syn_data_abort_with_iss(0,
954 (memop & MO_SIZE),
955 false,
956 iss_srt,
957 iss_sf,
958 iss_ar,
959 0, 0, 0, 0, 0, false);
960 disas_set_insn_syndrome(s, syn);
961 }
962}
963
964static void do_gpr_st(DisasContext *s, TCGv_i64 source,
965 TCGv_i64 tcg_addr, MemOp memop,
966 bool iss_valid,
967 unsigned int iss_srt,
968 bool iss_sf, bool iss_ar)
969{
970 do_gpr_st_memidx(s, source, tcg_addr, memop, get_mem_index(s),
971 iss_valid, iss_srt, iss_sf, iss_ar);
972}
973
974
975
976
977static void do_gpr_ld_memidx(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
978 MemOp memop, bool extend, int memidx,
979 bool iss_valid, unsigned int iss_srt,
980 bool iss_sf, bool iss_ar)
981{
982 tcg_gen_qemu_ld_i64(dest, tcg_addr, memidx, memop);
983
984 if (extend && (memop & MO_SIGN)) {
985 g_assert((memop & MO_SIZE) <= MO_32);
986 tcg_gen_ext32u_i64(dest, dest);
987 }
988
989 if (iss_valid) {
990 uint32_t syn;
991
992 syn = syn_data_abort_with_iss(0,
993 (memop & MO_SIZE),
994 (memop & MO_SIGN) != 0,
995 iss_srt,
996 iss_sf,
997 iss_ar,
998 0, 0, 0, 0, 0, false);
999 disas_set_insn_syndrome(s, syn);
1000 }
1001}
1002
1003static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
1004 MemOp memop, bool extend,
1005 bool iss_valid, unsigned int iss_srt,
1006 bool iss_sf, bool iss_ar)
1007{
1008 do_gpr_ld_memidx(s, dest, tcg_addr, memop, extend, get_mem_index(s),
1009 iss_valid, iss_srt, iss_sf, iss_ar);
1010}
1011
1012
1013
1014
1015static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, MemOp mop)
1016{
1017
1018 TCGv_i64 tmplo = tcg_temp_new_i64();
1019
1020 tcg_gen_ld_i64(tmplo, cpu_env, fp_reg_offset(s, srcidx, MO_64));
1021
1022 if ((mop & MO_SIZE) < MO_128) {
1023 tcg_gen_qemu_st_i64(tmplo, tcg_addr, get_mem_index(s), mop);
1024 } else {
1025 TCGv_i64 tmphi = tcg_temp_new_i64();
1026 TCGv_i128 t16 = tcg_temp_new_i128();
1027
1028 tcg_gen_ld_i64(tmphi, cpu_env, fp_reg_hi_offset(s, srcidx));
1029 tcg_gen_concat_i64_i128(t16, tmplo, tmphi);
1030
1031 tcg_gen_qemu_st_i128(t16, tcg_addr, get_mem_index(s), mop);
1032 }
1033}
1034
1035
1036
1037
1038static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, MemOp mop)
1039{
1040
1041 TCGv_i64 tmplo = tcg_temp_new_i64();
1042 TCGv_i64 tmphi = NULL;
1043
1044 if ((mop & MO_SIZE) < MO_128) {
1045 tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), mop);
1046 } else {
1047 TCGv_i128 t16 = tcg_temp_new_i128();
1048
1049 tcg_gen_qemu_ld_i128(t16, tcg_addr, get_mem_index(s), mop);
1050
1051 tmphi = tcg_temp_new_i64();
1052 tcg_gen_extr_i128_i64(tmplo, tmphi, t16);
1053 }
1054
1055 tcg_gen_st_i64(tmplo, cpu_env, fp_reg_offset(s, destidx, MO_64));
1056
1057 if (tmphi) {
1058 tcg_gen_st_i64(tmphi, cpu_env, fp_reg_hi_offset(s, destidx));
1059 }
1060 clear_vec_high(s, tmphi != NULL, destidx);
1061}
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx,
1077 int element, MemOp memop)
1078{
1079 int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE);
1080 switch ((unsigned)memop) {
1081 case MO_8:
1082 tcg_gen_ld8u_i64(tcg_dest, cpu_env, vect_off);
1083 break;
1084 case MO_16:
1085 tcg_gen_ld16u_i64(tcg_dest, cpu_env, vect_off);
1086 break;
1087 case MO_32:
1088 tcg_gen_ld32u_i64(tcg_dest, cpu_env, vect_off);
1089 break;
1090 case MO_8|MO_SIGN:
1091 tcg_gen_ld8s_i64(tcg_dest, cpu_env, vect_off);
1092 break;
1093 case MO_16|MO_SIGN:
1094 tcg_gen_ld16s_i64(tcg_dest, cpu_env, vect_off);
1095 break;
1096 case MO_32|MO_SIGN:
1097 tcg_gen_ld32s_i64(tcg_dest, cpu_env, vect_off);
1098 break;
1099 case MO_64:
1100 case MO_64|MO_SIGN:
1101 tcg_gen_ld_i64(tcg_dest, cpu_env, vect_off);
1102 break;
1103 default:
1104 g_assert_not_reached();
1105 }
1106}
1107
1108static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx,
1109 int element, MemOp memop)
1110{
1111 int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE);
1112 switch (memop) {
1113 case MO_8:
1114 tcg_gen_ld8u_i32(tcg_dest, cpu_env, vect_off);
1115 break;
1116 case MO_16:
1117 tcg_gen_ld16u_i32(tcg_dest, cpu_env, vect_off);
1118 break;
1119 case MO_8|MO_SIGN:
1120 tcg_gen_ld8s_i32(tcg_dest, cpu_env, vect_off);
1121 break;
1122 case MO_16|MO_SIGN:
1123 tcg_gen_ld16s_i32(tcg_dest, cpu_env, vect_off);
1124 break;
1125 case MO_32:
1126 case MO_32|MO_SIGN:
1127 tcg_gen_ld_i32(tcg_dest, cpu_env, vect_off);
1128 break;
1129 default:
1130 g_assert_not_reached();
1131 }
1132}
1133
1134
1135static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx,
1136 int element, MemOp memop)
1137{
1138 int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE);
1139 switch (memop) {
1140 case MO_8:
1141 tcg_gen_st8_i64(tcg_src, cpu_env, vect_off);
1142 break;
1143 case MO_16:
1144 tcg_gen_st16_i64(tcg_src, cpu_env, vect_off);
1145 break;
1146 case MO_32:
1147 tcg_gen_st32_i64(tcg_src, cpu_env, vect_off);
1148 break;
1149 case MO_64:
1150 tcg_gen_st_i64(tcg_src, cpu_env, vect_off);
1151 break;
1152 default:
1153 g_assert_not_reached();
1154 }
1155}
1156
1157static void write_vec_element_i32(DisasContext *s, TCGv_i32 tcg_src,
1158 int destidx, int element, MemOp memop)
1159{
1160 int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE);
1161 switch (memop) {
1162 case MO_8:
1163 tcg_gen_st8_i32(tcg_src, cpu_env, vect_off);
1164 break;
1165 case MO_16:
1166 tcg_gen_st16_i32(tcg_src, cpu_env, vect_off);
1167 break;
1168 case MO_32:
1169 tcg_gen_st_i32(tcg_src, cpu_env, vect_off);
1170 break;
1171 default:
1172 g_assert_not_reached();
1173 }
1174}
1175
1176
1177static void do_vec_st(DisasContext *s, int srcidx, int element,
1178 TCGv_i64 tcg_addr, MemOp mop)
1179{
1180 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
1181
1182 read_vec_element(s, tcg_tmp, srcidx, element, mop & MO_SIZE);
1183 tcg_gen_qemu_st_i64(tcg_tmp, tcg_addr, get_mem_index(s), mop);
1184}
1185
1186
1187static void do_vec_ld(DisasContext *s, int destidx, int element,
1188 TCGv_i64 tcg_addr, MemOp mop)
1189{
1190 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
1191
1192 tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr, get_mem_index(s), mop);
1193 write_vec_element(s, tcg_tmp, destidx, element, mop & MO_SIZE);
1194}
1195
1196
1197
1198
1199
1200
1201
1202
1203static bool fp_access_check_only(DisasContext *s)
1204{
1205 if (s->fp_excp_el) {
1206 assert(!s->fp_access_checked);
1207 s->fp_access_checked = true;
1208
1209 gen_exception_insn_el(s, 0, EXCP_UDEF,
1210 syn_fp_access_trap(1, 0xe, false, 0),
1211 s->fp_excp_el);
1212 return false;
1213 }
1214 s->fp_access_checked = true;
1215 return true;
1216}
1217
1218static bool fp_access_check(DisasContext *s)
1219{
1220 if (!fp_access_check_only(s)) {
1221 return false;
1222 }
1223 if (s->sme_trap_nonstreaming && s->is_nonstreaming) {
1224 gen_exception_insn(s, 0, EXCP_UDEF,
1225 syn_smetrap(SME_ET_Streaming, false));
1226 return false;
1227 }
1228 return true;
1229}
1230
1231
1232
1233
1234
1235
1236bool sve_access_check(DisasContext *s)
1237{
1238 if (s->pstate_sm || !dc_isar_feature(aa64_sve, s)) {
1239 assert(dc_isar_feature(aa64_sme, s));
1240 if (!sme_sm_enabled_check(s)) {
1241 goto fail_exit;
1242 }
1243 } else if (s->sve_excp_el) {
1244 gen_exception_insn_el(s, 0, EXCP_UDEF,
1245 syn_sve_access_trap(), s->sve_excp_el);
1246 goto fail_exit;
1247 }
1248 s->sve_access_checked = true;
1249 return fp_access_check(s);
1250
1251 fail_exit:
1252
1253 assert(!s->sve_access_checked);
1254 s->sve_access_checked = true;
1255 return false;
1256}
1257
1258
1259
1260
1261
1262
1263static bool sme_access_check(DisasContext *s)
1264{
1265 if (s->sme_excp_el) {
1266 gen_exception_insn_el(s, 0, EXCP_UDEF,
1267 syn_smetrap(SME_ET_AccessTrap, false),
1268 s->sme_excp_el);
1269 return false;
1270 }
1271 return true;
1272}
1273
1274
1275bool sme_enabled_check(DisasContext *s)
1276{
1277
1278
1279
1280
1281
1282 if (!s->fp_excp_el || s->sme_excp_el < s->fp_excp_el) {
1283 s->fp_access_checked = true;
1284 return sme_access_check(s);
1285 }
1286 return fp_access_check_only(s);
1287}
1288
1289
1290bool sme_enabled_check_with_svcr(DisasContext *s, unsigned req)
1291{
1292 if (!sme_enabled_check(s)) {
1293 return false;
1294 }
1295 if (FIELD_EX64(req, SVCR, SM) && !s->pstate_sm) {
1296 gen_exception_insn(s, 0, EXCP_UDEF,
1297 syn_smetrap(SME_ET_NotStreaming, false));
1298 return false;
1299 }
1300 if (FIELD_EX64(req, SVCR, ZA) && !s->pstate_za) {
1301 gen_exception_insn(s, 0, EXCP_UDEF,
1302 syn_smetrap(SME_ET_InactiveZA, false));
1303 return false;
1304 }
1305 return true;
1306}
1307
1308
1309
1310
1311
1312
1313static void ext_and_shift_reg(TCGv_i64 tcg_out, TCGv_i64 tcg_in,
1314 int option, unsigned int shift)
1315{
1316 int extsize = extract32(option, 0, 2);
1317 bool is_signed = extract32(option, 2, 1);
1318
1319 if (is_signed) {
1320 switch (extsize) {
1321 case 0:
1322 tcg_gen_ext8s_i64(tcg_out, tcg_in);
1323 break;
1324 case 1:
1325 tcg_gen_ext16s_i64(tcg_out, tcg_in);
1326 break;
1327 case 2:
1328 tcg_gen_ext32s_i64(tcg_out, tcg_in);
1329 break;
1330 case 3:
1331 tcg_gen_mov_i64(tcg_out, tcg_in);
1332 break;
1333 }
1334 } else {
1335 switch (extsize) {
1336 case 0:
1337 tcg_gen_ext8u_i64(tcg_out, tcg_in);
1338 break;
1339 case 1:
1340 tcg_gen_ext16u_i64(tcg_out, tcg_in);
1341 break;
1342 case 2:
1343 tcg_gen_ext32u_i64(tcg_out, tcg_in);
1344 break;
1345 case 3:
1346 tcg_gen_mov_i64(tcg_out, tcg_in);
1347 break;
1348 }
1349 }
1350
1351 if (shift) {
1352 tcg_gen_shli_i64(tcg_out, tcg_out, shift);
1353 }
1354}
1355
1356static inline void gen_check_sp_alignment(DisasContext *s)
1357{
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367}
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380static inline AArch64DecodeFn *lookup_disas_fn(const AArch64DecodeTable *table,
1381 uint32_t insn)
1382{
1383 const AArch64DecodeTable *tptr = table;
1384
1385 while (tptr->mask) {
1386 if ((insn & tptr->mask) == tptr->pattern) {
1387 return tptr->disas_fn;
1388 }
1389 tptr++;
1390 }
1391 return NULL;
1392}
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402static bool trans_B(DisasContext *s, arg_i *a)
1403{
1404 reset_btype(s);
1405 gen_goto_tb(s, 0, a->imm);
1406 return true;
1407}
1408
1409static bool trans_BL(DisasContext *s, arg_i *a)
1410{
1411 gen_pc_plus_diff(s, cpu_reg(s, 30), curr_insn_len(s));
1412 reset_btype(s);
1413 gen_goto_tb(s, 0, a->imm);
1414 return true;
1415}
1416
1417
1418static bool trans_CBZ(DisasContext *s, arg_cbz *a)
1419{
1420 DisasLabel match;
1421 TCGv_i64 tcg_cmp;
1422
1423 tcg_cmp = read_cpu_reg(s, a->rt, a->sf);
1424 reset_btype(s);
1425
1426 match = gen_disas_label(s);
1427 tcg_gen_brcondi_i64(a->nz ? TCG_COND_NE : TCG_COND_EQ,
1428 tcg_cmp, 0, match.label);
1429 gen_goto_tb(s, 0, 4);
1430 set_disas_label(s, match);
1431 gen_goto_tb(s, 1, a->imm);
1432 return true;
1433}
1434
1435static bool trans_TBZ(DisasContext *s, arg_tbz *a)
1436{
1437 DisasLabel match;
1438 TCGv_i64 tcg_cmp;
1439
1440 tcg_cmp = tcg_temp_new_i64();
1441 tcg_gen_andi_i64(tcg_cmp, cpu_reg(s, a->rt), 1ULL << a->bitpos);
1442
1443 reset_btype(s);
1444
1445 match = gen_disas_label(s);
1446 tcg_gen_brcondi_i64(a->nz ? TCG_COND_NE : TCG_COND_EQ,
1447 tcg_cmp, 0, match.label);
1448 gen_goto_tb(s, 0, 4);
1449 set_disas_label(s, match);
1450 gen_goto_tb(s, 1, a->imm);
1451 return true;
1452}
1453
1454static bool trans_B_cond(DisasContext *s, arg_B_cond *a)
1455{
1456 reset_btype(s);
1457 if (a->cond < 0x0e) {
1458
1459 DisasLabel match = gen_disas_label(s);
1460 arm_gen_test_cc(a->cond, match.label);
1461 gen_goto_tb(s, 0, 4);
1462 set_disas_label(s, match);
1463 gen_goto_tb(s, 1, a->imm);
1464 } else {
1465
1466 gen_goto_tb(s, 0, a->imm);
1467 }
1468 return true;
1469}
1470
1471static void set_btype_for_br(DisasContext *s, int rn)
1472{
1473 if (dc_isar_feature(aa64_bti, s)) {
1474
1475 set_btype(s, rn == 16 || rn == 17 || !s->guarded_page ? 1 : 3);
1476 }
1477}
1478
1479static void set_btype_for_blr(DisasContext *s)
1480{
1481 if (dc_isar_feature(aa64_bti, s)) {
1482
1483 set_btype(s, 2);
1484 }
1485}
1486
1487static bool trans_BR(DisasContext *s, arg_r *a)
1488{
1489 gen_a64_set_pc(s, cpu_reg(s, a->rn));
1490 set_btype_for_br(s, a->rn);
1491 s->base.is_jmp = DISAS_JUMP;
1492 return true;
1493}
1494
1495static bool trans_BLR(DisasContext *s, arg_r *a)
1496{
1497 TCGv_i64 dst = cpu_reg(s, a->rn);
1498 TCGv_i64 lr = cpu_reg(s, 30);
1499 if (dst == lr) {
1500 TCGv_i64 tmp = tcg_temp_new_i64();
1501 tcg_gen_mov_i64(tmp, dst);
1502 dst = tmp;
1503 }
1504 gen_pc_plus_diff(s, lr, curr_insn_len(s));
1505 gen_a64_set_pc(s, dst);
1506 set_btype_for_blr(s);
1507 s->base.is_jmp = DISAS_JUMP;
1508 return true;
1509}
1510
1511static bool trans_RET(DisasContext *s, arg_r *a)
1512{
1513 gen_a64_set_pc(s, cpu_reg(s, a->rn));
1514 s->base.is_jmp = DISAS_JUMP;
1515 return true;
1516}
1517
1518static TCGv_i64 auth_branch_target(DisasContext *s, TCGv_i64 dst,
1519 TCGv_i64 modifier, bool use_key_a)
1520{
1521 TCGv_i64 truedst;
1522
1523
1524
1525
1526
1527 if (!s->pauth_active) {
1528 return dst;
1529 }
1530
1531 truedst = tcg_temp_new_i64();
1532 if (use_key_a) {
1533 gen_helper_autia(truedst, cpu_env, dst, modifier);
1534 } else {
1535 gen_helper_autib(truedst, cpu_env, dst, modifier);
1536 }
1537 return truedst;
1538}
1539
1540static bool trans_BRAZ(DisasContext *s, arg_braz *a)
1541{
1542 TCGv_i64 dst;
1543
1544 if (!dc_isar_feature(aa64_pauth, s)) {
1545 return false;
1546 }
1547
1548 dst = auth_branch_target(s, cpu_reg(s, a->rn), tcg_constant_i64(0), !a->m);
1549 gen_a64_set_pc(s, dst);
1550 set_btype_for_br(s, a->rn);
1551 s->base.is_jmp = DISAS_JUMP;
1552 return true;
1553}
1554
1555static bool trans_BLRAZ(DisasContext *s, arg_braz *a)
1556{
1557 TCGv_i64 dst, lr;
1558
1559 if (!dc_isar_feature(aa64_pauth, s)) {
1560 return false;
1561 }
1562
1563 dst = auth_branch_target(s, cpu_reg(s, a->rn), tcg_constant_i64(0), !a->m);
1564 lr = cpu_reg(s, 30);
1565 if (dst == lr) {
1566 TCGv_i64 tmp = tcg_temp_new_i64();
1567 tcg_gen_mov_i64(tmp, dst);
1568 dst = tmp;
1569 }
1570 gen_pc_plus_diff(s, lr, curr_insn_len(s));
1571 gen_a64_set_pc(s, dst);
1572 set_btype_for_blr(s);
1573 s->base.is_jmp = DISAS_JUMP;
1574 return true;
1575}
1576
1577static bool trans_RETA(DisasContext *s, arg_reta *a)
1578{
1579 TCGv_i64 dst;
1580
1581 dst = auth_branch_target(s, cpu_reg(s, 30), cpu_X[31], !a->m);
1582 gen_a64_set_pc(s, dst);
1583 s->base.is_jmp = DISAS_JUMP;
1584 return true;
1585}
1586
1587static bool trans_BRA(DisasContext *s, arg_bra *a)
1588{
1589 TCGv_i64 dst;
1590
1591 if (!dc_isar_feature(aa64_pauth, s)) {
1592 return false;
1593 }
1594 dst = auth_branch_target(s, cpu_reg(s,a->rn), cpu_reg_sp(s, a->rm), !a->m);
1595 gen_a64_set_pc(s, dst);
1596 set_btype_for_br(s, a->rn);
1597 s->base.is_jmp = DISAS_JUMP;
1598 return true;
1599}
1600
1601static bool trans_BLRA(DisasContext *s, arg_bra *a)
1602{
1603 TCGv_i64 dst, lr;
1604
1605 if (!dc_isar_feature(aa64_pauth, s)) {
1606 return false;
1607 }
1608 dst = auth_branch_target(s, cpu_reg(s, a->rn), cpu_reg_sp(s, a->rm), !a->m);
1609 lr = cpu_reg(s, 30);
1610 if (dst == lr) {
1611 TCGv_i64 tmp = tcg_temp_new_i64();
1612 tcg_gen_mov_i64(tmp, dst);
1613 dst = tmp;
1614 }
1615 gen_pc_plus_diff(s, lr, curr_insn_len(s));
1616 gen_a64_set_pc(s, dst);
1617 set_btype_for_blr(s);
1618 s->base.is_jmp = DISAS_JUMP;
1619 return true;
1620}
1621
1622static bool trans_ERET(DisasContext *s, arg_ERET *a)
1623{
1624 TCGv_i64 dst;
1625
1626 if (s->current_el == 0) {
1627 return false;
1628 }
1629 if (s->fgt_eret) {
1630 gen_exception_insn_el(s, 0, EXCP_UDEF, 0, 2);
1631 return true;
1632 }
1633 dst = tcg_temp_new_i64();
1634 tcg_gen_ld_i64(dst, cpu_env,
1635 offsetof(CPUARMState, elr_el[s->current_el]));
1636
1637 translator_io_start(&s->base);
1638
1639 gen_helper_exception_return(cpu_env, dst);
1640
1641 s->base.is_jmp = DISAS_EXIT;
1642 return true;
1643}
1644
1645static bool trans_ERETA(DisasContext *s, arg_reta *a)
1646{
1647 TCGv_i64 dst;
1648
1649 if (!dc_isar_feature(aa64_pauth, s)) {
1650 return false;
1651 }
1652 if (s->current_el == 0) {
1653 return false;
1654 }
1655
1656 if (s->fgt_eret) {
1657 gen_exception_insn_el(s, 0, EXCP_UDEF, a->m ? 3 : 2, 2);
1658 return true;
1659 }
1660 dst = tcg_temp_new_i64();
1661 tcg_gen_ld_i64(dst, cpu_env,
1662 offsetof(CPUARMState, elr_el[s->current_el]));
1663
1664 dst = auth_branch_target(s, dst, cpu_X[31], !a->m);
1665
1666 translator_io_start(&s->base);
1667
1668 gen_helper_exception_return(cpu_env, dst);
1669
1670 s->base.is_jmp = DISAS_EXIT;
1671 return true;
1672}
1673
1674static bool trans_NOP(DisasContext *s, arg_NOP *a)
1675{
1676 return true;
1677}
1678
1679static bool trans_YIELD(DisasContext *s, arg_YIELD *a)
1680{
1681
1682
1683
1684
1685
1686
1687 if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
1688 s->base.is_jmp = DISAS_YIELD;
1689 }
1690 return true;
1691}
1692
1693static bool trans_WFI(DisasContext *s, arg_WFI *a)
1694{
1695 s->base.is_jmp = DISAS_WFI;
1696 return true;
1697}
1698
1699static bool trans_WFE(DisasContext *s, arg_WFI *a)
1700{
1701
1702
1703
1704
1705
1706
1707 if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
1708 s->base.is_jmp = DISAS_WFE;
1709 }
1710 return true;
1711}
1712
1713static bool trans_XPACLRI(DisasContext *s, arg_XPACLRI *a)
1714{
1715 if (s->pauth_active) {
1716 gen_helper_xpaci(cpu_X[30], cpu_env, cpu_X[30]);
1717 }
1718 return true;
1719}
1720
1721static bool trans_PACIA1716(DisasContext *s, arg_PACIA1716 *a)
1722{
1723 if (s->pauth_active) {
1724 gen_helper_pacia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
1725 }
1726 return true;
1727}
1728
1729static bool trans_PACIB1716(DisasContext *s, arg_PACIB1716 *a)
1730{
1731 if (s->pauth_active) {
1732 gen_helper_pacib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
1733 }
1734 return true;
1735}
1736
1737static bool trans_AUTIA1716(DisasContext *s, arg_AUTIA1716 *a)
1738{
1739 if (s->pauth_active) {
1740 gen_helper_autia(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
1741 }
1742 return true;
1743}
1744
1745static bool trans_AUTIB1716(DisasContext *s, arg_AUTIB1716 *a)
1746{
1747 if (s->pauth_active) {
1748 gen_helper_autib(cpu_X[17], cpu_env, cpu_X[17], cpu_X[16]);
1749 }
1750 return true;
1751}
1752
1753static bool trans_ESB(DisasContext *s, arg_ESB *a)
1754{
1755
1756 if (dc_isar_feature(aa64_ras, s)) {
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766 if (s->current_el <= 1 && arm_dc_feature(s, ARM_FEATURE_EL2)) {
1767 gen_helper_vesb(cpu_env);
1768 }
1769 }
1770 return true;
1771}
1772
1773static bool trans_PACIAZ(DisasContext *s, arg_PACIAZ *a)
1774{
1775 if (s->pauth_active) {
1776 gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0));
1777 }
1778 return true;
1779}
1780
1781static bool trans_PACIASP(DisasContext *s, arg_PACIASP *a)
1782{
1783 if (s->pauth_active) {
1784 gen_helper_pacia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
1785 }
1786 return true;
1787}
1788
1789static bool trans_PACIBZ(DisasContext *s, arg_PACIBZ *a)
1790{
1791 if (s->pauth_active) {
1792 gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0));
1793 }
1794 return true;
1795}
1796
1797static bool trans_PACIBSP(DisasContext *s, arg_PACIBSP *a)
1798{
1799 if (s->pauth_active) {
1800 gen_helper_pacib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
1801 }
1802 return true;
1803}
1804
1805static bool trans_AUTIAZ(DisasContext *s, arg_AUTIAZ *a)
1806{
1807 if (s->pauth_active) {
1808 gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0));
1809 }
1810 return true;
1811}
1812
1813static bool trans_AUTIASP(DisasContext *s, arg_AUTIASP *a)
1814{
1815 if (s->pauth_active) {
1816 gen_helper_autia(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
1817 }
1818 return true;
1819}
1820
1821static bool trans_AUTIBZ(DisasContext *s, arg_AUTIBZ *a)
1822{
1823 if (s->pauth_active) {
1824 gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30], tcg_constant_i64(0));
1825 }
1826 return true;
1827}
1828
1829static bool trans_AUTIBSP(DisasContext *s, arg_AUTIBSP *a)
1830{
1831 if (s->pauth_active) {
1832 gen_helper_autib(cpu_X[30], cpu_env, cpu_X[30], cpu_X[31]);
1833 }
1834 return true;
1835}
1836
1837static bool trans_CLREX(DisasContext *s, arg_CLREX *a)
1838{
1839 tcg_gen_movi_i64(cpu_exclusive_addr, -1);
1840 return true;
1841}
1842
1843static bool trans_DSB_DMB(DisasContext *s, arg_DSB_DMB *a)
1844{
1845
1846 TCGBar bar;
1847
1848 switch (a->types) {
1849 case 1:
1850 bar = TCG_BAR_SC | TCG_MO_LD_LD | TCG_MO_LD_ST;
1851 break;
1852 case 2:
1853 bar = TCG_BAR_SC | TCG_MO_ST_ST;
1854 break;
1855 default:
1856 bar = TCG_BAR_SC | TCG_MO_ALL;
1857 break;
1858 }
1859 tcg_gen_mb(bar);
1860 return true;
1861}
1862
1863static bool trans_ISB(DisasContext *s, arg_ISB *a)
1864{
1865
1866
1867
1868
1869
1870 reset_btype(s);
1871 gen_goto_tb(s, 0, 4);
1872 return true;
1873}
1874
1875static bool trans_SB(DisasContext *s, arg_SB *a)
1876{
1877 if (!dc_isar_feature(aa64_sb, s)) {
1878 return false;
1879 }
1880
1881
1882
1883
1884 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
1885 gen_goto_tb(s, 0, 4);
1886 return true;
1887}
1888
1889static bool trans_CFINV(DisasContext *s, arg_CFINV *a)
1890{
1891 if (!dc_isar_feature(aa64_condm_4, s)) {
1892 return false;
1893 }
1894 tcg_gen_xori_i32(cpu_CF, cpu_CF, 1);
1895 return true;
1896}
1897
1898static bool trans_XAFLAG(DisasContext *s, arg_XAFLAG *a)
1899{
1900 TCGv_i32 z;
1901
1902 if (!dc_isar_feature(aa64_condm_5, s)) {
1903 return false;
1904 }
1905
1906 z = tcg_temp_new_i32();
1907
1908 tcg_gen_setcondi_i32(TCG_COND_EQ, z, cpu_ZF, 0);
1909
1910
1911
1912
1913
1914
1915
1916
1917 tcg_gen_or_i32(cpu_NF, cpu_CF, z);
1918 tcg_gen_subi_i32(cpu_NF, cpu_NF, 1);
1919
1920
1921 tcg_gen_and_i32(cpu_ZF, z, cpu_CF);
1922 tcg_gen_xori_i32(cpu_ZF, cpu_ZF, 1);
1923
1924
1925 tcg_gen_andc_i32(cpu_VF, z, cpu_CF);
1926 tcg_gen_neg_i32(cpu_VF, cpu_VF);
1927
1928
1929 tcg_gen_or_i32(cpu_CF, cpu_CF, z);
1930
1931 return true;
1932}
1933
1934static bool trans_AXFLAG(DisasContext *s, arg_AXFLAG *a)
1935{
1936 if (!dc_isar_feature(aa64_condm_5, s)) {
1937 return false;
1938 }
1939
1940 tcg_gen_sari_i32(cpu_VF, cpu_VF, 31);
1941 tcg_gen_andc_i32(cpu_CF, cpu_CF, cpu_VF);
1942
1943
1944 tcg_gen_andc_i32(cpu_ZF, cpu_ZF, cpu_VF);
1945
1946 tcg_gen_movi_i32(cpu_NF, 0);
1947 tcg_gen_movi_i32(cpu_VF, 0);
1948
1949 return true;
1950}
1951
1952static bool trans_MSR_i_UAO(DisasContext *s, arg_i *a)
1953{
1954 if (!dc_isar_feature(aa64_uao, s) || s->current_el == 0) {
1955 return false;
1956 }
1957 if (a->imm & 1) {
1958 set_pstate_bits(PSTATE_UAO);
1959 } else {
1960 clear_pstate_bits(PSTATE_UAO);
1961 }
1962 gen_rebuild_hflags(s);
1963 s->base.is_jmp = DISAS_TOO_MANY;
1964 return true;
1965}
1966
1967static bool trans_MSR_i_PAN(DisasContext *s, arg_i *a)
1968{
1969 if (!dc_isar_feature(aa64_pan, s) || s->current_el == 0) {
1970 return false;
1971 }
1972 if (a->imm & 1) {
1973 set_pstate_bits(PSTATE_PAN);
1974 } else {
1975 clear_pstate_bits(PSTATE_PAN);
1976 }
1977 gen_rebuild_hflags(s);
1978 s->base.is_jmp = DISAS_TOO_MANY;
1979 return true;
1980}
1981
1982static bool trans_MSR_i_SPSEL(DisasContext *s, arg_i *a)
1983{
1984 if (s->current_el == 0) {
1985 return false;
1986 }
1987 gen_helper_msr_i_spsel(cpu_env, tcg_constant_i32(a->imm & PSTATE_SP));
1988 s->base.is_jmp = DISAS_TOO_MANY;
1989 return true;
1990}
1991
1992static bool trans_MSR_i_SBSS(DisasContext *s, arg_i *a)
1993{
1994 if (!dc_isar_feature(aa64_ssbs, s)) {
1995 return false;
1996 }
1997 if (a->imm & 1) {
1998 set_pstate_bits(PSTATE_SSBS);
1999 } else {
2000 clear_pstate_bits(PSTATE_SSBS);
2001 }
2002
2003 s->base.is_jmp = DISAS_TOO_MANY;
2004 return true;
2005}
2006
2007static bool trans_MSR_i_DIT(DisasContext *s, arg_i *a)
2008{
2009 if (!dc_isar_feature(aa64_dit, s)) {
2010 return false;
2011 }
2012 if (a->imm & 1) {
2013 set_pstate_bits(PSTATE_DIT);
2014 } else {
2015 clear_pstate_bits(PSTATE_DIT);
2016 }
2017
2018 s->base.is_jmp = DISAS_TOO_MANY;
2019 return true;
2020}
2021
2022static bool trans_MSR_i_TCO(DisasContext *s, arg_i *a)
2023{
2024 if (dc_isar_feature(aa64_mte, s)) {
2025
2026 if (a->imm & 1) {
2027 set_pstate_bits(PSTATE_TCO);
2028 } else {
2029 clear_pstate_bits(PSTATE_TCO);
2030 }
2031 gen_rebuild_hflags(s);
2032
2033 s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
2034 return true;
2035 } else if (dc_isar_feature(aa64_mte_insn_reg, s)) {
2036
2037 return true;
2038 } else {
2039
2040 return false;
2041 }
2042}
2043
2044static bool trans_MSR_i_DAIFSET(DisasContext *s, arg_i *a)
2045{
2046 gen_helper_msr_i_daifset(cpu_env, tcg_constant_i32(a->imm));
2047 s->base.is_jmp = DISAS_TOO_MANY;
2048 return true;
2049}
2050
2051static bool trans_MSR_i_DAIFCLEAR(DisasContext *s, arg_i *a)
2052{
2053 gen_helper_msr_i_daifclear(cpu_env, tcg_constant_i32(a->imm));
2054
2055 s->base.is_jmp = DISAS_UPDATE_EXIT;
2056 return true;
2057}
2058
2059static bool trans_MSR_i_SVCR(DisasContext *s, arg_MSR_i_SVCR *a)
2060{
2061 if (!dc_isar_feature(aa64_sme, s) || a->mask == 0) {
2062 return false;
2063 }
2064 if (sme_access_check(s)) {
2065 int old = s->pstate_sm | (s->pstate_za << 1);
2066 int new = a->imm * 3;
2067
2068 if ((old ^ new) & a->mask) {
2069
2070 gen_helper_set_svcr(cpu_env, tcg_constant_i32(new),
2071 tcg_constant_i32(a->mask));
2072 s->base.is_jmp = DISAS_TOO_MANY;
2073 }
2074 }
2075 return true;
2076}
2077
2078static void gen_get_nzcv(TCGv_i64 tcg_rt)
2079{
2080 TCGv_i32 tmp = tcg_temp_new_i32();
2081 TCGv_i32 nzcv = tcg_temp_new_i32();
2082
2083
2084 tcg_gen_andi_i32(nzcv, cpu_NF, (1U << 31));
2085
2086 tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
2087 tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
2088
2089 tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
2090
2091 tcg_gen_shri_i32(tmp, cpu_VF, 31);
2092 tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
2093
2094 tcg_gen_extu_i32_i64(tcg_rt, nzcv);
2095}
2096
2097static void gen_set_nzcv(TCGv_i64 tcg_rt)
2098{
2099 TCGv_i32 nzcv = tcg_temp_new_i32();
2100
2101
2102 tcg_gen_extrl_i64_i32(nzcv, tcg_rt);
2103
2104
2105 tcg_gen_andi_i32(cpu_NF, nzcv, (1U << 31));
2106
2107 tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
2108 tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
2109
2110 tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
2111 tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
2112
2113 tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
2114 tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
2115}
2116
2117static void gen_sysreg_undef(DisasContext *s, bool isread,
2118 uint8_t op0, uint8_t op1, uint8_t op2,
2119 uint8_t crn, uint8_t crm, uint8_t rt)
2120{
2121
2122
2123
2124
2125
2126
2127
2128
2129 uint32_t syndrome;
2130
2131 if (isread && dc_isar_feature(aa64_ids, s) &&
2132 arm_cpreg_encoding_in_idspace(op0, op1, op2, crn, crm)) {
2133 syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
2134 } else {
2135 syndrome = syn_uncategorized();
2136 }
2137 gen_exception_insn(s, 0, EXCP_UDEF, syndrome);
2138}
2139
2140
2141
2142
2143
2144
2145
2146
2147static void handle_sys(DisasContext *s, bool isread,
2148 unsigned int op0, unsigned int op1, unsigned int op2,
2149 unsigned int crn, unsigned int crm, unsigned int rt)
2150{
2151 uint32_t key = ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
2152 crn, crm, op0, op1, op2);
2153 const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
2154 bool need_exit_tb = false;
2155 TCGv_ptr tcg_ri = NULL;
2156 TCGv_i64 tcg_rt;
2157
2158 if (!ri) {
2159
2160
2161
2162 qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch64 "
2163 "system register op0:%d op1:%d crn:%d crm:%d op2:%d\n",
2164 isread ? "read" : "write", op0, op1, crn, crm, op2);
2165 gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt);
2166 return;
2167 }
2168
2169
2170 if (!cp_access_ok(s->current_el, ri, isread)) {
2171 gen_sysreg_undef(s, isread, op0, op1, op2, crn, crm, rt);
2172 return;
2173 }
2174
2175 if (ri->accessfn || (ri->fgt && s->fgt_active)) {
2176
2177
2178
2179 uint32_t syndrome;
2180
2181 syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
2182 gen_a64_update_pc(s, 0);
2183 tcg_ri = tcg_temp_new_ptr();
2184 gen_helper_access_check_cp_reg(tcg_ri, cpu_env,
2185 tcg_constant_i32(key),
2186 tcg_constant_i32(syndrome),
2187 tcg_constant_i32(isread));
2188 } else if (ri->type & ARM_CP_RAISES_EXC) {
2189
2190
2191
2192
2193 gen_a64_update_pc(s, 0);
2194 }
2195
2196
2197 switch (ri->type & ARM_CP_SPECIAL_MASK) {
2198 case 0:
2199 break;
2200 case ARM_CP_NOP:
2201 return;
2202 case ARM_CP_NZCV:
2203 tcg_rt = cpu_reg(s, rt);
2204 if (isread) {
2205 gen_get_nzcv(tcg_rt);
2206 } else {
2207 gen_set_nzcv(tcg_rt);
2208 }
2209 return;
2210 case ARM_CP_CURRENTEL:
2211
2212
2213
2214 tcg_rt = cpu_reg(s, rt);
2215 tcg_gen_movi_i64(tcg_rt, s->current_el << 2);
2216 return;
2217 case ARM_CP_DC_ZVA:
2218
2219 if (s->mte_active[0]) {
2220 int desc = 0;
2221
2222 desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s));
2223 desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid);
2224 desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma);
2225
2226 tcg_rt = tcg_temp_new_i64();
2227 gen_helper_mte_check_zva(tcg_rt, cpu_env,
2228 tcg_constant_i32(desc), cpu_reg(s, rt));
2229 } else {
2230 tcg_rt = clean_data_tbi(s, cpu_reg(s, rt));
2231 }
2232 gen_helper_dc_zva(cpu_env, tcg_rt);
2233 return;
2234 case ARM_CP_DC_GVA:
2235 {
2236 TCGv_i64 clean_addr, tag;
2237
2238
2239
2240
2241
2242 tcg_rt = cpu_reg(s, rt);
2243 clean_addr = clean_data_tbi(s, tcg_rt);
2244 gen_probe_access(s, clean_addr, MMU_DATA_STORE, MO_8);
2245
2246 if (s->ata) {
2247
2248 tag = tcg_temp_new_i64();
2249 tcg_gen_shri_i64(tag, tcg_rt, 56);
2250 gen_helper_stzgm_tags(cpu_env, clean_addr, tag);
2251 }
2252 }
2253 return;
2254 case ARM_CP_DC_GZVA:
2255 {
2256 TCGv_i64 clean_addr, tag;
2257
2258
2259 tcg_rt = cpu_reg(s, rt);
2260 clean_addr = clean_data_tbi(s, tcg_rt);
2261 gen_helper_dc_zva(cpu_env, clean_addr);
2262
2263 if (s->ata) {
2264
2265 tag = tcg_temp_new_i64();
2266 tcg_gen_shri_i64(tag, tcg_rt, 56);
2267 gen_helper_stzgm_tags(cpu_env, clean_addr, tag);
2268 }
2269 }
2270 return;
2271 default:
2272 g_assert_not_reached();
2273 }
2274 if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) {
2275 return;
2276 } else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) {
2277 return;
2278 } else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) {
2279 return;
2280 }
2281
2282 if (ri->type & ARM_CP_IO) {
2283
2284 need_exit_tb = translator_io_start(&s->base);
2285 }
2286
2287 tcg_rt = cpu_reg(s, rt);
2288
2289 if (isread) {
2290 if (ri->type & ARM_CP_CONST) {
2291 tcg_gen_movi_i64(tcg_rt, ri->resetvalue);
2292 } else if (ri->readfn) {
2293 if (!tcg_ri) {
2294 tcg_ri = gen_lookup_cp_reg(key);
2295 }
2296 gen_helper_get_cp_reg64(tcg_rt, cpu_env, tcg_ri);
2297 } else {
2298 tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset);
2299 }
2300 } else {
2301 if (ri->type & ARM_CP_CONST) {
2302
2303 return;
2304 } else if (ri->writefn) {
2305 if (!tcg_ri) {
2306 tcg_ri = gen_lookup_cp_reg(key);
2307 }
2308 gen_helper_set_cp_reg64(cpu_env, tcg_ri, tcg_rt);
2309 } else {
2310 tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset);
2311 }
2312 }
2313
2314 if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
2315
2316
2317
2318
2319 gen_rebuild_hflags(s);
2320
2321
2322
2323
2324
2325 need_exit_tb = true;
2326 }
2327 if (need_exit_tb) {
2328 s->base.is_jmp = DISAS_UPDATE_EXIT;
2329 }
2330}
2331
2332static bool trans_SYS(DisasContext *s, arg_SYS *a)
2333{
2334 handle_sys(s, a->l, a->op0, a->op1, a->op2, a->crn, a->crm, a->rt);
2335 return true;
2336}
2337
2338static bool trans_SVC(DisasContext *s, arg_i *a)
2339{
2340
2341
2342
2343
2344
2345
2346 uint32_t syndrome = syn_aa64_svc(a->imm);
2347 if (s->fgt_svc) {
2348 gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2);
2349 return true;
2350 }
2351 gen_ss_advance(s);
2352 gen_exception_insn(s, 4, EXCP_SWI, syndrome);
2353 return true;
2354}
2355
2356static bool trans_HVC(DisasContext *s, arg_i *a)
2357{
2358 if (s->current_el == 0) {
2359 unallocated_encoding(s);
2360 return true;
2361 }
2362
2363
2364
2365
2366 gen_a64_update_pc(s, 0);
2367 gen_helper_pre_hvc(cpu_env);
2368
2369 gen_ss_advance(s);
2370 gen_exception_insn_el(s, 4, EXCP_HVC, syn_aa64_hvc(a->imm), 2);
2371 return true;
2372}
2373
2374static bool trans_SMC(DisasContext *s, arg_i *a)
2375{
2376 if (s->current_el == 0) {
2377 unallocated_encoding(s);
2378 return true;
2379 }
2380 gen_a64_update_pc(s, 0);
2381 gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa64_smc(a->imm)));
2382
2383 gen_ss_advance(s);
2384 gen_exception_insn_el(s, 4, EXCP_SMC, syn_aa64_smc(a->imm), 3);
2385 return true;
2386}
2387
2388static bool trans_BRK(DisasContext *s, arg_i *a)
2389{
2390 gen_exception_bkpt_insn(s, syn_aa64_bkpt(a->imm));
2391 return true;
2392}
2393
2394static bool trans_HLT(DisasContext *s, arg_i *a)
2395{
2396
2397
2398
2399
2400
2401
2402
2403 if (semihosting_enabled(s->current_el == 0) && a->imm == 0xf000) {
2404 gen_exception_internal_insn(s, EXCP_SEMIHOST);
2405 } else {
2406 unallocated_encoding(s);
2407 }
2408 return true;
2409}
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422static void gen_load_exclusive(DisasContext *s, int rt, int rt2, int rn,
2423 int size, bool is_pair)
2424{
2425 int idx = get_mem_index(s);
2426 TCGv_i64 dirty_addr, clean_addr;
2427 MemOp memop = check_atomic_align(s, rn, size + is_pair);
2428
2429 s->is_ldex = true;
2430 dirty_addr = cpu_reg_sp(s, rn);
2431 clean_addr = gen_mte_check1(s, dirty_addr, false, rn != 31, memop);
2432
2433 g_assert(size <= 3);
2434 if (is_pair) {
2435 g_assert(size >= 2);
2436 if (size == 2) {
2437 tcg_gen_qemu_ld_i64(cpu_exclusive_val, clean_addr, idx, memop);
2438 if (s->be_data == MO_LE) {
2439 tcg_gen_extract_i64(cpu_reg(s, rt), cpu_exclusive_val, 0, 32);
2440 tcg_gen_extract_i64(cpu_reg(s, rt2), cpu_exclusive_val, 32, 32);
2441 } else {
2442 tcg_gen_extract_i64(cpu_reg(s, rt), cpu_exclusive_val, 32, 32);
2443 tcg_gen_extract_i64(cpu_reg(s, rt2), cpu_exclusive_val, 0, 32);
2444 }
2445 } else {
2446 TCGv_i128 t16 = tcg_temp_new_i128();
2447
2448 tcg_gen_qemu_ld_i128(t16, clean_addr, idx, memop);
2449
2450 if (s->be_data == MO_LE) {
2451 tcg_gen_extr_i128_i64(cpu_exclusive_val,
2452 cpu_exclusive_high, t16);
2453 } else {
2454 tcg_gen_extr_i128_i64(cpu_exclusive_high,
2455 cpu_exclusive_val, t16);
2456 }
2457 tcg_gen_mov_i64(cpu_reg(s, rt), cpu_exclusive_val);
2458 tcg_gen_mov_i64(cpu_reg(s, rt2), cpu_exclusive_high);
2459 }
2460 } else {
2461 tcg_gen_qemu_ld_i64(cpu_exclusive_val, clean_addr, idx, memop);
2462 tcg_gen_mov_i64(cpu_reg(s, rt), cpu_exclusive_val);
2463 }
2464 tcg_gen_mov_i64(cpu_exclusive_addr, clean_addr);
2465}
2466
2467static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
2468 int rn, int size, int is_pair)
2469{
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482 TCGLabel *fail_label = gen_new_label();
2483 TCGLabel *done_label = gen_new_label();
2484 TCGv_i64 tmp, clean_addr;
2485 MemOp memop;
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496 clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
2497 tcg_gen_brcond_i64(TCG_COND_NE, clean_addr, cpu_exclusive_addr, fail_label);
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518 memop = size + is_pair;
2519 if (memop == MO_128 || !dc_isar_feature(aa64_lse2, s)) {
2520 memop |= MO_ALIGN;
2521 }
2522 memop = finalize_memop(s, memop);
2523 gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, memop);
2524
2525 tmp = tcg_temp_new_i64();
2526 if (is_pair) {
2527 if (size == 2) {
2528 if (s->be_data == MO_LE) {
2529 tcg_gen_concat32_i64(tmp, cpu_reg(s, rt), cpu_reg(s, rt2));
2530 } else {
2531 tcg_gen_concat32_i64(tmp, cpu_reg(s, rt2), cpu_reg(s, rt));
2532 }
2533 tcg_gen_atomic_cmpxchg_i64(tmp, cpu_exclusive_addr,
2534 cpu_exclusive_val, tmp,
2535 get_mem_index(s), memop);
2536 tcg_gen_setcond_i64(TCG_COND_NE, tmp, tmp, cpu_exclusive_val);
2537 } else {
2538 TCGv_i128 t16 = tcg_temp_new_i128();
2539 TCGv_i128 c16 = tcg_temp_new_i128();
2540 TCGv_i64 a, b;
2541
2542 if (s->be_data == MO_LE) {
2543 tcg_gen_concat_i64_i128(t16, cpu_reg(s, rt), cpu_reg(s, rt2));
2544 tcg_gen_concat_i64_i128(c16, cpu_exclusive_val,
2545 cpu_exclusive_high);
2546 } else {
2547 tcg_gen_concat_i64_i128(t16, cpu_reg(s, rt2), cpu_reg(s, rt));
2548 tcg_gen_concat_i64_i128(c16, cpu_exclusive_high,
2549 cpu_exclusive_val);
2550 }
2551
2552 tcg_gen_atomic_cmpxchg_i128(t16, cpu_exclusive_addr, c16, t16,
2553 get_mem_index(s), memop);
2554
2555 a = tcg_temp_new_i64();
2556 b = tcg_temp_new_i64();
2557 if (s->be_data == MO_LE) {
2558 tcg_gen_extr_i128_i64(a, b, t16);
2559 } else {
2560 tcg_gen_extr_i128_i64(b, a, t16);
2561 }
2562
2563 tcg_gen_xor_i64(a, a, cpu_exclusive_val);
2564 tcg_gen_xor_i64(b, b, cpu_exclusive_high);
2565 tcg_gen_or_i64(tmp, a, b);
2566
2567 tcg_gen_setcondi_i64(TCG_COND_NE, tmp, tmp, 0);
2568 }
2569 } else {
2570 tcg_gen_atomic_cmpxchg_i64(tmp, cpu_exclusive_addr, cpu_exclusive_val,
2571 cpu_reg(s, rt), get_mem_index(s), memop);
2572 tcg_gen_setcond_i64(TCG_COND_NE, tmp, tmp, cpu_exclusive_val);
2573 }
2574 tcg_gen_mov_i64(cpu_reg(s, rd), tmp);
2575 tcg_gen_br(done_label);
2576
2577 gen_set_label(fail_label);
2578 tcg_gen_movi_i64(cpu_reg(s, rd), 1);
2579 gen_set_label(done_label);
2580 tcg_gen_movi_i64(cpu_exclusive_addr, -1);
2581}
2582
2583static void gen_compare_and_swap(DisasContext *s, int rs, int rt,
2584 int rn, int size)
2585{
2586 TCGv_i64 tcg_rs = cpu_reg(s, rs);
2587 TCGv_i64 tcg_rt = cpu_reg(s, rt);
2588 int memidx = get_mem_index(s);
2589 TCGv_i64 clean_addr;
2590 MemOp memop;
2591
2592 if (rn == 31) {
2593 gen_check_sp_alignment(s);
2594 }
2595 memop = check_atomic_align(s, rn, size);
2596 clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, memop);
2597 tcg_gen_atomic_cmpxchg_i64(tcg_rs, clean_addr, tcg_rs, tcg_rt,
2598 memidx, memop);
2599}
2600
2601static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
2602 int rn, int size)
2603{
2604 TCGv_i64 s1 = cpu_reg(s, rs);
2605 TCGv_i64 s2 = cpu_reg(s, rs + 1);
2606 TCGv_i64 t1 = cpu_reg(s, rt);
2607 TCGv_i64 t2 = cpu_reg(s, rt + 1);
2608 TCGv_i64 clean_addr;
2609 int memidx = get_mem_index(s);
2610 MemOp memop;
2611
2612 if (rn == 31) {
2613 gen_check_sp_alignment(s);
2614 }
2615
2616
2617 memop = check_atomic_align(s, rn, size + 1);
2618 clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, memop);
2619
2620 if (size == 2) {
2621 TCGv_i64 cmp = tcg_temp_new_i64();
2622 TCGv_i64 val = tcg_temp_new_i64();
2623
2624 if (s->be_data == MO_LE) {
2625 tcg_gen_concat32_i64(val, t1, t2);
2626 tcg_gen_concat32_i64(cmp, s1, s2);
2627 } else {
2628 tcg_gen_concat32_i64(val, t2, t1);
2629 tcg_gen_concat32_i64(cmp, s2, s1);
2630 }
2631
2632 tcg_gen_atomic_cmpxchg_i64(cmp, clean_addr, cmp, val, memidx, memop);
2633
2634 if (s->be_data == MO_LE) {
2635 tcg_gen_extr32_i64(s1, s2, cmp);
2636 } else {
2637 tcg_gen_extr32_i64(s2, s1, cmp);
2638 }
2639 } else {
2640 TCGv_i128 cmp = tcg_temp_new_i128();
2641 TCGv_i128 val = tcg_temp_new_i128();
2642
2643 if (s->be_data == MO_LE) {
2644 tcg_gen_concat_i64_i128(val, t1, t2);
2645 tcg_gen_concat_i64_i128(cmp, s1, s2);
2646 } else {
2647 tcg_gen_concat_i64_i128(val, t2, t1);
2648 tcg_gen_concat_i64_i128(cmp, s2, s1);
2649 }
2650
2651 tcg_gen_atomic_cmpxchg_i128(cmp, clean_addr, cmp, val, memidx, memop);
2652
2653 if (s->be_data == MO_LE) {
2654 tcg_gen_extr_i128_i64(s1, s2, cmp);
2655 } else {
2656 tcg_gen_extr_i128_i64(s2, s1, cmp);
2657 }
2658 }
2659}
2660
2661
2662
2663
2664
2665
2666
2667static bool ldst_iss_sf(int size, bool sign, bool ext)
2668{
2669
2670 if (sign) {
2671
2672
2673
2674
2675
2676 return !ext;
2677 } else {
2678
2679 return size == MO_64;
2680 }
2681}
2682
2683static bool trans_STXR(DisasContext *s, arg_stxr *a)
2684{
2685 if (a->rn == 31) {
2686 gen_check_sp_alignment(s);
2687 }
2688 if (a->lasr) {
2689 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
2690 }
2691 gen_store_exclusive(s, a->rs, a->rt, a->rt2, a->rn, a->sz, false);
2692 return true;
2693}
2694
2695static bool trans_LDXR(DisasContext *s, arg_stxr *a)
2696{
2697 if (a->rn == 31) {
2698 gen_check_sp_alignment(s);
2699 }
2700 gen_load_exclusive(s, a->rt, a->rt2, a->rn, a->sz, false);
2701 if (a->lasr) {
2702 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
2703 }
2704 return true;
2705}
2706
2707static bool trans_STLR(DisasContext *s, arg_stlr *a)
2708{
2709 TCGv_i64 clean_addr;
2710 MemOp memop;
2711 bool iss_sf = ldst_iss_sf(a->sz, false, false);
2712
2713
2714
2715
2716
2717 if (!a->lasr && !dc_isar_feature(aa64_lor, s)) {
2718 return false;
2719 }
2720
2721 if (a->rn == 31) {
2722 gen_check_sp_alignment(s);
2723 }
2724 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
2725 memop = check_ordered_align(s, a->rn, 0, true, a->sz);
2726 clean_addr = gen_mte_check1(s, cpu_reg_sp(s, a->rn),
2727 true, a->rn != 31, memop);
2728 do_gpr_st(s, cpu_reg(s, a->rt), clean_addr, memop, true, a->rt,
2729 iss_sf, a->lasr);
2730 return true;
2731}
2732
2733static bool trans_LDAR(DisasContext *s, arg_stlr *a)
2734{
2735 TCGv_i64 clean_addr;
2736 MemOp memop;
2737 bool iss_sf = ldst_iss_sf(a->sz, false, false);
2738
2739
2740 if (!a->lasr && !dc_isar_feature(aa64_lor, s)) {
2741 return false;
2742 }
2743
2744 if (a->rn == 31) {
2745 gen_check_sp_alignment(s);
2746 }
2747 memop = check_ordered_align(s, a->rn, 0, false, a->sz);
2748 clean_addr = gen_mte_check1(s, cpu_reg_sp(s, a->rn),
2749 false, a->rn != 31, memop);
2750 do_gpr_ld(s, cpu_reg(s, a->rt), clean_addr, memop, false, true,
2751 a->rt, iss_sf, a->lasr);
2752 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
2753 return true;
2754}
2755
2756static bool trans_STXP(DisasContext *s, arg_stxr *a)
2757{
2758 if (a->rn == 31) {
2759 gen_check_sp_alignment(s);
2760 }
2761 if (a->lasr) {
2762 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
2763 }
2764 gen_store_exclusive(s, a->rs, a->rt, a->rt2, a->rn, a->sz, true);
2765 return true;
2766}
2767
2768static bool trans_LDXP(DisasContext *s, arg_stxr *a)
2769{
2770 if (a->rn == 31) {
2771 gen_check_sp_alignment(s);
2772 }
2773 gen_load_exclusive(s, a->rt, a->rt2, a->rn, a->sz, true);
2774 if (a->lasr) {
2775 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
2776 }
2777 return true;
2778}
2779
2780static bool trans_CASP(DisasContext *s, arg_CASP *a)
2781{
2782 if (!dc_isar_feature(aa64_atomics, s)) {
2783 return false;
2784 }
2785 if (((a->rt | a->rs) & 1) != 0) {
2786 return false;
2787 }
2788
2789 gen_compare_and_swap_pair(s, a->rs, a->rt, a->rn, a->sz);
2790 return true;
2791}
2792
2793static bool trans_CAS(DisasContext *s, arg_CAS *a)
2794{
2795 if (!dc_isar_feature(aa64_atomics, s)) {
2796 return false;
2797 }
2798 gen_compare_and_swap(s, a->rs, a->rt, a->rn, a->sz);
2799 return true;
2800}
2801
2802static bool trans_LD_lit(DisasContext *s, arg_ldlit *a)
2803{
2804 bool iss_sf = ldst_iss_sf(a->sz, a->sign, false);
2805 TCGv_i64 tcg_rt = cpu_reg(s, a->rt);
2806 TCGv_i64 clean_addr = tcg_temp_new_i64();
2807 MemOp memop = finalize_memop(s, a->sz + a->sign * MO_SIGN);
2808
2809 gen_pc_plus_diff(s, clean_addr, a->imm);
2810 do_gpr_ld(s, tcg_rt, clean_addr, memop,
2811 false, true, a->rt, iss_sf, false);
2812 return true;
2813}
2814
2815static bool trans_LD_lit_v(DisasContext *s, arg_ldlit *a)
2816{
2817
2818 TCGv_i64 clean_addr;
2819 MemOp memop;
2820
2821 if (!fp_access_check(s)) {
2822 return true;
2823 }
2824 memop = finalize_memop_asimd(s, a->sz);
2825 clean_addr = tcg_temp_new_i64();
2826 gen_pc_plus_diff(s, clean_addr, a->imm);
2827 do_fp_ld(s, a->rt, clean_addr, memop);
2828 return true;
2829}
2830
2831static void op_addr_ldstpair_pre(DisasContext *s, arg_ldstpair *a,
2832 TCGv_i64 *clean_addr, TCGv_i64 *dirty_addr,
2833 uint64_t offset, bool is_store, MemOp mop)
2834{
2835 if (a->rn == 31) {
2836 gen_check_sp_alignment(s);
2837 }
2838
2839 *dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
2840 if (!a->p) {
2841 tcg_gen_addi_i64(*dirty_addr, *dirty_addr, offset);
2842 }
2843
2844 *clean_addr = gen_mte_checkN(s, *dirty_addr, is_store,
2845 (a->w || a->rn != 31), 2 << a->sz, mop);
2846}
2847
2848static void op_addr_ldstpair_post(DisasContext *s, arg_ldstpair *a,
2849 TCGv_i64 dirty_addr, uint64_t offset)
2850{
2851 if (a->w) {
2852 if (a->p) {
2853 tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
2854 }
2855 tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), dirty_addr);
2856 }
2857}
2858
2859static bool trans_STP(DisasContext *s, arg_ldstpair *a)
2860{
2861 uint64_t offset = a->imm << a->sz;
2862 TCGv_i64 clean_addr, dirty_addr, tcg_rt, tcg_rt2;
2863 MemOp mop = finalize_memop(s, a->sz);
2864
2865 op_addr_ldstpair_pre(s, a, &clean_addr, &dirty_addr, offset, true, mop);
2866 tcg_rt = cpu_reg(s, a->rt);
2867 tcg_rt2 = cpu_reg(s, a->rt2);
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878 mop = a->sz + 1;
2879 if (s->align_mem) {
2880 mop |= (a->sz == 2 ? MO_ALIGN_4 : MO_ALIGN_8);
2881 }
2882 mop = finalize_memop_pair(s, mop);
2883 if (a->sz == 2) {
2884 TCGv_i64 tmp = tcg_temp_new_i64();
2885
2886 if (s->be_data == MO_LE) {
2887 tcg_gen_concat32_i64(tmp, tcg_rt, tcg_rt2);
2888 } else {
2889 tcg_gen_concat32_i64(tmp, tcg_rt2, tcg_rt);
2890 }
2891 tcg_gen_qemu_st_i64(tmp, clean_addr, get_mem_index(s), mop);
2892 } else {
2893 TCGv_i128 tmp = tcg_temp_new_i128();
2894
2895 if (s->be_data == MO_LE) {
2896 tcg_gen_concat_i64_i128(tmp, tcg_rt, tcg_rt2);
2897 } else {
2898 tcg_gen_concat_i64_i128(tmp, tcg_rt2, tcg_rt);
2899 }
2900 tcg_gen_qemu_st_i128(tmp, clean_addr, get_mem_index(s), mop);
2901 }
2902 op_addr_ldstpair_post(s, a, dirty_addr, offset);
2903 return true;
2904}
2905
2906static bool trans_LDP(DisasContext *s, arg_ldstpair *a)
2907{
2908 uint64_t offset = a->imm << a->sz;
2909 TCGv_i64 clean_addr, dirty_addr, tcg_rt, tcg_rt2;
2910 MemOp mop = finalize_memop(s, a->sz);
2911
2912 op_addr_ldstpair_pre(s, a, &clean_addr, &dirty_addr, offset, false, mop);
2913 tcg_rt = cpu_reg(s, a->rt);
2914 tcg_rt2 = cpu_reg(s, a->rt2);
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929 mop = a->sz + 1;
2930 if (s->align_mem) {
2931 mop |= (a->sz == 2 ? MO_ALIGN_4 : MO_ALIGN_8);
2932 }
2933 mop = finalize_memop_pair(s, mop);
2934 if (a->sz == 2) {
2935 int o2 = s->be_data == MO_LE ? 32 : 0;
2936 int o1 = o2 ^ 32;
2937
2938 tcg_gen_qemu_ld_i64(tcg_rt, clean_addr, get_mem_index(s), mop);
2939 if (a->sign) {
2940 tcg_gen_sextract_i64(tcg_rt2, tcg_rt, o2, 32);
2941 tcg_gen_sextract_i64(tcg_rt, tcg_rt, o1, 32);
2942 } else {
2943 tcg_gen_extract_i64(tcg_rt2, tcg_rt, o2, 32);
2944 tcg_gen_extract_i64(tcg_rt, tcg_rt, o1, 32);
2945 }
2946 } else {
2947 TCGv_i128 tmp = tcg_temp_new_i128();
2948
2949 tcg_gen_qemu_ld_i128(tmp, clean_addr, get_mem_index(s), mop);
2950 if (s->be_data == MO_LE) {
2951 tcg_gen_extr_i128_i64(tcg_rt, tcg_rt2, tmp);
2952 } else {
2953 tcg_gen_extr_i128_i64(tcg_rt2, tcg_rt, tmp);
2954 }
2955 }
2956 op_addr_ldstpair_post(s, a, dirty_addr, offset);
2957 return true;
2958}
2959
2960static bool trans_STP_v(DisasContext *s, arg_ldstpair *a)
2961{
2962 uint64_t offset = a->imm << a->sz;
2963 TCGv_i64 clean_addr, dirty_addr;
2964 MemOp mop;
2965
2966 if (!fp_access_check(s)) {
2967 return true;
2968 }
2969
2970
2971 mop = finalize_memop_asimd(s, a->sz);
2972 op_addr_ldstpair_pre(s, a, &clean_addr, &dirty_addr, offset, true, mop);
2973 do_fp_st(s, a->rt, clean_addr, mop);
2974 tcg_gen_addi_i64(clean_addr, clean_addr, 1 << a->sz);
2975 do_fp_st(s, a->rt2, clean_addr, mop);
2976 op_addr_ldstpair_post(s, a, dirty_addr, offset);
2977 return true;
2978}
2979
2980static bool trans_LDP_v(DisasContext *s, arg_ldstpair *a)
2981{
2982 uint64_t offset = a->imm << a->sz;
2983 TCGv_i64 clean_addr, dirty_addr;
2984 MemOp mop;
2985
2986 if (!fp_access_check(s)) {
2987 return true;
2988 }
2989
2990
2991 mop = finalize_memop_asimd(s, a->sz);
2992 op_addr_ldstpair_pre(s, a, &clean_addr, &dirty_addr, offset, false, mop);
2993 do_fp_ld(s, a->rt, clean_addr, mop);
2994 tcg_gen_addi_i64(clean_addr, clean_addr, 1 << a->sz);
2995 do_fp_ld(s, a->rt2, clean_addr, mop);
2996 op_addr_ldstpair_post(s, a, dirty_addr, offset);
2997 return true;
2998}
2999
3000static bool trans_STGP(DisasContext *s, arg_ldstpair *a)
3001{
3002 TCGv_i64 clean_addr, dirty_addr, tcg_rt, tcg_rt2;
3003 uint64_t offset = a->imm << LOG2_TAG_GRANULE;
3004 MemOp mop;
3005 TCGv_i128 tmp;
3006
3007
3008 tcg_debug_assert(a->sz == MO_64);
3009
3010 if (!dc_isar_feature(aa64_mte_insn_reg, s)) {
3011 return false;
3012 }
3013
3014 if (a->rn == 31) {
3015 gen_check_sp_alignment(s);
3016 }
3017
3018 dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
3019 if (!a->p) {
3020 tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
3021 }
3022
3023 if (!s->ata) {
3024
3025
3026
3027
3028 gen_helper_stg_stub(cpu_env, dirty_addr);
3029 } else if (tb_cflags(s->base.tb) & CF_PARALLEL) {
3030 gen_helper_stg_parallel(cpu_env, dirty_addr, dirty_addr);
3031 } else {
3032 gen_helper_stg(cpu_env, dirty_addr, dirty_addr);
3033 }
3034
3035 mop = finalize_memop(s, MO_64);
3036 clean_addr = gen_mte_checkN(s, dirty_addr, true, false, 2 << MO_64, mop);
3037
3038 tcg_rt = cpu_reg(s, a->rt);
3039 tcg_rt2 = cpu_reg(s, a->rt2);
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049 mop = MO_128;
3050 if (s->align_mem) {
3051 mop |= MO_ALIGN_8;
3052 }
3053 mop = finalize_memop_pair(s, mop);
3054
3055 tmp = tcg_temp_new_i128();
3056 if (s->be_data == MO_LE) {
3057 tcg_gen_concat_i64_i128(tmp, tcg_rt, tcg_rt2);
3058 } else {
3059 tcg_gen_concat_i64_i128(tmp, tcg_rt2, tcg_rt);
3060 }
3061 tcg_gen_qemu_st_i128(tmp, clean_addr, get_mem_index(s), mop);
3062
3063 op_addr_ldstpair_post(s, a, dirty_addr, offset);
3064 return true;
3065}
3066
3067static void op_addr_ldst_imm_pre(DisasContext *s, arg_ldst_imm *a,
3068 TCGv_i64 *clean_addr, TCGv_i64 *dirty_addr,
3069 uint64_t offset, bool is_store, MemOp mop)
3070{
3071 int memidx;
3072
3073 if (a->rn == 31) {
3074 gen_check_sp_alignment(s);
3075 }
3076
3077 *dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
3078 if (!a->p) {
3079 tcg_gen_addi_i64(*dirty_addr, *dirty_addr, offset);
3080 }
3081 memidx = a->unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
3082 *clean_addr = gen_mte_check1_mmuidx(s, *dirty_addr, is_store,
3083 a->w || a->rn != 31,
3084 mop, a->unpriv, memidx);
3085}
3086
3087static void op_addr_ldst_imm_post(DisasContext *s, arg_ldst_imm *a,
3088 TCGv_i64 dirty_addr, uint64_t offset)
3089{
3090 if (a->w) {
3091 if (a->p) {
3092 tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
3093 }
3094 tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), dirty_addr);
3095 }
3096}
3097
3098static bool trans_STR_i(DisasContext *s, arg_ldst_imm *a)
3099{
3100 bool iss_sf, iss_valid = !a->w;
3101 TCGv_i64 clean_addr, dirty_addr, tcg_rt;
3102 int memidx = a->unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
3103 MemOp mop = finalize_memop(s, a->sz + a->sign * MO_SIGN);
3104
3105 op_addr_ldst_imm_pre(s, a, &clean_addr, &dirty_addr, a->imm, true, mop);
3106
3107 tcg_rt = cpu_reg(s, a->rt);
3108 iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
3109
3110 do_gpr_st_memidx(s, tcg_rt, clean_addr, mop, memidx,
3111 iss_valid, a->rt, iss_sf, false);
3112 op_addr_ldst_imm_post(s, a, dirty_addr, a->imm);
3113 return true;
3114}
3115
3116static bool trans_LDR_i(DisasContext *s, arg_ldst_imm *a)
3117{
3118 bool iss_sf, iss_valid = !a->w;
3119 TCGv_i64 clean_addr, dirty_addr, tcg_rt;
3120 int memidx = a->unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
3121 MemOp mop = finalize_memop(s, a->sz + a->sign * MO_SIGN);
3122
3123 op_addr_ldst_imm_pre(s, a, &clean_addr, &dirty_addr, a->imm, false, mop);
3124
3125 tcg_rt = cpu_reg(s, a->rt);
3126 iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
3127
3128 do_gpr_ld_memidx(s, tcg_rt, clean_addr, mop,
3129 a->ext, memidx, iss_valid, a->rt, iss_sf, false);
3130 op_addr_ldst_imm_post(s, a, dirty_addr, a->imm);
3131 return true;
3132}
3133
3134static bool trans_STR_v_i(DisasContext *s, arg_ldst_imm *a)
3135{
3136 TCGv_i64 clean_addr, dirty_addr;
3137 MemOp mop;
3138
3139 if (!fp_access_check(s)) {
3140 return true;
3141 }
3142 mop = finalize_memop_asimd(s, a->sz);
3143 op_addr_ldst_imm_pre(s, a, &clean_addr, &dirty_addr, a->imm, true, mop);
3144 do_fp_st(s, a->rt, clean_addr, mop);
3145 op_addr_ldst_imm_post(s, a, dirty_addr, a->imm);
3146 return true;
3147}
3148
3149static bool trans_LDR_v_i(DisasContext *s, arg_ldst_imm *a)
3150{
3151 TCGv_i64 clean_addr, dirty_addr;
3152 MemOp mop;
3153
3154 if (!fp_access_check(s)) {
3155 return true;
3156 }
3157 mop = finalize_memop_asimd(s, a->sz);
3158 op_addr_ldst_imm_pre(s, a, &clean_addr, &dirty_addr, a->imm, false, mop);
3159 do_fp_ld(s, a->rt, clean_addr, mop);
3160 op_addr_ldst_imm_post(s, a, dirty_addr, a->imm);
3161 return true;
3162}
3163
3164static void op_addr_ldst_pre(DisasContext *s, arg_ldst *a,
3165 TCGv_i64 *clean_addr, TCGv_i64 *dirty_addr,
3166 bool is_store, MemOp memop)
3167{
3168 TCGv_i64 tcg_rm;
3169
3170 if (a->rn == 31) {
3171 gen_check_sp_alignment(s);
3172 }
3173 *dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
3174
3175 tcg_rm = read_cpu_reg(s, a->rm, 1);
3176 ext_and_shift_reg(tcg_rm, tcg_rm, a->opt, a->s ? a->sz : 0);
3177
3178 tcg_gen_add_i64(*dirty_addr, *dirty_addr, tcg_rm);
3179 *clean_addr = gen_mte_check1(s, *dirty_addr, is_store, true, memop);
3180}
3181
3182static bool trans_LDR(DisasContext *s, arg_ldst *a)
3183{
3184 TCGv_i64 clean_addr, dirty_addr, tcg_rt;
3185 bool iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
3186 MemOp memop;
3187
3188 if (extract32(a->opt, 1, 1) == 0) {
3189 return false;
3190 }
3191
3192 memop = finalize_memop(s, a->sz + a->sign * MO_SIGN);
3193 op_addr_ldst_pre(s, a, &clean_addr, &dirty_addr, false, memop);
3194 tcg_rt = cpu_reg(s, a->rt);
3195 do_gpr_ld(s, tcg_rt, clean_addr, memop,
3196 a->ext, true, a->rt, iss_sf, false);
3197 return true;
3198}
3199
3200static bool trans_STR(DisasContext *s, arg_ldst *a)
3201{
3202 TCGv_i64 clean_addr, dirty_addr, tcg_rt;
3203 bool iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
3204 MemOp memop;
3205
3206 if (extract32(a->opt, 1, 1) == 0) {
3207 return false;
3208 }
3209
3210 memop = finalize_memop(s, a->sz);
3211 op_addr_ldst_pre(s, a, &clean_addr, &dirty_addr, true, memop);
3212 tcg_rt = cpu_reg(s, a->rt);
3213 do_gpr_st(s, tcg_rt, clean_addr, memop, true, a->rt, iss_sf, false);
3214 return true;
3215}
3216
3217static bool trans_LDR_v(DisasContext *s, arg_ldst *a)
3218{
3219 TCGv_i64 clean_addr, dirty_addr;
3220 MemOp memop;
3221
3222 if (extract32(a->opt, 1, 1) == 0) {
3223 return false;
3224 }
3225
3226 if (!fp_access_check(s)) {
3227 return true;
3228 }
3229
3230 memop = finalize_memop_asimd(s, a->sz);
3231 op_addr_ldst_pre(s, a, &clean_addr, &dirty_addr, false, memop);
3232 do_fp_ld(s, a->rt, clean_addr, memop);
3233 return true;
3234}
3235
3236static bool trans_STR_v(DisasContext *s, arg_ldst *a)
3237{
3238 TCGv_i64 clean_addr, dirty_addr;
3239 MemOp memop;
3240
3241 if (extract32(a->opt, 1, 1) == 0) {
3242 return false;
3243 }
3244
3245 if (!fp_access_check(s)) {
3246 return true;
3247 }
3248
3249 memop = finalize_memop_asimd(s, a->sz);
3250 op_addr_ldst_pre(s, a, &clean_addr, &dirty_addr, true, memop);
3251 do_fp_st(s, a->rt, clean_addr, memop);
3252 return true;
3253}
3254
3255
3256static bool do_atomic_ld(DisasContext *s, arg_atomic *a, AtomicThreeOpFn *fn,
3257 int sign, bool invert)
3258{
3259 MemOp mop = a->sz | sign;
3260 TCGv_i64 clean_addr, tcg_rs, tcg_rt;
3261
3262 if (a->rn == 31) {
3263 gen_check_sp_alignment(s);
3264 }
3265 mop = check_atomic_align(s, a->rn, mop);
3266 clean_addr = gen_mte_check1(s, cpu_reg_sp(s, a->rn), false,
3267 a->rn != 31, mop);
3268 tcg_rs = read_cpu_reg(s, a->rs, true);
3269 tcg_rt = cpu_reg(s, a->rt);
3270 if (invert) {
3271 tcg_gen_not_i64(tcg_rs, tcg_rs);
3272 }
3273
3274
3275
3276
3277 fn(tcg_rt, clean_addr, tcg_rs, get_mem_index(s), mop);
3278
3279 if (mop & MO_SIGN) {
3280 switch (a->sz) {
3281 case MO_8:
3282 tcg_gen_ext8u_i64(tcg_rt, tcg_rt);
3283 break;
3284 case MO_16:
3285 tcg_gen_ext16u_i64(tcg_rt, tcg_rt);
3286 break;
3287 case MO_32:
3288 tcg_gen_ext32u_i64(tcg_rt, tcg_rt);
3289 break;
3290 case MO_64:
3291 break;
3292 default:
3293 g_assert_not_reached();
3294 }
3295 }
3296 return true;
3297}
3298
3299TRANS_FEAT(LDADD, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_add_i64, 0, false)
3300TRANS_FEAT(LDCLR, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_and_i64, 0, true)
3301TRANS_FEAT(LDEOR, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_xor_i64, 0, false)
3302TRANS_FEAT(LDSET, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_or_i64, 0, false)
3303TRANS_FEAT(LDSMAX, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_smax_i64, MO_SIGN, false)
3304TRANS_FEAT(LDSMIN, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_smin_i64, MO_SIGN, false)
3305TRANS_FEAT(LDUMAX, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_umax_i64, 0, false)
3306TRANS_FEAT(LDUMIN, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_fetch_umin_i64, 0, false)
3307TRANS_FEAT(SWP, aa64_atomics, do_atomic_ld, a, tcg_gen_atomic_xchg_i64, 0, false)
3308
3309static bool trans_LDAPR(DisasContext *s, arg_LDAPR *a)
3310{
3311 bool iss_sf = ldst_iss_sf(a->sz, false, false);
3312 TCGv_i64 clean_addr;
3313 MemOp mop;
3314
3315 if (!dc_isar_feature(aa64_atomics, s) ||
3316 !dc_isar_feature(aa64_rcpc_8_3, s)) {
3317 return false;
3318 }
3319 if (a->rn == 31) {
3320 gen_check_sp_alignment(s);
3321 }
3322 mop = check_atomic_align(s, a->rn, a->sz);
3323 clean_addr = gen_mte_check1(s, cpu_reg_sp(s, a->rn), false,
3324 a->rn != 31, mop);
3325
3326
3327
3328
3329
3330
3331
3332 do_gpr_ld(s, cpu_reg(s, a->rt), clean_addr, mop, false,
3333 true, a->rt, iss_sf, true);
3334 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
3335 return true;
3336}
3337
3338static bool trans_LDRA(DisasContext *s, arg_LDRA *a)
3339{
3340 TCGv_i64 clean_addr, dirty_addr, tcg_rt;
3341 MemOp memop;
3342
3343
3344 if (!dc_isar_feature(aa64_pauth, s)) {
3345 return false;
3346 }
3347
3348 if (a->rn == 31) {
3349 gen_check_sp_alignment(s);
3350 }
3351 dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
3352
3353 if (s->pauth_active) {
3354 if (!a->m) {
3355 gen_helper_autda(dirty_addr, cpu_env, dirty_addr,
3356 tcg_constant_i64(0));
3357 } else {
3358 gen_helper_autdb(dirty_addr, cpu_env, dirty_addr,
3359 tcg_constant_i64(0));
3360 }
3361 }
3362
3363 tcg_gen_addi_i64(dirty_addr, dirty_addr, a->imm);
3364
3365 memop = finalize_memop(s, MO_64);
3366
3367
3368 clean_addr = gen_mte_check1(s, dirty_addr, false,
3369 a->w || a->rn != 31, memop);
3370
3371 tcg_rt = cpu_reg(s, a->rt);
3372 do_gpr_ld(s, tcg_rt, clean_addr, memop,
3373 false, !a->w,
3374 a->rt, true, false);
3375
3376 if (a->w) {
3377 tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), dirty_addr);
3378 }
3379 return true;
3380}
3381
3382static bool trans_LDAPR_i(DisasContext *s, arg_ldapr_stlr_i *a)
3383{
3384 TCGv_i64 clean_addr, dirty_addr;
3385 MemOp mop = a->sz | (a->sign ? MO_SIGN : 0);
3386 bool iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
3387
3388 if (!dc_isar_feature(aa64_rcpc_8_4, s)) {
3389 return false;
3390 }
3391
3392 if (a->rn == 31) {
3393 gen_check_sp_alignment(s);
3394 }
3395
3396 mop = check_ordered_align(s, a->rn, a->imm, false, mop);
3397 dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
3398 tcg_gen_addi_i64(dirty_addr, dirty_addr, a->imm);
3399 clean_addr = clean_data_tbi(s, dirty_addr);
3400
3401
3402
3403
3404
3405 do_gpr_ld(s, cpu_reg(s, a->rt), clean_addr, mop, a->ext, true,
3406 a->rt, iss_sf, true);
3407 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
3408 return true;
3409}
3410
3411static bool trans_STLR_i(DisasContext *s, arg_ldapr_stlr_i *a)
3412{
3413 TCGv_i64 clean_addr, dirty_addr;
3414 MemOp mop = a->sz;
3415 bool iss_sf = ldst_iss_sf(a->sz, a->sign, a->ext);
3416
3417 if (!dc_isar_feature(aa64_rcpc_8_4, s)) {
3418 return false;
3419 }
3420
3421
3422
3423 if (a->rn == 31) {
3424 gen_check_sp_alignment(s);
3425 }
3426
3427 mop = check_ordered_align(s, a->rn, a->imm, true, mop);
3428 dirty_addr = read_cpu_reg_sp(s, a->rn, 1);
3429 tcg_gen_addi_i64(dirty_addr, dirty_addr, a->imm);
3430 clean_addr = clean_data_tbi(s, dirty_addr);
3431
3432
3433 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
3434 do_gpr_st(s, cpu_reg(s, a->rt), clean_addr, mop, true, a->rt, iss_sf, true);
3435 return true;
3436}
3437
3438static bool trans_LD_mult(DisasContext *s, arg_ldst_mult *a)
3439{
3440 TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
3441 MemOp endian, align, mop;
3442
3443 int total;
3444 int elements;
3445 int r;
3446 int size = a->sz;
3447
3448 if (!a->p && a->rm != 0) {
3449
3450 return false;
3451 }
3452 if (size == 3 && !a->q && a->selem != 1) {
3453 return false;
3454 }
3455 if (!fp_access_check(s)) {
3456 return true;
3457 }
3458
3459 if (a->rn == 31) {
3460 gen_check_sp_alignment(s);
3461 }
3462
3463
3464 endian = s->be_data;
3465 if (size == 0) {
3466 endian = MO_LE;
3467 }
3468
3469 total = a->rpt * a->selem * (a->q ? 16 : 8);
3470 tcg_rn = cpu_reg_sp(s, a->rn);
3471
3472
3473
3474
3475
3476 clean_addr = gen_mte_checkN(s, tcg_rn, false, a->p || a->rn != 31, total,
3477 finalize_memop_asimd(s, size));
3478
3479
3480
3481
3482
3483 align = MO_ALIGN;
3484 if (a->selem == 1 && endian == MO_LE) {
3485 align = pow2_align(size);
3486 size = 3;
3487 }
3488 if (!s->align_mem) {
3489 align = 0;
3490 }
3491 mop = endian | size | align;
3492
3493 elements = (a->q ? 16 : 8) >> size;
3494 tcg_ebytes = tcg_constant_i64(1 << size);
3495 for (r = 0; r < a->rpt; r++) {
3496 int e;
3497 for (e = 0; e < elements; e++) {
3498 int xs;
3499 for (xs = 0; xs < a->selem; xs++) {
3500 int tt = (a->rt + r + xs) % 32;
3501 do_vec_ld(s, tt, e, clean_addr, mop);
3502 tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
3503 }
3504 }
3505 }
3506
3507
3508
3509
3510
3511
3512
3513
3514 for (r = 0; r < a->rpt * a->selem; r++) {
3515 int tt = (a->rt + r) % 32;
3516 clear_vec_high(s, a->q, tt);
3517 }
3518
3519 if (a->p) {
3520 if (a->rm == 31) {
3521 tcg_gen_addi_i64(tcg_rn, tcg_rn, total);
3522 } else {
3523 tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, a->rm));
3524 }
3525 }
3526 return true;
3527}
3528
3529static bool trans_ST_mult(DisasContext *s, arg_ldst_mult *a)
3530{
3531 TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
3532 MemOp endian, align, mop;
3533
3534 int total;
3535 int elements;
3536 int r;
3537 int size = a->sz;
3538
3539 if (!a->p && a->rm != 0) {
3540
3541 return false;
3542 }
3543 if (size == 3 && !a->q && a->selem != 1) {
3544 return false;
3545 }
3546 if (!fp_access_check(s)) {
3547 return true;
3548 }
3549
3550 if (a->rn == 31) {
3551 gen_check_sp_alignment(s);
3552 }
3553
3554
3555 endian = s->be_data;
3556 if (size == 0) {
3557 endian = MO_LE;
3558 }
3559
3560 total = a->rpt * a->selem * (a->q ? 16 : 8);
3561 tcg_rn = cpu_reg_sp(s, a->rn);
3562
3563
3564
3565
3566
3567 clean_addr = gen_mte_checkN(s, tcg_rn, true, a->p || a->rn != 31, total,
3568 finalize_memop_asimd(s, size));
3569
3570
3571
3572
3573
3574 align = MO_ALIGN;
3575 if (a->selem == 1 && endian == MO_LE) {
3576 align = pow2_align(size);
3577 size = 3;
3578 }
3579 if (!s->align_mem) {
3580 align = 0;
3581 }
3582 mop = endian | size | align;
3583
3584 elements = (a->q ? 16 : 8) >> size;
3585 tcg_ebytes = tcg_constant_i64(1 << size);
3586 for (r = 0; r < a->rpt; r++) {
3587 int e;
3588 for (e = 0; e < elements; e++) {
3589 int xs;
3590 for (xs = 0; xs < a->selem; xs++) {
3591 int tt = (a->rt + r + xs) % 32;
3592 do_vec_st(s, tt, e, clean_addr, mop);
3593 tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
3594 }
3595 }
3596 }
3597
3598 if (a->p) {
3599 if (a->rm == 31) {
3600 tcg_gen_addi_i64(tcg_rn, tcg_rn, total);
3601 } else {
3602 tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, a->rm));
3603 }
3604 }
3605 return true;
3606}
3607
3608static bool trans_ST_single(DisasContext *s, arg_ldst_single *a)
3609{
3610 int xs, total, rt;
3611 TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
3612 MemOp mop;
3613
3614 if (!a->p && a->rm != 0) {
3615 return false;
3616 }
3617 if (!fp_access_check(s)) {
3618 return true;
3619 }
3620
3621 if (a->rn == 31) {
3622 gen_check_sp_alignment(s);
3623 }
3624
3625 total = a->selem << a->scale;
3626 tcg_rn = cpu_reg_sp(s, a->rn);
3627
3628 mop = finalize_memop_asimd(s, a->scale);
3629 clean_addr = gen_mte_checkN(s, tcg_rn, true, a->p || a->rn != 31,
3630 total, mop);
3631
3632 tcg_ebytes = tcg_constant_i64(1 << a->scale);
3633 for (xs = 0, rt = a->rt; xs < a->selem; xs++, rt = (rt + 1) % 32) {
3634 do_vec_st(s, rt, a->index, clean_addr, mop);
3635 tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
3636 }
3637
3638 if (a->p) {
3639 if (a->rm == 31) {
3640 tcg_gen_addi_i64(tcg_rn, tcg_rn, total);
3641 } else {
3642 tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, a->rm));
3643 }
3644 }
3645 return true;
3646}
3647
3648static bool trans_LD_single(DisasContext *s, arg_ldst_single *a)
3649{
3650 int xs, total, rt;
3651 TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
3652 MemOp mop;
3653
3654 if (!a->p && a->rm != 0) {
3655 return false;
3656 }
3657 if (!fp_access_check(s)) {
3658 return true;
3659 }
3660
3661 if (a->rn == 31) {
3662 gen_check_sp_alignment(s);
3663 }
3664
3665 total = a->selem << a->scale;
3666 tcg_rn = cpu_reg_sp(s, a->rn);
3667
3668 mop = finalize_memop_asimd(s, a->scale);
3669 clean_addr = gen_mte_checkN(s, tcg_rn, false, a->p || a->rn != 31,
3670 total, mop);
3671
3672 tcg_ebytes = tcg_constant_i64(1 << a->scale);
3673 for (xs = 0, rt = a->rt; xs < a->selem; xs++, rt = (rt + 1) % 32) {
3674 do_vec_ld(s, rt, a->index, clean_addr, mop);
3675 tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
3676 }
3677
3678 if (a->p) {
3679 if (a->rm == 31) {
3680 tcg_gen_addi_i64(tcg_rn, tcg_rn, total);
3681 } else {
3682 tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, a->rm));
3683 }
3684 }
3685 return true;
3686}
3687
3688static bool trans_LD_single_repl(DisasContext *s, arg_LD_single_repl *a)
3689{
3690 int xs, total, rt;
3691 TCGv_i64 clean_addr, tcg_rn, tcg_ebytes;
3692 MemOp mop;
3693
3694 if (!a->p && a->rm != 0) {
3695 return false;
3696 }
3697 if (!fp_access_check(s)) {
3698 return true;
3699 }
3700
3701 if (a->rn == 31) {
3702 gen_check_sp_alignment(s);
3703 }
3704
3705 total = a->selem << a->scale;
3706 tcg_rn = cpu_reg_sp(s, a->rn);
3707
3708 mop = finalize_memop_asimd(s, a->scale);
3709 clean_addr = gen_mte_checkN(s, tcg_rn, false, a->p || a->rn != 31,
3710 total, mop);
3711
3712 tcg_ebytes = tcg_constant_i64(1 << a->scale);
3713 for (xs = 0, rt = a->rt; xs < a->selem; xs++, rt = (rt + 1) % 32) {
3714
3715 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
3716
3717 tcg_gen_qemu_ld_i64(tcg_tmp, clean_addr, get_mem_index(s), mop);
3718 tcg_gen_gvec_dup_i64(a->scale, vec_full_reg_offset(s, rt),
3719 (a->q + 1) * 8, vec_full_reg_size(s), tcg_tmp);
3720 tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes);
3721 }
3722
3723 if (a->p) {
3724 if (a->rm == 31) {
3725 tcg_gen_addi_i64(tcg_rn, tcg_rn, total);
3726 } else {
3727 tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, a->rm));
3728 }
3729 }
3730 return true;
3731}
3732
3733static bool trans_STZGM(DisasContext *s, arg_ldst_tag *a)
3734{
3735 TCGv_i64 addr, clean_addr, tcg_rt;
3736 int size = 4 << s->dcz_blocksize;
3737
3738 if (!dc_isar_feature(aa64_mte, s)) {
3739 return false;
3740 }
3741 if (s->current_el == 0) {
3742 return false;
3743 }
3744
3745 if (a->rn == 31) {
3746 gen_check_sp_alignment(s);
3747 }
3748
3749 addr = read_cpu_reg_sp(s, a->rn, true);
3750 tcg_gen_addi_i64(addr, addr, a->imm);
3751 tcg_rt = cpu_reg(s, a->rt);
3752
3753 if (s->ata) {
3754 gen_helper_stzgm_tags(cpu_env, addr, tcg_rt);
3755 }
3756
3757
3758
3759
3760 clean_addr = clean_data_tbi(s, addr);
3761 tcg_gen_andi_i64(clean_addr, clean_addr, -size);
3762 gen_helper_dc_zva(cpu_env, clean_addr);
3763 return true;
3764}
3765
3766static bool trans_STGM(DisasContext *s, arg_ldst_tag *a)
3767{
3768 TCGv_i64 addr, clean_addr, tcg_rt;
3769
3770 if (!dc_isar_feature(aa64_mte, s)) {
3771 return false;
3772 }
3773 if (s->current_el == 0) {
3774 return false;
3775 }
3776
3777 if (a->rn == 31) {
3778 gen_check_sp_alignment(s);
3779 }
3780
3781 addr = read_cpu_reg_sp(s, a->rn, true);
3782 tcg_gen_addi_i64(addr, addr, a->imm);
3783 tcg_rt = cpu_reg(s, a->rt);
3784
3785 if (s->ata) {
3786 gen_helper_stgm(cpu_env, addr, tcg_rt);
3787 } else {
3788 MMUAccessType acc = MMU_DATA_STORE;
3789 int size = 4 << GMID_EL1_BS;
3790
3791 clean_addr = clean_data_tbi(s, addr);
3792 tcg_gen_andi_i64(clean_addr, clean_addr, -size);
3793 gen_probe_access(s, clean_addr, acc, size);
3794 }
3795 return true;
3796}
3797
3798static bool trans_LDGM(DisasContext *s, arg_ldst_tag *a)
3799{
3800 TCGv_i64 addr, clean_addr, tcg_rt;
3801
3802 if (!dc_isar_feature(aa64_mte, s)) {
3803 return false;
3804 }
3805 if (s->current_el == 0) {
3806 return false;
3807 }
3808
3809 if (a->rn == 31) {
3810 gen_check_sp_alignment(s);
3811 }
3812
3813 addr = read_cpu_reg_sp(s, a->rn, true);
3814 tcg_gen_addi_i64(addr, addr, a->imm);
3815 tcg_rt = cpu_reg(s, a->rt);
3816
3817 if (s->ata) {
3818 gen_helper_ldgm(tcg_rt, cpu_env, addr);
3819 } else {
3820 MMUAccessType acc = MMU_DATA_LOAD;
3821 int size = 4 << GMID_EL1_BS;
3822
3823 clean_addr = clean_data_tbi(s, addr);
3824 tcg_gen_andi_i64(clean_addr, clean_addr, -size);
3825 gen_probe_access(s, clean_addr, acc, size);
3826
3827 tcg_gen_movi_i64(tcg_rt, 0);
3828 }
3829 return true;
3830}
3831
3832static bool trans_LDG(DisasContext *s, arg_ldst_tag *a)
3833{
3834 TCGv_i64 addr, clean_addr, tcg_rt;
3835
3836 if (!dc_isar_feature(aa64_mte_insn_reg, s)) {
3837 return false;
3838 }
3839
3840 if (a->rn == 31) {
3841 gen_check_sp_alignment(s);
3842 }
3843
3844 addr = read_cpu_reg_sp(s, a->rn, true);
3845 if (!a->p) {
3846
3847 tcg_gen_addi_i64(addr, addr, a->imm);
3848 }
3849
3850 tcg_gen_andi_i64(addr, addr, -TAG_GRANULE);
3851 tcg_rt = cpu_reg(s, a->rt);
3852 if (s->ata) {
3853 gen_helper_ldg(tcg_rt, cpu_env, addr, tcg_rt);
3854 } else {
3855
3856
3857
3858
3859 clean_addr = clean_data_tbi(s, addr);
3860 gen_probe_access(s, clean_addr, MMU_DATA_LOAD, MO_8);
3861 gen_address_with_allocation_tag0(tcg_rt, tcg_rt);
3862 }
3863
3864 if (a->w) {
3865
3866 if (a->p) {
3867
3868 tcg_gen_addi_i64(addr, addr, a->imm);
3869 }
3870 tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), addr);
3871 }
3872 return true;
3873}
3874
3875static bool do_STG(DisasContext *s, arg_ldst_tag *a, bool is_zero, bool is_pair)
3876{
3877 TCGv_i64 addr, tcg_rt;
3878
3879 if (a->rn == 31) {
3880 gen_check_sp_alignment(s);
3881 }
3882
3883 addr = read_cpu_reg_sp(s, a->rn, true);
3884 if (!a->p) {
3885
3886 tcg_gen_addi_i64(addr, addr, a->imm);
3887 }
3888 tcg_rt = cpu_reg_sp(s, a->rt);
3889 if (!s->ata) {
3890
3891
3892
3893
3894
3895 if (is_pair) {
3896 gen_helper_st2g_stub(cpu_env, addr);
3897 } else {
3898 gen_helper_stg_stub(cpu_env, addr);
3899 }
3900 } else if (tb_cflags(s->base.tb) & CF_PARALLEL) {
3901 if (is_pair) {
3902 gen_helper_st2g_parallel(cpu_env, addr, tcg_rt);
3903 } else {
3904 gen_helper_stg_parallel(cpu_env, addr, tcg_rt);
3905 }
3906 } else {
3907 if (is_pair) {
3908 gen_helper_st2g(cpu_env, addr, tcg_rt);
3909 } else {
3910 gen_helper_stg(cpu_env, addr, tcg_rt);
3911 }
3912 }
3913
3914 if (is_zero) {
3915 TCGv_i64 clean_addr = clean_data_tbi(s, addr);
3916 TCGv_i64 zero64 = tcg_constant_i64(0);
3917 TCGv_i128 zero128 = tcg_temp_new_i128();
3918 int mem_index = get_mem_index(s);
3919 MemOp mop = finalize_memop(s, MO_128 | MO_ALIGN);
3920
3921 tcg_gen_concat_i64_i128(zero128, zero64, zero64);
3922
3923
3924 tcg_gen_qemu_st_i128(zero128, clean_addr, mem_index, mop);
3925 if (is_pair) {
3926 tcg_gen_addi_i64(clean_addr, clean_addr, 16);
3927 tcg_gen_qemu_st_i128(zero128, clean_addr, mem_index, mop);
3928 }
3929 }
3930
3931 if (a->w) {
3932
3933 if (a->p) {
3934
3935 tcg_gen_addi_i64(addr, addr, a->imm);
3936 }
3937 tcg_gen_mov_i64(cpu_reg_sp(s, a->rn), addr);
3938 }
3939 return true;
3940}
3941
3942TRANS_FEAT(STG, aa64_mte_insn_reg, do_STG, a, false, false)
3943TRANS_FEAT(STZG, aa64_mte_insn_reg, do_STG, a, true, false)
3944TRANS_FEAT(ST2G, aa64_mte_insn_reg, do_STG, a, false, true)
3945TRANS_FEAT(STZ2G, aa64_mte_insn_reg, do_STG, a, true, true)
3946
3947typedef void ArithTwoOp(TCGv_i64, TCGv_i64, TCGv_i64);
3948
3949static bool gen_rri(DisasContext *s, arg_rri_sf *a,
3950 bool rd_sp, bool rn_sp, ArithTwoOp *fn)
3951{
3952 TCGv_i64 tcg_rn = rn_sp ? cpu_reg_sp(s, a->rn) : cpu_reg(s, a->rn);
3953 TCGv_i64 tcg_rd = rd_sp ? cpu_reg_sp(s, a->rd) : cpu_reg(s, a->rd);
3954 TCGv_i64 tcg_imm = tcg_constant_i64(a->imm);
3955
3956 fn(tcg_rd, tcg_rn, tcg_imm);
3957 if (!a->sf) {
3958 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
3959 }
3960 return true;
3961}
3962
3963
3964
3965
3966
3967static bool trans_ADR(DisasContext *s, arg_ri *a)
3968{
3969 gen_pc_plus_diff(s, cpu_reg(s, a->rd), a->imm);
3970 return true;
3971}
3972
3973static bool trans_ADRP(DisasContext *s, arg_ri *a)
3974{
3975 int64_t offset = (int64_t)a->imm << 12;
3976
3977
3978 offset -= s->pc_curr & 0xfff;
3979 gen_pc_plus_diff(s, cpu_reg(s, a->rd), offset);
3980 return true;
3981}
3982
3983
3984
3985
3986TRANS(ADD_i, gen_rri, a, 1, 1, tcg_gen_add_i64)
3987TRANS(SUB_i, gen_rri, a, 1, 1, tcg_gen_sub_i64)
3988TRANS(ADDS_i, gen_rri, a, 0, 1, a->sf ? gen_add64_CC : gen_add32_CC)
3989TRANS(SUBS_i, gen_rri, a, 0, 1, a->sf ? gen_sub64_CC : gen_sub32_CC)
3990
3991
3992
3993
3994
3995static bool gen_add_sub_imm_with_tags(DisasContext *s, arg_rri_tag *a,
3996 bool sub_op)
3997{
3998 TCGv_i64 tcg_rn, tcg_rd;
3999 int imm;
4000
4001 imm = a->uimm6 << LOG2_TAG_GRANULE;
4002 if (sub_op) {
4003 imm = -imm;
4004 }
4005
4006 tcg_rn = cpu_reg_sp(s, a->rn);
4007 tcg_rd = cpu_reg_sp(s, a->rd);
4008
4009 if (s->ata) {
4010 gen_helper_addsubg(tcg_rd, cpu_env, tcg_rn,
4011 tcg_constant_i32(imm),
4012 tcg_constant_i32(a->uimm4));
4013 } else {
4014 tcg_gen_addi_i64(tcg_rd, tcg_rn, imm);
4015 gen_address_with_allocation_tag0(tcg_rd, tcg_rd);
4016 }
4017 return true;
4018}
4019
4020TRANS_FEAT(ADDG_i, aa64_mte_insn_reg, gen_add_sub_imm_with_tags, a, false)
4021TRANS_FEAT(SUBG_i, aa64_mte_insn_reg, gen_add_sub_imm_with_tags, a, true)
4022
4023
4024
4025
4026
4027static uint64_t bitfield_replicate(uint64_t mask, unsigned int e)
4028{
4029 assert(e != 0);
4030 while (e < 64) {
4031 mask |= mask << e;
4032 e *= 2;
4033 }
4034 return mask;
4035}
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
4048 unsigned int imms, unsigned int immr)
4049{
4050 uint64_t mask;
4051 unsigned e, levels, s, r;
4052 int len;
4053
4054 assert(immn < 2 && imms < 64 && immr < 64);
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078 len = 31 - clz32((immn << 6) | (~imms & 0x3f));
4079 if (len < 1) {
4080
4081 return false;
4082 }
4083 e = 1 << len;
4084
4085 levels = e - 1;
4086 s = imms & levels;
4087 r = immr & levels;
4088
4089 if (s == levels) {
4090
4091 return false;
4092 }
4093
4094
4095
4096
4097 mask = MAKE_64BIT_MASK(0, s + 1);
4098 if (r) {
4099 mask = (mask >> r) | (mask << (e - r));
4100 mask &= MAKE_64BIT_MASK(0, e);
4101 }
4102
4103 mask = bitfield_replicate(mask, e);
4104 *result = mask;
4105 return true;
4106}
4107
4108static bool gen_rri_log(DisasContext *s, arg_rri_log *a, bool set_cc,
4109 void (*fn)(TCGv_i64, TCGv_i64, int64_t))
4110{
4111 TCGv_i64 tcg_rd, tcg_rn;
4112 uint64_t imm;
4113
4114
4115 if (!logic_imm_decode_wmask(&imm, extract32(a->dbm, 12, 1),
4116 extract32(a->dbm, 0, 6),
4117 extract32(a->dbm, 6, 6))) {
4118 return false;
4119 }
4120 if (!a->sf) {
4121 imm &= 0xffffffffull;
4122 }
4123
4124 tcg_rd = set_cc ? cpu_reg(s, a->rd) : cpu_reg_sp(s, a->rd);
4125 tcg_rn = cpu_reg(s, a->rn);
4126
4127 fn(tcg_rd, tcg_rn, imm);
4128 if (set_cc) {
4129 gen_logic_CC(a->sf, tcg_rd);
4130 }
4131 if (!a->sf) {
4132 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
4133 }
4134 return true;
4135}
4136
4137TRANS(AND_i, gen_rri_log, a, false, tcg_gen_andi_i64)
4138TRANS(ORR_i, gen_rri_log, a, false, tcg_gen_ori_i64)
4139TRANS(EOR_i, gen_rri_log, a, false, tcg_gen_xori_i64)
4140TRANS(ANDS_i, gen_rri_log, a, true, tcg_gen_andi_i64)
4141
4142
4143
4144
4145
4146static bool trans_MOVZ(DisasContext *s, arg_movw *a)
4147{
4148 int pos = a->hw << 4;
4149 tcg_gen_movi_i64(cpu_reg(s, a->rd), (uint64_t)a->imm << pos);
4150 return true;
4151}
4152
4153static bool trans_MOVN(DisasContext *s, arg_movw *a)
4154{
4155 int pos = a->hw << 4;
4156 uint64_t imm = a->imm;
4157
4158 imm = ~(imm << pos);
4159 if (!a->sf) {
4160 imm = (uint32_t)imm;
4161 }
4162 tcg_gen_movi_i64(cpu_reg(s, a->rd), imm);
4163 return true;
4164}
4165
4166static bool trans_MOVK(DisasContext *s, arg_movw *a)
4167{
4168 int pos = a->hw << 4;
4169 TCGv_i64 tcg_rd, tcg_im;
4170
4171 tcg_rd = cpu_reg(s, a->rd);
4172 tcg_im = tcg_constant_i64(a->imm);
4173 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_im, pos, 16);
4174 if (!a->sf) {
4175 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
4176 }
4177 return true;
4178}
4179
4180
4181
4182
4183
4184static bool trans_SBFM(DisasContext *s, arg_SBFM *a)
4185{
4186 TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
4187 TCGv_i64 tcg_tmp = read_cpu_reg(s, a->rn, 1);
4188 unsigned int bitsize = a->sf ? 64 : 32;
4189 unsigned int ri = a->immr;
4190 unsigned int si = a->imms;
4191 unsigned int pos, len;
4192
4193 if (si >= ri) {
4194
4195 len = (si - ri) + 1;
4196 tcg_gen_sextract_i64(tcg_rd, tcg_tmp, ri, len);
4197 if (!a->sf) {
4198 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
4199 }
4200 } else {
4201
4202 len = si + 1;
4203 pos = (bitsize - ri) & (bitsize - 1);
4204
4205 if (len < ri) {
4206
4207
4208
4209
4210
4211 tcg_gen_sextract_i64(tcg_tmp, tcg_tmp, 0, len);
4212 len = ri;
4213 }
4214
4215
4216
4217
4218
4219 tcg_gen_deposit_z_i64(tcg_rd, tcg_tmp, pos, len);
4220 }
4221 return true;
4222}
4223
4224static bool trans_UBFM(DisasContext *s, arg_UBFM *a)
4225{
4226 TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
4227 TCGv_i64 tcg_tmp = read_cpu_reg(s, a->rn, 1);
4228 unsigned int bitsize = a->sf ? 64 : 32;
4229 unsigned int ri = a->immr;
4230 unsigned int si = a->imms;
4231 unsigned int pos, len;
4232
4233 tcg_rd = cpu_reg(s, a->rd);
4234 tcg_tmp = read_cpu_reg(s, a->rn, 1);
4235
4236 if (si >= ri) {
4237
4238 len = (si - ri) + 1;
4239 tcg_gen_extract_i64(tcg_rd, tcg_tmp, ri, len);
4240 } else {
4241
4242 len = si + 1;
4243 pos = (bitsize - ri) & (bitsize - 1);
4244 tcg_gen_deposit_z_i64(tcg_rd, tcg_tmp, pos, len);
4245 }
4246 return true;
4247}
4248
4249static bool trans_BFM(DisasContext *s, arg_BFM *a)
4250{
4251 TCGv_i64 tcg_rd = cpu_reg(s, a->rd);
4252 TCGv_i64 tcg_tmp = read_cpu_reg(s, a->rn, 1);
4253 unsigned int bitsize = a->sf ? 64 : 32;
4254 unsigned int ri = a->immr;
4255 unsigned int si = a->imms;
4256 unsigned int pos, len;
4257
4258 tcg_rd = cpu_reg(s, a->rd);
4259 tcg_tmp = read_cpu_reg(s, a->rn, 1);
4260
4261 if (si >= ri) {
4262
4263 tcg_gen_shri_i64(tcg_tmp, tcg_tmp, ri);
4264 len = (si - ri) + 1;
4265 pos = 0;
4266 } else {
4267
4268 len = si + 1;
4269 pos = (bitsize - ri) & (bitsize - 1);
4270 }
4271
4272 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_tmp, pos, len);
4273 if (!a->sf) {
4274 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
4275 }
4276 return true;
4277}
4278
4279static bool trans_EXTR(DisasContext *s, arg_extract *a)
4280{
4281 TCGv_i64 tcg_rd, tcg_rm, tcg_rn;
4282
4283 tcg_rd = cpu_reg(s, a->rd);
4284
4285 if (unlikely(a->imm == 0)) {
4286
4287
4288
4289
4290 if (a->sf) {
4291 tcg_gen_mov_i64(tcg_rd, cpu_reg(s, a->rm));
4292 } else {
4293 tcg_gen_ext32u_i64(tcg_rd, cpu_reg(s, a->rm));
4294 }
4295 } else {
4296 tcg_rm = cpu_reg(s, a->rm);
4297 tcg_rn = cpu_reg(s, a->rn);
4298
4299 if (a->sf) {
4300
4301 tcg_gen_extract2_i64(tcg_rd, tcg_rm, tcg_rn, a->imm);
4302 } else {
4303 TCGv_i32 t0 = tcg_temp_new_i32();
4304
4305 tcg_gen_extrl_i64_i32(t0, tcg_rm);
4306 if (a->rm == a->rn) {
4307 tcg_gen_rotri_i32(t0, t0, a->imm);
4308 } else {
4309 TCGv_i32 t1 = tcg_temp_new_i32();
4310 tcg_gen_extrl_i64_i32(t1, tcg_rn);
4311 tcg_gen_extract2_i32(t0, t0, t1, a->imm);
4312 }
4313 tcg_gen_extu_i32_i64(tcg_rd, t0);
4314 }
4315 }
4316 return true;
4317}
4318
4319
4320
4321
4322
4323
4324static void shift_reg(TCGv_i64 dst, TCGv_i64 src, int sf,
4325 enum a64_shift_type shift_type, TCGv_i64 shift_amount)
4326{
4327 switch (shift_type) {
4328 case A64_SHIFT_TYPE_LSL:
4329 tcg_gen_shl_i64(dst, src, shift_amount);
4330 break;
4331 case A64_SHIFT_TYPE_LSR:
4332 tcg_gen_shr_i64(dst, src, shift_amount);
4333 break;
4334 case A64_SHIFT_TYPE_ASR:
4335 if (!sf) {
4336 tcg_gen_ext32s_i64(dst, src);
4337 }
4338 tcg_gen_sar_i64(dst, sf ? src : dst, shift_amount);
4339 break;
4340 case A64_SHIFT_TYPE_ROR:
4341 if (sf) {
4342 tcg_gen_rotr_i64(dst, src, shift_amount);
4343 } else {
4344 TCGv_i32 t0, t1;
4345 t0 = tcg_temp_new_i32();
4346 t1 = tcg_temp_new_i32();
4347 tcg_gen_extrl_i64_i32(t0, src);
4348 tcg_gen_extrl_i64_i32(t1, shift_amount);
4349 tcg_gen_rotr_i32(t0, t0, t1);
4350 tcg_gen_extu_i32_i64(dst, t0);
4351 }
4352 break;
4353 default:
4354 assert(FALSE);
4355 break;
4356 }
4357
4358 if (!sf) {
4359 tcg_gen_ext32u_i64(dst, dst);
4360 }
4361}
4362
4363
4364
4365
4366
4367static void shift_reg_imm(TCGv_i64 dst, TCGv_i64 src, int sf,
4368 enum a64_shift_type shift_type, unsigned int shift_i)
4369{
4370 assert(shift_i < (sf ? 64 : 32));
4371
4372 if (shift_i == 0) {
4373 tcg_gen_mov_i64(dst, src);
4374 } else {
4375 shift_reg(dst, src, sf, shift_type, tcg_constant_i64(shift_i));
4376 }
4377}
4378
4379
4380
4381
4382
4383
4384
4385static void disas_logic_reg(DisasContext *s, uint32_t insn)
4386{
4387 TCGv_i64 tcg_rd, tcg_rn, tcg_rm;
4388 unsigned int sf, opc, shift_type, invert, rm, shift_amount, rn, rd;
4389
4390 sf = extract32(insn, 31, 1);
4391 opc = extract32(insn, 29, 2);
4392 shift_type = extract32(insn, 22, 2);
4393 invert = extract32(insn, 21, 1);
4394 rm = extract32(insn, 16, 5);
4395 shift_amount = extract32(insn, 10, 6);
4396 rn = extract32(insn, 5, 5);
4397 rd = extract32(insn, 0, 5);
4398
4399 if (!sf && (shift_amount & (1 << 5))) {
4400 unallocated_encoding(s);
4401 return;
4402 }
4403
4404 tcg_rd = cpu_reg(s, rd);
4405
4406 if (opc == 1 && shift_amount == 0 && shift_type == 0 && rn == 31) {
4407
4408
4409
4410 tcg_rm = cpu_reg(s, rm);
4411 if (invert) {
4412 tcg_gen_not_i64(tcg_rd, tcg_rm);
4413 if (!sf) {
4414 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
4415 }
4416 } else {
4417 if (sf) {
4418 tcg_gen_mov_i64(tcg_rd, tcg_rm);
4419 } else {
4420 tcg_gen_ext32u_i64(tcg_rd, tcg_rm);
4421 }
4422 }
4423 return;
4424 }
4425
4426 tcg_rm = read_cpu_reg(s, rm, sf);
4427
4428 if (shift_amount) {
4429 shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, shift_amount);
4430 }
4431
4432 tcg_rn = cpu_reg(s, rn);
4433
4434 switch (opc | (invert << 2)) {
4435 case 0:
4436 case 3:
4437 tcg_gen_and_i64(tcg_rd, tcg_rn, tcg_rm);
4438 break;
4439 case 1:
4440 tcg_gen_or_i64(tcg_rd, tcg_rn, tcg_rm);
4441 break;
4442 case 2:
4443 tcg_gen_xor_i64(tcg_rd, tcg_rn, tcg_rm);
4444 break;
4445 case 4:
4446 case 7:
4447 tcg_gen_andc_i64(tcg_rd, tcg_rn, tcg_rm);
4448 break;
4449 case 5:
4450 tcg_gen_orc_i64(tcg_rd, tcg_rn, tcg_rm);
4451 break;
4452 case 6:
4453 tcg_gen_eqv_i64(tcg_rd, tcg_rn, tcg_rm);
4454 break;
4455 default:
4456 assert(FALSE);
4457 break;
4458 }
4459
4460 if (!sf) {
4461 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
4462 }
4463
4464 if (opc == 3) {
4465 gen_logic_CC(sf, tcg_rd);
4466 }
4467}
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
4487{
4488 int rd = extract32(insn, 0, 5);
4489 int rn = extract32(insn, 5, 5);
4490 int imm3 = extract32(insn, 10, 3);
4491 int option = extract32(insn, 13, 3);
4492 int rm = extract32(insn, 16, 5);
4493 int opt = extract32(insn, 22, 2);
4494 bool setflags = extract32(insn, 29, 1);
4495 bool sub_op = extract32(insn, 30, 1);
4496 bool sf = extract32(insn, 31, 1);
4497
4498 TCGv_i64 tcg_rm, tcg_rn;
4499 TCGv_i64 tcg_rd;
4500 TCGv_i64 tcg_result;
4501
4502 if (imm3 > 4 || opt != 0) {
4503 unallocated_encoding(s);
4504 return;
4505 }
4506
4507
4508 if (!setflags) {
4509 tcg_rd = cpu_reg_sp(s, rd);
4510 } else {
4511 tcg_rd = cpu_reg(s, rd);
4512 }
4513 tcg_rn = read_cpu_reg_sp(s, rn, sf);
4514
4515 tcg_rm = read_cpu_reg(s, rm, sf);
4516 ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3);
4517
4518 tcg_result = tcg_temp_new_i64();
4519
4520 if (!setflags) {
4521 if (sub_op) {
4522 tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
4523 } else {
4524 tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
4525 }
4526 } else {
4527 if (sub_op) {
4528 gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
4529 } else {
4530 gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
4531 }
4532 }
4533
4534 if (sf) {
4535 tcg_gen_mov_i64(tcg_rd, tcg_result);
4536 } else {
4537 tcg_gen_ext32u_i64(tcg_rd, tcg_result);
4538 }
4539}
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
4556{
4557 int rd = extract32(insn, 0, 5);
4558 int rn = extract32(insn, 5, 5);
4559 int imm6 = extract32(insn, 10, 6);
4560 int rm = extract32(insn, 16, 5);
4561 int shift_type = extract32(insn, 22, 2);
4562 bool setflags = extract32(insn, 29, 1);
4563 bool sub_op = extract32(insn, 30, 1);
4564 bool sf = extract32(insn, 31, 1);
4565
4566 TCGv_i64 tcg_rd = cpu_reg(s, rd);
4567 TCGv_i64 tcg_rn, tcg_rm;
4568 TCGv_i64 tcg_result;
4569
4570 if ((shift_type == 3) || (!sf && (imm6 > 31))) {
4571 unallocated_encoding(s);
4572 return;
4573 }
4574
4575 tcg_rn = read_cpu_reg(s, rn, sf);
4576 tcg_rm = read_cpu_reg(s, rm, sf);
4577
4578 shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6);
4579
4580 tcg_result = tcg_temp_new_i64();
4581
4582 if (!setflags) {
4583 if (sub_op) {
4584 tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
4585 } else {
4586 tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
4587 }
4588 } else {
4589 if (sub_op) {
4590 gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
4591 } else {
4592 gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
4593 }
4594 }
4595
4596 if (sf) {
4597 tcg_gen_mov_i64(tcg_rd, tcg_result);
4598 } else {
4599 tcg_gen_ext32u_i64(tcg_rd, tcg_result);
4600 }
4601}
4602
4603
4604
4605
4606
4607
4608
4609
4610static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
4611{
4612 int rd = extract32(insn, 0, 5);
4613 int rn = extract32(insn, 5, 5);
4614 int ra = extract32(insn, 10, 5);
4615 int rm = extract32(insn, 16, 5);
4616 int op_id = (extract32(insn, 29, 3) << 4) |
4617 (extract32(insn, 21, 3) << 1) |
4618 extract32(insn, 15, 1);
4619 bool sf = extract32(insn, 31, 1);
4620 bool is_sub = extract32(op_id, 0, 1);
4621 bool is_high = extract32(op_id, 2, 1);
4622 bool is_signed = false;
4623 TCGv_i64 tcg_op1;
4624 TCGv_i64 tcg_op2;
4625 TCGv_i64 tcg_tmp;
4626
4627
4628 switch (op_id) {
4629 case 0x42:
4630 case 0x43:
4631 case 0x44:
4632 is_signed = true;
4633 break;
4634 case 0x0:
4635 case 0x1:
4636 case 0x40:
4637 case 0x41:
4638 case 0x4a:
4639 case 0x4b:
4640 case 0x4c:
4641 break;
4642 default:
4643 unallocated_encoding(s);
4644 return;
4645 }
4646
4647 if (is_high) {
4648 TCGv_i64 low_bits = tcg_temp_new_i64();
4649 TCGv_i64 tcg_rd = cpu_reg(s, rd);
4650 TCGv_i64 tcg_rn = cpu_reg(s, rn);
4651 TCGv_i64 tcg_rm = cpu_reg(s, rm);
4652
4653 if (is_signed) {
4654 tcg_gen_muls2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
4655 } else {
4656 tcg_gen_mulu2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
4657 }
4658 return;
4659 }
4660
4661 tcg_op1 = tcg_temp_new_i64();
4662 tcg_op2 = tcg_temp_new_i64();
4663 tcg_tmp = tcg_temp_new_i64();
4664
4665 if (op_id < 0x42) {
4666 tcg_gen_mov_i64(tcg_op1, cpu_reg(s, rn));
4667 tcg_gen_mov_i64(tcg_op2, cpu_reg(s, rm));
4668 } else {
4669 if (is_signed) {
4670 tcg_gen_ext32s_i64(tcg_op1, cpu_reg(s, rn));
4671 tcg_gen_ext32s_i64(tcg_op2, cpu_reg(s, rm));
4672 } else {
4673 tcg_gen_ext32u_i64(tcg_op1, cpu_reg(s, rn));
4674 tcg_gen_ext32u_i64(tcg_op2, cpu_reg(s, rm));
4675 }
4676 }
4677
4678 if (ra == 31 && !is_sub) {
4679
4680 tcg_gen_mul_i64(cpu_reg(s, rd), tcg_op1, tcg_op2);
4681 } else {
4682 tcg_gen_mul_i64(tcg_tmp, tcg_op1, tcg_op2);
4683 if (is_sub) {
4684 tcg_gen_sub_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
4685 } else {
4686 tcg_gen_add_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
4687 }
4688 }
4689
4690 if (!sf) {
4691 tcg_gen_ext32u_i64(cpu_reg(s, rd), cpu_reg(s, rd));
4692 }
4693}
4694
4695
4696
4697
4698
4699
4700
4701
4702static void disas_adc_sbc(DisasContext *s, uint32_t insn)
4703{
4704 unsigned int sf, op, setflags, rm, rn, rd;
4705 TCGv_i64 tcg_y, tcg_rn, tcg_rd;
4706
4707 sf = extract32(insn, 31, 1);
4708 op = extract32(insn, 30, 1);
4709 setflags = extract32(insn, 29, 1);
4710 rm = extract32(insn, 16, 5);
4711 rn = extract32(insn, 5, 5);
4712 rd = extract32(insn, 0, 5);
4713
4714 tcg_rd = cpu_reg(s, rd);
4715 tcg_rn = cpu_reg(s, rn);
4716
4717 if (op) {
4718 tcg_y = tcg_temp_new_i64();
4719 tcg_gen_not_i64(tcg_y, cpu_reg(s, rm));
4720 } else {
4721 tcg_y = cpu_reg(s, rm);
4722 }
4723
4724 if (setflags) {
4725 gen_adc_CC(sf, tcg_rd, tcg_rn, tcg_y);
4726 } else {
4727 gen_adc(sf, tcg_rd, tcg_rn, tcg_y);
4728 }
4729}
4730
4731
4732
4733
4734
4735
4736
4737
4738static void disas_rotate_right_into_flags(DisasContext *s, uint32_t insn)
4739{
4740 int mask = extract32(insn, 0, 4);
4741 int o2 = extract32(insn, 4, 1);
4742 int rn = extract32(insn, 5, 5);
4743 int imm6 = extract32(insn, 15, 6);
4744 int sf_op_s = extract32(insn, 29, 3);
4745 TCGv_i64 tcg_rn;
4746 TCGv_i32 nzcv;
4747
4748 if (sf_op_s != 5 || o2 != 0 || !dc_isar_feature(aa64_condm_4, s)) {
4749 unallocated_encoding(s);
4750 return;
4751 }
4752
4753 tcg_rn = read_cpu_reg(s, rn, 1);
4754 tcg_gen_rotri_i64(tcg_rn, tcg_rn, imm6);
4755
4756 nzcv = tcg_temp_new_i32();
4757 tcg_gen_extrl_i64_i32(nzcv, tcg_rn);
4758
4759 if (mask & 8) {
4760 tcg_gen_shli_i32(cpu_NF, nzcv, 31 - 3);
4761 }
4762 if (mask & 4) {
4763 tcg_gen_not_i32(cpu_ZF, nzcv);
4764 tcg_gen_andi_i32(cpu_ZF, cpu_ZF, 4);
4765 }
4766 if (mask & 2) {
4767 tcg_gen_extract_i32(cpu_CF, nzcv, 1, 1);
4768 }
4769 if (mask & 1) {
4770 tcg_gen_shli_i32(cpu_VF, nzcv, 31 - 0);
4771 }
4772}
4773
4774
4775
4776
4777
4778
4779
4780
4781static void disas_evaluate_into_flags(DisasContext *s, uint32_t insn)
4782{
4783 int o3_mask = extract32(insn, 0, 5);
4784 int rn = extract32(insn, 5, 5);
4785 int o2 = extract32(insn, 15, 6);
4786 int sz = extract32(insn, 14, 1);
4787 int sf_op_s = extract32(insn, 29, 3);
4788 TCGv_i32 tmp;
4789 int shift;
4790
4791 if (sf_op_s != 1 || o2 != 0 || o3_mask != 0xd ||
4792 !dc_isar_feature(aa64_condm_4, s)) {
4793 unallocated_encoding(s);
4794 return;
4795 }
4796 shift = sz ? 16 : 24;
4797
4798 tmp = tcg_temp_new_i32();
4799 tcg_gen_extrl_i64_i32(tmp, cpu_reg(s, rn));
4800 tcg_gen_shli_i32(cpu_NF, tmp, shift);
4801 tcg_gen_shli_i32(cpu_VF, tmp, shift - 1);
4802 tcg_gen_mov_i32(cpu_ZF, cpu_NF);
4803 tcg_gen_xor_i32(cpu_VF, cpu_VF, cpu_NF);
4804}
4805
4806
4807
4808
4809
4810
4811
4812
4813static void disas_cc(DisasContext *s, uint32_t insn)
4814{
4815 unsigned int sf, op, y, cond, rn, nzcv, is_imm;
4816 TCGv_i32 tcg_t0, tcg_t1, tcg_t2;
4817 TCGv_i64 tcg_tmp, tcg_y, tcg_rn;
4818 DisasCompare c;
4819
4820 if (!extract32(insn, 29, 1)) {
4821 unallocated_encoding(s);
4822 return;
4823 }
4824 if (insn & (1 << 10 | 1 << 4)) {
4825 unallocated_encoding(s);
4826 return;
4827 }
4828 sf = extract32(insn, 31, 1);
4829 op = extract32(insn, 30, 1);
4830 is_imm = extract32(insn, 11, 1);
4831 y = extract32(insn, 16, 5);
4832 cond = extract32(insn, 12, 4);
4833 rn = extract32(insn, 5, 5);
4834 nzcv = extract32(insn, 0, 4);
4835
4836
4837 tcg_t0 = tcg_temp_new_i32();
4838 arm_test_cc(&c, cond);
4839 tcg_gen_setcondi_i32(tcg_invert_cond(c.cond), tcg_t0, c.value, 0);
4840
4841
4842 if (is_imm) {
4843 tcg_y = tcg_temp_new_i64();
4844 tcg_gen_movi_i64(tcg_y, y);
4845 } else {
4846 tcg_y = cpu_reg(s, y);
4847 }
4848 tcg_rn = cpu_reg(s, rn);
4849
4850
4851 tcg_tmp = tcg_temp_new_i64();
4852 if (op) {
4853 gen_sub_CC(sf, tcg_tmp, tcg_rn, tcg_y);
4854 } else {
4855 gen_add_CC(sf, tcg_tmp, tcg_rn, tcg_y);
4856 }
4857
4858
4859
4860
4861
4862
4863 tcg_t1 = tcg_temp_new_i32();
4864 tcg_t2 = tcg_temp_new_i32();
4865 tcg_gen_neg_i32(tcg_t1, tcg_t0);
4866 tcg_gen_subi_i32(tcg_t2, tcg_t0, 1);
4867
4868 if (nzcv & 8) {
4869 tcg_gen_or_i32(cpu_NF, cpu_NF, tcg_t1);
4870 } else {
4871 if (TCG_TARGET_HAS_andc_i32) {
4872 tcg_gen_andc_i32(cpu_NF, cpu_NF, tcg_t1);
4873 } else {
4874 tcg_gen_and_i32(cpu_NF, cpu_NF, tcg_t2);
4875 }
4876 }
4877 if (nzcv & 4) {
4878 if (TCG_TARGET_HAS_andc_i32) {
4879 tcg_gen_andc_i32(cpu_ZF, cpu_ZF, tcg_t1);
4880 } else {
4881 tcg_gen_and_i32(cpu_ZF, cpu_ZF, tcg_t2);
4882 }
4883 } else {
4884 tcg_gen_or_i32(cpu_ZF, cpu_ZF, tcg_t0);
4885 }
4886 if (nzcv & 2) {
4887 tcg_gen_or_i32(cpu_CF, cpu_CF, tcg_t0);
4888 } else {
4889 if (TCG_TARGET_HAS_andc_i32) {
4890 tcg_gen_andc_i32(cpu_CF, cpu_CF, tcg_t1);
4891 } else {
4892 tcg_gen_and_i32(cpu_CF, cpu_CF, tcg_t2);
4893 }
4894 }
4895 if (nzcv & 1) {
4896 tcg_gen_or_i32(cpu_VF, cpu_VF, tcg_t1);
4897 } else {
4898 if (TCG_TARGET_HAS_andc_i32) {
4899 tcg_gen_andc_i32(cpu_VF, cpu_VF, tcg_t1);
4900 } else {
4901 tcg_gen_and_i32(cpu_VF, cpu_VF, tcg_t2);
4902 }
4903 }
4904}
4905
4906
4907
4908
4909
4910
4911
4912static void disas_cond_select(DisasContext *s, uint32_t insn)
4913{
4914 unsigned int sf, else_inv, rm, cond, else_inc, rn, rd;
4915 TCGv_i64 tcg_rd, zero;
4916 DisasCompare64 c;
4917
4918 if (extract32(insn, 29, 1) || extract32(insn, 11, 1)) {
4919
4920 unallocated_encoding(s);
4921 return;
4922 }
4923 sf = extract32(insn, 31, 1);
4924 else_inv = extract32(insn, 30, 1);
4925 rm = extract32(insn, 16, 5);
4926 cond = extract32(insn, 12, 4);
4927 else_inc = extract32(insn, 10, 1);
4928 rn = extract32(insn, 5, 5);
4929 rd = extract32(insn, 0, 5);
4930
4931 tcg_rd = cpu_reg(s, rd);
4932
4933 a64_test_cc(&c, cond);
4934 zero = tcg_constant_i64(0);
4935
4936 if (rn == 31 && rm == 31 && (else_inc ^ else_inv)) {
4937
4938 tcg_gen_setcond_i64(tcg_invert_cond(c.cond), tcg_rd, c.value, zero);
4939 if (else_inv) {
4940 tcg_gen_neg_i64(tcg_rd, tcg_rd);
4941 }
4942 } else {
4943 TCGv_i64 t_true = cpu_reg(s, rn);
4944 TCGv_i64 t_false = read_cpu_reg(s, rm, 1);
4945 if (else_inv && else_inc) {
4946 tcg_gen_neg_i64(t_false, t_false);
4947 } else if (else_inv) {
4948 tcg_gen_not_i64(t_false, t_false);
4949 } else if (else_inc) {
4950 tcg_gen_addi_i64(t_false, t_false, 1);
4951 }
4952 tcg_gen_movcond_i64(c.cond, tcg_rd, c.value, zero, t_true, t_false);
4953 }
4954
4955 if (!sf) {
4956 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
4957 }
4958}
4959
4960static void handle_clz(DisasContext *s, unsigned int sf,
4961 unsigned int rn, unsigned int rd)
4962{
4963 TCGv_i64 tcg_rd, tcg_rn;
4964 tcg_rd = cpu_reg(s, rd);
4965 tcg_rn = cpu_reg(s, rn);
4966
4967 if (sf) {
4968 tcg_gen_clzi_i64(tcg_rd, tcg_rn, 64);
4969 } else {
4970 TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
4971 tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
4972 tcg_gen_clzi_i32(tcg_tmp32, tcg_tmp32, 32);
4973 tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
4974 }
4975}
4976
4977static void handle_cls(DisasContext *s, unsigned int sf,
4978 unsigned int rn, unsigned int rd)
4979{
4980 TCGv_i64 tcg_rd, tcg_rn;
4981 tcg_rd = cpu_reg(s, rd);
4982 tcg_rn = cpu_reg(s, rn);
4983
4984 if (sf) {
4985 tcg_gen_clrsb_i64(tcg_rd, tcg_rn);
4986 } else {
4987 TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
4988 tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
4989 tcg_gen_clrsb_i32(tcg_tmp32, tcg_tmp32);
4990 tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
4991 }
4992}
4993
4994static void handle_rbit(DisasContext *s, unsigned int sf,
4995 unsigned int rn, unsigned int rd)
4996{
4997 TCGv_i64 tcg_rd, tcg_rn;
4998 tcg_rd = cpu_reg(s, rd);
4999 tcg_rn = cpu_reg(s, rn);
5000
5001 if (sf) {
5002 gen_helper_rbit64(tcg_rd, tcg_rn);
5003 } else {
5004 TCGv_i32 tcg_tmp32 = tcg_temp_new_i32();
5005 tcg_gen_extrl_i64_i32(tcg_tmp32, tcg_rn);
5006 gen_helper_rbit(tcg_tmp32, tcg_tmp32);
5007 tcg_gen_extu_i32_i64(tcg_rd, tcg_tmp32);
5008 }
5009}
5010
5011
5012static void handle_rev64(DisasContext *s, unsigned int sf,
5013 unsigned int rn, unsigned int rd)
5014{
5015 if (!sf) {
5016 unallocated_encoding(s);
5017 return;
5018 }
5019 tcg_gen_bswap64_i64(cpu_reg(s, rd), cpu_reg(s, rn));
5020}
5021
5022
5023
5024
5025static void handle_rev32(DisasContext *s, unsigned int sf,
5026 unsigned int rn, unsigned int rd)
5027{
5028 TCGv_i64 tcg_rd = cpu_reg(s, rd);
5029 TCGv_i64 tcg_rn = cpu_reg(s, rn);
5030
5031 if (sf) {
5032 tcg_gen_bswap64_i64(tcg_rd, tcg_rn);
5033 tcg_gen_rotri_i64(tcg_rd, tcg_rd, 32);
5034 } else {
5035 tcg_gen_bswap32_i64(tcg_rd, tcg_rn, TCG_BSWAP_OZ);
5036 }
5037}
5038
5039
5040static void handle_rev16(DisasContext *s, unsigned int sf,
5041 unsigned int rn, unsigned int rd)
5042{
5043 TCGv_i64 tcg_rd = cpu_reg(s, rd);
5044 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
5045 TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
5046 TCGv_i64 mask = tcg_constant_i64(sf ? 0x00ff00ff00ff00ffull : 0x00ff00ff);
5047
5048 tcg_gen_shri_i64(tcg_tmp, tcg_rn, 8);
5049 tcg_gen_and_i64(tcg_rd, tcg_rn, mask);
5050 tcg_gen_and_i64(tcg_tmp, tcg_tmp, mask);
5051 tcg_gen_shli_i64(tcg_rd, tcg_rd, 8);
5052 tcg_gen_or_i64(tcg_rd, tcg_rd, tcg_tmp);
5053}
5054
5055
5056
5057
5058
5059
5060
5061static void disas_data_proc_1src(DisasContext *s, uint32_t insn)
5062{
5063 unsigned int sf, opcode, opcode2, rn, rd;
5064 TCGv_i64 tcg_rd;
5065
5066 if (extract32(insn, 29, 1)) {
5067 unallocated_encoding(s);
5068 return;
5069 }
5070
5071 sf = extract32(insn, 31, 1);
5072 opcode = extract32(insn, 10, 6);
5073 opcode2 = extract32(insn, 16, 5);
5074 rn = extract32(insn, 5, 5);
5075 rd = extract32(insn, 0, 5);
5076
5077#define MAP(SF, O2, O1) ((SF) | (O1 << 1) | (O2 << 7))
5078
5079 switch (MAP(sf, opcode2, opcode)) {
5080 case MAP(0, 0x00, 0x00):
5081 case MAP(1, 0x00, 0x00):
5082 handle_rbit(s, sf, rn, rd);
5083 break;
5084 case MAP(0, 0x00, 0x01):
5085 case MAP(1, 0x00, 0x01):
5086 handle_rev16(s, sf, rn, rd);
5087 break;
5088 case MAP(0, 0x00, 0x02):
5089 case MAP(1, 0x00, 0x02):
5090 handle_rev32(s, sf, rn, rd);
5091 break;
5092 case MAP(1, 0x00, 0x03):
5093 handle_rev64(s, sf, rn, rd);
5094 break;
5095 case MAP(0, 0x00, 0x04):
5096 case MAP(1, 0x00, 0x04):
5097 handle_clz(s, sf, rn, rd);
5098 break;
5099 case MAP(0, 0x00, 0x05):
5100 case MAP(1, 0x00, 0x05):
5101 handle_cls(s, sf, rn, rd);
5102 break;
5103 case MAP(1, 0x01, 0x00):
5104 if (s->pauth_active) {
5105 tcg_rd = cpu_reg(s, rd);
5106 gen_helper_pacia(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
5107 } else if (!dc_isar_feature(aa64_pauth, s)) {
5108 goto do_unallocated;
5109 }
5110 break;
5111 case MAP(1, 0x01, 0x01):
5112 if (s->pauth_active) {
5113 tcg_rd = cpu_reg(s, rd);
5114 gen_helper_pacib(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
5115 } else if (!dc_isar_feature(aa64_pauth, s)) {
5116 goto do_unallocated;
5117 }
5118 break;
5119 case MAP(1, 0x01, 0x02):
5120 if (s->pauth_active) {
5121 tcg_rd = cpu_reg(s, rd);
5122 gen_helper_pacda(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
5123 } else if (!dc_isar_feature(aa64_pauth, s)) {
5124 goto do_unallocated;
5125 }
5126 break;
5127 case MAP(1, 0x01, 0x03):
5128 if (s->pauth_active) {
5129 tcg_rd = cpu_reg(s, rd);
5130 gen_helper_pacdb(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
5131 } else if (!dc_isar_feature(aa64_pauth, s)) {
5132 goto do_unallocated;
5133 }
5134 break;
5135 case MAP(1, 0x01, 0x04):
5136 if (s->pauth_active) {
5137 tcg_rd = cpu_reg(s, rd);
5138 gen_helper_autia(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
5139 } else if (!dc_isar_feature(aa64_pauth, s)) {
5140 goto do_unallocated;
5141 }
5142 break;
5143 case MAP(1, 0x01, 0x05):
5144 if (s->pauth_active) {
5145 tcg_rd = cpu_reg(s, rd);
5146 gen_helper_autib(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
5147 } else if (!dc_isar_feature(aa64_pauth, s)) {
5148 goto do_unallocated;
5149 }
5150 break;
5151 case MAP(1, 0x01, 0x06):
5152 if (s->pauth_active) {
5153 tcg_rd = cpu_reg(s, rd);
5154 gen_helper_autda(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
5155 } else if (!dc_isar_feature(aa64_pauth, s)) {
5156 goto do_unallocated;
5157 }
5158 break;
5159 case MAP(1, 0x01, 0x07):
5160 if (s->pauth_active) {
5161 tcg_rd = cpu_reg(s, rd);
5162 gen_helper_autdb(tcg_rd, cpu_env, tcg_rd, cpu_reg_sp(s, rn));
5163 } else if (!dc_isar_feature(aa64_pauth, s)) {
5164 goto do_unallocated;
5165 }
5166 break;
5167 case MAP(1, 0x01, 0x08):
5168 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
5169 goto do_unallocated;
5170 } else if (s->pauth_active) {
5171 tcg_rd = cpu_reg(s, rd);
5172 gen_helper_pacia(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0));
5173 }
5174 break;
5175 case MAP(1, 0x01, 0x09):
5176 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
5177 goto do_unallocated;
5178 } else if (s->pauth_active) {
5179 tcg_rd = cpu_reg(s, rd);
5180 gen_helper_pacib(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0));
5181 }
5182 break;
5183 case MAP(1, 0x01, 0x0a):
5184 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
5185 goto do_unallocated;
5186 } else if (s->pauth_active) {
5187 tcg_rd = cpu_reg(s, rd);
5188 gen_helper_pacda(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0));
5189 }
5190 break;
5191 case MAP(1, 0x01, 0x0b):
5192 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
5193 goto do_unallocated;
5194 } else if (s->pauth_active) {
5195 tcg_rd = cpu_reg(s, rd);
5196 gen_helper_pacdb(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0));
5197 }
5198 break;
5199 case MAP(1, 0x01, 0x0c):
5200 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
5201 goto do_unallocated;
5202 } else if (s->pauth_active) {
5203 tcg_rd = cpu_reg(s, rd);
5204 gen_helper_autia(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0));
5205 }
5206 break;
5207 case MAP(1, 0x01, 0x0d):
5208 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
5209 goto do_unallocated;
5210 } else if (s->pauth_active) {
5211 tcg_rd = cpu_reg(s, rd);
5212 gen_helper_autib(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0));
5213 }
5214 break;
5215 case MAP(1, 0x01, 0x0e):
5216 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
5217 goto do_unallocated;
5218 } else if (s->pauth_active) {
5219 tcg_rd = cpu_reg(s, rd);
5220 gen_helper_autda(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0));
5221 }
5222 break;
5223 case MAP(1, 0x01, 0x0f):
5224 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
5225 goto do_unallocated;
5226 } else if (s->pauth_active) {
5227 tcg_rd = cpu_reg(s, rd);
5228 gen_helper_autdb(tcg_rd, cpu_env, tcg_rd, tcg_constant_i64(0));
5229 }
5230 break;
5231 case MAP(1, 0x01, 0x10):
5232 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
5233 goto do_unallocated;
5234 } else if (s->pauth_active) {
5235 tcg_rd = cpu_reg(s, rd);
5236 gen_helper_xpaci(tcg_rd, cpu_env, tcg_rd);
5237 }
5238 break;
5239 case MAP(1, 0x01, 0x11):
5240 if (!dc_isar_feature(aa64_pauth, s) || rn != 31) {
5241 goto do_unallocated;
5242 } else if (s->pauth_active) {
5243 tcg_rd = cpu_reg(s, rd);
5244 gen_helper_xpacd(tcg_rd, cpu_env, tcg_rd);
5245 }
5246 break;
5247 default:
5248 do_unallocated:
5249 unallocated_encoding(s);
5250 break;
5251 }
5252
5253#undef MAP
5254}
5255
5256static void handle_div(DisasContext *s, bool is_signed, unsigned int sf,
5257 unsigned int rm, unsigned int rn, unsigned int rd)
5258{
5259 TCGv_i64 tcg_n, tcg_m, tcg_rd;
5260 tcg_rd = cpu_reg(s, rd);
5261
5262 if (!sf && is_signed) {
5263 tcg_n = tcg_temp_new_i64();
5264 tcg_m = tcg_temp_new_i64();
5265 tcg_gen_ext32s_i64(tcg_n, cpu_reg(s, rn));
5266 tcg_gen_ext32s_i64(tcg_m, cpu_reg(s, rm));
5267 } else {
5268 tcg_n = read_cpu_reg(s, rn, sf);
5269 tcg_m = read_cpu_reg(s, rm, sf);
5270 }
5271
5272 if (is_signed) {
5273 gen_helper_sdiv64(tcg_rd, tcg_n, tcg_m);
5274 } else {
5275 gen_helper_udiv64(tcg_rd, tcg_n, tcg_m);
5276 }
5277
5278 if (!sf) {
5279 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
5280 }
5281}
5282
5283
5284static void handle_shift_reg(DisasContext *s,
5285 enum a64_shift_type shift_type, unsigned int sf,
5286 unsigned int rm, unsigned int rn, unsigned int rd)
5287{
5288 TCGv_i64 tcg_shift = tcg_temp_new_i64();
5289 TCGv_i64 tcg_rd = cpu_reg(s, rd);
5290 TCGv_i64 tcg_rn = read_cpu_reg(s, rn, sf);
5291
5292 tcg_gen_andi_i64(tcg_shift, cpu_reg(s, rm), sf ? 63 : 31);
5293 shift_reg(tcg_rd, tcg_rn, sf, shift_type, tcg_shift);
5294}
5295
5296
5297static void handle_crc32(DisasContext *s,
5298 unsigned int sf, unsigned int sz, bool crc32c,
5299 unsigned int rm, unsigned int rn, unsigned int rd)
5300{
5301 TCGv_i64 tcg_acc, tcg_val;
5302 TCGv_i32 tcg_bytes;
5303
5304 if (!dc_isar_feature(aa64_crc32, s)
5305 || (sf == 1 && sz != 3)
5306 || (sf == 0 && sz == 3)) {
5307 unallocated_encoding(s);
5308 return;
5309 }
5310
5311 if (sz == 3) {
5312 tcg_val = cpu_reg(s, rm);
5313 } else {
5314 uint64_t mask;
5315 switch (sz) {
5316 case 0:
5317 mask = 0xFF;
5318 break;
5319 case 1:
5320 mask = 0xFFFF;
5321 break;
5322 case 2:
5323 mask = 0xFFFFFFFF;
5324 break;
5325 default:
5326 g_assert_not_reached();
5327 }
5328 tcg_val = tcg_temp_new_i64();
5329 tcg_gen_andi_i64(tcg_val, cpu_reg(s, rm), mask);
5330 }
5331
5332 tcg_acc = cpu_reg(s, rn);
5333 tcg_bytes = tcg_constant_i32(1 << sz);
5334
5335 if (crc32c) {
5336 gen_helper_crc32c_64(cpu_reg(s, rd), tcg_acc, tcg_val, tcg_bytes);
5337 } else {
5338 gen_helper_crc32_64(cpu_reg(s, rd), tcg_acc, tcg_val, tcg_bytes);
5339 }
5340}
5341
5342
5343
5344
5345
5346
5347
5348static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
5349{
5350 unsigned int sf, rm, opcode, rn, rd, setflag;
5351 sf = extract32(insn, 31, 1);
5352 setflag = extract32(insn, 29, 1);
5353 rm = extract32(insn, 16, 5);
5354 opcode = extract32(insn, 10, 6);
5355 rn = extract32(insn, 5, 5);
5356 rd = extract32(insn, 0, 5);
5357
5358 if (setflag && opcode != 0) {
5359 unallocated_encoding(s);
5360 return;
5361 }
5362
5363 switch (opcode) {
5364 case 0:
5365 if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) {
5366 goto do_unallocated;
5367 } else {
5368 TCGv_i64 tcg_n, tcg_m, tcg_d;
5369
5370 tcg_n = read_cpu_reg_sp(s, rn, true);
5371 tcg_m = read_cpu_reg_sp(s, rm, true);
5372 tcg_gen_sextract_i64(tcg_n, tcg_n, 0, 56);
5373 tcg_gen_sextract_i64(tcg_m, tcg_m, 0, 56);
5374 tcg_d = cpu_reg(s, rd);
5375
5376 if (setflag) {
5377 gen_sub_CC(true, tcg_d, tcg_n, tcg_m);
5378 } else {
5379 tcg_gen_sub_i64(tcg_d, tcg_n, tcg_m);
5380 }
5381 }
5382 break;
5383 case 2:
5384 handle_div(s, false, sf, rm, rn, rd);
5385 break;
5386 case 3:
5387 handle_div(s, true, sf, rm, rn, rd);
5388 break;
5389 case 4:
5390 if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) {
5391 goto do_unallocated;
5392 }
5393 if (s->ata) {
5394 gen_helper_irg(cpu_reg_sp(s, rd), cpu_env,
5395 cpu_reg_sp(s, rn), cpu_reg(s, rm));
5396 } else {
5397 gen_address_with_allocation_tag0(cpu_reg_sp(s, rd),
5398 cpu_reg_sp(s, rn));
5399 }
5400 break;
5401 case 5:
5402 if (sf == 0 || !dc_isar_feature(aa64_mte_insn_reg, s)) {
5403 goto do_unallocated;
5404 } else {
5405 TCGv_i64 t = tcg_temp_new_i64();
5406
5407 tcg_gen_extract_i64(t, cpu_reg_sp(s, rn), 56, 4);
5408 tcg_gen_shl_i64(t, tcg_constant_i64(1), t);
5409 tcg_gen_or_i64(cpu_reg(s, rd), cpu_reg(s, rm), t);
5410 }
5411 break;
5412 case 8:
5413 handle_shift_reg(s, A64_SHIFT_TYPE_LSL, sf, rm, rn, rd);
5414 break;
5415 case 9:
5416 handle_shift_reg(s, A64_SHIFT_TYPE_LSR, sf, rm, rn, rd);
5417 break;
5418 case 10:
5419 handle_shift_reg(s, A64_SHIFT_TYPE_ASR, sf, rm, rn, rd);
5420 break;
5421 case 11:
5422 handle_shift_reg(s, A64_SHIFT_TYPE_ROR, sf, rm, rn, rd);
5423 break;
5424 case 12:
5425 if (sf == 0 || !dc_isar_feature(aa64_pauth, s)) {
5426 goto do_unallocated;
5427 }
5428 gen_helper_pacga(cpu_reg(s, rd), cpu_env,
5429 cpu_reg(s, rn), cpu_reg_sp(s, rm));
5430 break;
5431 case 16:
5432 case 17:
5433 case 18:
5434 case 19:
5435 case 20:
5436 case 21:
5437 case 22:
5438 case 23:
5439 {
5440 int sz = extract32(opcode, 0, 2);
5441 bool crc32c = extract32(opcode, 2, 1);
5442 handle_crc32(s, sf, sz, crc32c, rm, rn, rd);
5443 break;
5444 }
5445 default:
5446 do_unallocated:
5447 unallocated_encoding(s);
5448 break;
5449 }
5450}
5451
5452
5453
5454
5455
5456
5457
5458
5459static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
5460{
5461 int op0 = extract32(insn, 30, 1);
5462 int op1 = extract32(insn, 28, 1);
5463 int op2 = extract32(insn, 21, 4);
5464 int op3 = extract32(insn, 10, 6);
5465
5466 if (!op1) {
5467 if (op2 & 8) {
5468 if (op2 & 1) {
5469
5470 disas_add_sub_ext_reg(s, insn);
5471 } else {
5472
5473 disas_add_sub_reg(s, insn);
5474 }
5475 } else {
5476
5477 disas_logic_reg(s, insn);
5478 }
5479 return;
5480 }
5481
5482 switch (op2) {
5483 case 0x0:
5484 switch (op3) {
5485 case 0x00:
5486 disas_adc_sbc(s, insn);
5487 break;
5488
5489 case 0x01:
5490 case 0x21:
5491 disas_rotate_right_into_flags(s, insn);
5492 break;
5493
5494 case 0x02:
5495 case 0x12:
5496 case 0x22:
5497 case 0x32:
5498 disas_evaluate_into_flags(s, insn);
5499 break;
5500
5501 default:
5502 goto do_unallocated;
5503 }
5504 break;
5505
5506 case 0x2:
5507 disas_cc(s, insn);
5508 break;
5509
5510 case 0x4:
5511 disas_cond_select(s, insn);
5512 break;
5513
5514 case 0x6:
5515 if (op0) {
5516 disas_data_proc_1src(s, insn);
5517 } else {
5518 disas_data_proc_2src(s, insn);
5519 }
5520 break;
5521 case 0x8 ... 0xf:
5522 disas_data_proc_3src(s, insn);
5523 break;
5524
5525 default:
5526 do_unallocated:
5527 unallocated_encoding(s);
5528 break;
5529 }
5530}
5531
5532static void handle_fp_compare(DisasContext *s, int size,
5533 unsigned int rn, unsigned int rm,
5534 bool cmp_with_zero, bool signal_all_nans)
5535{
5536 TCGv_i64 tcg_flags = tcg_temp_new_i64();
5537 TCGv_ptr fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
5538
5539 if (size == MO_64) {
5540 TCGv_i64 tcg_vn, tcg_vm;
5541
5542 tcg_vn = read_fp_dreg(s, rn);
5543 if (cmp_with_zero) {
5544 tcg_vm = tcg_constant_i64(0);
5545 } else {
5546 tcg_vm = read_fp_dreg(s, rm);
5547 }
5548 if (signal_all_nans) {
5549 gen_helper_vfp_cmped_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5550 } else {
5551 gen_helper_vfp_cmpd_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5552 }
5553 } else {
5554 TCGv_i32 tcg_vn = tcg_temp_new_i32();
5555 TCGv_i32 tcg_vm = tcg_temp_new_i32();
5556
5557 read_vec_element_i32(s, tcg_vn, rn, 0, size);
5558 if (cmp_with_zero) {
5559 tcg_gen_movi_i32(tcg_vm, 0);
5560 } else {
5561 read_vec_element_i32(s, tcg_vm, rm, 0, size);
5562 }
5563
5564 switch (size) {
5565 case MO_32:
5566 if (signal_all_nans) {
5567 gen_helper_vfp_cmpes_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5568 } else {
5569 gen_helper_vfp_cmps_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5570 }
5571 break;
5572 case MO_16:
5573 if (signal_all_nans) {
5574 gen_helper_vfp_cmpeh_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5575 } else {
5576 gen_helper_vfp_cmph_a64(tcg_flags, tcg_vn, tcg_vm, fpst);
5577 }
5578 break;
5579 default:
5580 g_assert_not_reached();
5581 }
5582 }
5583
5584 gen_set_nzcv(tcg_flags);
5585}
5586
5587
5588
5589
5590
5591
5592
5593static void disas_fp_compare(DisasContext *s, uint32_t insn)
5594{
5595 unsigned int mos, type, rm, op, rn, opc, op2r;
5596 int size;
5597
5598 mos = extract32(insn, 29, 3);
5599 type = extract32(insn, 22, 2);
5600 rm = extract32(insn, 16, 5);
5601 op = extract32(insn, 14, 2);
5602 rn = extract32(insn, 5, 5);
5603 opc = extract32(insn, 3, 2);
5604 op2r = extract32(insn, 0, 3);
5605
5606 if (mos || op || op2r) {
5607 unallocated_encoding(s);
5608 return;
5609 }
5610
5611 switch (type) {
5612 case 0:
5613 size = MO_32;
5614 break;
5615 case 1:
5616 size = MO_64;
5617 break;
5618 case 3:
5619 size = MO_16;
5620 if (dc_isar_feature(aa64_fp16, s)) {
5621 break;
5622 }
5623
5624 default:
5625 unallocated_encoding(s);
5626 return;
5627 }
5628
5629 if (!fp_access_check(s)) {
5630 return;
5631 }
5632
5633 handle_fp_compare(s, size, rn, rm, opc & 1, opc & 2);
5634}
5635
5636
5637
5638
5639
5640
5641
5642static void disas_fp_ccomp(DisasContext *s, uint32_t insn)
5643{
5644 unsigned int mos, type, rm, cond, rn, op, nzcv;
5645 TCGLabel *label_continue = NULL;
5646 int size;
5647
5648 mos = extract32(insn, 29, 3);
5649 type = extract32(insn, 22, 2);
5650 rm = extract32(insn, 16, 5);
5651 cond = extract32(insn, 12, 4);
5652 rn = extract32(insn, 5, 5);
5653 op = extract32(insn, 4, 1);
5654 nzcv = extract32(insn, 0, 4);
5655
5656 if (mos) {
5657 unallocated_encoding(s);
5658 return;
5659 }
5660
5661 switch (type) {
5662 case 0:
5663 size = MO_32;
5664 break;
5665 case 1:
5666 size = MO_64;
5667 break;
5668 case 3:
5669 size = MO_16;
5670 if (dc_isar_feature(aa64_fp16, s)) {
5671 break;
5672 }
5673
5674 default:
5675 unallocated_encoding(s);
5676 return;
5677 }
5678
5679 if (!fp_access_check(s)) {
5680 return;
5681 }
5682
5683 if (cond < 0x0e) {
5684 TCGLabel *label_match = gen_new_label();
5685 label_continue = gen_new_label();
5686 arm_gen_test_cc(cond, label_match);
5687
5688 gen_set_nzcv(tcg_constant_i64(nzcv << 28));
5689 tcg_gen_br(label_continue);
5690 gen_set_label(label_match);
5691 }
5692
5693 handle_fp_compare(s, size, rn, rm, false, op);
5694
5695 if (cond < 0x0e) {
5696 gen_set_label(label_continue);
5697 }
5698}
5699
5700
5701
5702
5703
5704
5705
5706static void disas_fp_csel(DisasContext *s, uint32_t insn)
5707{
5708 unsigned int mos, type, rm, cond, rn, rd;
5709 TCGv_i64 t_true, t_false;
5710 DisasCompare64 c;
5711 MemOp sz;
5712
5713 mos = extract32(insn, 29, 3);
5714 type = extract32(insn, 22, 2);
5715 rm = extract32(insn, 16, 5);
5716 cond = extract32(insn, 12, 4);
5717 rn = extract32(insn, 5, 5);
5718 rd = extract32(insn, 0, 5);
5719
5720 if (mos) {
5721 unallocated_encoding(s);
5722 return;
5723 }
5724
5725 switch (type) {
5726 case 0:
5727 sz = MO_32;
5728 break;
5729 case 1:
5730 sz = MO_64;
5731 break;
5732 case 3:
5733 sz = MO_16;
5734 if (dc_isar_feature(aa64_fp16, s)) {
5735 break;
5736 }
5737
5738 default:
5739 unallocated_encoding(s);
5740 return;
5741 }
5742
5743 if (!fp_access_check(s)) {
5744 return;
5745 }
5746
5747
5748 t_true = tcg_temp_new_i64();
5749 t_false = tcg_temp_new_i64();
5750 read_vec_element(s, t_true, rn, 0, sz);
5751 read_vec_element(s, t_false, rm, 0, sz);
5752
5753 a64_test_cc(&c, cond);
5754 tcg_gen_movcond_i64(c.cond, t_true, c.value, tcg_constant_i64(0),
5755 t_true, t_false);
5756
5757
5758
5759 write_fp_dreg(s, rd, t_true);
5760}
5761
5762
5763static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn)
5764{
5765 TCGv_ptr fpst = NULL;
5766 TCGv_i32 tcg_op = read_fp_hreg(s, rn);
5767 TCGv_i32 tcg_res = tcg_temp_new_i32();
5768
5769 switch (opcode) {
5770 case 0x0:
5771 tcg_gen_mov_i32(tcg_res, tcg_op);
5772 break;
5773 case 0x1:
5774 tcg_gen_andi_i32(tcg_res, tcg_op, 0x7fff);
5775 break;
5776 case 0x2:
5777 tcg_gen_xori_i32(tcg_res, tcg_op, 0x8000);
5778 break;
5779 case 0x3:
5780 fpst = fpstatus_ptr(FPST_FPCR_F16);
5781 gen_helper_sqrt_f16(tcg_res, tcg_op, fpst);
5782 break;
5783 case 0x8:
5784 case 0x9:
5785 case 0xa:
5786 case 0xb:
5787 case 0xc:
5788 {
5789 TCGv_i32 tcg_rmode;
5790
5791 fpst = fpstatus_ptr(FPST_FPCR_F16);
5792 tcg_rmode = gen_set_rmode(opcode & 7, fpst);
5793 gen_helper_advsimd_rinth(tcg_res, tcg_op, fpst);
5794 gen_restore_rmode(tcg_rmode, fpst);
5795 break;
5796 }
5797 case 0xe:
5798 fpst = fpstatus_ptr(FPST_FPCR_F16);
5799 gen_helper_advsimd_rinth_exact(tcg_res, tcg_op, fpst);
5800 break;
5801 case 0xf:
5802 fpst = fpstatus_ptr(FPST_FPCR_F16);
5803 gen_helper_advsimd_rinth(tcg_res, tcg_op, fpst);
5804 break;
5805 default:
5806 g_assert_not_reached();
5807 }
5808
5809 write_fp_sreg(s, rd, tcg_res);
5810}
5811
5812
5813static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
5814{
5815 void (*gen_fpst)(TCGv_i32, TCGv_i32, TCGv_ptr);
5816 TCGv_i32 tcg_op, tcg_res;
5817 TCGv_ptr fpst;
5818 int rmode = -1;
5819
5820 tcg_op = read_fp_sreg(s, rn);
5821 tcg_res = tcg_temp_new_i32();
5822
5823 switch (opcode) {
5824 case 0x0:
5825 tcg_gen_mov_i32(tcg_res, tcg_op);
5826 goto done;
5827 case 0x1:
5828 gen_helper_vfp_abss(tcg_res, tcg_op);
5829 goto done;
5830 case 0x2:
5831 gen_helper_vfp_negs(tcg_res, tcg_op);
5832 goto done;
5833 case 0x3:
5834 gen_helper_vfp_sqrts(tcg_res, tcg_op, cpu_env);
5835 goto done;
5836 case 0x6:
5837 gen_fpst = gen_helper_bfcvt;
5838 break;
5839 case 0x8:
5840 case 0x9:
5841 case 0xa:
5842 case 0xb:
5843 case 0xc:
5844 rmode = opcode & 7;
5845 gen_fpst = gen_helper_rints;
5846 break;
5847 case 0xe:
5848 gen_fpst = gen_helper_rints_exact;
5849 break;
5850 case 0xf:
5851 gen_fpst = gen_helper_rints;
5852 break;
5853 case 0x10:
5854 rmode = FPROUNDING_ZERO;
5855 gen_fpst = gen_helper_frint32_s;
5856 break;
5857 case 0x11:
5858 gen_fpst = gen_helper_frint32_s;
5859 break;
5860 case 0x12:
5861 rmode = FPROUNDING_ZERO;
5862 gen_fpst = gen_helper_frint64_s;
5863 break;
5864 case 0x13:
5865 gen_fpst = gen_helper_frint64_s;
5866 break;
5867 default:
5868 g_assert_not_reached();
5869 }
5870
5871 fpst = fpstatus_ptr(FPST_FPCR);
5872 if (rmode >= 0) {
5873 TCGv_i32 tcg_rmode = gen_set_rmode(rmode, fpst);
5874 gen_fpst(tcg_res, tcg_op, fpst);
5875 gen_restore_rmode(tcg_rmode, fpst);
5876 } else {
5877 gen_fpst(tcg_res, tcg_op, fpst);
5878 }
5879
5880 done:
5881 write_fp_sreg(s, rd, tcg_res);
5882}
5883
5884
5885static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn)
5886{
5887 void (*gen_fpst)(TCGv_i64, TCGv_i64, TCGv_ptr);
5888 TCGv_i64 tcg_op, tcg_res;
5889 TCGv_ptr fpst;
5890 int rmode = -1;
5891
5892 switch (opcode) {
5893 case 0x0:
5894 gen_gvec_fn2(s, false, rd, rn, tcg_gen_gvec_mov, 0);
5895 return;
5896 }
5897
5898 tcg_op = read_fp_dreg(s, rn);
5899 tcg_res = tcg_temp_new_i64();
5900
5901 switch (opcode) {
5902 case 0x1:
5903 gen_helper_vfp_absd(tcg_res, tcg_op);
5904 goto done;
5905 case 0x2:
5906 gen_helper_vfp_negd(tcg_res, tcg_op);
5907 goto done;
5908 case 0x3:
5909 gen_helper_vfp_sqrtd(tcg_res, tcg_op, cpu_env);
5910 goto done;
5911 case 0x8:
5912 case 0x9:
5913 case 0xa:
5914 case 0xb:
5915 case 0xc:
5916 rmode = opcode & 7;
5917 gen_fpst = gen_helper_rintd;
5918 break;
5919 case 0xe:
5920 gen_fpst = gen_helper_rintd_exact;
5921 break;
5922 case 0xf:
5923 gen_fpst = gen_helper_rintd;
5924 break;
5925 case 0x10:
5926 rmode = FPROUNDING_ZERO;
5927 gen_fpst = gen_helper_frint32_d;
5928 break;
5929 case 0x11:
5930 gen_fpst = gen_helper_frint32_d;
5931 break;
5932 case 0x12:
5933 rmode = FPROUNDING_ZERO;
5934 gen_fpst = gen_helper_frint64_d;
5935 break;
5936 case 0x13:
5937 gen_fpst = gen_helper_frint64_d;
5938 break;
5939 default:
5940 g_assert_not_reached();
5941 }
5942
5943 fpst = fpstatus_ptr(FPST_FPCR);
5944 if (rmode >= 0) {
5945 TCGv_i32 tcg_rmode = gen_set_rmode(rmode, fpst);
5946 gen_fpst(tcg_res, tcg_op, fpst);
5947 gen_restore_rmode(tcg_rmode, fpst);
5948 } else {
5949 gen_fpst(tcg_res, tcg_op, fpst);
5950 }
5951
5952 done:
5953 write_fp_dreg(s, rd, tcg_res);
5954}
5955
5956static void handle_fp_fcvt(DisasContext *s, int opcode,
5957 int rd, int rn, int dtype, int ntype)
5958{
5959 switch (ntype) {
5960 case 0x0:
5961 {
5962 TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
5963 if (dtype == 1) {
5964
5965 TCGv_i64 tcg_rd = tcg_temp_new_i64();
5966 gen_helper_vfp_fcvtds(tcg_rd, tcg_rn, cpu_env);
5967 write_fp_dreg(s, rd, tcg_rd);
5968 } else {
5969
5970 TCGv_i32 tcg_rd = tcg_temp_new_i32();
5971 TCGv_i32 ahp = get_ahp_flag();
5972 TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
5973
5974 gen_helper_vfp_fcvt_f32_to_f16(tcg_rd, tcg_rn, fpst, ahp);
5975
5976 write_fp_sreg(s, rd, tcg_rd);
5977 }
5978 break;
5979 }
5980 case 0x1:
5981 {
5982 TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
5983 TCGv_i32 tcg_rd = tcg_temp_new_i32();
5984 if (dtype == 0) {
5985
5986 gen_helper_vfp_fcvtsd(tcg_rd, tcg_rn, cpu_env);
5987 } else {
5988 TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
5989 TCGv_i32 ahp = get_ahp_flag();
5990
5991 gen_helper_vfp_fcvt_f64_to_f16(tcg_rd, tcg_rn, fpst, ahp);
5992
5993 }
5994 write_fp_sreg(s, rd, tcg_rd);
5995 break;
5996 }
5997 case 0x3:
5998 {
5999 TCGv_i32 tcg_rn = read_fp_sreg(s, rn);
6000 TCGv_ptr tcg_fpst = fpstatus_ptr(FPST_FPCR);
6001 TCGv_i32 tcg_ahp = get_ahp_flag();
6002 tcg_gen_ext16u_i32(tcg_rn, tcg_rn);
6003 if (dtype == 0) {
6004
6005 TCGv_i32 tcg_rd = tcg_temp_new_i32();
6006 gen_helper_vfp_fcvt_f16_to_f32(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
6007 write_fp_sreg(s, rd, tcg_rd);
6008 } else {
6009
6010 TCGv_i64 tcg_rd = tcg_temp_new_i64();
6011 gen_helper_vfp_fcvt_f16_to_f64(tcg_rd, tcg_rn, tcg_fpst, tcg_ahp);
6012 write_fp_dreg(s, rd, tcg_rd);
6013 }
6014 break;
6015 }
6016 default:
6017 g_assert_not_reached();
6018 }
6019}
6020
6021
6022
6023
6024
6025
6026
6027static void disas_fp_1src(DisasContext *s, uint32_t insn)
6028{
6029 int mos = extract32(insn, 29, 3);
6030 int type = extract32(insn, 22, 2);
6031 int opcode = extract32(insn, 15, 6);
6032 int rn = extract32(insn, 5, 5);
6033 int rd = extract32(insn, 0, 5);
6034
6035 if (mos) {
6036 goto do_unallocated;
6037 }
6038
6039 switch (opcode) {
6040 case 0x4: case 0x5: case 0x7:
6041 {
6042
6043 int dtype = extract32(opcode, 0, 2);
6044 if (type == 2 || dtype == type) {
6045 goto do_unallocated;
6046 }
6047 if (!fp_access_check(s)) {
6048 return;
6049 }
6050
6051 handle_fp_fcvt(s, opcode, rd, rn, dtype, type);
6052 break;
6053 }
6054
6055 case 0x10 ... 0x13:
6056 if (type > 1 || !dc_isar_feature(aa64_frint, s)) {
6057 goto do_unallocated;
6058 }
6059
6060 case 0x0 ... 0x3:
6061 case 0x8 ... 0xc:
6062 case 0xe ... 0xf:
6063
6064 switch (type) {
6065 case 0:
6066 if (!fp_access_check(s)) {
6067 return;
6068 }
6069 handle_fp_1src_single(s, opcode, rd, rn);
6070 break;
6071 case 1:
6072 if (!fp_access_check(s)) {
6073 return;
6074 }
6075 handle_fp_1src_double(s, opcode, rd, rn);
6076 break;
6077 case 3:
6078 if (!dc_isar_feature(aa64_fp16, s)) {
6079 goto do_unallocated;
6080 }
6081
6082 if (!fp_access_check(s)) {
6083 return;
6084 }
6085 handle_fp_1src_half(s, opcode, rd, rn);
6086 break;
6087 default:
6088 goto do_unallocated;
6089 }
6090 break;
6091
6092 case 0x6:
6093 switch (type) {
6094 case 1:
6095 if (!dc_isar_feature(aa64_bf16, s)) {
6096 goto do_unallocated;
6097 }
6098 if (!fp_access_check(s)) {
6099 return;
6100 }
6101 handle_fp_1src_single(s, opcode, rd, rn);
6102 break;
6103 default:
6104 goto do_unallocated;
6105 }
6106 break;
6107
6108 default:
6109 do_unallocated:
6110 unallocated_encoding(s);
6111 break;
6112 }
6113}
6114
6115
6116static void handle_fp_2src_single(DisasContext *s, int opcode,
6117 int rd, int rn, int rm)
6118{
6119 TCGv_i32 tcg_op1;
6120 TCGv_i32 tcg_op2;
6121 TCGv_i32 tcg_res;
6122 TCGv_ptr fpst;
6123
6124 tcg_res = tcg_temp_new_i32();
6125 fpst = fpstatus_ptr(FPST_FPCR);
6126 tcg_op1 = read_fp_sreg(s, rn);
6127 tcg_op2 = read_fp_sreg(s, rm);
6128
6129 switch (opcode) {
6130 case 0x0:
6131 gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
6132 break;
6133 case 0x1:
6134 gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst);
6135 break;
6136 case 0x2:
6137 gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
6138 break;
6139 case 0x3:
6140 gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
6141 break;
6142 case 0x4:
6143 gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
6144 break;
6145 case 0x5:
6146 gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
6147 break;
6148 case 0x6:
6149 gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
6150 break;
6151 case 0x7:
6152 gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
6153 break;
6154 case 0x8:
6155 gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
6156 gen_helper_vfp_negs(tcg_res, tcg_res);
6157 break;
6158 }
6159
6160 write_fp_sreg(s, rd, tcg_res);
6161}
6162
6163
6164static void handle_fp_2src_double(DisasContext *s, int opcode,
6165 int rd, int rn, int rm)
6166{
6167 TCGv_i64 tcg_op1;
6168 TCGv_i64 tcg_op2;
6169 TCGv_i64 tcg_res;
6170 TCGv_ptr fpst;
6171
6172 tcg_res = tcg_temp_new_i64();
6173 fpst = fpstatus_ptr(FPST_FPCR);
6174 tcg_op1 = read_fp_dreg(s, rn);
6175 tcg_op2 = read_fp_dreg(s, rm);
6176
6177 switch (opcode) {
6178 case 0x0:
6179 gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
6180 break;
6181 case 0x1:
6182 gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst);
6183 break;
6184 case 0x2:
6185 gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
6186 break;
6187 case 0x3:
6188 gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
6189 break;
6190 case 0x4:
6191 gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
6192 break;
6193 case 0x5:
6194 gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
6195 break;
6196 case 0x6:
6197 gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
6198 break;
6199 case 0x7:
6200 gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
6201 break;
6202 case 0x8:
6203 gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
6204 gen_helper_vfp_negd(tcg_res, tcg_res);
6205 break;
6206 }
6207
6208 write_fp_dreg(s, rd, tcg_res);
6209}
6210
6211
6212static void handle_fp_2src_half(DisasContext *s, int opcode,
6213 int rd, int rn, int rm)
6214{
6215 TCGv_i32 tcg_op1;
6216 TCGv_i32 tcg_op2;
6217 TCGv_i32 tcg_res;
6218 TCGv_ptr fpst;
6219
6220 tcg_res = tcg_temp_new_i32();
6221 fpst = fpstatus_ptr(FPST_FPCR_F16);
6222 tcg_op1 = read_fp_hreg(s, rn);
6223 tcg_op2 = read_fp_hreg(s, rm);
6224
6225 switch (opcode) {
6226 case 0x0:
6227 gen_helper_advsimd_mulh(tcg_res, tcg_op1, tcg_op2, fpst);
6228 break;
6229 case 0x1:
6230 gen_helper_advsimd_divh(tcg_res, tcg_op1, tcg_op2, fpst);
6231 break;
6232 case 0x2:
6233 gen_helper_advsimd_addh(tcg_res, tcg_op1, tcg_op2, fpst);
6234 break;
6235 case 0x3:
6236 gen_helper_advsimd_subh(tcg_res, tcg_op1, tcg_op2, fpst);
6237 break;
6238 case 0x4:
6239 gen_helper_advsimd_maxh(tcg_res, tcg_op1, tcg_op2, fpst);
6240 break;
6241 case 0x5:
6242 gen_helper_advsimd_minh(tcg_res, tcg_op1, tcg_op2, fpst);
6243 break;
6244 case 0x6:
6245 gen_helper_advsimd_maxnumh(tcg_res, tcg_op1, tcg_op2, fpst);
6246 break;
6247 case 0x7:
6248 gen_helper_advsimd_minnumh(tcg_res, tcg_op1, tcg_op2, fpst);
6249 break;
6250 case 0x8:
6251 gen_helper_advsimd_mulh(tcg_res, tcg_op1, tcg_op2, fpst);
6252 tcg_gen_xori_i32(tcg_res, tcg_res, 0x8000);
6253 break;
6254 default:
6255 g_assert_not_reached();
6256 }
6257
6258 write_fp_sreg(s, rd, tcg_res);
6259}
6260
6261
6262
6263
6264
6265
6266
6267static void disas_fp_2src(DisasContext *s, uint32_t insn)
6268{
6269 int mos = extract32(insn, 29, 3);
6270 int type = extract32(insn, 22, 2);
6271 int rd = extract32(insn, 0, 5);
6272 int rn = extract32(insn, 5, 5);
6273 int rm = extract32(insn, 16, 5);
6274 int opcode = extract32(insn, 12, 4);
6275
6276 if (opcode > 8 || mos) {
6277 unallocated_encoding(s);
6278 return;
6279 }
6280
6281 switch (type) {
6282 case 0:
6283 if (!fp_access_check(s)) {
6284 return;
6285 }
6286 handle_fp_2src_single(s, opcode, rd, rn, rm);
6287 break;
6288 case 1:
6289 if (!fp_access_check(s)) {
6290 return;
6291 }
6292 handle_fp_2src_double(s, opcode, rd, rn, rm);
6293 break;
6294 case 3:
6295 if (!dc_isar_feature(aa64_fp16, s)) {
6296 unallocated_encoding(s);
6297 return;
6298 }
6299 if (!fp_access_check(s)) {
6300 return;
6301 }
6302 handle_fp_2src_half(s, opcode, rd, rn, rm);
6303 break;
6304 default:
6305 unallocated_encoding(s);
6306 }
6307}
6308
6309
6310static void handle_fp_3src_single(DisasContext *s, bool o0, bool o1,
6311 int rd, int rn, int rm, int ra)
6312{
6313 TCGv_i32 tcg_op1, tcg_op2, tcg_op3;
6314 TCGv_i32 tcg_res = tcg_temp_new_i32();
6315 TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
6316
6317 tcg_op1 = read_fp_sreg(s, rn);
6318 tcg_op2 = read_fp_sreg(s, rm);
6319 tcg_op3 = read_fp_sreg(s, ra);
6320
6321
6322
6323
6324
6325
6326
6327
6328 if (o1 == true) {
6329 gen_helper_vfp_negs(tcg_op3, tcg_op3);
6330 }
6331
6332 if (o0 != o1) {
6333 gen_helper_vfp_negs(tcg_op1, tcg_op1);
6334 }
6335
6336 gen_helper_vfp_muladds(tcg_res, tcg_op1, tcg_op2, tcg_op3, fpst);
6337
6338 write_fp_sreg(s, rd, tcg_res);
6339}
6340
6341
6342static void handle_fp_3src_double(DisasContext *s, bool o0, bool o1,
6343 int rd, int rn, int rm, int ra)
6344{
6345 TCGv_i64 tcg_op1, tcg_op2, tcg_op3;
6346 TCGv_i64 tcg_res = tcg_temp_new_i64();
6347 TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
6348
6349 tcg_op1 = read_fp_dreg(s, rn);
6350 tcg_op2 = read_fp_dreg(s, rm);
6351 tcg_op3 = read_fp_dreg(s, ra);
6352
6353
6354
6355
6356
6357
6358
6359
6360 if (o1 == true) {
6361 gen_helper_vfp_negd(tcg_op3, tcg_op3);
6362 }
6363
6364 if (o0 != o1) {
6365 gen_helper_vfp_negd(tcg_op1, tcg_op1);
6366 }
6367
6368 gen_helper_vfp_muladdd(tcg_res, tcg_op1, tcg_op2, tcg_op3, fpst);
6369
6370 write_fp_dreg(s, rd, tcg_res);
6371}
6372
6373
6374static void handle_fp_3src_half(DisasContext *s, bool o0, bool o1,
6375 int rd, int rn, int rm, int ra)
6376{
6377 TCGv_i32 tcg_op1, tcg_op2, tcg_op3;
6378 TCGv_i32 tcg_res = tcg_temp_new_i32();
6379 TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR_F16);
6380
6381 tcg_op1 = read_fp_hreg(s, rn);
6382 tcg_op2 = read_fp_hreg(s, rm);
6383 tcg_op3 = read_fp_hreg(s, ra);
6384
6385
6386
6387
6388
6389
6390
6391
6392 if (o1 == true) {
6393 tcg_gen_xori_i32(tcg_op3, tcg_op3, 0x8000);
6394 }
6395
6396 if (o0 != o1) {
6397 tcg_gen_xori_i32(tcg_op1, tcg_op1, 0x8000);
6398 }
6399
6400 gen_helper_advsimd_muladdh(tcg_res, tcg_op1, tcg_op2, tcg_op3, fpst);
6401
6402 write_fp_sreg(s, rd, tcg_res);
6403}
6404
6405
6406
6407
6408
6409
6410
6411static void disas_fp_3src(DisasContext *s, uint32_t insn)
6412{
6413 int mos = extract32(insn, 29, 3);
6414 int type = extract32(insn, 22, 2);
6415 int rd = extract32(insn, 0, 5);
6416 int rn = extract32(insn, 5, 5);
6417 int ra = extract32(insn, 10, 5);
6418 int rm = extract32(insn, 16, 5);
6419 bool o0 = extract32(insn, 15, 1);
6420 bool o1 = extract32(insn, 21, 1);
6421
6422 if (mos) {
6423 unallocated_encoding(s);
6424 return;
6425 }
6426
6427 switch (type) {
6428 case 0:
6429 if (!fp_access_check(s)) {
6430 return;
6431 }
6432 handle_fp_3src_single(s, o0, o1, rd, rn, rm, ra);
6433 break;
6434 case 1:
6435 if (!fp_access_check(s)) {
6436 return;
6437 }
6438 handle_fp_3src_double(s, o0, o1, rd, rn, rm, ra);
6439 break;
6440 case 3:
6441 if (!dc_isar_feature(aa64_fp16, s)) {
6442 unallocated_encoding(s);
6443 return;
6444 }
6445 if (!fp_access_check(s)) {
6446 return;
6447 }
6448 handle_fp_3src_half(s, o0, o1, rd, rn, rm, ra);
6449 break;
6450 default:
6451 unallocated_encoding(s);
6452 }
6453}
6454
6455
6456
6457
6458
6459
6460
6461static void disas_fp_imm(DisasContext *s, uint32_t insn)
6462{
6463 int rd = extract32(insn, 0, 5);
6464 int imm5 = extract32(insn, 5, 5);
6465 int imm8 = extract32(insn, 13, 8);
6466 int type = extract32(insn, 22, 2);
6467 int mos = extract32(insn, 29, 3);
6468 uint64_t imm;
6469 MemOp sz;
6470
6471 if (mos || imm5) {
6472 unallocated_encoding(s);
6473 return;
6474 }
6475
6476 switch (type) {
6477 case 0:
6478 sz = MO_32;
6479 break;
6480 case 1:
6481 sz = MO_64;
6482 break;
6483 case 3:
6484 sz = MO_16;
6485 if (dc_isar_feature(aa64_fp16, s)) {
6486 break;
6487 }
6488
6489 default:
6490 unallocated_encoding(s);
6491 return;
6492 }
6493
6494 if (!fp_access_check(s)) {
6495 return;
6496 }
6497
6498 imm = vfp_expand_imm(sz, imm8);
6499 write_fp_dreg(s, rd, tcg_constant_i64(imm));
6500}
6501
6502
6503
6504
6505
6506
6507static void handle_fpfpcvt(DisasContext *s, int rd, int rn, int opcode,
6508 bool itof, int rmode, int scale, int sf, int type)
6509{
6510 bool is_signed = !(opcode & 1);
6511 TCGv_ptr tcg_fpstatus;
6512 TCGv_i32 tcg_shift, tcg_single;
6513 TCGv_i64 tcg_double;
6514
6515 tcg_fpstatus = fpstatus_ptr(type == 3 ? FPST_FPCR_F16 : FPST_FPCR);
6516
6517 tcg_shift = tcg_constant_i32(64 - scale);
6518
6519 if (itof) {
6520 TCGv_i64 tcg_int = cpu_reg(s, rn);
6521 if (!sf) {
6522 TCGv_i64 tcg_extend = tcg_temp_new_i64();
6523
6524 if (is_signed) {
6525 tcg_gen_ext32s_i64(tcg_extend, tcg_int);
6526 } else {
6527 tcg_gen_ext32u_i64(tcg_extend, tcg_int);
6528 }
6529
6530 tcg_int = tcg_extend;
6531 }
6532
6533 switch (type) {
6534 case 1:
6535 tcg_double = tcg_temp_new_i64();
6536 if (is_signed) {
6537 gen_helper_vfp_sqtod(tcg_double, tcg_int,
6538 tcg_shift, tcg_fpstatus);
6539 } else {
6540 gen_helper_vfp_uqtod(tcg_double, tcg_int,
6541 tcg_shift, tcg_fpstatus);
6542 }
6543 write_fp_dreg(s, rd, tcg_double);
6544 break;
6545
6546 case 0:
6547 tcg_single = tcg_temp_new_i32();
6548 if (is_signed) {
6549 gen_helper_vfp_sqtos(tcg_single, tcg_int,
6550 tcg_shift, tcg_fpstatus);
6551 } else {
6552 gen_helper_vfp_uqtos(tcg_single, tcg_int,
6553 tcg_shift, tcg_fpstatus);
6554 }
6555 write_fp_sreg(s, rd, tcg_single);
6556 break;
6557
6558 case 3:
6559 tcg_single = tcg_temp_new_i32();
6560 if (is_signed) {
6561 gen_helper_vfp_sqtoh(tcg_single, tcg_int,
6562 tcg_shift, tcg_fpstatus);
6563 } else {
6564 gen_helper_vfp_uqtoh(tcg_single, tcg_int,
6565 tcg_shift, tcg_fpstatus);
6566 }
6567 write_fp_sreg(s, rd, tcg_single);
6568 break;
6569
6570 default:
6571 g_assert_not_reached();
6572 }
6573 } else {
6574 TCGv_i64 tcg_int = cpu_reg(s, rd);
6575 TCGv_i32 tcg_rmode;
6576
6577 if (extract32(opcode, 2, 1)) {
6578
6579
6580
6581 rmode = FPROUNDING_TIEAWAY;
6582 }
6583
6584 tcg_rmode = gen_set_rmode(rmode, tcg_fpstatus);
6585
6586 switch (type) {
6587 case 1:
6588 tcg_double = read_fp_dreg(s, rn);
6589 if (is_signed) {
6590 if (!sf) {
6591 gen_helper_vfp_tosld(tcg_int, tcg_double,
6592 tcg_shift, tcg_fpstatus);
6593 } else {
6594 gen_helper_vfp_tosqd(tcg_int, tcg_double,
6595 tcg_shift, tcg_fpstatus);
6596 }
6597 } else {
6598 if (!sf) {
6599 gen_helper_vfp_tould(tcg_int, tcg_double,
6600 tcg_shift, tcg_fpstatus);
6601 } else {
6602 gen_helper_vfp_touqd(tcg_int, tcg_double,
6603 tcg_shift, tcg_fpstatus);
6604 }
6605 }
6606 if (!sf) {
6607 tcg_gen_ext32u_i64(tcg_int, tcg_int);
6608 }
6609 break;
6610
6611 case 0:
6612 tcg_single = read_fp_sreg(s, rn);
6613 if (sf) {
6614 if (is_signed) {
6615 gen_helper_vfp_tosqs(tcg_int, tcg_single,
6616 tcg_shift, tcg_fpstatus);
6617 } else {
6618 gen_helper_vfp_touqs(tcg_int, tcg_single,
6619 tcg_shift, tcg_fpstatus);
6620 }
6621 } else {
6622 TCGv_i32 tcg_dest = tcg_temp_new_i32();
6623 if (is_signed) {
6624 gen_helper_vfp_tosls(tcg_dest, tcg_single,
6625 tcg_shift, tcg_fpstatus);
6626 } else {
6627 gen_helper_vfp_touls(tcg_dest, tcg_single,
6628 tcg_shift, tcg_fpstatus);
6629 }
6630 tcg_gen_extu_i32_i64(tcg_int, tcg_dest);
6631 }
6632 break;
6633
6634 case 3:
6635 tcg_single = read_fp_sreg(s, rn);
6636 if (sf) {
6637 if (is_signed) {
6638 gen_helper_vfp_tosqh(tcg_int, tcg_single,
6639 tcg_shift, tcg_fpstatus);
6640 } else {
6641 gen_helper_vfp_touqh(tcg_int, tcg_single,
6642 tcg_shift, tcg_fpstatus);
6643 }
6644 } else {
6645 TCGv_i32 tcg_dest = tcg_temp_new_i32();
6646 if (is_signed) {
6647 gen_helper_vfp_toslh(tcg_dest, tcg_single,
6648 tcg_shift, tcg_fpstatus);
6649 } else {
6650 gen_helper_vfp_toulh(tcg_dest, tcg_single,
6651 tcg_shift, tcg_fpstatus);
6652 }
6653 tcg_gen_extu_i32_i64(tcg_int, tcg_dest);
6654 }
6655 break;
6656
6657 default:
6658 g_assert_not_reached();
6659 }
6660
6661 gen_restore_rmode(tcg_rmode, tcg_fpstatus);
6662 }
6663}
6664
6665
6666
6667
6668
6669
6670
6671static void disas_fp_fixed_conv(DisasContext *s, uint32_t insn)
6672{
6673 int rd = extract32(insn, 0, 5);
6674 int rn = extract32(insn, 5, 5);
6675 int scale = extract32(insn, 10, 6);
6676 int opcode = extract32(insn, 16, 3);
6677 int rmode = extract32(insn, 19, 2);
6678 int type = extract32(insn, 22, 2);
6679 bool sbit = extract32(insn, 29, 1);
6680 bool sf = extract32(insn, 31, 1);
6681 bool itof;
6682
6683 if (sbit || (!sf && scale < 32)) {
6684 unallocated_encoding(s);
6685 return;
6686 }
6687
6688 switch (type) {
6689 case 0:
6690 case 1:
6691 break;
6692 case 3:
6693 if (dc_isar_feature(aa64_fp16, s)) {
6694 break;
6695 }
6696
6697 default:
6698 unallocated_encoding(s);
6699 return;
6700 }
6701
6702 switch ((rmode << 3) | opcode) {
6703 case 0x2:
6704 case 0x3:
6705 itof = true;
6706 break;
6707 case 0x18:
6708 case 0x19:
6709 itof = false;
6710 break;
6711 default:
6712 unallocated_encoding(s);
6713 return;
6714 }
6715
6716 if (!fp_access_check(s)) {
6717 return;
6718 }
6719
6720 handle_fpfpcvt(s, rd, rn, opcode, itof, FPROUNDING_ZERO, scale, sf, type);
6721}
6722
6723static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
6724{
6725
6726
6727
6728
6729 if (itof) {
6730 TCGv_i64 tcg_rn = cpu_reg(s, rn);
6731 TCGv_i64 tmp;
6732
6733 switch (type) {
6734 case 0:
6735
6736 tmp = tcg_temp_new_i64();
6737 tcg_gen_ext32u_i64(tmp, tcg_rn);
6738 write_fp_dreg(s, rd, tmp);
6739 break;
6740 case 1:
6741
6742 write_fp_dreg(s, rd, tcg_rn);
6743 break;
6744 case 2:
6745
6746 tcg_gen_st_i64(tcg_rn, cpu_env, fp_reg_hi_offset(s, rd));
6747 clear_vec_high(s, true, rd);
6748 break;
6749 case 3:
6750
6751 tmp = tcg_temp_new_i64();
6752 tcg_gen_ext16u_i64(tmp, tcg_rn);
6753 write_fp_dreg(s, rd, tmp);
6754 break;
6755 default:
6756 g_assert_not_reached();
6757 }
6758 } else {
6759 TCGv_i64 tcg_rd = cpu_reg(s, rd);
6760
6761 switch (type) {
6762 case 0:
6763
6764 tcg_gen_ld32u_i64(tcg_rd, cpu_env, fp_reg_offset(s, rn, MO_32));
6765 break;
6766 case 1:
6767
6768 tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_offset(s, rn, MO_64));
6769 break;
6770 case 2:
6771
6772 tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_hi_offset(s, rn));
6773 break;
6774 case 3:
6775
6776 tcg_gen_ld16u_i64(tcg_rd, cpu_env, fp_reg_offset(s, rn, MO_16));
6777 break;
6778 default:
6779 g_assert_not_reached();
6780 }
6781 }
6782}
6783
6784static void handle_fjcvtzs(DisasContext *s, int rd, int rn)
6785{
6786 TCGv_i64 t = read_fp_dreg(s, rn);
6787 TCGv_ptr fpstatus = fpstatus_ptr(FPST_FPCR);
6788
6789 gen_helper_fjcvtzs(t, t, fpstatus);
6790
6791 tcg_gen_ext32u_i64(cpu_reg(s, rd), t);
6792 tcg_gen_extrh_i64_i32(cpu_ZF, t);
6793 tcg_gen_movi_i32(cpu_CF, 0);
6794 tcg_gen_movi_i32(cpu_NF, 0);
6795 tcg_gen_movi_i32(cpu_VF, 0);
6796}
6797
6798
6799
6800
6801
6802
6803
6804static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
6805{
6806 int rd = extract32(insn, 0, 5);
6807 int rn = extract32(insn, 5, 5);
6808 int opcode = extract32(insn, 16, 3);
6809 int rmode = extract32(insn, 19, 2);
6810 int type = extract32(insn, 22, 2);
6811 bool sbit = extract32(insn, 29, 1);
6812 bool sf = extract32(insn, 31, 1);
6813 bool itof = false;
6814
6815 if (sbit) {
6816 goto do_unallocated;
6817 }
6818
6819 switch (opcode) {
6820 case 2:
6821 case 3:
6822 itof = true;
6823
6824 case 4:
6825 case 5:
6826 if (rmode != 0) {
6827 goto do_unallocated;
6828 }
6829
6830 case 0:
6831 case 1:
6832 switch (type) {
6833 case 0:
6834 case 1:
6835 break;
6836 case 3:
6837 if (!dc_isar_feature(aa64_fp16, s)) {
6838 goto do_unallocated;
6839 }
6840 break;
6841 default:
6842 goto do_unallocated;
6843 }
6844 if (!fp_access_check(s)) {
6845 return;
6846 }
6847 handle_fpfpcvt(s, rd, rn, opcode, itof, rmode, 64, sf, type);
6848 break;
6849
6850 default:
6851 switch (sf << 7 | type << 5 | rmode << 3 | opcode) {
6852 case 0b01100110:
6853 case 0b01100111:
6854 case 0b11100110:
6855 case 0b11100111:
6856 if (!dc_isar_feature(aa64_fp16, s)) {
6857 goto do_unallocated;
6858 }
6859
6860 case 0b00000110:
6861 case 0b00000111:
6862 case 0b10100110:
6863 case 0b10100111:
6864 case 0b11001110:
6865 case 0b11001111:
6866 if (!fp_access_check(s)) {
6867 return;
6868 }
6869 itof = opcode & 1;
6870 handle_fmov(s, rd, rn, type, itof);
6871 break;
6872
6873 case 0b00111110:
6874 if (!dc_isar_feature(aa64_jscvt, s)) {
6875 goto do_unallocated;
6876 } else if (fp_access_check(s)) {
6877 handle_fjcvtzs(s, rd, rn);
6878 }
6879 break;
6880
6881 default:
6882 do_unallocated:
6883 unallocated_encoding(s);
6884 return;
6885 }
6886 break;
6887 }
6888}
6889
6890
6891
6892
6893
6894
6895
6896static void disas_data_proc_fp(DisasContext *s, uint32_t insn)
6897{
6898 if (extract32(insn, 24, 1)) {
6899
6900 disas_fp_3src(s, insn);
6901 } else if (extract32(insn, 21, 1) == 0) {
6902
6903 disas_fp_fixed_conv(s, insn);
6904 } else {
6905 switch (extract32(insn, 10, 2)) {
6906 case 1:
6907
6908 disas_fp_ccomp(s, insn);
6909 break;
6910 case 2:
6911
6912 disas_fp_2src(s, insn);
6913 break;
6914 case 3:
6915
6916 disas_fp_csel(s, insn);
6917 break;
6918 case 0:
6919 switch (ctz32(extract32(insn, 12, 4))) {
6920 case 0:
6921
6922 disas_fp_imm(s, insn);
6923 break;
6924 case 1:
6925
6926 disas_fp_compare(s, insn);
6927 break;
6928 case 2:
6929
6930 disas_fp_1src(s, insn);
6931 break;
6932 case 3:
6933 unallocated_encoding(s);
6934 break;
6935 default:
6936
6937 disas_fp_int_conv(s, insn);
6938 break;
6939 }
6940 break;
6941 }
6942 }
6943}
6944
6945static void do_ext64(DisasContext *s, TCGv_i64 tcg_left, TCGv_i64 tcg_right,
6946 int pos)
6947{
6948
6949
6950
6951
6952
6953
6954 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
6955 assert(pos > 0 && pos < 64);
6956
6957 tcg_gen_shri_i64(tcg_right, tcg_right, pos);
6958 tcg_gen_shli_i64(tcg_tmp, tcg_left, 64 - pos);
6959 tcg_gen_or_i64(tcg_right, tcg_right, tcg_tmp);
6960}
6961
6962
6963
6964
6965
6966
6967
6968static void disas_simd_ext(DisasContext *s, uint32_t insn)
6969{
6970 int is_q = extract32(insn, 30, 1);
6971 int op2 = extract32(insn, 22, 2);
6972 int imm4 = extract32(insn, 11, 4);
6973 int rm = extract32(insn, 16, 5);
6974 int rn = extract32(insn, 5, 5);
6975 int rd = extract32(insn, 0, 5);
6976 int pos = imm4 << 3;
6977 TCGv_i64 tcg_resl, tcg_resh;
6978
6979 if (op2 != 0 || (!is_q && extract32(imm4, 3, 1))) {
6980 unallocated_encoding(s);
6981 return;
6982 }
6983
6984 if (!fp_access_check(s)) {
6985 return;
6986 }
6987
6988 tcg_resh = tcg_temp_new_i64();
6989 tcg_resl = tcg_temp_new_i64();
6990
6991
6992
6993
6994
6995 if (!is_q) {
6996 read_vec_element(s, tcg_resl, rn, 0, MO_64);
6997 if (pos != 0) {
6998 read_vec_element(s, tcg_resh, rm, 0, MO_64);
6999 do_ext64(s, tcg_resh, tcg_resl, pos);
7000 }
7001 } else {
7002 TCGv_i64 tcg_hh;
7003 typedef struct {
7004 int reg;
7005 int elt;
7006 } EltPosns;
7007 EltPosns eltposns[] = { {rn, 0}, {rn, 1}, {rm, 0}, {rm, 1} };
7008 EltPosns *elt = eltposns;
7009
7010 if (pos >= 64) {
7011 elt++;
7012 pos -= 64;
7013 }
7014
7015 read_vec_element(s, tcg_resl, elt->reg, elt->elt, MO_64);
7016 elt++;
7017 read_vec_element(s, tcg_resh, elt->reg, elt->elt, MO_64);
7018 elt++;
7019 if (pos != 0) {
7020 do_ext64(s, tcg_resh, tcg_resl, pos);
7021 tcg_hh = tcg_temp_new_i64();
7022 read_vec_element(s, tcg_hh, elt->reg, elt->elt, MO_64);
7023 do_ext64(s, tcg_hh, tcg_resh, pos);
7024 }
7025 }
7026
7027 write_vec_element(s, tcg_resl, rd, 0, MO_64);
7028 if (is_q) {
7029 write_vec_element(s, tcg_resh, rd, 1, MO_64);
7030 }
7031 clear_vec_high(s, is_q, rd);
7032}
7033
7034
7035
7036
7037
7038
7039
7040static void disas_simd_tb(DisasContext *s, uint32_t insn)
7041{
7042 int op2 = extract32(insn, 22, 2);
7043 int is_q = extract32(insn, 30, 1);
7044 int rm = extract32(insn, 16, 5);
7045 int rn = extract32(insn, 5, 5);
7046 int rd = extract32(insn, 0, 5);
7047 int is_tbx = extract32(insn, 12, 1);
7048 int len = (extract32(insn, 13, 2) + 1) * 16;
7049
7050 if (op2 != 0) {
7051 unallocated_encoding(s);
7052 return;
7053 }
7054
7055 if (!fp_access_check(s)) {
7056 return;
7057 }
7058
7059 tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, rd),
7060 vec_full_reg_offset(s, rm), cpu_env,
7061 is_q ? 16 : 8, vec_full_reg_size(s),
7062 (len << 6) | (is_tbx << 5) | rn,
7063 gen_helper_simd_tblx);
7064}
7065
7066
7067
7068
7069
7070
7071
7072static void disas_simd_zip_trn(DisasContext *s, uint32_t insn)
7073{
7074 int rd = extract32(insn, 0, 5);
7075 int rn = extract32(insn, 5, 5);
7076 int rm = extract32(insn, 16, 5);
7077 int size = extract32(insn, 22, 2);
7078
7079
7080
7081 int opcode = extract32(insn, 12, 2);
7082 bool part = extract32(insn, 14, 1);
7083 bool is_q = extract32(insn, 30, 1);
7084 int esize = 8 << size;
7085 int i;
7086 int datasize = is_q ? 128 : 64;
7087 int elements = datasize / esize;
7088 TCGv_i64 tcg_res[2], tcg_ele;
7089
7090 if (opcode == 0 || (size == 3 && !is_q)) {
7091 unallocated_encoding(s);
7092 return;
7093 }
7094
7095 if (!fp_access_check(s)) {
7096 return;
7097 }
7098
7099 tcg_res[0] = tcg_temp_new_i64();
7100 tcg_res[1] = is_q ? tcg_temp_new_i64() : NULL;
7101 tcg_ele = tcg_temp_new_i64();
7102
7103 for (i = 0; i < elements; i++) {
7104 int o, w;
7105
7106 switch (opcode) {
7107 case 1:
7108 {
7109 int midpoint = elements / 2;
7110 if (i < midpoint) {
7111 read_vec_element(s, tcg_ele, rn, 2 * i + part, size);
7112 } else {
7113 read_vec_element(s, tcg_ele, rm,
7114 2 * (i - midpoint) + part, size);
7115 }
7116 break;
7117 }
7118 case 2:
7119 if (i & 1) {
7120 read_vec_element(s, tcg_ele, rm, (i & ~1) + part, size);
7121 } else {
7122 read_vec_element(s, tcg_ele, rn, (i & ~1) + part, size);
7123 }
7124 break;
7125 case 3:
7126 {
7127 int base = part * elements / 2;
7128 if (i & 1) {
7129 read_vec_element(s, tcg_ele, rm, base + (i >> 1), size);
7130 } else {
7131 read_vec_element(s, tcg_ele, rn, base + (i >> 1), size);
7132 }
7133 break;
7134 }
7135 default:
7136 g_assert_not_reached();
7137 }
7138
7139 w = (i * esize) / 64;
7140 o = (i * esize) % 64;
7141 if (o == 0) {
7142 tcg_gen_mov_i64(tcg_res[w], tcg_ele);
7143 } else {
7144 tcg_gen_shli_i64(tcg_ele, tcg_ele, o);
7145 tcg_gen_or_i64(tcg_res[w], tcg_res[w], tcg_ele);
7146 }
7147 }
7148
7149 for (i = 0; i <= is_q; ++i) {
7150 write_vec_element(s, tcg_res[i], rd, i, MO_64);
7151 }
7152 clear_vec_high(s, is_q, rd);
7153}
7154
7155
7156
7157
7158
7159
7160
7161
7162
7163
7164
7165static TCGv_i32 do_reduction_op(DisasContext *s, int fpopcode, int rn,
7166 int esize, int size, int vmap, TCGv_ptr fpst)
7167{
7168 if (esize == size) {
7169 int element;
7170 MemOp msize = esize == 16 ? MO_16 : MO_32;
7171 TCGv_i32 tcg_elem;
7172
7173
7174 assert(ctpop8(vmap) == 1);
7175 element = ctz32(vmap);
7176 assert(element < 8);
7177
7178 tcg_elem = tcg_temp_new_i32();
7179 read_vec_element_i32(s, tcg_elem, rn, element, msize);
7180 return tcg_elem;
7181 } else {
7182 int bits = size / 2;
7183 int shift = ctpop8(vmap) / 2;
7184 int vmap_lo = (vmap >> shift) & vmap;
7185 int vmap_hi = (vmap & ~vmap_lo);
7186 TCGv_i32 tcg_hi, tcg_lo, tcg_res;
7187
7188 tcg_hi = do_reduction_op(s, fpopcode, rn, esize, bits, vmap_hi, fpst);
7189 tcg_lo = do_reduction_op(s, fpopcode, rn, esize, bits, vmap_lo, fpst);
7190 tcg_res = tcg_temp_new_i32();
7191
7192 switch (fpopcode) {
7193 case 0x0c:
7194 gen_helper_advsimd_maxnumh(tcg_res, tcg_lo, tcg_hi, fpst);
7195 break;
7196 case 0x0f:
7197 gen_helper_advsimd_maxh(tcg_res, tcg_lo, tcg_hi, fpst);
7198 break;
7199 case 0x1c:
7200 gen_helper_advsimd_minnumh(tcg_res, tcg_lo, tcg_hi, fpst);
7201 break;
7202 case 0x1f:
7203 gen_helper_advsimd_minh(tcg_res, tcg_lo, tcg_hi, fpst);
7204 break;
7205 case 0x2c:
7206 gen_helper_vfp_maxnums(tcg_res, tcg_lo, tcg_hi, fpst);
7207 break;
7208 case 0x2f:
7209 gen_helper_vfp_maxs(tcg_res, tcg_lo, tcg_hi, fpst);
7210 break;
7211 case 0x3c:
7212 gen_helper_vfp_minnums(tcg_res, tcg_lo, tcg_hi, fpst);
7213 break;
7214 case 0x3f:
7215 gen_helper_vfp_mins(tcg_res, tcg_lo, tcg_hi, fpst);
7216 break;
7217 default:
7218 g_assert_not_reached();
7219 }
7220 return tcg_res;
7221 }
7222}
7223
7224
7225
7226
7227
7228
7229
7230static void disas_simd_across_lanes(DisasContext *s, uint32_t insn)
7231{
7232 int rd = extract32(insn, 0, 5);
7233 int rn = extract32(insn, 5, 5);
7234 int size = extract32(insn, 22, 2);
7235 int opcode = extract32(insn, 12, 5);
7236 bool is_q = extract32(insn, 30, 1);
7237 bool is_u = extract32(insn, 29, 1);
7238 bool is_fp = false;
7239 bool is_min = false;
7240 int esize;
7241 int elements;
7242 int i;
7243 TCGv_i64 tcg_res, tcg_elt;
7244
7245 switch (opcode) {
7246 case 0x1b:
7247 if (is_u) {
7248 unallocated_encoding(s);
7249 return;
7250 }
7251
7252 case 0x3:
7253 case 0xa:
7254 case 0x1a:
7255 if (size == 3 || (size == 2 && !is_q)) {
7256 unallocated_encoding(s);
7257 return;
7258 }
7259 break;
7260 case 0xc:
7261 case 0xf:
7262
7263
7264
7265
7266
7267 is_min = extract32(size, 1, 1);
7268 is_fp = true;
7269 if (!is_u && dc_isar_feature(aa64_fp16, s)) {
7270 size = 1;
7271 } else if (!is_u || !is_q || extract32(size, 0, 1)) {
7272 unallocated_encoding(s);
7273 return;
7274 } else {
7275 size = 2;
7276 }
7277 break;
7278 default:
7279 unallocated_encoding(s);
7280 return;
7281 }
7282
7283 if (!fp_access_check(s)) {
7284 return;
7285 }
7286
7287 esize = 8 << size;
7288 elements = (is_q ? 128 : 64) / esize;
7289
7290 tcg_res = tcg_temp_new_i64();
7291 tcg_elt = tcg_temp_new_i64();
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305 if (!is_fp) {
7306 read_vec_element(s, tcg_res, rn, 0, size | (is_u ? 0 : MO_SIGN));
7307
7308 for (i = 1; i < elements; i++) {
7309 read_vec_element(s, tcg_elt, rn, i, size | (is_u ? 0 : MO_SIGN));
7310
7311 switch (opcode) {
7312 case 0x03:
7313 case 0x1b:
7314 tcg_gen_add_i64(tcg_res, tcg_res, tcg_elt);
7315 break;
7316 case 0x0a:
7317 if (is_u) {
7318 tcg_gen_umax_i64(tcg_res, tcg_res, tcg_elt);
7319 } else {
7320 tcg_gen_smax_i64(tcg_res, tcg_res, tcg_elt);
7321 }
7322 break;
7323 case 0x1a:
7324 if (is_u) {
7325 tcg_gen_umin_i64(tcg_res, tcg_res, tcg_elt);
7326 } else {
7327 tcg_gen_smin_i64(tcg_res, tcg_res, tcg_elt);
7328 }
7329 break;
7330 default:
7331 g_assert_not_reached();
7332 }
7333
7334 }
7335 } else {
7336
7337
7338
7339
7340
7341 TCGv_ptr fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
7342 int fpopcode = opcode | is_min << 4 | is_u << 5;
7343 int vmap = (1 << elements) - 1;
7344 TCGv_i32 tcg_res32 = do_reduction_op(s, fpopcode, rn, esize,
7345 (is_q ? 128 : 64), vmap, fpst);
7346 tcg_gen_extu_i32_i64(tcg_res, tcg_res32);
7347 }
7348
7349
7350 if (opcode == 0x03) {
7351
7352 size++;
7353 }
7354
7355 switch (size) {
7356 case 0:
7357 tcg_gen_ext8u_i64(tcg_res, tcg_res);
7358 break;
7359 case 1:
7360 tcg_gen_ext16u_i64(tcg_res, tcg_res);
7361 break;
7362 case 2:
7363 tcg_gen_ext32u_i64(tcg_res, tcg_res);
7364 break;
7365 case 3:
7366 break;
7367 default:
7368 g_assert_not_reached();
7369 }
7370
7371 write_fp_dreg(s, rd, tcg_res);
7372}
7373
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383static void handle_simd_dupe(DisasContext *s, int is_q, int rd, int rn,
7384 int imm5)
7385{
7386 int size = ctz32(imm5);
7387 int index;
7388
7389 if (size > 3 || (size == 3 && !is_q)) {
7390 unallocated_encoding(s);
7391 return;
7392 }
7393
7394 if (!fp_access_check(s)) {
7395 return;
7396 }
7397
7398 index = imm5 >> (size + 1);
7399 tcg_gen_gvec_dup_mem(size, vec_full_reg_offset(s, rd),
7400 vec_reg_offset(s, rn, index, size),
7401 is_q ? 16 : 8, vec_full_reg_size(s));
7402}
7403
7404
7405
7406
7407
7408
7409
7410static void handle_simd_dupes(DisasContext *s, int rd, int rn,
7411 int imm5)
7412{
7413 int size = ctz32(imm5);
7414 int index;
7415 TCGv_i64 tmp;
7416
7417 if (size > 3) {
7418 unallocated_encoding(s);
7419 return;
7420 }
7421
7422 if (!fp_access_check(s)) {
7423 return;
7424 }
7425
7426 index = imm5 >> (size + 1);
7427
7428
7429
7430
7431 tmp = tcg_temp_new_i64();
7432 read_vec_element(s, tmp, rn, index, size);
7433 write_fp_dreg(s, rd, tmp);
7434}
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445static void handle_simd_dupg(DisasContext *s, int is_q, int rd, int rn,
7446 int imm5)
7447{
7448 int size = ctz32(imm5);
7449 uint32_t dofs, oprsz, maxsz;
7450
7451 if (size > 3 || ((size == 3) && !is_q)) {
7452 unallocated_encoding(s);
7453 return;
7454 }
7455
7456 if (!fp_access_check(s)) {
7457 return;
7458 }
7459
7460 dofs = vec_full_reg_offset(s, rd);
7461 oprsz = is_q ? 16 : 8;
7462 maxsz = vec_full_reg_size(s);
7463
7464 tcg_gen_gvec_dup_i64(size, dofs, oprsz, maxsz, cpu_reg(s, rn));
7465}
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477static void handle_simd_inse(DisasContext *s, int rd, int rn,
7478 int imm4, int imm5)
7479{
7480 int size = ctz32(imm5);
7481 int src_index, dst_index;
7482 TCGv_i64 tmp;
7483
7484 if (size > 3) {
7485 unallocated_encoding(s);
7486 return;
7487 }
7488
7489 if (!fp_access_check(s)) {
7490 return;
7491 }
7492
7493 dst_index = extract32(imm5, 1+size, 5);
7494 src_index = extract32(imm4, size, 4);
7495
7496 tmp = tcg_temp_new_i64();
7497
7498 read_vec_element(s, tmp, rn, src_index, size);
7499 write_vec_element(s, tmp, rd, dst_index, size);
7500
7501
7502 clear_vec_high(s, true, rd);
7503}
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516static void handle_simd_insg(DisasContext *s, int rd, int rn, int imm5)
7517{
7518 int size = ctz32(imm5);
7519 int idx;
7520
7521 if (size > 3) {
7522 unallocated_encoding(s);
7523 return;
7524 }
7525
7526 if (!fp_access_check(s)) {
7527 return;
7528 }
7529
7530 idx = extract32(imm5, 1 + size, 4 - size);
7531 write_vec_element(s, cpu_reg(s, rn), rd, idx, size);
7532
7533
7534 clear_vec_high(s, true, rd);
7535}
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549static void handle_simd_umov_smov(DisasContext *s, int is_q, int is_signed,
7550 int rn, int rd, int imm5)
7551{
7552 int size = ctz32(imm5);
7553 int element;
7554 TCGv_i64 tcg_rd;
7555
7556
7557 if (is_signed) {
7558 if (size > 2 || (size == 2 && !is_q)) {
7559 unallocated_encoding(s);
7560 return;
7561 }
7562 } else {
7563 if (size > 3
7564 || (size < 3 && is_q)
7565 || (size == 3 && !is_q)) {
7566 unallocated_encoding(s);
7567 return;
7568 }
7569 }
7570
7571 if (!fp_access_check(s)) {
7572 return;
7573 }
7574
7575 element = extract32(imm5, 1+size, 4);
7576
7577 tcg_rd = cpu_reg(s, rd);
7578 read_vec_element(s, tcg_rd, rn, element, size | (is_signed ? MO_SIGN : 0));
7579 if (is_signed && !is_q) {
7580 tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
7581 }
7582}
7583
7584
7585
7586
7587
7588
7589
7590static void disas_simd_copy(DisasContext *s, uint32_t insn)
7591{
7592 int rd = extract32(insn, 0, 5);
7593 int rn = extract32(insn, 5, 5);
7594 int imm4 = extract32(insn, 11, 4);
7595 int op = extract32(insn, 29, 1);
7596 int is_q = extract32(insn, 30, 1);
7597 int imm5 = extract32(insn, 16, 5);
7598
7599 if (op) {
7600 if (is_q) {
7601
7602 handle_simd_inse(s, rd, rn, imm4, imm5);
7603 } else {
7604 unallocated_encoding(s);
7605 }
7606 } else {
7607 switch (imm4) {
7608 case 0:
7609
7610 handle_simd_dupe(s, is_q, rd, rn, imm5);
7611 break;
7612 case 1:
7613
7614 handle_simd_dupg(s, is_q, rd, rn, imm5);
7615 break;
7616 case 3:
7617 if (is_q) {
7618
7619 handle_simd_insg(s, rd, rn, imm5);
7620 } else {
7621 unallocated_encoding(s);
7622 }
7623 break;
7624 case 5:
7625 case 7:
7626
7627 handle_simd_umov_smov(s, is_q, (imm4 == 5), rn, rd, imm5);
7628 break;
7629 default:
7630 unallocated_encoding(s);
7631 break;
7632 }
7633 }
7634}
7635
7636
7637
7638
7639
7640
7641
7642
7643
7644
7645
7646
7647
7648
7649
7650static void disas_simd_mod_imm(DisasContext *s, uint32_t insn)
7651{
7652 int rd = extract32(insn, 0, 5);
7653 int cmode = extract32(insn, 12, 4);
7654 int o2 = extract32(insn, 11, 1);
7655 uint64_t abcdefgh = extract32(insn, 5, 5) | (extract32(insn, 16, 3) << 5);
7656 bool is_neg = extract32(insn, 29, 1);
7657 bool is_q = extract32(insn, 30, 1);
7658 uint64_t imm = 0;
7659
7660 if (o2 != 0 || ((cmode == 0xf) && is_neg && !is_q)) {
7661
7662 if (!(dc_isar_feature(aa64_fp16, s) && o2 && cmode == 0xf)) {
7663 unallocated_encoding(s);
7664 return;
7665 }
7666 }
7667
7668 if (!fp_access_check(s)) {
7669 return;
7670 }
7671
7672 if (cmode == 15 && o2 && !is_neg) {
7673
7674 imm = vfp_expand_imm(MO_16, abcdefgh);
7675
7676 imm = dup_const(MO_16, imm);
7677 } else {
7678 imm = asimd_imm_const(abcdefgh, cmode, is_neg);
7679 }
7680
7681 if (!((cmode & 0x9) == 0x1 || (cmode & 0xd) == 0x9)) {
7682
7683 tcg_gen_gvec_dup_imm(MO_64, vec_full_reg_offset(s, rd), is_q ? 16 : 8,
7684 vec_full_reg_size(s), imm);
7685 } else {
7686
7687 if (is_neg) {
7688 gen_gvec_fn2i(s, is_q, rd, rd, imm, tcg_gen_gvec_andi, MO_64);
7689 } else {
7690 gen_gvec_fn2i(s, is_q, rd, rd, imm, tcg_gen_gvec_ori, MO_64);
7691 }
7692 }
7693}
7694
7695
7696
7697
7698
7699
7700
7701static void disas_simd_scalar_copy(DisasContext *s, uint32_t insn)
7702{
7703 int rd = extract32(insn, 0, 5);
7704 int rn = extract32(insn, 5, 5);
7705 int imm4 = extract32(insn, 11, 4);
7706 int imm5 = extract32(insn, 16, 5);
7707 int op = extract32(insn, 29, 1);
7708
7709 if (op != 0 || imm4 != 0) {
7710 unallocated_encoding(s);
7711 return;
7712 }
7713
7714
7715 handle_simd_dupes(s, rd, rn, imm5);
7716}
7717
7718
7719
7720
7721
7722
7723
7724static void disas_simd_scalar_pairwise(DisasContext *s, uint32_t insn)
7725{
7726 int u = extract32(insn, 29, 1);
7727 int size = extract32(insn, 22, 2);
7728 int opcode = extract32(insn, 12, 5);
7729 int rn = extract32(insn, 5, 5);
7730 int rd = extract32(insn, 0, 5);
7731 TCGv_ptr fpst;
7732
7733
7734
7735
7736
7737 opcode |= (extract32(size, 1, 1) << 5);
7738
7739 switch (opcode) {
7740 case 0x3b:
7741 if (u || size != 3) {
7742 unallocated_encoding(s);
7743 return;
7744 }
7745 if (!fp_access_check(s)) {
7746 return;
7747 }
7748
7749 fpst = NULL;
7750 break;
7751 case 0xc:
7752 case 0xd:
7753 case 0xf:
7754 case 0x2c:
7755 case 0x2f:
7756
7757 if (!u) {
7758 if (!dc_isar_feature(aa64_fp16, s)) {
7759 unallocated_encoding(s);
7760 return;
7761 } else {
7762 size = MO_16;
7763 }
7764 } else {
7765 size = extract32(size, 0, 1) ? MO_64 : MO_32;
7766 }
7767
7768 if (!fp_access_check(s)) {
7769 return;
7770 }
7771
7772 fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
7773 break;
7774 default:
7775 unallocated_encoding(s);
7776 return;
7777 }
7778
7779 if (size == MO_64) {
7780 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
7781 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
7782 TCGv_i64 tcg_res = tcg_temp_new_i64();
7783
7784 read_vec_element(s, tcg_op1, rn, 0, MO_64);
7785 read_vec_element(s, tcg_op2, rn, 1, MO_64);
7786
7787 switch (opcode) {
7788 case 0x3b:
7789 tcg_gen_add_i64(tcg_res, tcg_op1, tcg_op2);
7790 break;
7791 case 0xc:
7792 gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
7793 break;
7794 case 0xd:
7795 gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
7796 break;
7797 case 0xf:
7798 gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
7799 break;
7800 case 0x2c:
7801 gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
7802 break;
7803 case 0x2f:
7804 gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
7805 break;
7806 default:
7807 g_assert_not_reached();
7808 }
7809
7810 write_fp_dreg(s, rd, tcg_res);
7811 } else {
7812 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
7813 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
7814 TCGv_i32 tcg_res = tcg_temp_new_i32();
7815
7816 read_vec_element_i32(s, tcg_op1, rn, 0, size);
7817 read_vec_element_i32(s, tcg_op2, rn, 1, size);
7818
7819 if (size == MO_16) {
7820 switch (opcode) {
7821 case 0xc:
7822 gen_helper_advsimd_maxnumh(tcg_res, tcg_op1, tcg_op2, fpst);
7823 break;
7824 case 0xd:
7825 gen_helper_advsimd_addh(tcg_res, tcg_op1, tcg_op2, fpst);
7826 break;
7827 case 0xf:
7828 gen_helper_advsimd_maxh(tcg_res, tcg_op1, tcg_op2, fpst);
7829 break;
7830 case 0x2c:
7831 gen_helper_advsimd_minnumh(tcg_res, tcg_op1, tcg_op2, fpst);
7832 break;
7833 case 0x2f:
7834 gen_helper_advsimd_minh(tcg_res, tcg_op1, tcg_op2, fpst);
7835 break;
7836 default:
7837 g_assert_not_reached();
7838 }
7839 } else {
7840 switch (opcode) {
7841 case 0xc:
7842 gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
7843 break;
7844 case 0xd:
7845 gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
7846 break;
7847 case 0xf:
7848 gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
7849 break;
7850 case 0x2c:
7851 gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
7852 break;
7853 case 0x2f:
7854 gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
7855 break;
7856 default:
7857 g_assert_not_reached();
7858 }
7859 }
7860
7861 write_fp_sreg(s, rd, tcg_res);
7862 }
7863}
7864
7865
7866
7867
7868
7869
7870
7871static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src,
7872 TCGv_i64 tcg_rnd, bool accumulate,
7873 bool is_u, int size, int shift)
7874{
7875 bool extended_result = false;
7876 bool round = tcg_rnd != NULL;
7877 int ext_lshift = 0;
7878 TCGv_i64 tcg_src_hi;
7879
7880 if (round && size == 3) {
7881 extended_result = true;
7882 ext_lshift = 64 - shift;
7883 tcg_src_hi = tcg_temp_new_i64();
7884 } else if (shift == 64) {
7885 if (!accumulate && is_u) {
7886
7887 tcg_gen_movi_i64(tcg_res, 0);
7888 return;
7889 }
7890 }
7891
7892
7893 if (round) {
7894 if (extended_result) {
7895 TCGv_i64 tcg_zero = tcg_constant_i64(0);
7896 if (!is_u) {
7897
7898 tcg_gen_sari_i64(tcg_src_hi, tcg_src, 63);
7899 tcg_gen_add2_i64(tcg_src, tcg_src_hi,
7900 tcg_src, tcg_src_hi,
7901 tcg_rnd, tcg_zero);
7902 } else {
7903 tcg_gen_add2_i64(tcg_src, tcg_src_hi,
7904 tcg_src, tcg_zero,
7905 tcg_rnd, tcg_zero);
7906 }
7907 } else {
7908 tcg_gen_add_i64(tcg_src, tcg_src, tcg_rnd);
7909 }
7910 }
7911
7912
7913 if (round && extended_result) {
7914
7915 if (ext_lshift == 0) {
7916
7917 tcg_gen_mov_i64(tcg_src, tcg_src_hi);
7918 } else {
7919 tcg_gen_shri_i64(tcg_src, tcg_src, shift);
7920 tcg_gen_shli_i64(tcg_src_hi, tcg_src_hi, ext_lshift);
7921 tcg_gen_or_i64(tcg_src, tcg_src, tcg_src_hi);
7922 }
7923 } else {
7924 if (is_u) {
7925 if (shift == 64) {
7926
7927 tcg_gen_movi_i64(tcg_src, 0);
7928 } else {
7929 tcg_gen_shri_i64(tcg_src, tcg_src, shift);
7930 }
7931 } else {
7932 if (shift == 64) {
7933
7934 tcg_gen_sari_i64(tcg_src, tcg_src, 63);
7935 } else {
7936 tcg_gen_sari_i64(tcg_src, tcg_src, shift);
7937 }
7938 }
7939 }
7940
7941 if (accumulate) {
7942 tcg_gen_add_i64(tcg_res, tcg_res, tcg_src);
7943 } else {
7944 tcg_gen_mov_i64(tcg_res, tcg_src);
7945 }
7946}
7947
7948
7949static void handle_scalar_simd_shri(DisasContext *s,
7950 bool is_u, int immh, int immb,
7951 int opcode, int rn, int rd)
7952{
7953 const int size = 3;
7954 int immhb = immh << 3 | immb;
7955 int shift = 2 * (8 << size) - immhb;
7956 bool accumulate = false;
7957 bool round = false;
7958 bool insert = false;
7959 TCGv_i64 tcg_rn;
7960 TCGv_i64 tcg_rd;
7961 TCGv_i64 tcg_round;
7962
7963 if (!extract32(immh, 3, 1)) {
7964 unallocated_encoding(s);
7965 return;
7966 }
7967
7968 if (!fp_access_check(s)) {
7969 return;
7970 }
7971
7972 switch (opcode) {
7973 case 0x02:
7974 accumulate = true;
7975 break;
7976 case 0x04:
7977 round = true;
7978 break;
7979 case 0x06:
7980 accumulate = round = true;
7981 break;
7982 case 0x08:
7983 insert = true;
7984 break;
7985 }
7986
7987 if (round) {
7988 tcg_round = tcg_constant_i64(1ULL << (shift - 1));
7989 } else {
7990 tcg_round = NULL;
7991 }
7992
7993 tcg_rn = read_fp_dreg(s, rn);
7994 tcg_rd = (accumulate || insert) ? read_fp_dreg(s, rd) : tcg_temp_new_i64();
7995
7996 if (insert) {
7997
7998
7999
8000 int esize = 8 << size;
8001 if (shift != esize) {
8002 tcg_gen_shri_i64(tcg_rn, tcg_rn, shift);
8003 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, 0, esize - shift);
8004 }
8005 } else {
8006 handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
8007 accumulate, is_u, size, shift);
8008 }
8009
8010 write_fp_dreg(s, rd, tcg_rd);
8011}
8012
8013
8014static void handle_scalar_simd_shli(DisasContext *s, bool insert,
8015 int immh, int immb, int opcode,
8016 int rn, int rd)
8017{
8018 int size = 32 - clz32(immh) - 1;
8019 int immhb = immh << 3 | immb;
8020 int shift = immhb - (8 << size);
8021 TCGv_i64 tcg_rn;
8022 TCGv_i64 tcg_rd;
8023
8024 if (!extract32(immh, 3, 1)) {
8025 unallocated_encoding(s);
8026 return;
8027 }
8028
8029 if (!fp_access_check(s)) {
8030 return;
8031 }
8032
8033 tcg_rn = read_fp_dreg(s, rn);
8034 tcg_rd = insert ? read_fp_dreg(s, rd) : tcg_temp_new_i64();
8035
8036 if (insert) {
8037 tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_rn, shift, 64 - shift);
8038 } else {
8039 tcg_gen_shli_i64(tcg_rd, tcg_rn, shift);
8040 }
8041
8042 write_fp_dreg(s, rd, tcg_rd);
8043}
8044
8045
8046
8047static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q,
8048 bool is_u_shift, bool is_u_narrow,
8049 int immh, int immb, int opcode,
8050 int rn, int rd)
8051{
8052 int immhb = immh << 3 | immb;
8053 int size = 32 - clz32(immh) - 1;
8054 int esize = 8 << size;
8055 int shift = (2 * esize) - immhb;
8056 int elements = is_scalar ? 1 : (64 / esize);
8057 bool round = extract32(opcode, 0, 1);
8058 MemOp ldop = (size + 1) | (is_u_shift ? 0 : MO_SIGN);
8059 TCGv_i64 tcg_rn, tcg_rd, tcg_round;
8060 TCGv_i32 tcg_rd_narrowed;
8061 TCGv_i64 tcg_final;
8062
8063 static NeonGenNarrowEnvFn * const signed_narrow_fns[4][2] = {
8064 { gen_helper_neon_narrow_sat_s8,
8065 gen_helper_neon_unarrow_sat8 },
8066 { gen_helper_neon_narrow_sat_s16,
8067 gen_helper_neon_unarrow_sat16 },
8068 { gen_helper_neon_narrow_sat_s32,
8069 gen_helper_neon_unarrow_sat32 },
8070 { NULL, NULL },
8071 };
8072 static NeonGenNarrowEnvFn * const unsigned_narrow_fns[4] = {
8073 gen_helper_neon_narrow_sat_u8,
8074 gen_helper_neon_narrow_sat_u16,
8075 gen_helper_neon_narrow_sat_u32,
8076 NULL
8077 };
8078 NeonGenNarrowEnvFn *narrowfn;
8079
8080 int i;
8081
8082 assert(size < 4);
8083
8084 if (extract32(immh, 3, 1)) {
8085 unallocated_encoding(s);
8086 return;
8087 }
8088
8089 if (!fp_access_check(s)) {
8090 return;
8091 }
8092
8093 if (is_u_shift) {
8094 narrowfn = unsigned_narrow_fns[size];
8095 } else {
8096 narrowfn = signed_narrow_fns[size][is_u_narrow ? 1 : 0];
8097 }
8098
8099 tcg_rn = tcg_temp_new_i64();
8100 tcg_rd = tcg_temp_new_i64();
8101 tcg_rd_narrowed = tcg_temp_new_i32();
8102 tcg_final = tcg_temp_new_i64();
8103
8104 if (round) {
8105 tcg_round = tcg_constant_i64(1ULL << (shift - 1));
8106 } else {
8107 tcg_round = NULL;
8108 }
8109
8110 for (i = 0; i < elements; i++) {
8111 read_vec_element(s, tcg_rn, rn, i, ldop);
8112 handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
8113 false, is_u_shift, size+1, shift);
8114 narrowfn(tcg_rd_narrowed, cpu_env, tcg_rd);
8115 tcg_gen_extu_i32_i64(tcg_rd, tcg_rd_narrowed);
8116 if (i == 0) {
8117 tcg_gen_mov_i64(tcg_final, tcg_rd);
8118 } else {
8119 tcg_gen_deposit_i64(tcg_final, tcg_final, tcg_rd, esize * i, esize);
8120 }
8121 }
8122
8123 if (!is_q) {
8124 write_vec_element(s, tcg_final, rd, 0, MO_64);
8125 } else {
8126 write_vec_element(s, tcg_final, rd, 1, MO_64);
8127 }
8128 clear_vec_high(s, is_q, rd);
8129}
8130
8131
8132static void handle_simd_qshl(DisasContext *s, bool scalar, bool is_q,
8133 bool src_unsigned, bool dst_unsigned,
8134 int immh, int immb, int rn, int rd)
8135{
8136 int immhb = immh << 3 | immb;
8137 int size = 32 - clz32(immh) - 1;
8138 int shift = immhb - (8 << size);
8139 int pass;
8140
8141 assert(immh != 0);
8142 assert(!(scalar && is_q));
8143
8144 if (!scalar) {
8145 if (!is_q && extract32(immh, 3, 1)) {
8146 unallocated_encoding(s);
8147 return;
8148 }
8149
8150
8151
8152
8153
8154 switch (size) {
8155 case 0:
8156 shift |= shift << 8;
8157
8158 case 1:
8159 shift |= shift << 16;
8160 break;
8161 case 2:
8162 case 3:
8163 break;
8164 default:
8165 g_assert_not_reached();
8166 }
8167 }
8168
8169 if (!fp_access_check(s)) {
8170 return;
8171 }
8172
8173 if (size == 3) {
8174 TCGv_i64 tcg_shift = tcg_constant_i64(shift);
8175 static NeonGenTwo64OpEnvFn * const fns[2][2] = {
8176 { gen_helper_neon_qshl_s64, gen_helper_neon_qshlu_s64 },
8177 { NULL, gen_helper_neon_qshl_u64 },
8178 };
8179 NeonGenTwo64OpEnvFn *genfn = fns[src_unsigned][dst_unsigned];
8180 int maxpass = is_q ? 2 : 1;
8181
8182 for (pass = 0; pass < maxpass; pass++) {
8183 TCGv_i64 tcg_op = tcg_temp_new_i64();
8184
8185 read_vec_element(s, tcg_op, rn, pass, MO_64);
8186 genfn(tcg_op, cpu_env, tcg_op, tcg_shift);
8187 write_vec_element(s, tcg_op, rd, pass, MO_64);
8188 }
8189 clear_vec_high(s, is_q, rd);
8190 } else {
8191 TCGv_i32 tcg_shift = tcg_constant_i32(shift);
8192 static NeonGenTwoOpEnvFn * const fns[2][2][3] = {
8193 {
8194 { gen_helper_neon_qshl_s8,
8195 gen_helper_neon_qshl_s16,
8196 gen_helper_neon_qshl_s32 },
8197 { gen_helper_neon_qshlu_s8,
8198 gen_helper_neon_qshlu_s16,
8199 gen_helper_neon_qshlu_s32 }
8200 }, {
8201 { NULL, NULL, NULL },
8202 { gen_helper_neon_qshl_u8,
8203 gen_helper_neon_qshl_u16,
8204 gen_helper_neon_qshl_u32 }
8205 }
8206 };
8207 NeonGenTwoOpEnvFn *genfn = fns[src_unsigned][dst_unsigned][size];
8208 MemOp memop = scalar ? size : MO_32;
8209 int maxpass = scalar ? 1 : is_q ? 4 : 2;
8210
8211 for (pass = 0; pass < maxpass; pass++) {
8212 TCGv_i32 tcg_op = tcg_temp_new_i32();
8213
8214 read_vec_element_i32(s, tcg_op, rn, pass, memop);
8215 genfn(tcg_op, cpu_env, tcg_op, tcg_shift);
8216 if (scalar) {
8217 switch (size) {
8218 case 0:
8219 tcg_gen_ext8u_i32(tcg_op, tcg_op);
8220 break;
8221 case 1:
8222 tcg_gen_ext16u_i32(tcg_op, tcg_op);
8223 break;
8224 case 2:
8225 break;
8226 default:
8227 g_assert_not_reached();
8228 }
8229 write_fp_sreg(s, rd, tcg_op);
8230 } else {
8231 write_vec_element_i32(s, tcg_op, rd, pass, MO_32);
8232 }
8233 }
8234
8235 if (!scalar) {
8236 clear_vec_high(s, is_q, rd);
8237 }
8238 }
8239}
8240
8241
8242static void handle_simd_intfp_conv(DisasContext *s, int rd, int rn,
8243 int elements, int is_signed,
8244 int fracbits, int size)
8245{
8246 TCGv_ptr tcg_fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
8247 TCGv_i32 tcg_shift = NULL;
8248
8249 MemOp mop = size | (is_signed ? MO_SIGN : 0);
8250 int pass;
8251
8252 if (fracbits || size == MO_64) {
8253 tcg_shift = tcg_constant_i32(fracbits);
8254 }
8255
8256 if (size == MO_64) {
8257 TCGv_i64 tcg_int64 = tcg_temp_new_i64();
8258 TCGv_i64 tcg_double = tcg_temp_new_i64();
8259
8260 for (pass = 0; pass < elements; pass++) {
8261 read_vec_element(s, tcg_int64, rn, pass, mop);
8262
8263 if (is_signed) {
8264 gen_helper_vfp_sqtod(tcg_double, tcg_int64,
8265 tcg_shift, tcg_fpst);
8266 } else {
8267 gen_helper_vfp_uqtod(tcg_double, tcg_int64,
8268 tcg_shift, tcg_fpst);
8269 }
8270 if (elements == 1) {
8271 write_fp_dreg(s, rd, tcg_double);
8272 } else {
8273 write_vec_element(s, tcg_double, rd, pass, MO_64);
8274 }
8275 }
8276 } else {
8277 TCGv_i32 tcg_int32 = tcg_temp_new_i32();
8278 TCGv_i32 tcg_float = tcg_temp_new_i32();
8279
8280 for (pass = 0; pass < elements; pass++) {
8281 read_vec_element_i32(s, tcg_int32, rn, pass, mop);
8282
8283 switch (size) {
8284 case MO_32:
8285 if (fracbits) {
8286 if (is_signed) {
8287 gen_helper_vfp_sltos(tcg_float, tcg_int32,
8288 tcg_shift, tcg_fpst);
8289 } else {
8290 gen_helper_vfp_ultos(tcg_float, tcg_int32,
8291 tcg_shift, tcg_fpst);
8292 }
8293 } else {
8294 if (is_signed) {
8295 gen_helper_vfp_sitos(tcg_float, tcg_int32, tcg_fpst);
8296 } else {
8297 gen_helper_vfp_uitos(tcg_float, tcg_int32, tcg_fpst);
8298 }
8299 }
8300 break;
8301 case MO_16:
8302 if (fracbits) {
8303 if (is_signed) {
8304 gen_helper_vfp_sltoh(tcg_float, tcg_int32,
8305 tcg_shift, tcg_fpst);
8306 } else {
8307 gen_helper_vfp_ultoh(tcg_float, tcg_int32,
8308 tcg_shift, tcg_fpst);
8309 }
8310 } else {
8311 if (is_signed) {
8312 gen_helper_vfp_sitoh(tcg_float, tcg_int32, tcg_fpst);
8313 } else {
8314 gen_helper_vfp_uitoh(tcg_float, tcg_int32, tcg_fpst);
8315 }
8316 }
8317 break;
8318 default:
8319 g_assert_not_reached();
8320 }
8321
8322 if (elements == 1) {
8323 write_fp_sreg(s, rd, tcg_float);
8324 } else {
8325 write_vec_element_i32(s, tcg_float, rd, pass, size);
8326 }
8327 }
8328 }
8329
8330 clear_vec_high(s, elements << size == 16, rd);
8331}
8332
8333
8334static void handle_simd_shift_intfp_conv(DisasContext *s, bool is_scalar,
8335 bool is_q, bool is_u,
8336 int immh, int immb, int opcode,
8337 int rn, int rd)
8338{
8339 int size, elements, fracbits;
8340 int immhb = immh << 3 | immb;
8341
8342 if (immh & 8) {
8343 size = MO_64;
8344 if (!is_scalar && !is_q) {
8345 unallocated_encoding(s);
8346 return;
8347 }
8348 } else if (immh & 4) {
8349 size = MO_32;
8350 } else if (immh & 2) {
8351 size = MO_16;
8352 if (!dc_isar_feature(aa64_fp16, s)) {
8353 unallocated_encoding(s);
8354 return;
8355 }
8356 } else {
8357
8358 g_assert(immh == 1);
8359 unallocated_encoding(s);
8360 return;
8361 }
8362
8363 if (is_scalar) {
8364 elements = 1;
8365 } else {
8366 elements = (8 << is_q) >> size;
8367 }
8368 fracbits = (16 << size) - immhb;
8369
8370 if (!fp_access_check(s)) {
8371 return;
8372 }
8373
8374 handle_simd_intfp_conv(s, rd, rn, elements, !is_u, fracbits, size);
8375}
8376
8377
8378static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar,
8379 bool is_q, bool is_u,
8380 int immh, int immb, int rn, int rd)
8381{
8382 int immhb = immh << 3 | immb;
8383 int pass, size, fracbits;
8384 TCGv_ptr tcg_fpstatus;
8385 TCGv_i32 tcg_rmode, tcg_shift;
8386
8387 if (immh & 0x8) {
8388 size = MO_64;
8389 if (!is_scalar && !is_q) {
8390 unallocated_encoding(s);
8391 return;
8392 }
8393 } else if (immh & 0x4) {
8394 size = MO_32;
8395 } else if (immh & 0x2) {
8396 size = MO_16;
8397 if (!dc_isar_feature(aa64_fp16, s)) {
8398 unallocated_encoding(s);
8399 return;
8400 }
8401 } else {
8402
8403 assert(immh == 1);
8404 unallocated_encoding(s);
8405 return;
8406 }
8407
8408 if (!fp_access_check(s)) {
8409 return;
8410 }
8411
8412 assert(!(is_scalar && is_q));
8413
8414 tcg_fpstatus = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
8415 tcg_rmode = gen_set_rmode(FPROUNDING_ZERO, tcg_fpstatus);
8416 fracbits = (16 << size) - immhb;
8417 tcg_shift = tcg_constant_i32(fracbits);
8418
8419 if (size == MO_64) {
8420 int maxpass = is_scalar ? 1 : 2;
8421
8422 for (pass = 0; pass < maxpass; pass++) {
8423 TCGv_i64 tcg_op = tcg_temp_new_i64();
8424
8425 read_vec_element(s, tcg_op, rn, pass, MO_64);
8426 if (is_u) {
8427 gen_helper_vfp_touqd(tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
8428 } else {
8429 gen_helper_vfp_tosqd(tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
8430 }
8431 write_vec_element(s, tcg_op, rd, pass, MO_64);
8432 }
8433 clear_vec_high(s, is_q, rd);
8434 } else {
8435 void (*fn)(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
8436 int maxpass = is_scalar ? 1 : ((8 << is_q) >> size);
8437
8438 switch (size) {
8439 case MO_16:
8440 if (is_u) {
8441 fn = gen_helper_vfp_touhh;
8442 } else {
8443 fn = gen_helper_vfp_toshh;
8444 }
8445 break;
8446 case MO_32:
8447 if (is_u) {
8448 fn = gen_helper_vfp_touls;
8449 } else {
8450 fn = gen_helper_vfp_tosls;
8451 }
8452 break;
8453 default:
8454 g_assert_not_reached();
8455 }
8456
8457 for (pass = 0; pass < maxpass; pass++) {
8458 TCGv_i32 tcg_op = tcg_temp_new_i32();
8459
8460 read_vec_element_i32(s, tcg_op, rn, pass, size);
8461 fn(tcg_op, tcg_op, tcg_shift, tcg_fpstatus);
8462 if (is_scalar) {
8463 write_fp_sreg(s, rd, tcg_op);
8464 } else {
8465 write_vec_element_i32(s, tcg_op, rd, pass, size);
8466 }
8467 }
8468 if (!is_scalar) {
8469 clear_vec_high(s, is_q, rd);
8470 }
8471 }
8472
8473 gen_restore_rmode(tcg_rmode, tcg_fpstatus);
8474}
8475
8476
8477
8478
8479
8480
8481
8482
8483
8484static void disas_simd_scalar_shift_imm(DisasContext *s, uint32_t insn)
8485{
8486 int rd = extract32(insn, 0, 5);
8487 int rn = extract32(insn, 5, 5);
8488 int opcode = extract32(insn, 11, 5);
8489 int immb = extract32(insn, 16, 3);
8490 int immh = extract32(insn, 19, 4);
8491 bool is_u = extract32(insn, 29, 1);
8492
8493 if (immh == 0) {
8494 unallocated_encoding(s);
8495 return;
8496 }
8497
8498 switch (opcode) {
8499 case 0x08:
8500 if (!is_u) {
8501 unallocated_encoding(s);
8502 return;
8503 }
8504
8505 case 0x00:
8506 case 0x02:
8507 case 0x04:
8508 case 0x06:
8509 handle_scalar_simd_shri(s, is_u, immh, immb, opcode, rn, rd);
8510 break;
8511 case 0x0a:
8512 handle_scalar_simd_shli(s, is_u, immh, immb, opcode, rn, rd);
8513 break;
8514 case 0x1c:
8515 handle_simd_shift_intfp_conv(s, true, false, is_u, immh, immb,
8516 opcode, rn, rd);
8517 break;
8518 case 0x10:
8519 case 0x11:
8520 if (!is_u) {
8521 unallocated_encoding(s);
8522 return;
8523 }
8524 handle_vec_simd_sqshrn(s, true, false, false, true,
8525 immh, immb, opcode, rn, rd);
8526 break;
8527 case 0x12:
8528 case 0x13:
8529 handle_vec_simd_sqshrn(s, true, false, is_u, is_u,
8530 immh, immb, opcode, rn, rd);
8531 break;
8532 case 0xc:
8533 if (!is_u) {
8534 unallocated_encoding(s);
8535 return;
8536 }
8537 handle_simd_qshl(s, true, false, false, true, immh, immb, rn, rd);
8538 break;
8539 case 0xe:
8540 handle_simd_qshl(s, true, false, is_u, is_u, immh, immb, rn, rd);
8541 break;
8542 case 0x1f:
8543 handle_simd_shift_fpint_conv(s, true, false, is_u, immh, immb, rn, rd);
8544 break;
8545 default:
8546 unallocated_encoding(s);
8547 break;
8548 }
8549}
8550
8551
8552
8553
8554
8555
8556
8557static void disas_simd_scalar_three_reg_diff(DisasContext *s, uint32_t insn)
8558{
8559 bool is_u = extract32(insn, 29, 1);
8560 int size = extract32(insn, 22, 2);
8561 int opcode = extract32(insn, 12, 4);
8562 int rm = extract32(insn, 16, 5);
8563 int rn = extract32(insn, 5, 5);
8564 int rd = extract32(insn, 0, 5);
8565
8566 if (is_u) {
8567 unallocated_encoding(s);
8568 return;
8569 }
8570
8571 switch (opcode) {
8572 case 0x9:
8573 case 0xb:
8574 case 0xd:
8575 if (size == 0 || size == 3) {
8576 unallocated_encoding(s);
8577 return;
8578 }
8579 break;
8580 default:
8581 unallocated_encoding(s);
8582 return;
8583 }
8584
8585 if (!fp_access_check(s)) {
8586 return;
8587 }
8588
8589 if (size == 2) {
8590 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
8591 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
8592 TCGv_i64 tcg_res = tcg_temp_new_i64();
8593
8594 read_vec_element(s, tcg_op1, rn, 0, MO_32 | MO_SIGN);
8595 read_vec_element(s, tcg_op2, rm, 0, MO_32 | MO_SIGN);
8596
8597 tcg_gen_mul_i64(tcg_res, tcg_op1, tcg_op2);
8598 gen_helper_neon_addl_saturate_s64(tcg_res, cpu_env, tcg_res, tcg_res);
8599
8600 switch (opcode) {
8601 case 0xd:
8602 break;
8603 case 0xb:
8604 tcg_gen_neg_i64(tcg_res, tcg_res);
8605
8606 case 0x9:
8607 read_vec_element(s, tcg_op1, rd, 0, MO_64);
8608 gen_helper_neon_addl_saturate_s64(tcg_res, cpu_env,
8609 tcg_res, tcg_op1);
8610 break;
8611 default:
8612 g_assert_not_reached();
8613 }
8614
8615 write_fp_dreg(s, rd, tcg_res);
8616 } else {
8617 TCGv_i32 tcg_op1 = read_fp_hreg(s, rn);
8618 TCGv_i32 tcg_op2 = read_fp_hreg(s, rm);
8619 TCGv_i64 tcg_res = tcg_temp_new_i64();
8620
8621 gen_helper_neon_mull_s16(tcg_res, tcg_op1, tcg_op2);
8622 gen_helper_neon_addl_saturate_s32(tcg_res, cpu_env, tcg_res, tcg_res);
8623
8624 switch (opcode) {
8625 case 0xd:
8626 break;
8627 case 0xb:
8628 gen_helper_neon_negl_u32(tcg_res, tcg_res);
8629
8630 case 0x9:
8631 {
8632 TCGv_i64 tcg_op3 = tcg_temp_new_i64();
8633 read_vec_element(s, tcg_op3, rd, 0, MO_32);
8634 gen_helper_neon_addl_saturate_s32(tcg_res, cpu_env,
8635 tcg_res, tcg_op3);
8636 break;
8637 }
8638 default:
8639 g_assert_not_reached();
8640 }
8641
8642 tcg_gen_ext32u_i64(tcg_res, tcg_res);
8643 write_fp_dreg(s, rd, tcg_res);
8644 }
8645}
8646
8647static void handle_3same_64(DisasContext *s, int opcode, bool u,
8648 TCGv_i64 tcg_rd, TCGv_i64 tcg_rn, TCGv_i64 tcg_rm)
8649{
8650
8651
8652
8653
8654
8655 TCGCond cond;
8656
8657 switch (opcode) {
8658 case 0x1:
8659 if (u) {
8660 gen_helper_neon_qadd_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8661 } else {
8662 gen_helper_neon_qadd_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8663 }
8664 break;
8665 case 0x5:
8666 if (u) {
8667 gen_helper_neon_qsub_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8668 } else {
8669 gen_helper_neon_qsub_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8670 }
8671 break;
8672 case 0x6:
8673
8674
8675
8676 cond = u ? TCG_COND_GTU : TCG_COND_GT;
8677 do_cmop:
8678 tcg_gen_setcond_i64(cond, tcg_rd, tcg_rn, tcg_rm);
8679 tcg_gen_neg_i64(tcg_rd, tcg_rd);
8680 break;
8681 case 0x7:
8682 cond = u ? TCG_COND_GEU : TCG_COND_GE;
8683 goto do_cmop;
8684 case 0x11:
8685 if (u) {
8686 cond = TCG_COND_EQ;
8687 goto do_cmop;
8688 }
8689 gen_cmtst_i64(tcg_rd, tcg_rn, tcg_rm);
8690 break;
8691 case 0x8:
8692 if (u) {
8693 gen_ushl_i64(tcg_rd, tcg_rn, tcg_rm);
8694 } else {
8695 gen_sshl_i64(tcg_rd, tcg_rn, tcg_rm);
8696 }
8697 break;
8698 case 0x9:
8699 if (u) {
8700 gen_helper_neon_qshl_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8701 } else {
8702 gen_helper_neon_qshl_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8703 }
8704 break;
8705 case 0xa:
8706 if (u) {
8707 gen_helper_neon_rshl_u64(tcg_rd, tcg_rn, tcg_rm);
8708 } else {
8709 gen_helper_neon_rshl_s64(tcg_rd, tcg_rn, tcg_rm);
8710 }
8711 break;
8712 case 0xb:
8713 if (u) {
8714 gen_helper_neon_qrshl_u64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8715 } else {
8716 gen_helper_neon_qrshl_s64(tcg_rd, cpu_env, tcg_rn, tcg_rm);
8717 }
8718 break;
8719 case 0x10:
8720 if (u) {
8721 tcg_gen_sub_i64(tcg_rd, tcg_rn, tcg_rm);
8722 } else {
8723 tcg_gen_add_i64(tcg_rd, tcg_rn, tcg_rm);
8724 }
8725 break;
8726 default:
8727 g_assert_not_reached();
8728 }
8729}
8730
8731
8732
8733
8734
8735static void handle_3same_float(DisasContext *s, int size, int elements,
8736 int fpopcode, int rd, int rn, int rm)
8737{
8738 int pass;
8739 TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
8740
8741 for (pass = 0; pass < elements; pass++) {
8742 if (size) {
8743
8744 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
8745 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
8746 TCGv_i64 tcg_res = tcg_temp_new_i64();
8747
8748 read_vec_element(s, tcg_op1, rn, pass, MO_64);
8749 read_vec_element(s, tcg_op2, rm, pass, MO_64);
8750
8751 switch (fpopcode) {
8752 case 0x39:
8753
8754 gen_helper_vfp_negd(tcg_op1, tcg_op1);
8755
8756 case 0x19:
8757 read_vec_element(s, tcg_res, rd, pass, MO_64);
8758 gen_helper_vfp_muladdd(tcg_res, tcg_op1, tcg_op2,
8759 tcg_res, fpst);
8760 break;
8761 case 0x18:
8762 gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst);
8763 break;
8764 case 0x1a:
8765 gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst);
8766 break;
8767 case 0x1b:
8768 gen_helper_vfp_mulxd(tcg_res, tcg_op1, tcg_op2, fpst);
8769 break;
8770 case 0x1c:
8771 gen_helper_neon_ceq_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8772 break;
8773 case 0x1e:
8774 gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst);
8775 break;
8776 case 0x1f:
8777 gen_helper_recpsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8778 break;
8779 case 0x38:
8780 gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst);
8781 break;
8782 case 0x3a:
8783 gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
8784 break;
8785 case 0x3e:
8786 gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst);
8787 break;
8788 case 0x3f:
8789 gen_helper_rsqrtsf_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8790 break;
8791 case 0x5b:
8792 gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst);
8793 break;
8794 case 0x5c:
8795 gen_helper_neon_cge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8796 break;
8797 case 0x5d:
8798 gen_helper_neon_acge_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8799 break;
8800 case 0x5f:
8801 gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst);
8802 break;
8803 case 0x7a:
8804 gen_helper_vfp_subd(tcg_res, tcg_op1, tcg_op2, fpst);
8805 gen_helper_vfp_absd(tcg_res, tcg_res);
8806 break;
8807 case 0x7c:
8808 gen_helper_neon_cgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8809 break;
8810 case 0x7d:
8811 gen_helper_neon_acgt_f64(tcg_res, tcg_op1, tcg_op2, fpst);
8812 break;
8813 default:
8814 g_assert_not_reached();
8815 }
8816
8817 write_vec_element(s, tcg_res, rd, pass, MO_64);
8818 } else {
8819
8820 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
8821 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
8822 TCGv_i32 tcg_res = tcg_temp_new_i32();
8823
8824 read_vec_element_i32(s, tcg_op1, rn, pass, MO_32);
8825 read_vec_element_i32(s, tcg_op2, rm, pass, MO_32);
8826
8827 switch (fpopcode) {
8828 case 0x39:
8829
8830 gen_helper_vfp_negs(tcg_op1, tcg_op1);
8831
8832 case 0x19:
8833 read_vec_element_i32(s, tcg_res, rd, pass, MO_32);
8834 gen_helper_vfp_muladds(tcg_res, tcg_op1, tcg_op2,
8835 tcg_res, fpst);
8836 break;
8837 case 0x1a:
8838 gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst);
8839 break;
8840 case 0x1b:
8841 gen_helper_vfp_mulxs(tcg_res, tcg_op1, tcg_op2, fpst);
8842 break;
8843 case 0x1c:
8844 gen_helper_neon_ceq_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8845 break;
8846 case 0x1e:
8847 gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst);
8848 break;
8849 case 0x1f:
8850 gen_helper_recpsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8851 break;
8852 case 0x18:
8853 gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst);
8854 break;
8855 case 0x38:
8856 gen_helper_vfp_minnums(tcg_res, tcg_op1, tcg_op2, fpst);
8857 break;
8858 case 0x3a:
8859 gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
8860 break;
8861 case 0x3e:
8862 gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst);
8863 break;
8864 case 0x3f:
8865 gen_helper_rsqrtsf_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8866 break;
8867 case 0x5b:
8868 gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst);
8869 break;
8870 case 0x5c:
8871 gen_helper_neon_cge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8872 break;
8873 case 0x5d:
8874 gen_helper_neon_acge_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8875 break;
8876 case 0x5f:
8877 gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst);
8878 break;
8879 case 0x7a:
8880 gen_helper_vfp_subs(tcg_res, tcg_op1, tcg_op2, fpst);
8881 gen_helper_vfp_abss(tcg_res, tcg_res);
8882 break;
8883 case 0x7c:
8884 gen_helper_neon_cgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8885 break;
8886 case 0x7d:
8887 gen_helper_neon_acgt_f32(tcg_res, tcg_op1, tcg_op2, fpst);
8888 break;
8889 default:
8890 g_assert_not_reached();
8891 }
8892
8893 if (elements == 1) {
8894
8895 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
8896
8897 tcg_gen_extu_i32_i64(tcg_tmp, tcg_res);
8898 write_vec_element(s, tcg_tmp, rd, pass, MO_64);
8899 } else {
8900 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
8901 }
8902 }
8903 }
8904
8905 clear_vec_high(s, elements * (size ? 8 : 4) > 8, rd);
8906}
8907
8908
8909
8910
8911
8912
8913
8914static void disas_simd_scalar_three_reg_same(DisasContext *s, uint32_t insn)
8915{
8916 int rd = extract32(insn, 0, 5);
8917 int rn = extract32(insn, 5, 5);
8918 int opcode = extract32(insn, 11, 5);
8919 int rm = extract32(insn, 16, 5);
8920 int size = extract32(insn, 22, 2);
8921 bool u = extract32(insn, 29, 1);
8922 TCGv_i64 tcg_rd;
8923
8924 if (opcode >= 0x18) {
8925
8926 int fpopcode = opcode | (extract32(size, 1, 1) << 5) | (u << 6);
8927 switch (fpopcode) {
8928 case 0x1b:
8929 case 0x1f:
8930 case 0x3f:
8931 case 0x5d:
8932 case 0x7d:
8933 case 0x1c:
8934 case 0x5c:
8935 case 0x7c:
8936 case 0x7a:
8937 break;
8938 default:
8939 unallocated_encoding(s);
8940 return;
8941 }
8942
8943 if (!fp_access_check(s)) {
8944 return;
8945 }
8946
8947 handle_3same_float(s, extract32(size, 0, 1), 1, fpopcode, rd, rn, rm);
8948 return;
8949 }
8950
8951 switch (opcode) {
8952 case 0x1:
8953 case 0x5:
8954 case 0x9:
8955 case 0xb:
8956 break;
8957 case 0x8:
8958 case 0xa:
8959 case 0x6:
8960 case 0x7:
8961 case 0x11:
8962 case 0x10:
8963 if (size != 3) {
8964 unallocated_encoding(s);
8965 return;
8966 }
8967 break;
8968 case 0x16:
8969 if (size != 1 && size != 2) {
8970 unallocated_encoding(s);
8971 return;
8972 }
8973 break;
8974 default:
8975 unallocated_encoding(s);
8976 return;
8977 }
8978
8979 if (!fp_access_check(s)) {
8980 return;
8981 }
8982
8983 tcg_rd = tcg_temp_new_i64();
8984
8985 if (size == 3) {
8986 TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
8987 TCGv_i64 tcg_rm = read_fp_dreg(s, rm);
8988
8989 handle_3same_64(s, opcode, u, tcg_rd, tcg_rn, tcg_rm);
8990 } else {
8991
8992
8993
8994
8995
8996
8997 NeonGenTwoOpEnvFn *genenvfn;
8998 TCGv_i32 tcg_rn = tcg_temp_new_i32();
8999 TCGv_i32 tcg_rm = tcg_temp_new_i32();
9000 TCGv_i32 tcg_rd32 = tcg_temp_new_i32();
9001
9002 read_vec_element_i32(s, tcg_rn, rn, 0, size);
9003 read_vec_element_i32(s, tcg_rm, rm, 0, size);
9004
9005 switch (opcode) {
9006 case 0x1:
9007 {
9008 static NeonGenTwoOpEnvFn * const fns[3][2] = {
9009 { gen_helper_neon_qadd_s8, gen_helper_neon_qadd_u8 },
9010 { gen_helper_neon_qadd_s16, gen_helper_neon_qadd_u16 },
9011 { gen_helper_neon_qadd_s32, gen_helper_neon_qadd_u32 },
9012 };
9013 genenvfn = fns[size][u];
9014 break;
9015 }
9016 case 0x5:
9017 {
9018 static NeonGenTwoOpEnvFn * const fns[3][2] = {
9019 { gen_helper_neon_qsub_s8, gen_helper_neon_qsub_u8 },
9020 { gen_helper_neon_qsub_s16, gen_helper_neon_qsub_u16 },
9021 { gen_helper_neon_qsub_s32, gen_helper_neon_qsub_u32 },
9022 };
9023 genenvfn = fns[size][u];
9024 break;
9025 }
9026 case 0x9:
9027 {
9028 static NeonGenTwoOpEnvFn * const fns[3][2] = {
9029 { gen_helper_neon_qshl_s8, gen_helper_neon_qshl_u8 },
9030 { gen_helper_neon_qshl_s16, gen_helper_neon_qshl_u16 },
9031 { gen_helper_neon_qshl_s32, gen_helper_neon_qshl_u32 },
9032 };
9033 genenvfn = fns[size][u];
9034 break;
9035 }
9036 case 0xb:
9037 {
9038 static NeonGenTwoOpEnvFn * const fns[3][2] = {
9039 { gen_helper_neon_qrshl_s8, gen_helper_neon_qrshl_u8 },
9040 { gen_helper_neon_qrshl_s16, gen_helper_neon_qrshl_u16 },
9041 { gen_helper_neon_qrshl_s32, gen_helper_neon_qrshl_u32 },
9042 };
9043 genenvfn = fns[size][u];
9044 break;
9045 }
9046 case 0x16:
9047 {
9048 static NeonGenTwoOpEnvFn * const fns[2][2] = {
9049 { gen_helper_neon_qdmulh_s16, gen_helper_neon_qrdmulh_s16 },
9050 { gen_helper_neon_qdmulh_s32, gen_helper_neon_qrdmulh_s32 },
9051 };
9052 assert(size == 1 || size == 2);
9053 genenvfn = fns[size - 1][u];
9054 break;
9055 }
9056 default:
9057 g_assert_not_reached();
9058 }
9059
9060 genenvfn(tcg_rd32, cpu_env, tcg_rn, tcg_rm);
9061 tcg_gen_extu_i32_i64(tcg_rd, tcg_rd32);
9062 }
9063
9064 write_fp_dreg(s, rd, tcg_rd);
9065}
9066
9067
9068
9069
9070
9071
9072
9073
9074
9075static void disas_simd_scalar_three_reg_same_fp16(DisasContext *s,
9076 uint32_t insn)
9077{
9078 int rd = extract32(insn, 0, 5);
9079 int rn = extract32(insn, 5, 5);
9080 int opcode = extract32(insn, 11, 3);
9081 int rm = extract32(insn, 16, 5);
9082 bool u = extract32(insn, 29, 1);
9083 bool a = extract32(insn, 23, 1);
9084 int fpopcode = opcode | (a << 3) | (u << 4);
9085 TCGv_ptr fpst;
9086 TCGv_i32 tcg_op1;
9087 TCGv_i32 tcg_op2;
9088 TCGv_i32 tcg_res;
9089
9090 switch (fpopcode) {
9091 case 0x03:
9092 case 0x04:
9093 case 0x07:
9094 case 0x0f:
9095 case 0x14:
9096 case 0x15:
9097 case 0x1a:
9098 case 0x1c:
9099 case 0x1d:
9100 break;
9101 default:
9102 unallocated_encoding(s);
9103 return;
9104 }
9105
9106 if (!dc_isar_feature(aa64_fp16, s)) {
9107 unallocated_encoding(s);
9108 }
9109
9110 if (!fp_access_check(s)) {
9111 return;
9112 }
9113
9114 fpst = fpstatus_ptr(FPST_FPCR_F16);
9115
9116 tcg_op1 = read_fp_hreg(s, rn);
9117 tcg_op2 = read_fp_hreg(s, rm);
9118 tcg_res = tcg_temp_new_i32();
9119
9120 switch (fpopcode) {
9121 case 0x03:
9122 gen_helper_advsimd_mulxh(tcg_res, tcg_op1, tcg_op2, fpst);
9123 break;
9124 case 0x04:
9125 gen_helper_advsimd_ceq_f16(tcg_res, tcg_op1, tcg_op2, fpst);
9126 break;
9127 case 0x07:
9128 gen_helper_recpsf_f16(tcg_res, tcg_op1, tcg_op2, fpst);
9129 break;
9130 case 0x0f:
9131 gen_helper_rsqrtsf_f16(tcg_res, tcg_op1, tcg_op2, fpst);
9132 break;
9133 case 0x14:
9134 gen_helper_advsimd_cge_f16(tcg_res, tcg_op1, tcg_op2, fpst);
9135 break;
9136 case 0x15:
9137 gen_helper_advsimd_acge_f16(tcg_res, tcg_op1, tcg_op2, fpst);
9138 break;
9139 case 0x1a:
9140 gen_helper_advsimd_subh(tcg_res, tcg_op1, tcg_op2, fpst);
9141 tcg_gen_andi_i32(tcg_res, tcg_res, 0x7fff);
9142 break;
9143 case 0x1c:
9144 gen_helper_advsimd_cgt_f16(tcg_res, tcg_op1, tcg_op2, fpst);
9145 break;
9146 case 0x1d:
9147 gen_helper_advsimd_acgt_f16(tcg_res, tcg_op1, tcg_op2, fpst);
9148 break;
9149 default:
9150 g_assert_not_reached();
9151 }
9152
9153 write_fp_sreg(s, rd, tcg_res);
9154}
9155
9156
9157
9158
9159
9160
9161
9162static void disas_simd_scalar_three_reg_same_extra(DisasContext *s,
9163 uint32_t insn)
9164{
9165 int rd = extract32(insn, 0, 5);
9166 int rn = extract32(insn, 5, 5);
9167 int opcode = extract32(insn, 11, 4);
9168 int rm = extract32(insn, 16, 5);
9169 int size = extract32(insn, 22, 2);
9170 bool u = extract32(insn, 29, 1);
9171 TCGv_i32 ele1, ele2, ele3;
9172 TCGv_i64 res;
9173 bool feature;
9174
9175 switch (u * 16 + opcode) {
9176 case 0x10:
9177 case 0x11:
9178 if (size != 1 && size != 2) {
9179 unallocated_encoding(s);
9180 return;
9181 }
9182 feature = dc_isar_feature(aa64_rdm, s);
9183 break;
9184 default:
9185 unallocated_encoding(s);
9186 return;
9187 }
9188 if (!feature) {
9189 unallocated_encoding(s);
9190 return;
9191 }
9192 if (!fp_access_check(s)) {
9193 return;
9194 }
9195
9196
9197
9198
9199
9200
9201
9202 ele1 = tcg_temp_new_i32();
9203 ele2 = tcg_temp_new_i32();
9204 ele3 = tcg_temp_new_i32();
9205
9206 read_vec_element_i32(s, ele1, rn, 0, size);
9207 read_vec_element_i32(s, ele2, rm, 0, size);
9208 read_vec_element_i32(s, ele3, rd, 0, size);
9209
9210 switch (opcode) {
9211 case 0x0:
9212 if (size == 1) {
9213 gen_helper_neon_qrdmlah_s16(ele3, cpu_env, ele1, ele2, ele3);
9214 } else {
9215 gen_helper_neon_qrdmlah_s32(ele3, cpu_env, ele1, ele2, ele3);
9216 }
9217 break;
9218 case 0x1:
9219 if (size == 1) {
9220 gen_helper_neon_qrdmlsh_s16(ele3, cpu_env, ele1, ele2, ele3);
9221 } else {
9222 gen_helper_neon_qrdmlsh_s32(ele3, cpu_env, ele1, ele2, ele3);
9223 }
9224 break;
9225 default:
9226 g_assert_not_reached();
9227 }
9228
9229 res = tcg_temp_new_i64();
9230 tcg_gen_extu_i32_i64(res, ele3);
9231 write_fp_dreg(s, rd, res);
9232}
9233
9234static void handle_2misc_64(DisasContext *s, int opcode, bool u,
9235 TCGv_i64 tcg_rd, TCGv_i64 tcg_rn,
9236 TCGv_i32 tcg_rmode, TCGv_ptr tcg_fpstatus)
9237{
9238
9239
9240
9241
9242
9243
9244 TCGCond cond;
9245
9246 switch (opcode) {
9247 case 0x4:
9248 if (u) {
9249 tcg_gen_clzi_i64(tcg_rd, tcg_rn, 64);
9250 } else {
9251 tcg_gen_clrsb_i64(tcg_rd, tcg_rn);
9252 }
9253 break;
9254 case 0x5:
9255
9256
9257
9258 tcg_gen_not_i64(tcg_rd, tcg_rn);
9259 break;
9260 case 0x7:
9261 if (u) {
9262 gen_helper_neon_qneg_s64(tcg_rd, cpu_env, tcg_rn);
9263 } else {
9264 gen_helper_neon_qabs_s64(tcg_rd, cpu_env, tcg_rn);
9265 }
9266 break;
9267 case 0xa:
9268
9269
9270
9271
9272 cond = TCG_COND_LT;
9273 do_cmop:
9274 tcg_gen_setcondi_i64(cond, tcg_rd, tcg_rn, 0);
9275 tcg_gen_neg_i64(tcg_rd, tcg_rd);
9276 break;
9277 case 0x8:
9278 cond = u ? TCG_COND_GE : TCG_COND_GT;
9279 goto do_cmop;
9280 case 0x9:
9281 cond = u ? TCG_COND_LE : TCG_COND_EQ;
9282 goto do_cmop;
9283 case 0xb:
9284 if (u) {
9285 tcg_gen_neg_i64(tcg_rd, tcg_rn);
9286 } else {
9287 tcg_gen_abs_i64(tcg_rd, tcg_rn);
9288 }
9289 break;
9290 case 0x2f:
9291 gen_helper_vfp_absd(tcg_rd, tcg_rn);
9292 break;
9293 case 0x6f:
9294 gen_helper_vfp_negd(tcg_rd, tcg_rn);
9295 break;
9296 case 0x7f:
9297 gen_helper_vfp_sqrtd(tcg_rd, tcg_rn, cpu_env);
9298 break;
9299 case 0x1a:
9300 case 0x1b:
9301 case 0x1c:
9302 case 0x3a:
9303 case 0x3b:
9304 gen_helper_vfp_tosqd(tcg_rd, tcg_rn, tcg_constant_i32(0), tcg_fpstatus);
9305 break;
9306 case 0x5a:
9307 case 0x5b:
9308 case 0x5c:
9309 case 0x7a:
9310 case 0x7b:
9311 gen_helper_vfp_touqd(tcg_rd, tcg_rn, tcg_constant_i32(0), tcg_fpstatus);
9312 break;
9313 case 0x18:
9314 case 0x19:
9315 case 0x38:
9316 case 0x39:
9317 case 0x58:
9318 case 0x79:
9319 gen_helper_rintd(tcg_rd, tcg_rn, tcg_fpstatus);
9320 break;
9321 case 0x59:
9322 gen_helper_rintd_exact(tcg_rd, tcg_rn, tcg_fpstatus);
9323 break;
9324 case 0x1e:
9325 case 0x5e:
9326 gen_helper_frint32_d(tcg_rd, tcg_rn, tcg_fpstatus);
9327 break;
9328 case 0x1f:
9329 case 0x5f:
9330 gen_helper_frint64_d(tcg_rd, tcg_rn, tcg_fpstatus);
9331 break;
9332 default:
9333 g_assert_not_reached();
9334 }
9335}
9336
9337static void handle_2misc_fcmp_zero(DisasContext *s, int opcode,
9338 bool is_scalar, bool is_u, bool is_q,
9339 int size, int rn, int rd)
9340{
9341 bool is_double = (size == MO_64);
9342 TCGv_ptr fpst;
9343
9344 if (!fp_access_check(s)) {
9345 return;
9346 }
9347
9348 fpst = fpstatus_ptr(size == MO_16 ? FPST_FPCR_F16 : FPST_FPCR);
9349
9350 if (is_double) {
9351 TCGv_i64 tcg_op = tcg_temp_new_i64();
9352 TCGv_i64 tcg_zero = tcg_constant_i64(0);
9353 TCGv_i64 tcg_res = tcg_temp_new_i64();
9354 NeonGenTwoDoubleOpFn *genfn;
9355 bool swap = false;
9356 int pass;
9357
9358 switch (opcode) {
9359 case 0x2e:
9360 swap = true;
9361
9362 case 0x2c:
9363 genfn = gen_helper_neon_cgt_f64;
9364 break;
9365 case 0x2d:
9366 genfn = gen_helper_neon_ceq_f64;
9367 break;
9368 case 0x6d:
9369 swap = true;
9370
9371 case 0x6c:
9372 genfn = gen_helper_neon_cge_f64;
9373 break;
9374 default:
9375 g_assert_not_reached();
9376 }
9377
9378 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
9379 read_vec_element(s, tcg_op, rn, pass, MO_64);
9380 if (swap) {
9381 genfn(tcg_res, tcg_zero, tcg_op, fpst);
9382 } else {
9383 genfn(tcg_res, tcg_op, tcg_zero, fpst);
9384 }
9385 write_vec_element(s, tcg_res, rd, pass, MO_64);
9386 }
9387
9388 clear_vec_high(s, !is_scalar, rd);
9389 } else {
9390 TCGv_i32 tcg_op = tcg_temp_new_i32();
9391 TCGv_i32 tcg_zero = tcg_constant_i32(0);
9392 TCGv_i32 tcg_res = tcg_temp_new_i32();
9393 NeonGenTwoSingleOpFn *genfn;
9394 bool swap = false;
9395 int pass, maxpasses;
9396
9397 if (size == MO_16) {
9398 switch (opcode) {
9399 case 0x2e:
9400 swap = true;
9401
9402 case 0x2c:
9403 genfn = gen_helper_advsimd_cgt_f16;
9404 break;
9405 case 0x2d:
9406 genfn = gen_helper_advsimd_ceq_f16;
9407 break;
9408 case 0x6d:
9409 swap = true;
9410
9411 case 0x6c:
9412 genfn = gen_helper_advsimd_cge_f16;
9413 break;
9414 default:
9415 g_assert_not_reached();
9416 }
9417 } else {
9418 switch (opcode) {
9419 case 0x2e:
9420 swap = true;
9421
9422 case 0x2c:
9423 genfn = gen_helper_neon_cgt_f32;
9424 break;
9425 case 0x2d:
9426 genfn = gen_helper_neon_ceq_f32;
9427 break;
9428 case 0x6d:
9429 swap = true;
9430
9431 case 0x6c:
9432 genfn = gen_helper_neon_cge_f32;
9433 break;
9434 default:
9435 g_assert_not_reached();
9436 }
9437 }
9438
9439 if (is_scalar) {
9440 maxpasses = 1;
9441 } else {
9442 int vector_size = 8 << is_q;
9443 maxpasses = vector_size >> size;
9444 }
9445
9446 for (pass = 0; pass < maxpasses; pass++) {
9447 read_vec_element_i32(s, tcg_op, rn, pass, size);
9448 if (swap) {
9449 genfn(tcg_res, tcg_zero, tcg_op, fpst);
9450 } else {
9451 genfn(tcg_res, tcg_op, tcg_zero, fpst);
9452 }
9453 if (is_scalar) {
9454 write_fp_sreg(s, rd, tcg_res);
9455 } else {
9456 write_vec_element_i32(s, tcg_res, rd, pass, size);
9457 }
9458 }
9459
9460 if (!is_scalar) {
9461 clear_vec_high(s, is_q, rd);
9462 }
9463 }
9464}
9465
9466static void handle_2misc_reciprocal(DisasContext *s, int opcode,
9467 bool is_scalar, bool is_u, bool is_q,
9468 int size, int rn, int rd)
9469{
9470 bool is_double = (size == 3);
9471 TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
9472
9473 if (is_double) {
9474 TCGv_i64 tcg_op = tcg_temp_new_i64();
9475 TCGv_i64 tcg_res = tcg_temp_new_i64();
9476 int pass;
9477
9478 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
9479 read_vec_element(s, tcg_op, rn, pass, MO_64);
9480 switch (opcode) {
9481 case 0x3d:
9482 gen_helper_recpe_f64(tcg_res, tcg_op, fpst);
9483 break;
9484 case 0x3f:
9485 gen_helper_frecpx_f64(tcg_res, tcg_op, fpst);
9486 break;
9487 case 0x7d:
9488 gen_helper_rsqrte_f64(tcg_res, tcg_op, fpst);
9489 break;
9490 default:
9491 g_assert_not_reached();
9492 }
9493 write_vec_element(s, tcg_res, rd, pass, MO_64);
9494 }
9495 clear_vec_high(s, !is_scalar, rd);
9496 } else {
9497 TCGv_i32 tcg_op = tcg_temp_new_i32();
9498 TCGv_i32 tcg_res = tcg_temp_new_i32();
9499 int pass, maxpasses;
9500
9501 if (is_scalar) {
9502 maxpasses = 1;
9503 } else {
9504 maxpasses = is_q ? 4 : 2;
9505 }
9506
9507 for (pass = 0; pass < maxpasses; pass++) {
9508 read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
9509
9510 switch (opcode) {
9511 case 0x3c:
9512 gen_helper_recpe_u32(tcg_res, tcg_op);
9513 break;
9514 case 0x3d:
9515 gen_helper_recpe_f32(tcg_res, tcg_op, fpst);
9516 break;
9517 case 0x3f:
9518 gen_helper_frecpx_f32(tcg_res, tcg_op, fpst);
9519 break;
9520 case 0x7d:
9521 gen_helper_rsqrte_f32(tcg_res, tcg_op, fpst);
9522 break;
9523 default:
9524 g_assert_not_reached();
9525 }
9526
9527 if (is_scalar) {
9528 write_fp_sreg(s, rd, tcg_res);
9529 } else {
9530 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
9531 }
9532 }
9533 if (!is_scalar) {
9534 clear_vec_high(s, is_q, rd);
9535 }
9536 }
9537}
9538
9539static void handle_2misc_narrow(DisasContext *s, bool scalar,
9540 int opcode, bool u, bool is_q,
9541 int size, int rn, int rd)
9542{
9543
9544
9545
9546 int pass;
9547 TCGv_i32 tcg_res[2];
9548 int destelt = is_q ? 2 : 0;
9549 int passes = scalar ? 1 : 2;
9550
9551 if (scalar) {
9552 tcg_res[1] = tcg_constant_i32(0);
9553 }
9554
9555 for (pass = 0; pass < passes; pass++) {
9556 TCGv_i64 tcg_op = tcg_temp_new_i64();
9557 NeonGenNarrowFn *genfn = NULL;
9558 NeonGenNarrowEnvFn *genenvfn = NULL;
9559
9560 if (scalar) {
9561 read_vec_element(s, tcg_op, rn, pass, size + 1);
9562 } else {
9563 read_vec_element(s, tcg_op, rn, pass, MO_64);
9564 }
9565 tcg_res[pass] = tcg_temp_new_i32();
9566
9567 switch (opcode) {
9568 case 0x12:
9569 {
9570 static NeonGenNarrowFn * const xtnfns[3] = {
9571 gen_helper_neon_narrow_u8,
9572 gen_helper_neon_narrow_u16,
9573 tcg_gen_extrl_i64_i32,
9574 };
9575 static NeonGenNarrowEnvFn * const sqxtunfns[3] = {
9576 gen_helper_neon_unarrow_sat8,
9577 gen_helper_neon_unarrow_sat16,
9578 gen_helper_neon_unarrow_sat32,
9579 };
9580 if (u) {
9581 genenvfn = sqxtunfns[size];
9582 } else {
9583 genfn = xtnfns[size];
9584 }
9585 break;
9586 }
9587 case 0x14:
9588 {
9589 static NeonGenNarrowEnvFn * const fns[3][2] = {
9590 { gen_helper_neon_narrow_sat_s8,
9591 gen_helper_neon_narrow_sat_u8 },
9592 { gen_helper_neon_narrow_sat_s16,
9593 gen_helper_neon_narrow_sat_u16 },
9594 { gen_helper_neon_narrow_sat_s32,
9595 gen_helper_neon_narrow_sat_u32 },
9596 };
9597 genenvfn = fns[size][u];
9598 break;
9599 }
9600 case 0x16:
9601
9602 if (size == 2) {
9603 gen_helper_vfp_fcvtsd(tcg_res[pass], tcg_op, cpu_env);
9604 } else {
9605 TCGv_i32 tcg_lo = tcg_temp_new_i32();
9606 TCGv_i32 tcg_hi = tcg_temp_new_i32();
9607 TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
9608 TCGv_i32 ahp = get_ahp_flag();
9609
9610 tcg_gen_extr_i64_i32(tcg_lo, tcg_hi, tcg_op);
9611 gen_helper_vfp_fcvt_f32_to_f16(tcg_lo, tcg_lo, fpst, ahp);
9612 gen_helper_vfp_fcvt_f32_to_f16(tcg_hi, tcg_hi, fpst, ahp);
9613 tcg_gen_deposit_i32(tcg_res[pass], tcg_lo, tcg_hi, 16, 16);
9614 }
9615 break;
9616 case 0x36:
9617 {
9618 TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
9619 gen_helper_bfcvt_pair(tcg_res[pass], tcg_op, fpst);
9620 }
9621 break;
9622 case 0x56:
9623
9624
9625
9626 assert(size == 2);
9627 gen_helper_fcvtx_f64_to_f32(tcg_res[pass], tcg_op, cpu_env);
9628 break;
9629 default:
9630 g_assert_not_reached();
9631 }
9632
9633 if (genfn) {
9634 genfn(tcg_res[pass], tcg_op);
9635 } else if (genenvfn) {
9636 genenvfn(tcg_res[pass], cpu_env, tcg_op);
9637 }
9638 }
9639
9640 for (pass = 0; pass < 2; pass++) {
9641 write_vec_element_i32(s, tcg_res[pass], rd, destelt + pass, MO_32);
9642 }
9643 clear_vec_high(s, is_q, rd);
9644}
9645
9646
9647static void handle_2misc_satacc(DisasContext *s, bool is_scalar, bool is_u,
9648 bool is_q, int size, int rn, int rd)
9649{
9650 bool is_double = (size == 3);
9651
9652 if (is_double) {
9653 TCGv_i64 tcg_rn = tcg_temp_new_i64();
9654 TCGv_i64 tcg_rd = tcg_temp_new_i64();
9655 int pass;
9656
9657 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
9658 read_vec_element(s, tcg_rn, rn, pass, MO_64);
9659 read_vec_element(s, tcg_rd, rd, pass, MO_64);
9660
9661 if (is_u) {
9662 gen_helper_neon_uqadd_s64(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9663 } else {
9664 gen_helper_neon_sqadd_u64(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9665 }
9666 write_vec_element(s, tcg_rd, rd, pass, MO_64);
9667 }
9668 clear_vec_high(s, !is_scalar, rd);
9669 } else {
9670 TCGv_i32 tcg_rn = tcg_temp_new_i32();
9671 TCGv_i32 tcg_rd = tcg_temp_new_i32();
9672 int pass, maxpasses;
9673
9674 if (is_scalar) {
9675 maxpasses = 1;
9676 } else {
9677 maxpasses = is_q ? 4 : 2;
9678 }
9679
9680 for (pass = 0; pass < maxpasses; pass++) {
9681 if (is_scalar) {
9682 read_vec_element_i32(s, tcg_rn, rn, pass, size);
9683 read_vec_element_i32(s, tcg_rd, rd, pass, size);
9684 } else {
9685 read_vec_element_i32(s, tcg_rn, rn, pass, MO_32);
9686 read_vec_element_i32(s, tcg_rd, rd, pass, MO_32);
9687 }
9688
9689 if (is_u) {
9690 switch (size) {
9691 case 0:
9692 gen_helper_neon_uqadd_s8(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9693 break;
9694 case 1:
9695 gen_helper_neon_uqadd_s16(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9696 break;
9697 case 2:
9698 gen_helper_neon_uqadd_s32(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9699 break;
9700 default:
9701 g_assert_not_reached();
9702 }
9703 } else {
9704 switch (size) {
9705 case 0:
9706 gen_helper_neon_sqadd_u8(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9707 break;
9708 case 1:
9709 gen_helper_neon_sqadd_u16(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9710 break;
9711 case 2:
9712 gen_helper_neon_sqadd_u32(tcg_rd, cpu_env, tcg_rn, tcg_rd);
9713 break;
9714 default:
9715 g_assert_not_reached();
9716 }
9717 }
9718
9719 if (is_scalar) {
9720 write_vec_element(s, tcg_constant_i64(0), rd, 0, MO_64);
9721 }
9722 write_vec_element_i32(s, tcg_rd, rd, pass, MO_32);
9723 }
9724 clear_vec_high(s, is_q, rd);
9725 }
9726}
9727
9728
9729
9730
9731
9732
9733
9734static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn)
9735{
9736 int rd = extract32(insn, 0, 5);
9737 int rn = extract32(insn, 5, 5);
9738 int opcode = extract32(insn, 12, 5);
9739 int size = extract32(insn, 22, 2);
9740 bool u = extract32(insn, 29, 1);
9741 bool is_fcvt = false;
9742 int rmode;
9743 TCGv_i32 tcg_rmode;
9744 TCGv_ptr tcg_fpstatus;
9745
9746 switch (opcode) {
9747 case 0x3:
9748 if (!fp_access_check(s)) {
9749 return;
9750 }
9751 handle_2misc_satacc(s, true, u, false, size, rn, rd);
9752 return;
9753 case 0x7:
9754 break;
9755 case 0xa:
9756 if (u) {
9757 unallocated_encoding(s);
9758 return;
9759 }
9760
9761 case 0x8:
9762 case 0x9:
9763 case 0xb:
9764 if (size != 3) {
9765 unallocated_encoding(s);
9766 return;
9767 }
9768 break;
9769 case 0x12:
9770 if (!u) {
9771 unallocated_encoding(s);
9772 return;
9773 }
9774
9775 case 0x14:
9776 if (size == 3) {
9777 unallocated_encoding(s);
9778 return;
9779 }
9780 if (!fp_access_check(s)) {
9781 return;
9782 }
9783 handle_2misc_narrow(s, true, opcode, u, false, size, rn, rd);
9784 return;
9785 case 0xc ... 0xf:
9786 case 0x16 ... 0x1d:
9787 case 0x1f:
9788
9789
9790
9791 opcode |= (extract32(size, 1, 1) << 5) | (u << 6);
9792 size = extract32(size, 0, 1) ? 3 : 2;
9793 switch (opcode) {
9794 case 0x2c:
9795 case 0x2d:
9796 case 0x2e:
9797 case 0x6c:
9798 case 0x6d:
9799 handle_2misc_fcmp_zero(s, opcode, true, u, true, size, rn, rd);
9800 return;
9801 case 0x1d:
9802 case 0x5d:
9803 {
9804 bool is_signed = (opcode == 0x1d);
9805 if (!fp_access_check(s)) {
9806 return;
9807 }
9808 handle_simd_intfp_conv(s, rd, rn, 1, is_signed, 0, size);
9809 return;
9810 }
9811 case 0x3d:
9812 case 0x3f:
9813 case 0x7d:
9814 if (!fp_access_check(s)) {
9815 return;
9816 }
9817 handle_2misc_reciprocal(s, opcode, true, u, true, size, rn, rd);
9818 return;
9819 case 0x1a:
9820 case 0x1b:
9821 case 0x3a:
9822 case 0x3b:
9823 case 0x5a:
9824 case 0x5b:
9825 case 0x7a:
9826 case 0x7b:
9827 is_fcvt = true;
9828 rmode = extract32(opcode, 5, 1) | (extract32(opcode, 0, 1) << 1);
9829 break;
9830 case 0x1c:
9831 case 0x5c:
9832
9833 is_fcvt = true;
9834 rmode = FPROUNDING_TIEAWAY;
9835 break;
9836 case 0x56:
9837 if (size == 2) {
9838 unallocated_encoding(s);
9839 return;
9840 }
9841 if (!fp_access_check(s)) {
9842 return;
9843 }
9844 handle_2misc_narrow(s, true, opcode, u, false, size - 1, rn, rd);
9845 return;
9846 default:
9847 unallocated_encoding(s);
9848 return;
9849 }
9850 break;
9851 default:
9852 unallocated_encoding(s);
9853 return;
9854 }
9855
9856 if (!fp_access_check(s)) {
9857 return;
9858 }
9859
9860 if (is_fcvt) {
9861 tcg_fpstatus = fpstatus_ptr(FPST_FPCR);
9862 tcg_rmode = gen_set_rmode(rmode, tcg_fpstatus);
9863 } else {
9864 tcg_fpstatus = NULL;
9865 tcg_rmode = NULL;
9866 }
9867
9868 if (size == 3) {
9869 TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
9870 TCGv_i64 tcg_rd = tcg_temp_new_i64();
9871
9872 handle_2misc_64(s, opcode, u, tcg_rd, tcg_rn, tcg_rmode, tcg_fpstatus);
9873 write_fp_dreg(s, rd, tcg_rd);
9874 } else {
9875 TCGv_i32 tcg_rn = tcg_temp_new_i32();
9876 TCGv_i32 tcg_rd = tcg_temp_new_i32();
9877
9878 read_vec_element_i32(s, tcg_rn, rn, 0, size);
9879
9880 switch (opcode) {
9881 case 0x7:
9882 {
9883 NeonGenOneOpEnvFn *genfn;
9884 static NeonGenOneOpEnvFn * const fns[3][2] = {
9885 { gen_helper_neon_qabs_s8, gen_helper_neon_qneg_s8 },
9886 { gen_helper_neon_qabs_s16, gen_helper_neon_qneg_s16 },
9887 { gen_helper_neon_qabs_s32, gen_helper_neon_qneg_s32 },
9888 };
9889 genfn = fns[size][u];
9890 genfn(tcg_rd, cpu_env, tcg_rn);
9891 break;
9892 }
9893 case 0x1a:
9894 case 0x1b:
9895 case 0x1c:
9896 case 0x3a:
9897 case 0x3b:
9898 gen_helper_vfp_tosls(tcg_rd, tcg_rn, tcg_constant_i32(0),
9899 tcg_fpstatus);
9900 break;
9901 case 0x5a:
9902 case 0x5b:
9903 case 0x5c:
9904 case 0x7a:
9905 case 0x7b:
9906 gen_helper_vfp_touls(tcg_rd, tcg_rn, tcg_constant_i32(0),
9907 tcg_fpstatus);
9908 break;
9909 default:
9910 g_assert_not_reached();
9911 }
9912
9913 write_fp_sreg(s, rd, tcg_rd);
9914 }
9915
9916 if (is_fcvt) {
9917 gen_restore_rmode(tcg_rmode, tcg_fpstatus);
9918 }
9919}
9920
9921
9922static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u,
9923 int immh, int immb, int opcode, int rn, int rd)
9924{
9925 int size = 32 - clz32(immh) - 1;
9926 int immhb = immh << 3 | immb;
9927 int shift = 2 * (8 << size) - immhb;
9928 GVecGen2iFn *gvec_fn;
9929
9930 if (extract32(immh, 3, 1) && !is_q) {
9931 unallocated_encoding(s);
9932 return;
9933 }
9934 tcg_debug_assert(size <= 3);
9935
9936 if (!fp_access_check(s)) {
9937 return;
9938 }
9939
9940 switch (opcode) {
9941 case 0x02:
9942 gvec_fn = is_u ? gen_gvec_usra : gen_gvec_ssra;
9943 break;
9944
9945 case 0x08:
9946 gvec_fn = gen_gvec_sri;
9947 break;
9948
9949 case 0x00:
9950 if (is_u) {
9951 if (shift == 8 << size) {
9952
9953 tcg_gen_gvec_dup_imm(size, vec_full_reg_offset(s, rd),
9954 is_q ? 16 : 8, vec_full_reg_size(s), 0);
9955 return;
9956 }
9957 gvec_fn = tcg_gen_gvec_shri;
9958 } else {
9959
9960 if (shift == 8 << size) {
9961 shift -= 1;
9962 }
9963 gvec_fn = tcg_gen_gvec_sari;
9964 }
9965 break;
9966
9967 case 0x04:
9968 gvec_fn = is_u ? gen_gvec_urshr : gen_gvec_srshr;
9969 break;
9970
9971 case 0x06:
9972 gvec_fn = is_u ? gen_gvec_ursra : gen_gvec_srsra;
9973 break;
9974
9975 default:
9976 g_assert_not_reached();
9977 }
9978
9979 gen_gvec_fn2i(s, is_q, rd, rn, shift, gvec_fn, size);
9980}
9981
9982
9983static void handle_vec_simd_shli(DisasContext *s, bool is_q, bool insert,
9984 int immh, int immb, int opcode, int rn, int rd)
9985{
9986 int size = 32 - clz32(immh) - 1;
9987 int immhb = immh << 3 | immb;
9988 int shift = immhb - (8 << size);
9989
9990
9991 assert(size >= 0 && size <= 3);
9992
9993 if (extract32(immh, 3, 1) && !is_q) {
9994 unallocated_encoding(s);
9995 return;
9996 }
9997
9998 if (!fp_access_check(s)) {
9999 return;
10000 }
10001
10002 if (insert) {
10003 gen_gvec_fn2i(s, is_q, rd, rn, shift, gen_gvec_sli, size);
10004 } else {
10005 gen_gvec_fn2i(s, is_q, rd, rn, shift, tcg_gen_gvec_shli, size);
10006 }
10007}
10008
10009
10010static void handle_vec_simd_wshli(DisasContext *s, bool is_q, bool is_u,
10011 int immh, int immb, int opcode, int rn, int rd)
10012{
10013 int size = 32 - clz32(immh) - 1;
10014 int immhb = immh << 3 | immb;
10015 int shift = immhb - (8 << size);
10016 int dsize = 64;
10017 int esize = 8 << size;
10018 int elements = dsize/esize;
10019 TCGv_i64 tcg_rn = tcg_temp_new_i64();
10020 TCGv_i64 tcg_rd = tcg_temp_new_i64();
10021 int i;
10022
10023 if (size >= 3) {
10024 unallocated_encoding(s);
10025 return;
10026 }
10027
10028 if (!fp_access_check(s)) {
10029 return;
10030 }
10031
10032
10033
10034
10035
10036 read_vec_element(s, tcg_rn, rn, is_q ? 1 : 0, MO_64);
10037
10038 for (i = 0; i < elements; i++) {
10039 tcg_gen_shri_i64(tcg_rd, tcg_rn, i * esize);
10040 ext_and_shift_reg(tcg_rd, tcg_rd, size | (!is_u << 2), 0);
10041 tcg_gen_shli_i64(tcg_rd, tcg_rd, shift);
10042 write_vec_element(s, tcg_rd, rd, i, size + 1);
10043 }
10044}
10045
10046
10047static void handle_vec_simd_shrn(DisasContext *s, bool is_q,
10048 int immh, int immb, int opcode, int rn, int rd)
10049{
10050 int immhb = immh << 3 | immb;
10051 int size = 32 - clz32(immh) - 1;
10052 int dsize = 64;
10053 int esize = 8 << size;
10054 int elements = dsize/esize;
10055 int shift = (2 * esize) - immhb;
10056 bool round = extract32(opcode, 0, 1);
10057 TCGv_i64 tcg_rn, tcg_rd, tcg_final;
10058 TCGv_i64 tcg_round;
10059 int i;
10060
10061 if (extract32(immh, 3, 1)) {
10062 unallocated_encoding(s);
10063 return;
10064 }
10065
10066 if (!fp_access_check(s)) {
10067 return;
10068 }
10069
10070 tcg_rn = tcg_temp_new_i64();
10071 tcg_rd = tcg_temp_new_i64();
10072 tcg_final = tcg_temp_new_i64();
10073 read_vec_element(s, tcg_final, rd, is_q ? 1 : 0, MO_64);
10074
10075 if (round) {
10076 tcg_round = tcg_constant_i64(1ULL << (shift - 1));
10077 } else {
10078 tcg_round = NULL;
10079 }
10080
10081 for (i = 0; i < elements; i++) {
10082 read_vec_element(s, tcg_rn, rn, i, size+1);
10083 handle_shri_with_rndacc(tcg_rd, tcg_rn, tcg_round,
10084 false, true, size+1, shift);
10085
10086 tcg_gen_deposit_i64(tcg_final, tcg_final, tcg_rd, esize * i, esize);
10087 }
10088
10089 if (!is_q) {
10090 write_vec_element(s, tcg_final, rd, 0, MO_64);
10091 } else {
10092 write_vec_element(s, tcg_final, rd, 1, MO_64);
10093 }
10094
10095 clear_vec_high(s, is_q, rd);
10096}
10097
10098
10099
10100
10101
10102
10103
10104
10105static void disas_simd_shift_imm(DisasContext *s, uint32_t insn)
10106{
10107 int rd = extract32(insn, 0, 5);
10108 int rn = extract32(insn, 5, 5);
10109 int opcode = extract32(insn, 11, 5);
10110 int immb = extract32(insn, 16, 3);
10111 int immh = extract32(insn, 19, 4);
10112 bool is_u = extract32(insn, 29, 1);
10113 bool is_q = extract32(insn, 30, 1);
10114
10115
10116 assert(immh != 0);
10117
10118 switch (opcode) {
10119 case 0x08:
10120 if (!is_u) {
10121 unallocated_encoding(s);
10122 return;
10123 }
10124
10125 case 0x00:
10126 case 0x02:
10127 case 0x04:
10128 case 0x06:
10129 handle_vec_simd_shri(s, is_q, is_u, immh, immb, opcode, rn, rd);
10130 break;
10131 case 0x0a:
10132 handle_vec_simd_shli(s, is_q, is_u, immh, immb, opcode, rn, rd);
10133 break;
10134 case 0x10:
10135 case 0x11:
10136 if (is_u) {
10137 handle_vec_simd_sqshrn(s, false, is_q, false, true, immh, immb,
10138 opcode, rn, rd);
10139 } else {
10140 handle_vec_simd_shrn(s, is_q, immh, immb, opcode, rn, rd);
10141 }
10142 break;
10143 case 0x12:
10144 case 0x13:
10145 handle_vec_simd_sqshrn(s, false, is_q, is_u, is_u, immh, immb,
10146 opcode, rn, rd);
10147 break;
10148 case 0x14:
10149 handle_vec_simd_wshli(s, is_q, is_u, immh, immb, opcode, rn, rd);
10150 break;
10151 case 0x1c:
10152 handle_simd_shift_intfp_conv(s, false, is_q, is_u, immh, immb,
10153 opcode, rn, rd);
10154 break;
10155 case 0xc:
10156 if (!is_u) {
10157 unallocated_encoding(s);
10158 return;
10159 }
10160 handle_simd_qshl(s, false, is_q, false, true, immh, immb, rn, rd);
10161 break;
10162 case 0xe:
10163 handle_simd_qshl(s, false, is_q, is_u, is_u, immh, immb, rn, rd);
10164 break;
10165 case 0x1f:
10166 handle_simd_shift_fpint_conv(s, false, is_q, is_u, immh, immb, rn, rd);
10167 return;
10168 default:
10169 unallocated_encoding(s);
10170 return;
10171 }
10172}
10173
10174
10175
10176
10177static void gen_neon_addl(int size, bool is_sub, TCGv_i64 tcg_res,
10178 TCGv_i64 tcg_op1, TCGv_i64 tcg_op2)
10179{
10180 static NeonGenTwo64OpFn * const fns[3][2] = {
10181 { gen_helper_neon_addl_u16, gen_helper_neon_subl_u16 },
10182 { gen_helper_neon_addl_u32, gen_helper_neon_subl_u32 },
10183 { tcg_gen_add_i64, tcg_gen_sub_i64 },
10184 };
10185 NeonGenTwo64OpFn *genfn;
10186 assert(size < 3);
10187
10188 genfn = fns[size][is_sub];
10189 genfn(tcg_res, tcg_op1, tcg_op2);
10190}
10191
10192static void handle_3rd_widening(DisasContext *s, int is_q, int is_u, int size,
10193 int opcode, int rd, int rn, int rm)
10194{
10195
10196 TCGv_i64 tcg_res[2];
10197 int pass, accop;
10198
10199 tcg_res[0] = tcg_temp_new_i64();
10200 tcg_res[1] = tcg_temp_new_i64();
10201
10202
10203
10204
10205 switch (opcode) {
10206 case 5:
10207 case 8:
10208 case 9:
10209 accop = 1;
10210 break;
10211 case 10:
10212 case 11:
10213 accop = -1;
10214 break;
10215 default:
10216 accop = 0;
10217 break;
10218 }
10219
10220 if (accop != 0) {
10221 read_vec_element(s, tcg_res[0], rd, 0, MO_64);
10222 read_vec_element(s, tcg_res[1], rd, 1, MO_64);
10223 }
10224
10225
10226
10227
10228 if (size == 2) {
10229 for (pass = 0; pass < 2; pass++) {
10230 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
10231 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
10232 TCGv_i64 tcg_passres;
10233 MemOp memop = MO_32 | (is_u ? 0 : MO_SIGN);
10234
10235 int elt = pass + is_q * 2;
10236
10237 read_vec_element(s, tcg_op1, rn, elt, memop);
10238 read_vec_element(s, tcg_op2, rm, elt, memop);
10239
10240 if (accop == 0) {
10241 tcg_passres = tcg_res[pass];
10242 } else {
10243 tcg_passres = tcg_temp_new_i64();
10244 }
10245
10246 switch (opcode) {
10247 case 0:
10248 tcg_gen_add_i64(tcg_passres, tcg_op1, tcg_op2);
10249 break;
10250 case 2:
10251 tcg_gen_sub_i64(tcg_passres, tcg_op1, tcg_op2);
10252 break;
10253 case 5:
10254 case 7:
10255 {
10256 TCGv_i64 tcg_tmp1 = tcg_temp_new_i64();
10257 TCGv_i64 tcg_tmp2 = tcg_temp_new_i64();
10258
10259 tcg_gen_sub_i64(tcg_tmp1, tcg_op1, tcg_op2);
10260 tcg_gen_sub_i64(tcg_tmp2, tcg_op2, tcg_op1);
10261 tcg_gen_movcond_i64(is_u ? TCG_COND_GEU : TCG_COND_GE,
10262 tcg_passres,
10263 tcg_op1, tcg_op2, tcg_tmp1, tcg_tmp2);
10264 break;
10265 }
10266 case 8:
10267 case 10:
10268 case 12:
10269 tcg_gen_mul_i64(tcg_passres, tcg_op1, tcg_op2);
10270 break;
10271 case 9:
10272 case 11:
10273 case 13:
10274 tcg_gen_mul_i64(tcg_passres, tcg_op1, tcg_op2);
10275 gen_helper_neon_addl_saturate_s64(tcg_passres, cpu_env,
10276 tcg_passres, tcg_passres);
10277 break;
10278 default:
10279 g_assert_not_reached();
10280 }
10281
10282 if (opcode == 9 || opcode == 11) {
10283
10284 if (accop < 0) {
10285 tcg_gen_neg_i64(tcg_passres, tcg_passres);
10286 }
10287 gen_helper_neon_addl_saturate_s64(tcg_res[pass], cpu_env,
10288 tcg_res[pass], tcg_passres);
10289 } else if (accop > 0) {
10290 tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
10291 } else if (accop < 0) {
10292 tcg_gen_sub_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
10293 }
10294 }
10295 } else {
10296
10297 for (pass = 0; pass < 2; pass++) {
10298 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
10299 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
10300 TCGv_i64 tcg_passres;
10301 int elt = pass + is_q * 2;
10302
10303 read_vec_element_i32(s, tcg_op1, rn, elt, MO_32);
10304 read_vec_element_i32(s, tcg_op2, rm, elt, MO_32);
10305
10306 if (accop == 0) {
10307 tcg_passres = tcg_res[pass];
10308 } else {
10309 tcg_passres = tcg_temp_new_i64();
10310 }
10311
10312 switch (opcode) {
10313 case 0:
10314 case 2:
10315 {
10316 TCGv_i64 tcg_op2_64 = tcg_temp_new_i64();
10317 static NeonGenWidenFn * const widenfns[2][2] = {
10318 { gen_helper_neon_widen_s8, gen_helper_neon_widen_u8 },
10319 { gen_helper_neon_widen_s16, gen_helper_neon_widen_u16 },
10320 };
10321 NeonGenWidenFn *widenfn = widenfns[size][is_u];
10322
10323 widenfn(tcg_op2_64, tcg_op2);
10324 widenfn(tcg_passres, tcg_op1);
10325 gen_neon_addl(size, (opcode == 2), tcg_passres,
10326 tcg_passres, tcg_op2_64);
10327 break;
10328 }
10329 case 5:
10330 case 7:
10331 if (size == 0) {
10332 if (is_u) {
10333 gen_helper_neon_abdl_u16(tcg_passres, tcg_op1, tcg_op2);
10334 } else {
10335 gen_helper_neon_abdl_s16(tcg_passres, tcg_op1, tcg_op2);
10336 }
10337 } else {
10338 if (is_u) {
10339 gen_helper_neon_abdl_u32(tcg_passres, tcg_op1, tcg_op2);
10340 } else {
10341 gen_helper_neon_abdl_s32(tcg_passres, tcg_op1, tcg_op2);
10342 }
10343 }
10344 break;
10345 case 8:
10346 case 10:
10347 case 12:
10348 if (size == 0) {
10349 if (is_u) {
10350 gen_helper_neon_mull_u8(tcg_passres, tcg_op1, tcg_op2);
10351 } else {
10352 gen_helper_neon_mull_s8(tcg_passres, tcg_op1, tcg_op2);
10353 }
10354 } else {
10355 if (is_u) {
10356 gen_helper_neon_mull_u16(tcg_passres, tcg_op1, tcg_op2);
10357 } else {
10358 gen_helper_neon_mull_s16(tcg_passres, tcg_op1, tcg_op2);
10359 }
10360 }
10361 break;
10362 case 9:
10363 case 11:
10364 case 13:
10365 assert(size == 1);
10366 gen_helper_neon_mull_s16(tcg_passres, tcg_op1, tcg_op2);
10367 gen_helper_neon_addl_saturate_s32(tcg_passres, cpu_env,
10368 tcg_passres, tcg_passres);
10369 break;
10370 default:
10371 g_assert_not_reached();
10372 }
10373
10374 if (accop != 0) {
10375 if (opcode == 9 || opcode == 11) {
10376
10377 if (accop < 0) {
10378 gen_helper_neon_negl_u32(tcg_passres, tcg_passres);
10379 }
10380 gen_helper_neon_addl_saturate_s32(tcg_res[pass], cpu_env,
10381 tcg_res[pass],
10382 tcg_passres);
10383 } else {
10384 gen_neon_addl(size, (accop < 0), tcg_res[pass],
10385 tcg_res[pass], tcg_passres);
10386 }
10387 }
10388 }
10389 }
10390
10391 write_vec_element(s, tcg_res[0], rd, 0, MO_64);
10392 write_vec_element(s, tcg_res[1], rd, 1, MO_64);
10393}
10394
10395static void handle_3rd_wide(DisasContext *s, int is_q, int is_u, int size,
10396 int opcode, int rd, int rn, int rm)
10397{
10398 TCGv_i64 tcg_res[2];
10399 int part = is_q ? 2 : 0;
10400 int pass;
10401
10402 for (pass = 0; pass < 2; pass++) {
10403 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
10404 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
10405 TCGv_i64 tcg_op2_wide = tcg_temp_new_i64();
10406 static NeonGenWidenFn * const widenfns[3][2] = {
10407 { gen_helper_neon_widen_s8, gen_helper_neon_widen_u8 },
10408 { gen_helper_neon_widen_s16, gen_helper_neon_widen_u16 },
10409 { tcg_gen_ext_i32_i64, tcg_gen_extu_i32_i64 },
10410 };
10411 NeonGenWidenFn *widenfn = widenfns[size][is_u];
10412
10413 read_vec_element(s, tcg_op1, rn, pass, MO_64);
10414 read_vec_element_i32(s, tcg_op2, rm, part + pass, MO_32);
10415 widenfn(tcg_op2_wide, tcg_op2);
10416 tcg_res[pass] = tcg_temp_new_i64();
10417 gen_neon_addl(size, (opcode == 3),
10418 tcg_res[pass], tcg_op1, tcg_op2_wide);
10419 }
10420
10421 for (pass = 0; pass < 2; pass++) {
10422 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
10423 }
10424}
10425
10426static void do_narrow_round_high_u32(TCGv_i32 res, TCGv_i64 in)
10427{
10428 tcg_gen_addi_i64(in, in, 1U << 31);
10429 tcg_gen_extrh_i64_i32(res, in);
10430}
10431
10432static void handle_3rd_narrowing(DisasContext *s, int is_q, int is_u, int size,
10433 int opcode, int rd, int rn, int rm)
10434{
10435 TCGv_i32 tcg_res[2];
10436 int part = is_q ? 2 : 0;
10437 int pass;
10438
10439 for (pass = 0; pass < 2; pass++) {
10440 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
10441 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
10442 TCGv_i64 tcg_wideres = tcg_temp_new_i64();
10443 static NeonGenNarrowFn * const narrowfns[3][2] = {
10444 { gen_helper_neon_narrow_high_u8,
10445 gen_helper_neon_narrow_round_high_u8 },
10446 { gen_helper_neon_narrow_high_u16,
10447 gen_helper_neon_narrow_round_high_u16 },
10448 { tcg_gen_extrh_i64_i32, do_narrow_round_high_u32 },
10449 };
10450 NeonGenNarrowFn *gennarrow = narrowfns[size][is_u];
10451
10452 read_vec_element(s, tcg_op1, rn, pass, MO_64);
10453 read_vec_element(s, tcg_op2, rm, pass, MO_64);
10454
10455 gen_neon_addl(size, (opcode == 6), tcg_wideres, tcg_op1, tcg_op2);
10456
10457 tcg_res[pass] = tcg_temp_new_i32();
10458 gennarrow(tcg_res[pass], tcg_wideres);
10459 }
10460
10461 for (pass = 0; pass < 2; pass++) {
10462 write_vec_element_i32(s, tcg_res[pass], rd, pass + part, MO_32);
10463 }
10464 clear_vec_high(s, is_q, rd);
10465}
10466
10467
10468
10469
10470
10471
10472
10473static void disas_simd_three_reg_diff(DisasContext *s, uint32_t insn)
10474{
10475
10476
10477
10478
10479
10480
10481
10482
10483
10484
10485 int is_q = extract32(insn, 30, 1);
10486 int is_u = extract32(insn, 29, 1);
10487 int size = extract32(insn, 22, 2);
10488 int opcode = extract32(insn, 12, 4);
10489 int rm = extract32(insn, 16, 5);
10490 int rn = extract32(insn, 5, 5);
10491 int rd = extract32(insn, 0, 5);
10492
10493 switch (opcode) {
10494 case 1:
10495 case 3:
10496
10497 if (size == 3) {
10498 unallocated_encoding(s);
10499 return;
10500 }
10501 if (!fp_access_check(s)) {
10502 return;
10503 }
10504 handle_3rd_wide(s, is_q, is_u, size, opcode, rd, rn, rm);
10505 break;
10506 case 4:
10507 case 6:
10508
10509 if (size == 3) {
10510 unallocated_encoding(s);
10511 return;
10512 }
10513 if (!fp_access_check(s)) {
10514 return;
10515 }
10516 handle_3rd_narrowing(s, is_q, is_u, size, opcode, rd, rn, rm);
10517 break;
10518 case 14:
10519 if (is_u) {
10520 unallocated_encoding(s);
10521 return;
10522 }
10523 switch (size) {
10524 case 0:
10525 if (!fp_access_check(s)) {
10526 return;
10527 }
10528
10529 gen_gvec_op3_ool(s, true, rd, rn, rm, is_q,
10530 gen_helper_neon_pmull_h);
10531 break;
10532
10533 case 3:
10534 if (!dc_isar_feature(aa64_pmull, s)) {
10535 unallocated_encoding(s);
10536 return;
10537 }
10538 if (!fp_access_check(s)) {
10539 return;
10540 }
10541
10542 gen_gvec_op3_ool(s, true, rd, rn, rm, is_q,
10543 gen_helper_gvec_pmull_q);
10544 break;
10545
10546 default:
10547 unallocated_encoding(s);
10548 break;
10549 }
10550 return;
10551 case 9:
10552 case 11:
10553 case 13:
10554 if (is_u || size == 0) {
10555 unallocated_encoding(s);
10556 return;
10557 }
10558
10559 case 0:
10560 case 2:
10561 case 5:
10562 case 7:
10563 case 8:
10564 case 10:
10565 case 12:
10566
10567 if (size == 3) {
10568 unallocated_encoding(s);
10569 return;
10570 }
10571 if (!fp_access_check(s)) {
10572 return;
10573 }
10574
10575 handle_3rd_widening(s, is_q, is_u, size, opcode, rd, rn, rm);
10576 break;
10577 default:
10578
10579 unallocated_encoding(s);
10580 break;
10581 }
10582}
10583
10584
10585static void disas_simd_3same_logic(DisasContext *s, uint32_t insn)
10586{
10587 int rd = extract32(insn, 0, 5);
10588 int rn = extract32(insn, 5, 5);
10589 int rm = extract32(insn, 16, 5);
10590 int size = extract32(insn, 22, 2);
10591 bool is_u = extract32(insn, 29, 1);
10592 bool is_q = extract32(insn, 30, 1);
10593
10594 if (!fp_access_check(s)) {
10595 return;
10596 }
10597
10598 switch (size + 4 * is_u) {
10599 case 0:
10600 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_and, 0);
10601 return;
10602 case 1:
10603 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_andc, 0);
10604 return;
10605 case 2:
10606 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_or, 0);
10607 return;
10608 case 3:
10609 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_orc, 0);
10610 return;
10611 case 4:
10612 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_xor, 0);
10613 return;
10614
10615 case 5:
10616 gen_gvec_fn4(s, is_q, rd, rd, rn, rm, tcg_gen_gvec_bitsel, 0);
10617 return;
10618 case 6:
10619 gen_gvec_fn4(s, is_q, rd, rm, rn, rd, tcg_gen_gvec_bitsel, 0);
10620 return;
10621 case 7:
10622 gen_gvec_fn4(s, is_q, rd, rm, rd, rn, tcg_gen_gvec_bitsel, 0);
10623 return;
10624
10625 default:
10626 g_assert_not_reached();
10627 }
10628}
10629
10630
10631
10632
10633
10634
10635static void handle_simd_3same_pair(DisasContext *s, int is_q, int u, int opcode,
10636 int size, int rn, int rm, int rd)
10637{
10638 TCGv_ptr fpst;
10639 int pass;
10640
10641
10642 if (opcode >= 0x58) {
10643 fpst = fpstatus_ptr(FPST_FPCR);
10644 } else {
10645 fpst = NULL;
10646 }
10647
10648 if (!fp_access_check(s)) {
10649 return;
10650 }
10651
10652
10653
10654
10655 if (size == 3) {
10656 TCGv_i64 tcg_res[2];
10657
10658 for (pass = 0; pass < 2; pass++) {
10659 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
10660 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
10661 int passreg = (pass == 0) ? rn : rm;
10662
10663 read_vec_element(s, tcg_op1, passreg, 0, MO_64);
10664 read_vec_element(s, tcg_op2, passreg, 1, MO_64);
10665 tcg_res[pass] = tcg_temp_new_i64();
10666
10667 switch (opcode) {
10668 case 0x17:
10669 tcg_gen_add_i64(tcg_res[pass], tcg_op1, tcg_op2);
10670 break;
10671 case 0x58:
10672 gen_helper_vfp_maxnumd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10673 break;
10674 case 0x5a:
10675 gen_helper_vfp_addd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10676 break;
10677 case 0x5e:
10678 gen_helper_vfp_maxd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10679 break;
10680 case 0x78:
10681 gen_helper_vfp_minnumd(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10682 break;
10683 case 0x7e:
10684 gen_helper_vfp_mind(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10685 break;
10686 default:
10687 g_assert_not_reached();
10688 }
10689 }
10690
10691 for (pass = 0; pass < 2; pass++) {
10692 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
10693 }
10694 } else {
10695 int maxpass = is_q ? 4 : 2;
10696 TCGv_i32 tcg_res[4];
10697
10698 for (pass = 0; pass < maxpass; pass++) {
10699 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
10700 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
10701 NeonGenTwoOpFn *genfn = NULL;
10702 int passreg = pass < (maxpass / 2) ? rn : rm;
10703 int passelt = (is_q && (pass & 1)) ? 2 : 0;
10704
10705 read_vec_element_i32(s, tcg_op1, passreg, passelt, MO_32);
10706 read_vec_element_i32(s, tcg_op2, passreg, passelt + 1, MO_32);
10707 tcg_res[pass] = tcg_temp_new_i32();
10708
10709 switch (opcode) {
10710 case 0x17:
10711 {
10712 static NeonGenTwoOpFn * const fns[3] = {
10713 gen_helper_neon_padd_u8,
10714 gen_helper_neon_padd_u16,
10715 tcg_gen_add_i32,
10716 };
10717 genfn = fns[size];
10718 break;
10719 }
10720 case 0x14:
10721 {
10722 static NeonGenTwoOpFn * const fns[3][2] = {
10723 { gen_helper_neon_pmax_s8, gen_helper_neon_pmax_u8 },
10724 { gen_helper_neon_pmax_s16, gen_helper_neon_pmax_u16 },
10725 { tcg_gen_smax_i32, tcg_gen_umax_i32 },
10726 };
10727 genfn = fns[size][u];
10728 break;
10729 }
10730 case 0x15:
10731 {
10732 static NeonGenTwoOpFn * const fns[3][2] = {
10733 { gen_helper_neon_pmin_s8, gen_helper_neon_pmin_u8 },
10734 { gen_helper_neon_pmin_s16, gen_helper_neon_pmin_u16 },
10735 { tcg_gen_smin_i32, tcg_gen_umin_i32 },
10736 };
10737 genfn = fns[size][u];
10738 break;
10739 }
10740
10741 case 0x58:
10742 gen_helper_vfp_maxnums(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10743 break;
10744 case 0x5a:
10745 gen_helper_vfp_adds(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10746 break;
10747 case 0x5e:
10748 gen_helper_vfp_maxs(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10749 break;
10750 case 0x78:
10751 gen_helper_vfp_minnums(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10752 break;
10753 case 0x7e:
10754 gen_helper_vfp_mins(tcg_res[pass], tcg_op1, tcg_op2, fpst);
10755 break;
10756 default:
10757 g_assert_not_reached();
10758 }
10759
10760
10761 if (genfn) {
10762 genfn(tcg_res[pass], tcg_op1, tcg_op2);
10763 }
10764 }
10765
10766 for (pass = 0; pass < maxpass; pass++) {
10767 write_vec_element_i32(s, tcg_res[pass], rd, pass, MO_32);
10768 }
10769 clear_vec_high(s, is_q, rd);
10770 }
10771}
10772
10773
10774static void disas_simd_3same_float(DisasContext *s, uint32_t insn)
10775{
10776
10777
10778
10779
10780 int fpopcode = extract32(insn, 11, 5)
10781 | (extract32(insn, 23, 1) << 5)
10782 | (extract32(insn, 29, 1) << 6);
10783 int is_q = extract32(insn, 30, 1);
10784 int size = extract32(insn, 22, 1);
10785 int rm = extract32(insn, 16, 5);
10786 int rn = extract32(insn, 5, 5);
10787 int rd = extract32(insn, 0, 5);
10788
10789 int datasize = is_q ? 128 : 64;
10790 int esize = 32 << size;
10791 int elements = datasize / esize;
10792
10793 if (size == 1 && !is_q) {
10794 unallocated_encoding(s);
10795 return;
10796 }
10797
10798 switch (fpopcode) {
10799 case 0x58:
10800 case 0x5a:
10801 case 0x5e:
10802 case 0x78:
10803 case 0x7e:
10804 if (size && !is_q) {
10805 unallocated_encoding(s);
10806 return;
10807 }
10808 handle_simd_3same_pair(s, is_q, 0, fpopcode, size ? MO_64 : MO_32,
10809 rn, rm, rd);
10810 return;
10811 case 0x1b:
10812 case 0x1f:
10813 case 0x3f:
10814 case 0x5d:
10815 case 0x7d:
10816 case 0x19:
10817 case 0x39:
10818 case 0x18:
10819 case 0x1a:
10820 case 0x1c:
10821 case 0x1e:
10822 case 0x38:
10823 case 0x3a:
10824 case 0x3e:
10825 case 0x5b:
10826 case 0x5c:
10827 case 0x5f:
10828 case 0x7a:
10829 case 0x7c:
10830 if (!fp_access_check(s)) {
10831 return;
10832 }
10833 handle_3same_float(s, size, elements, fpopcode, rd, rn, rm);
10834 return;
10835
10836 case 0x1d:
10837 case 0x3d:
10838 case 0x59:
10839 case 0x79:
10840 if (size & 1 || !dc_isar_feature(aa64_fhm, s)) {
10841 unallocated_encoding(s);
10842 return;
10843 }
10844 if (fp_access_check(s)) {
10845 int is_s = extract32(insn, 23, 1);
10846 int is_2 = extract32(insn, 29, 1);
10847 int data = (is_2 << 1) | is_s;
10848 tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd),
10849 vec_full_reg_offset(s, rn),
10850 vec_full_reg_offset(s, rm), cpu_env,
10851 is_q ? 16 : 8, vec_full_reg_size(s),
10852 data, gen_helper_gvec_fmlal_a64);
10853 }
10854 return;
10855
10856 default:
10857 unallocated_encoding(s);
10858 return;
10859 }
10860}
10861
10862
10863static void disas_simd_3same_int(DisasContext *s, uint32_t insn)
10864{
10865 int is_q = extract32(insn, 30, 1);
10866 int u = extract32(insn, 29, 1);
10867 int size = extract32(insn, 22, 2);
10868 int opcode = extract32(insn, 11, 5);
10869 int rm = extract32(insn, 16, 5);
10870 int rn = extract32(insn, 5, 5);
10871 int rd = extract32(insn, 0, 5);
10872 int pass;
10873 TCGCond cond;
10874
10875 switch (opcode) {
10876 case 0x13:
10877 if (u && size != 0) {
10878 unallocated_encoding(s);
10879 return;
10880 }
10881
10882 case 0x0:
10883 case 0x2:
10884 case 0x4:
10885 case 0xc:
10886 case 0xd:
10887 case 0xe:
10888 case 0xf:
10889 case 0x12:
10890 if (size == 3) {
10891 unallocated_encoding(s);
10892 return;
10893 }
10894 break;
10895 case 0x16:
10896 if (size == 0 || size == 3) {
10897 unallocated_encoding(s);
10898 return;
10899 }
10900 break;
10901 default:
10902 if (size == 3 && !is_q) {
10903 unallocated_encoding(s);
10904 return;
10905 }
10906 break;
10907 }
10908
10909 if (!fp_access_check(s)) {
10910 return;
10911 }
10912
10913 switch (opcode) {
10914 case 0x01:
10915 if (u) {
10916 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_uqadd_qc, size);
10917 } else {
10918 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sqadd_qc, size);
10919 }
10920 return;
10921 case 0x05:
10922 if (u) {
10923 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_uqsub_qc, size);
10924 } else {
10925 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sqsub_qc, size);
10926 }
10927 return;
10928 case 0x08:
10929 if (u) {
10930 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_ushl, size);
10931 } else {
10932 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sshl, size);
10933 }
10934 return;
10935 case 0x0c:
10936 if (u) {
10937 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_umax, size);
10938 } else {
10939 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_smax, size);
10940 }
10941 return;
10942 case 0x0d:
10943 if (u) {
10944 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_umin, size);
10945 } else {
10946 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_smin, size);
10947 }
10948 return;
10949 case 0xe:
10950 if (u) {
10951 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_uabd, size);
10952 } else {
10953 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sabd, size);
10954 }
10955 return;
10956 case 0xf:
10957 if (u) {
10958 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_uaba, size);
10959 } else {
10960 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_saba, size);
10961 }
10962 return;
10963 case 0x10:
10964 if (u) {
10965 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_sub, size);
10966 } else {
10967 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_add, size);
10968 }
10969 return;
10970 case 0x13:
10971 if (!u) {
10972 gen_gvec_fn3(s, is_q, rd, rn, rm, tcg_gen_gvec_mul, size);
10973 } else {
10974 gen_gvec_op3_ool(s, is_q, rd, rn, rm, 0, gen_helper_gvec_pmul_b);
10975 }
10976 return;
10977 case 0x12:
10978 if (u) {
10979 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_mls, size);
10980 } else {
10981 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_mla, size);
10982 }
10983 return;
10984 case 0x16:
10985 {
10986 static gen_helper_gvec_3_ptr * const fns[2][2] = {
10987 { gen_helper_neon_sqdmulh_h, gen_helper_neon_sqrdmulh_h },
10988 { gen_helper_neon_sqdmulh_s, gen_helper_neon_sqrdmulh_s },
10989 };
10990 gen_gvec_op3_qc(s, is_q, rd, rn, rm, fns[size - 1][u]);
10991 }
10992 return;
10993 case 0x11:
10994 if (!u) {
10995 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_cmtst, size);
10996 return;
10997 }
10998
10999 cond = TCG_COND_EQ;
11000 goto do_gvec_cmp;
11001 case 0x06:
11002 cond = u ? TCG_COND_GTU : TCG_COND_GT;
11003 goto do_gvec_cmp;
11004 case 0x07:
11005 cond = u ? TCG_COND_GEU : TCG_COND_GE;
11006 do_gvec_cmp:
11007 tcg_gen_gvec_cmp(cond, size, vec_full_reg_offset(s, rd),
11008 vec_full_reg_offset(s, rn),
11009 vec_full_reg_offset(s, rm),
11010 is_q ? 16 : 8, vec_full_reg_size(s));
11011 return;
11012 }
11013
11014 if (size == 3) {
11015 assert(is_q);
11016 for (pass = 0; pass < 2; pass++) {
11017 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
11018 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
11019 TCGv_i64 tcg_res = tcg_temp_new_i64();
11020
11021 read_vec_element(s, tcg_op1, rn, pass, MO_64);
11022 read_vec_element(s, tcg_op2, rm, pass, MO_64);
11023
11024 handle_3same_64(s, opcode, u, tcg_res, tcg_op1, tcg_op2);
11025
11026 write_vec_element(s, tcg_res, rd, pass, MO_64);
11027 }
11028 } else {
11029 for (pass = 0; pass < (is_q ? 4 : 2); pass++) {
11030 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
11031 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
11032 TCGv_i32 tcg_res = tcg_temp_new_i32();
11033 NeonGenTwoOpFn *genfn = NULL;
11034 NeonGenTwoOpEnvFn *genenvfn = NULL;
11035
11036 read_vec_element_i32(s, tcg_op1, rn, pass, MO_32);
11037 read_vec_element_i32(s, tcg_op2, rm, pass, MO_32);
11038
11039 switch (opcode) {
11040 case 0x0:
11041 {
11042 static NeonGenTwoOpFn * const fns[3][2] = {
11043 { gen_helper_neon_hadd_s8, gen_helper_neon_hadd_u8 },
11044 { gen_helper_neon_hadd_s16, gen_helper_neon_hadd_u16 },
11045 { gen_helper_neon_hadd_s32, gen_helper_neon_hadd_u32 },
11046 };
11047 genfn = fns[size][u];
11048 break;
11049 }
11050 case 0x2:
11051 {
11052 static NeonGenTwoOpFn * const fns[3][2] = {
11053 { gen_helper_neon_rhadd_s8, gen_helper_neon_rhadd_u8 },
11054 { gen_helper_neon_rhadd_s16, gen_helper_neon_rhadd_u16 },
11055 { gen_helper_neon_rhadd_s32, gen_helper_neon_rhadd_u32 },
11056 };
11057 genfn = fns[size][u];
11058 break;
11059 }
11060 case 0x4:
11061 {
11062 static NeonGenTwoOpFn * const fns[3][2] = {
11063 { gen_helper_neon_hsub_s8, gen_helper_neon_hsub_u8 },
11064 { gen_helper_neon_hsub_s16, gen_helper_neon_hsub_u16 },
11065 { gen_helper_neon_hsub_s32, gen_helper_neon_hsub_u32 },
11066 };
11067 genfn = fns[size][u];
11068 break;
11069 }
11070 case 0x9:
11071 {
11072 static NeonGenTwoOpEnvFn * const fns[3][2] = {
11073 { gen_helper_neon_qshl_s8, gen_helper_neon_qshl_u8 },
11074 { gen_helper_neon_qshl_s16, gen_helper_neon_qshl_u16 },
11075 { gen_helper_neon_qshl_s32, gen_helper_neon_qshl_u32 },
11076 };
11077 genenvfn = fns[size][u];
11078 break;
11079 }
11080 case 0xa:
11081 {
11082 static NeonGenTwoOpFn * const fns[3][2] = {
11083 { gen_helper_neon_rshl_s8, gen_helper_neon_rshl_u8 },
11084 { gen_helper_neon_rshl_s16, gen_helper_neon_rshl_u16 },
11085 { gen_helper_neon_rshl_s32, gen_helper_neon_rshl_u32 },
11086 };
11087 genfn = fns[size][u];
11088 break;
11089 }
11090 case 0xb:
11091 {
11092 static NeonGenTwoOpEnvFn * const fns[3][2] = {
11093 { gen_helper_neon_qrshl_s8, gen_helper_neon_qrshl_u8 },
11094 { gen_helper_neon_qrshl_s16, gen_helper_neon_qrshl_u16 },
11095 { gen_helper_neon_qrshl_s32, gen_helper_neon_qrshl_u32 },
11096 };
11097 genenvfn = fns[size][u];
11098 break;
11099 }
11100 default:
11101 g_assert_not_reached();
11102 }
11103
11104 if (genenvfn) {
11105 genenvfn(tcg_res, cpu_env, tcg_op1, tcg_op2);
11106 } else {
11107 genfn(tcg_res, tcg_op1, tcg_op2);
11108 }
11109
11110 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
11111 }
11112 }
11113 clear_vec_high(s, is_q, rd);
11114}
11115
11116
11117
11118
11119
11120
11121
11122static void disas_simd_three_reg_same(DisasContext *s, uint32_t insn)
11123{
11124 int opcode = extract32(insn, 11, 5);
11125
11126 switch (opcode) {
11127 case 0x3:
11128 disas_simd_3same_logic(s, insn);
11129 break;
11130 case 0x17:
11131 case 0x14:
11132 case 0x15:
11133 {
11134
11135 int is_q = extract32(insn, 30, 1);
11136 int u = extract32(insn, 29, 1);
11137 int size = extract32(insn, 22, 2);
11138 int rm = extract32(insn, 16, 5);
11139 int rn = extract32(insn, 5, 5);
11140 int rd = extract32(insn, 0, 5);
11141 if (opcode == 0x17) {
11142 if (u || (size == 3 && !is_q)) {
11143 unallocated_encoding(s);
11144 return;
11145 }
11146 } else {
11147 if (size == 3) {
11148 unallocated_encoding(s);
11149 return;
11150 }
11151 }
11152 handle_simd_3same_pair(s, is_q, u, opcode, size, rn, rm, rd);
11153 break;
11154 }
11155 case 0x18 ... 0x31:
11156
11157 disas_simd_3same_float(s, insn);
11158 break;
11159 default:
11160 disas_simd_3same_int(s, insn);
11161 break;
11162 }
11163}
11164
11165
11166
11167
11168
11169
11170
11171
11172
11173
11174
11175
11176
11177static void disas_simd_three_reg_same_fp16(DisasContext *s, uint32_t insn)
11178{
11179 int opcode = extract32(insn, 11, 3);
11180 int u = extract32(insn, 29, 1);
11181 int a = extract32(insn, 23, 1);
11182 int is_q = extract32(insn, 30, 1);
11183 int rm = extract32(insn, 16, 5);
11184 int rn = extract32(insn, 5, 5);
11185 int rd = extract32(insn, 0, 5);
11186
11187
11188
11189
11190 int fpopcode = opcode | (a << 3) | (u << 4);
11191 int datasize = is_q ? 128 : 64;
11192 int elements = datasize / 16;
11193 bool pairwise;
11194 TCGv_ptr fpst;
11195 int pass;
11196
11197 switch (fpopcode) {
11198 case 0x0:
11199 case 0x1:
11200 case 0x2:
11201 case 0x3:
11202 case 0x4:
11203 case 0x6:
11204 case 0x7:
11205 case 0x8:
11206 case 0x9:
11207 case 0xa:
11208 case 0xe:
11209 case 0xf:
11210 case 0x13:
11211 case 0x14:
11212 case 0x15:
11213 case 0x17:
11214 case 0x1a:
11215 case 0x1c:
11216 case 0x1d:
11217 pairwise = false;
11218 break;
11219 case 0x10:
11220 case 0x12:
11221 case 0x16:
11222 case 0x18:
11223 case 0x1e:
11224 pairwise = true;
11225 break;
11226 default:
11227 unallocated_encoding(s);
11228 return;
11229 }
11230
11231 if (!dc_isar_feature(aa64_fp16, s)) {
11232 unallocated_encoding(s);
11233 return;
11234 }
11235
11236 if (!fp_access_check(s)) {
11237 return;
11238 }
11239
11240 fpst = fpstatus_ptr(FPST_FPCR_F16);
11241
11242 if (pairwise) {
11243 int maxpass = is_q ? 8 : 4;
11244 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
11245 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
11246 TCGv_i32 tcg_res[8];
11247
11248 for (pass = 0; pass < maxpass; pass++) {
11249 int passreg = pass < (maxpass / 2) ? rn : rm;
11250 int passelt = (pass << 1) & (maxpass - 1);
11251
11252 read_vec_element_i32(s, tcg_op1, passreg, passelt, MO_16);
11253 read_vec_element_i32(s, tcg_op2, passreg, passelt + 1, MO_16);
11254 tcg_res[pass] = tcg_temp_new_i32();
11255
11256 switch (fpopcode) {
11257 case 0x10:
11258 gen_helper_advsimd_maxnumh(tcg_res[pass], tcg_op1, tcg_op2,
11259 fpst);
11260 break;
11261 case 0x12:
11262 gen_helper_advsimd_addh(tcg_res[pass], tcg_op1, tcg_op2, fpst);
11263 break;
11264 case 0x16:
11265 gen_helper_advsimd_maxh(tcg_res[pass], tcg_op1, tcg_op2, fpst);
11266 break;
11267 case 0x18:
11268 gen_helper_advsimd_minnumh(tcg_res[pass], tcg_op1, tcg_op2,
11269 fpst);
11270 break;
11271 case 0x1e:
11272 gen_helper_advsimd_minh(tcg_res[pass], tcg_op1, tcg_op2, fpst);
11273 break;
11274 default:
11275 g_assert_not_reached();
11276 }
11277 }
11278
11279 for (pass = 0; pass < maxpass; pass++) {
11280 write_vec_element_i32(s, tcg_res[pass], rd, pass, MO_16);
11281 }
11282 } else {
11283 for (pass = 0; pass < elements; pass++) {
11284 TCGv_i32 tcg_op1 = tcg_temp_new_i32();
11285 TCGv_i32 tcg_op2 = tcg_temp_new_i32();
11286 TCGv_i32 tcg_res = tcg_temp_new_i32();
11287
11288 read_vec_element_i32(s, tcg_op1, rn, pass, MO_16);
11289 read_vec_element_i32(s, tcg_op2, rm, pass, MO_16);
11290
11291 switch (fpopcode) {
11292 case 0x0:
11293 gen_helper_advsimd_maxnumh(tcg_res, tcg_op1, tcg_op2, fpst);
11294 break;
11295 case 0x1:
11296 read_vec_element_i32(s, tcg_res, rd, pass, MO_16);
11297 gen_helper_advsimd_muladdh(tcg_res, tcg_op1, tcg_op2, tcg_res,
11298 fpst);
11299 break;
11300 case 0x2:
11301 gen_helper_advsimd_addh(tcg_res, tcg_op1, tcg_op2, fpst);
11302 break;
11303 case 0x3:
11304 gen_helper_advsimd_mulxh(tcg_res, tcg_op1, tcg_op2, fpst);
11305 break;
11306 case 0x4:
11307 gen_helper_advsimd_ceq_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11308 break;
11309 case 0x6:
11310 gen_helper_advsimd_maxh(tcg_res, tcg_op1, tcg_op2, fpst);
11311 break;
11312 case 0x7:
11313 gen_helper_recpsf_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11314 break;
11315 case 0x8:
11316 gen_helper_advsimd_minnumh(tcg_res, tcg_op1, tcg_op2, fpst);
11317 break;
11318 case 0x9:
11319
11320 tcg_gen_xori_i32(tcg_op1, tcg_op1, 0x8000);
11321 read_vec_element_i32(s, tcg_res, rd, pass, MO_16);
11322 gen_helper_advsimd_muladdh(tcg_res, tcg_op1, tcg_op2, tcg_res,
11323 fpst);
11324 break;
11325 case 0xa:
11326 gen_helper_advsimd_subh(tcg_res, tcg_op1, tcg_op2, fpst);
11327 break;
11328 case 0xe:
11329 gen_helper_advsimd_minh(tcg_res, tcg_op1, tcg_op2, fpst);
11330 break;
11331 case 0xf:
11332 gen_helper_rsqrtsf_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11333 break;
11334 case 0x13:
11335 gen_helper_advsimd_mulh(tcg_res, tcg_op1, tcg_op2, fpst);
11336 break;
11337 case 0x14:
11338 gen_helper_advsimd_cge_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11339 break;
11340 case 0x15:
11341 gen_helper_advsimd_acge_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11342 break;
11343 case 0x17:
11344 gen_helper_advsimd_divh(tcg_res, tcg_op1, tcg_op2, fpst);
11345 break;
11346 case 0x1a:
11347 gen_helper_advsimd_subh(tcg_res, tcg_op1, tcg_op2, fpst);
11348 tcg_gen_andi_i32(tcg_res, tcg_res, 0x7fff);
11349 break;
11350 case 0x1c:
11351 gen_helper_advsimd_cgt_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11352 break;
11353 case 0x1d:
11354 gen_helper_advsimd_acgt_f16(tcg_res, tcg_op1, tcg_op2, fpst);
11355 break;
11356 default:
11357 g_assert_not_reached();
11358 }
11359
11360 write_vec_element_i32(s, tcg_res, rd, pass, MO_16);
11361 }
11362 }
11363
11364 clear_vec_high(s, is_q, rd);
11365}
11366
11367
11368
11369
11370
11371
11372
11373static void disas_simd_three_reg_same_extra(DisasContext *s, uint32_t insn)
11374{
11375 int rd = extract32(insn, 0, 5);
11376 int rn = extract32(insn, 5, 5);
11377 int opcode = extract32(insn, 11, 4);
11378 int rm = extract32(insn, 16, 5);
11379 int size = extract32(insn, 22, 2);
11380 bool u = extract32(insn, 29, 1);
11381 bool is_q = extract32(insn, 30, 1);
11382 bool feature;
11383 int rot;
11384
11385 switch (u * 16 + opcode) {
11386 case 0x10:
11387 case 0x11:
11388 if (size != 1 && size != 2) {
11389 unallocated_encoding(s);
11390 return;
11391 }
11392 feature = dc_isar_feature(aa64_rdm, s);
11393 break;
11394 case 0x02:
11395 case 0x12:
11396 if (size != MO_32) {
11397 unallocated_encoding(s);
11398 return;
11399 }
11400 feature = dc_isar_feature(aa64_dp, s);
11401 break;
11402 case 0x03:
11403 if (size != MO_32) {
11404 unallocated_encoding(s);
11405 return;
11406 }
11407 feature = dc_isar_feature(aa64_i8mm, s);
11408 break;
11409 case 0x04:
11410 case 0x14:
11411 case 0x05:
11412 if (!is_q || size != MO_32) {
11413 unallocated_encoding(s);
11414 return;
11415 }
11416 feature = dc_isar_feature(aa64_i8mm, s);
11417 break;
11418 case 0x18:
11419 case 0x19:
11420 case 0x1a:
11421 case 0x1b:
11422 case 0x1c:
11423 case 0x1e:
11424 if (size == 0
11425 || (size == 1 && !dc_isar_feature(aa64_fp16, s))
11426 || (size == 3 && !is_q)) {
11427 unallocated_encoding(s);
11428 return;
11429 }
11430 feature = dc_isar_feature(aa64_fcma, s);
11431 break;
11432 case 0x1d:
11433 if (size != MO_16 || !is_q) {
11434 unallocated_encoding(s);
11435 return;
11436 }
11437 feature = dc_isar_feature(aa64_bf16, s);
11438 break;
11439 case 0x1f:
11440 switch (size) {
11441 case 1:
11442 case 3:
11443 feature = dc_isar_feature(aa64_bf16, s);
11444 break;
11445 default:
11446 unallocated_encoding(s);
11447 return;
11448 }
11449 break;
11450 default:
11451 unallocated_encoding(s);
11452 return;
11453 }
11454 if (!feature) {
11455 unallocated_encoding(s);
11456 return;
11457 }
11458 if (!fp_access_check(s)) {
11459 return;
11460 }
11461
11462 switch (opcode) {
11463 case 0x0:
11464 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sqrdmlah_qc, size);
11465 return;
11466
11467 case 0x1:
11468 gen_gvec_fn3(s, is_q, rd, rn, rm, gen_gvec_sqrdmlsh_qc, size);
11469 return;
11470
11471 case 0x2:
11472 gen_gvec_op4_ool(s, is_q, rd, rn, rm, rd, 0,
11473 u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b);
11474 return;
11475
11476 case 0x3:
11477 gen_gvec_op4_ool(s, is_q, rd, rn, rm, rd, 0, gen_helper_gvec_usdot_b);
11478 return;
11479
11480 case 0x04:
11481 gen_gvec_op4_ool(s, 1, rd, rn, rm, rd, 0,
11482 u ? gen_helper_gvec_ummla_b
11483 : gen_helper_gvec_smmla_b);
11484 return;
11485 case 0x05:
11486 gen_gvec_op4_ool(s, 1, rd, rn, rm, rd, 0, gen_helper_gvec_usmmla_b);
11487 return;
11488
11489 case 0x8:
11490 case 0x9:
11491 case 0xa:
11492 case 0xb:
11493 rot = extract32(opcode, 0, 2);
11494 switch (size) {
11495 case 1:
11496 gen_gvec_op4_fpst(s, is_q, rd, rn, rm, rd, true, rot,
11497 gen_helper_gvec_fcmlah);
11498 break;
11499 case 2:
11500 gen_gvec_op4_fpst(s, is_q, rd, rn, rm, rd, false, rot,
11501 gen_helper_gvec_fcmlas);
11502 break;
11503 case 3:
11504 gen_gvec_op4_fpst(s, is_q, rd, rn, rm, rd, false, rot,
11505 gen_helper_gvec_fcmlad);
11506 break;
11507 default:
11508 g_assert_not_reached();
11509 }
11510 return;
11511
11512 case 0xc:
11513 case 0xe:
11514 rot = extract32(opcode, 1, 1);
11515 switch (size) {
11516 case 1:
11517 gen_gvec_op3_fpst(s, is_q, rd, rn, rm, size == 1, rot,
11518 gen_helper_gvec_fcaddh);
11519 break;
11520 case 2:
11521 gen_gvec_op3_fpst(s, is_q, rd, rn, rm, size == 1, rot,
11522 gen_helper_gvec_fcadds);
11523 break;
11524 case 3:
11525 gen_gvec_op3_fpst(s, is_q, rd, rn, rm, size == 1, rot,
11526 gen_helper_gvec_fcaddd);
11527 break;
11528 default:
11529 g_assert_not_reached();
11530 }
11531 return;
11532
11533 case 0xd:
11534 gen_gvec_op4_ool(s, is_q, rd, rn, rm, rd, 0, gen_helper_gvec_bfmmla);
11535 return;
11536 case 0xf:
11537 switch (size) {
11538 case 1:
11539 gen_gvec_op4_ool(s, is_q, rd, rn, rm, rd, 0, gen_helper_gvec_bfdot);
11540 break;
11541 case 3:
11542 gen_gvec_op4_fpst(s, 1, rd, rn, rm, rd, false, is_q,
11543 gen_helper_gvec_bfmlal);
11544 break;
11545 default:
11546 g_assert_not_reached();
11547 }
11548 return;
11549
11550 default:
11551 g_assert_not_reached();
11552 }
11553}
11554
11555static void handle_2misc_widening(DisasContext *s, int opcode, bool is_q,
11556 int size, int rn, int rd)
11557{
11558
11559
11560
11561
11562 int pass;
11563
11564 if (size == 3) {
11565
11566 TCGv_i64 tcg_res[2];
11567 int srcelt = is_q ? 2 : 0;
11568
11569 for (pass = 0; pass < 2; pass++) {
11570 TCGv_i32 tcg_op = tcg_temp_new_i32();
11571 tcg_res[pass] = tcg_temp_new_i64();
11572
11573 read_vec_element_i32(s, tcg_op, rn, srcelt + pass, MO_32);
11574 gen_helper_vfp_fcvtds(tcg_res[pass], tcg_op, cpu_env);
11575 }
11576 for (pass = 0; pass < 2; pass++) {
11577 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
11578 }
11579 } else {
11580
11581 int srcelt = is_q ? 4 : 0;
11582 TCGv_i32 tcg_res[4];
11583 TCGv_ptr fpst = fpstatus_ptr(FPST_FPCR);
11584 TCGv_i32 ahp = get_ahp_flag();
11585
11586 for (pass = 0; pass < 4; pass++) {
11587 tcg_res[pass] = tcg_temp_new_i32();
11588
11589 read_vec_element_i32(s, tcg_res[pass], rn, srcelt + pass, MO_16);
11590 gen_helper_vfp_fcvt_f16_to_f32(tcg_res[pass], tcg_res[pass],
11591 fpst, ahp);
11592 }
11593 for (pass = 0; pass < 4; pass++) {
11594 write_vec_element_i32(s, tcg_res[pass], rd, pass, MO_32);
11595 }
11596 }
11597}
11598
11599static void handle_rev(DisasContext *s, int opcode, bool u,
11600 bool is_q, int size, int rn, int rd)
11601{
11602 int op = (opcode << 1) | u;
11603 int opsz = op + size;
11604 int grp_size = 3 - opsz;
11605 int dsize = is_q ? 128 : 64;
11606 int i;
11607
11608 if (opsz >= 3) {
11609 unallocated_encoding(s);
11610 return;
11611 }
11612
11613 if (!fp_access_check(s)) {
11614 return;
11615 }
11616
11617 if (size == 0) {
11618
11619 int groups = dsize / (8 << grp_size);
11620
11621 for (i = 0; i < groups; i++) {
11622 TCGv_i64 tcg_tmp = tcg_temp_new_i64();
11623
11624 read_vec_element(s, tcg_tmp, rn, i, grp_size);
11625 switch (grp_size) {
11626 case MO_16:
11627 tcg_gen_bswap16_i64(tcg_tmp, tcg_tmp, TCG_BSWAP_IZ);
11628 break;
11629 case MO_32:
11630 tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp, TCG_BSWAP_IZ);
11631 break;
11632 case MO_64:
11633 tcg_gen_bswap64_i64(tcg_tmp, tcg_tmp);
11634 break;
11635 default:
11636 g_assert_not_reached();
11637 }
11638 write_vec_element(s, tcg_tmp, rd, i, grp_size);
11639 }
11640 clear_vec_high(s, is_q, rd);
11641 } else {
11642 int revmask = (1 << grp_size) - 1;
11643 int esize = 8 << size;
11644 int elements = dsize / esize;
11645 TCGv_i64 tcg_rn = tcg_temp_new_i64();
11646 TCGv_i64 tcg_rd[2];
11647
11648 for (i = 0; i < 2; i++) {
11649 tcg_rd[i] = tcg_temp_new_i64();
11650 tcg_gen_movi_i64(tcg_rd[i], 0);
11651 }
11652
11653 for (i = 0; i < elements; i++) {
11654 int e_rev = (i & 0xf) ^ revmask;
11655 int w = (e_rev * esize) / 64;
11656 int o = (e_rev * esize) % 64;
11657
11658 read_vec_element(s, tcg_rn, rn, i, size);
11659 tcg_gen_deposit_i64(tcg_rd[w], tcg_rd[w], tcg_rn, o, esize);
11660 }
11661
11662 for (i = 0; i < 2; i++) {
11663 write_vec_element(s, tcg_rd[i], rd, i, MO_64);
11664 }
11665 clear_vec_high(s, true, rd);
11666 }
11667}
11668
11669static void handle_2misc_pairwise(DisasContext *s, int opcode, bool u,
11670 bool is_q, int size, int rn, int rd)
11671{
11672
11673
11674
11675
11676
11677 bool accum = (opcode == 0x6);
11678 int maxpass = is_q ? 2 : 1;
11679 int pass;
11680 TCGv_i64 tcg_res[2];
11681
11682 if (size == 2) {
11683
11684 MemOp memop = size + (u ? 0 : MO_SIGN);
11685
11686 for (pass = 0; pass < maxpass; pass++) {
11687 TCGv_i64 tcg_op1 = tcg_temp_new_i64();
11688 TCGv_i64 tcg_op2 = tcg_temp_new_i64();
11689
11690 tcg_res[pass] = tcg_temp_new_i64();
11691
11692 read_vec_element(s, tcg_op1, rn, pass * 2, memop);
11693 read_vec_element(s, tcg_op2, rn, pass * 2 + 1, memop);
11694 tcg_gen_add_i64(tcg_res[pass], tcg_op1, tcg_op2);
11695 if (accum) {
11696 read_vec_element(s, tcg_op1, rd, pass, MO_64);
11697 tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_op1);
11698 }
11699 }
11700 } else {
11701 for (pass = 0; pass < maxpass; pass++) {
11702 TCGv_i64 tcg_op = tcg_temp_new_i64();
11703 NeonGenOne64OpFn *genfn;
11704 static NeonGenOne64OpFn * const fns[2][2] = {
11705 { gen_helper_neon_addlp_s8, gen_helper_neon_addlp_u8 },
11706 { gen_helper_neon_addlp_s16, gen_helper_neon_addlp_u16 },
11707 };
11708
11709 genfn = fns[size][u];
11710
11711 tcg_res[pass] = tcg_temp_new_i64();
11712
11713 read_vec_element(s, tcg_op, rn, pass, MO_64);
11714 genfn(tcg_res[pass], tcg_op);
11715
11716 if (accum) {
11717 read_vec_element(s, tcg_op, rd, pass, MO_64);
11718 if (size == 0) {
11719 gen_helper_neon_addl_u16(tcg_res[pass],
11720 tcg_res[pass], tcg_op);
11721 } else {
11722 gen_helper_neon_addl_u32(tcg_res[pass],
11723 tcg_res[pass], tcg_op);
11724 }
11725 }
11726 }
11727 }
11728 if (!is_q) {
11729 tcg_res[1] = tcg_constant_i64(0);
11730 }
11731 for (pass = 0; pass < 2; pass++) {
11732 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
11733 }
11734}
11735
11736static void handle_shll(DisasContext *s, bool is_q, int size, int rn, int rd)
11737{
11738
11739 int pass;
11740 int part = is_q ? 2 : 0;
11741 TCGv_i64 tcg_res[2];
11742
11743 for (pass = 0; pass < 2; pass++) {
11744 static NeonGenWidenFn * const widenfns[3] = {
11745 gen_helper_neon_widen_u8,
11746 gen_helper_neon_widen_u16,
11747 tcg_gen_extu_i32_i64,
11748 };
11749 NeonGenWidenFn *widenfn = widenfns[size];
11750 TCGv_i32 tcg_op = tcg_temp_new_i32();
11751
11752 read_vec_element_i32(s, tcg_op, rn, part + pass, MO_32);
11753 tcg_res[pass] = tcg_temp_new_i64();
11754 widenfn(tcg_res[pass], tcg_op);
11755 tcg_gen_shli_i64(tcg_res[pass], tcg_res[pass], 8 << size);
11756 }
11757
11758 for (pass = 0; pass < 2; pass++) {
11759 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
11760 }
11761}
11762
11763
11764
11765
11766
11767
11768
11769static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
11770{
11771 int size = extract32(insn, 22, 2);
11772 int opcode = extract32(insn, 12, 5);
11773 bool u = extract32(insn, 29, 1);
11774 bool is_q = extract32(insn, 30, 1);
11775 int rn = extract32(insn, 5, 5);
11776 int rd = extract32(insn, 0, 5);
11777 bool need_fpstatus = false;
11778 int rmode = -1;
11779 TCGv_i32 tcg_rmode;
11780 TCGv_ptr tcg_fpstatus;
11781
11782 switch (opcode) {
11783 case 0x0:
11784 case 0x1:
11785 handle_rev(s, opcode, u, is_q, size, rn, rd);
11786 return;
11787 case 0x5:
11788 if (u && size == 0) {
11789
11790 break;
11791 } else if (u && size == 1) {
11792
11793 break;
11794 } else if (!u && size == 0) {
11795
11796 break;
11797 }
11798 unallocated_encoding(s);
11799 return;
11800 case 0x12:
11801 case 0x14:
11802 if (size == 3) {
11803 unallocated_encoding(s);
11804 return;
11805 }
11806 if (!fp_access_check(s)) {
11807 return;
11808 }
11809
11810 handle_2misc_narrow(s, false, opcode, u, is_q, size, rn, rd);
11811 return;
11812 case 0x4:
11813 if (size == 3) {
11814 unallocated_encoding(s);
11815 return;
11816 }
11817 break;
11818 case 0x2:
11819 case 0x6:
11820 if (size == 3) {
11821 unallocated_encoding(s);
11822 return;
11823 }
11824 if (!fp_access_check(s)) {
11825 return;
11826 }
11827 handle_2misc_pairwise(s, opcode, u, is_q, size, rn, rd);
11828 return;
11829 case 0x13:
11830 if (u == 0 || size == 3) {
11831 unallocated_encoding(s);
11832 return;
11833 }
11834 if (!fp_access_check(s)) {
11835 return;
11836 }
11837 handle_shll(s, is_q, size, rn, rd);
11838 return;
11839 case 0xa:
11840 if (u == 1) {
11841 unallocated_encoding(s);
11842 return;
11843 }
11844
11845 case 0x8:
11846 case 0x9:
11847 case 0xb:
11848 if (size == 3 && !is_q) {
11849 unallocated_encoding(s);
11850 return;
11851 }
11852 break;
11853 case 0x3:
11854 if (size == 3 && !is_q) {
11855 unallocated_encoding(s);
11856 return;
11857 }
11858 if (!fp_access_check(s)) {
11859 return;
11860 }
11861 handle_2misc_satacc(s, false, u, is_q, size, rn, rd);
11862 return;
11863 case 0x7:
11864 if (size == 3 && !is_q) {
11865 unallocated_encoding(s);
11866 return;
11867 }
11868 break;
11869 case 0xc ... 0xf:
11870 case 0x16 ... 0x1f:
11871 {
11872
11873
11874
11875 int is_double = extract32(size, 0, 1);
11876 opcode |= (extract32(size, 1, 1) << 5) | (u << 6);
11877 size = is_double ? 3 : 2;
11878 switch (opcode) {
11879 case 0x2f:
11880 case 0x6f:
11881 if (size == 3 && !is_q) {
11882 unallocated_encoding(s);
11883 return;
11884 }
11885 break;
11886 case 0x1d:
11887 case 0x5d:
11888 {
11889 bool is_signed = (opcode == 0x1d) ? true : false;
11890 int elements = is_double ? 2 : is_q ? 4 : 2;
11891 if (is_double && !is_q) {
11892 unallocated_encoding(s);
11893 return;
11894 }
11895 if (!fp_access_check(s)) {
11896 return;
11897 }
11898 handle_simd_intfp_conv(s, rd, rn, elements, is_signed, 0, size);
11899 return;
11900 }
11901 case 0x2c:
11902 case 0x2d:
11903 case 0x2e:
11904 case 0x6c:
11905 case 0x6d:
11906 if (size == 3 && !is_q) {
11907 unallocated_encoding(s);
11908 return;
11909 }
11910 handle_2misc_fcmp_zero(s, opcode, false, u, is_q, size, rn, rd);
11911 return;
11912 case 0x7f:
11913 if (size == 3 && !is_q) {
11914 unallocated_encoding(s);
11915 return;
11916 }
11917 break;
11918 case 0x1a:
11919 case 0x1b:
11920 case 0x3a:
11921 case 0x3b:
11922 case 0x5a:
11923 case 0x5b:
11924 case 0x7a:
11925 case 0x7b:
11926 need_fpstatus = true;
11927 rmode = extract32(opcode, 5, 1) | (extract32(opcode, 0, 1) << 1);
11928 if (size == 3 && !is_q) {
11929 unallocated_encoding(s);
11930 return;
11931 }
11932 break;
11933 case 0x5c:
11934 case 0x1c:
11935 need_fpstatus = true;
11936 rmode = FPROUNDING_TIEAWAY;
11937 if (size == 3 && !is_q) {
11938 unallocated_encoding(s);
11939 return;
11940 }
11941 break;
11942 case 0x3c:
11943 if (size == 3) {
11944 unallocated_encoding(s);
11945 return;
11946 }
11947
11948 case 0x3d:
11949 case 0x7d:
11950 if (size == 3 && !is_q) {
11951 unallocated_encoding(s);
11952 return;
11953 }
11954 if (!fp_access_check(s)) {
11955 return;
11956 }
11957 handle_2misc_reciprocal(s, opcode, false, u, is_q, size, rn, rd);
11958 return;
11959 case 0x56:
11960 if (size == 2) {
11961 unallocated_encoding(s);
11962 return;
11963 }
11964
11965 case 0x16:
11966
11967
11968
11969 if (!fp_access_check(s)) {
11970 return;
11971 }
11972 handle_2misc_narrow(s, false, opcode, 0, is_q, size - 1, rn, rd);
11973 return;
11974 case 0x36:
11975 if (!dc_isar_feature(aa64_bf16, s) || size != 2) {
11976 unallocated_encoding(s);
11977 return;
11978 }
11979 if (!fp_access_check(s)) {
11980 return;
11981 }
11982 handle_2misc_narrow(s, false, opcode, 0, is_q, size - 1, rn, rd);
11983 return;
11984 case 0x17:
11985 if (!fp_access_check(s)) {
11986 return;
11987 }
11988 handle_2misc_widening(s, opcode, is_q, size, rn, rd);
11989 return;
11990 case 0x18:
11991 case 0x19:
11992 case 0x38:
11993 case 0x39:
11994 rmode = extract32(opcode, 5, 1) | (extract32(opcode, 0, 1) << 1);
11995
11996 case 0x59:
11997 case 0x79:
11998 need_fpstatus = true;
11999 if (size == 3 && !is_q) {
12000 unallocated_encoding(s);
12001 return;
12002 }
12003 break;
12004 case 0x58:
12005 rmode = FPROUNDING_TIEAWAY;
12006 need_fpstatus = true;
12007 if (size == 3 && !is_q) {
12008 unallocated_encoding(s);
12009 return;
12010 }
12011 break;
12012 case 0x7c:
12013 if (size == 3) {
12014 unallocated_encoding(s);
12015 return;
12016 }
12017 break;
12018 case 0x1e:
12019 case 0x1f:
12020 rmode = FPROUNDING_ZERO;
12021
12022 case 0x5e:
12023 case 0x5f:
12024 need_fpstatus = true;
12025 if ((size == 3 && !is_q) || !dc_isar_feature(aa64_frint, s)) {
12026 unallocated_encoding(s);
12027 return;
12028 }
12029 break;
12030 default:
12031 unallocated_encoding(s);
12032 return;
12033 }
12034 break;
12035 }
12036 default:
12037 unallocated_encoding(s);
12038 return;
12039 }
12040
12041 if (!fp_access_check(s)) {
12042 return;
12043 }
12044
12045 if (need_fpstatus || rmode >= 0) {
12046 tcg_fpstatus = fpstatus_ptr(FPST_FPCR);
12047 } else {
12048 tcg_fpstatus = NULL;
12049 }
12050 if (rmode >= 0) {
12051 tcg_rmode = gen_set_rmode(rmode, tcg_fpstatus);
12052 } else {
12053 tcg_rmode = NULL;
12054 }
12055
12056 switch (opcode) {
12057 case 0x5:
12058 if (u && size == 0) {
12059 gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_not, 0);
12060 return;
12061 }
12062 break;
12063 case 0x8:
12064 if (u) {
12065 gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cge0, size);
12066 } else {
12067 gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cgt0, size);
12068 }
12069 return;
12070 case 0x9:
12071 if (u) {
12072 gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_cle0, size);
12073 } else {
12074 gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_ceq0, size);
12075 }
12076 return;
12077 case 0xa:
12078 gen_gvec_fn2(s, is_q, rd, rn, gen_gvec_clt0, size);
12079 return;
12080 case 0xb:
12081 if (u) {
12082 gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_neg, size);
12083 } else {
12084 gen_gvec_fn2(s, is_q, rd, rn, tcg_gen_gvec_abs, size);
12085 }
12086 return;
12087 }
12088
12089 if (size == 3) {
12090
12091 int pass;
12092
12093
12094
12095
12096 tcg_debug_assert(is_q);
12097 for (pass = 0; pass < 2; pass++) {
12098 TCGv_i64 tcg_op = tcg_temp_new_i64();
12099 TCGv_i64 tcg_res = tcg_temp_new_i64();
12100
12101 read_vec_element(s, tcg_op, rn, pass, MO_64);
12102
12103 handle_2misc_64(s, opcode, u, tcg_res, tcg_op,
12104 tcg_rmode, tcg_fpstatus);
12105
12106 write_vec_element(s, tcg_res, rd, pass, MO_64);
12107 }
12108 } else {
12109 int pass;
12110
12111 for (pass = 0; pass < (is_q ? 4 : 2); pass++) {
12112 TCGv_i32 tcg_op = tcg_temp_new_i32();
12113 TCGv_i32 tcg_res = tcg_temp_new_i32();
12114
12115 read_vec_element_i32(s, tcg_op, rn, pass, MO_32);
12116
12117 if (size == 2) {
12118
12119 switch (opcode) {
12120 case 0x4:
12121 if (u) {
12122 tcg_gen_clzi_i32(tcg_res, tcg_op, 32);
12123 } else {
12124 tcg_gen_clrsb_i32(tcg_res, tcg_op);
12125 }
12126 break;
12127 case 0x7:
12128 if (u) {
12129 gen_helper_neon_qneg_s32(tcg_res, cpu_env, tcg_op);
12130 } else {
12131 gen_helper_neon_qabs_s32(tcg_res, cpu_env, tcg_op);
12132 }
12133 break;
12134 case 0x2f:
12135 gen_helper_vfp_abss(tcg_res, tcg_op);
12136 break;
12137 case 0x6f:
12138 gen_helper_vfp_negs(tcg_res, tcg_op);
12139 break;
12140 case 0x7f:
12141 gen_helper_vfp_sqrts(tcg_res, tcg_op, cpu_env);
12142 break;
12143 case 0x1a:
12144 case 0x1b:
12145 case 0x1c:
12146 case 0x3a:
12147 case 0x3b:
12148 gen_helper_vfp_tosls(tcg_res, tcg_op,
12149 tcg_constant_i32(0), tcg_fpstatus);
12150 break;
12151 case 0x5a:
12152 case 0x5b:
12153 case 0x5c:
12154 case 0x7a:
12155 case 0x7b:
12156 gen_helper_vfp_touls(tcg_res, tcg_op,
12157 tcg_constant_i32(0), tcg_fpstatus);
12158 break;
12159 case 0x18:
12160 case 0x19:
12161 case 0x38:
12162 case 0x39:
12163 case 0x58:
12164 case 0x79:
12165 gen_helper_rints(tcg_res, tcg_op, tcg_fpstatus);
12166 break;
12167 case 0x59:
12168 gen_helper_rints_exact(tcg_res, tcg_op, tcg_fpstatus);
12169 break;
12170 case 0x7c:
12171 gen_helper_rsqrte_u32(tcg_res, tcg_op);
12172 break;
12173 case 0x1e:
12174 case 0x5e:
12175 gen_helper_frint32_s(tcg_res, tcg_op, tcg_fpstatus);
12176 break;
12177 case 0x1f:
12178 case 0x5f:
12179 gen_helper_frint64_s(tcg_res, tcg_op, tcg_fpstatus);
12180 break;
12181 default:
12182 g_assert_not_reached();
12183 }
12184 } else {
12185
12186 switch (opcode) {
12187 case 0x5:
12188
12189
12190
12191 if (u) {
12192 gen_helper_neon_rbit_u8(tcg_res, tcg_op);
12193 } else {
12194 gen_helper_neon_cnt_u8(tcg_res, tcg_op);
12195 }
12196 break;
12197 case 0x7:
12198 {
12199 NeonGenOneOpEnvFn *genfn;
12200 static NeonGenOneOpEnvFn * const fns[2][2] = {
12201 { gen_helper_neon_qabs_s8, gen_helper_neon_qneg_s8 },
12202 { gen_helper_neon_qabs_s16, gen_helper_neon_qneg_s16 },
12203 };
12204 genfn = fns[size][u];
12205 genfn(tcg_res, cpu_env, tcg_op);
12206 break;
12207 }
12208 case 0x4:
12209 if (u) {
12210 if (size == 0) {
12211 gen_helper_neon_clz_u8(tcg_res, tcg_op);
12212 } else {
12213 gen_helper_neon_clz_u16(tcg_res, tcg_op);
12214 }
12215 } else {
12216 if (size == 0) {
12217 gen_helper_neon_cls_s8(tcg_res, tcg_op);
12218 } else {
12219 gen_helper_neon_cls_s16(tcg_res, tcg_op);
12220 }
12221 }
12222 break;
12223 default:
12224 g_assert_not_reached();
12225 }
12226 }
12227
12228 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
12229 }
12230 }
12231 clear_vec_high(s, is_q, rd);
12232
12233 if (tcg_rmode) {
12234 gen_restore_rmode(tcg_rmode, tcg_fpstatus);
12235 }
12236}
12237
12238
12239
12240
12241
12242
12243
12244
12245
12246
12247
12248
12249
12250
12251
12252static void disas_simd_two_reg_misc_fp16(DisasContext *s, uint32_t insn)
12253{
12254 int fpop, opcode, a, u;
12255 int rn, rd;
12256 bool is_q;
12257 bool is_scalar;
12258 bool only_in_vector = false;
12259
12260 int pass;
12261 TCGv_i32 tcg_rmode = NULL;
12262 TCGv_ptr tcg_fpstatus = NULL;
12263 bool need_fpst = true;
12264 int rmode = -1;
12265
12266 if (!dc_isar_feature(aa64_fp16, s)) {
12267 unallocated_encoding(s);
12268 return;
12269 }
12270
12271 rd = extract32(insn, 0, 5);
12272 rn = extract32(insn, 5, 5);
12273
12274 a = extract32(insn, 23, 1);
12275 u = extract32(insn, 29, 1);
12276 is_scalar = extract32(insn, 28, 1);
12277 is_q = extract32(insn, 30, 1);
12278
12279 opcode = extract32(insn, 12, 5);
12280 fpop = deposit32(opcode, 5, 1, a);
12281 fpop = deposit32(fpop, 6, 1, u);
12282
12283 switch (fpop) {
12284 case 0x1d:
12285 case 0x5d:
12286 {
12287 int elements;
12288
12289 if (is_scalar) {
12290 elements = 1;
12291 } else {
12292 elements = (is_q ? 8 : 4);
12293 }
12294
12295 if (!fp_access_check(s)) {
12296 return;
12297 }
12298 handle_simd_intfp_conv(s, rd, rn, elements, !u, 0, MO_16);
12299 return;
12300 }
12301 break;
12302 case 0x2c:
12303 case 0x2d:
12304 case 0x2e:
12305 case 0x6c:
12306 case 0x6d:
12307 handle_2misc_fcmp_zero(s, fpop, is_scalar, 0, is_q, MO_16, rn, rd);
12308 return;
12309 case 0x3d:
12310 case 0x3f:
12311 break;
12312 case 0x18:
12313 only_in_vector = true;
12314 rmode = FPROUNDING_TIEEVEN;
12315 break;
12316 case 0x19:
12317 only_in_vector = true;
12318 rmode = FPROUNDING_NEGINF;
12319 break;
12320 case 0x38:
12321 only_in_vector = true;
12322 rmode = FPROUNDING_POSINF;
12323 break;
12324 case 0x39:
12325 only_in_vector = true;
12326 rmode = FPROUNDING_ZERO;
12327 break;
12328 case 0x58:
12329 only_in_vector = true;
12330 rmode = FPROUNDING_TIEAWAY;
12331 break;
12332 case 0x59:
12333 case 0x79:
12334 only_in_vector = true;
12335
12336 break;
12337 case 0x1a:
12338 rmode = FPROUNDING_TIEEVEN;
12339 break;
12340 case 0x1b:
12341 rmode = FPROUNDING_NEGINF;
12342 break;
12343 case 0x1c:
12344 rmode = FPROUNDING_TIEAWAY;
12345 break;
12346 case 0x3a:
12347 rmode = FPROUNDING_POSINF;
12348 break;
12349 case 0x3b:
12350 rmode = FPROUNDING_ZERO;
12351 break;
12352 case 0x5a:
12353 rmode = FPROUNDING_TIEEVEN;
12354 break;
12355 case 0x5b:
12356 rmode = FPROUNDING_NEGINF;
12357 break;
12358 case 0x5c:
12359 rmode = FPROUNDING_TIEAWAY;
12360 break;
12361 case 0x7a:
12362 rmode = FPROUNDING_POSINF;
12363 break;
12364 case 0x7b:
12365 rmode = FPROUNDING_ZERO;
12366 break;
12367 case 0x2f:
12368 case 0x6f:
12369 need_fpst = false;
12370 break;
12371 case 0x7d:
12372 case 0x7f:
12373 break;
12374 default:
12375 unallocated_encoding(s);
12376 return;
12377 }
12378
12379
12380
12381 if (is_scalar) {
12382 if (!is_q) {
12383 unallocated_encoding(s);
12384 return;
12385 }
12386
12387 if (only_in_vector) {
12388 unallocated_encoding(s);
12389 return;
12390 }
12391 }
12392
12393 if (!fp_access_check(s)) {
12394 return;
12395 }
12396
12397 if (rmode >= 0 || need_fpst) {
12398 tcg_fpstatus = fpstatus_ptr(FPST_FPCR_F16);
12399 }
12400
12401 if (rmode >= 0) {
12402 tcg_rmode = gen_set_rmode(rmode, tcg_fpstatus);
12403 }
12404
12405 if (is_scalar) {
12406 TCGv_i32 tcg_op = read_fp_hreg(s, rn);
12407 TCGv_i32 tcg_res = tcg_temp_new_i32();
12408
12409 switch (fpop) {
12410 case 0x1a:
12411 case 0x1b:
12412 case 0x1c:
12413 case 0x3a:
12414 case 0x3b:
12415 gen_helper_advsimd_f16tosinth(tcg_res, tcg_op, tcg_fpstatus);
12416 break;
12417 case 0x3d:
12418 gen_helper_recpe_f16(tcg_res, tcg_op, tcg_fpstatus);
12419 break;
12420 case 0x3f:
12421 gen_helper_frecpx_f16(tcg_res, tcg_op, tcg_fpstatus);
12422 break;
12423 case 0x5a:
12424 case 0x5b:
12425 case 0x5c:
12426 case 0x7a:
12427 case 0x7b:
12428 gen_helper_advsimd_f16touinth(tcg_res, tcg_op, tcg_fpstatus);
12429 break;
12430 case 0x6f:
12431 tcg_gen_xori_i32(tcg_res, tcg_op, 0x8000);
12432 break;
12433 case 0x7d:
12434 gen_helper_rsqrte_f16(tcg_res, tcg_op, tcg_fpstatus);
12435 break;
12436 default:
12437 g_assert_not_reached();
12438 }
12439
12440
12441 tcg_gen_andi_i32(tcg_res, tcg_res, 0xffff);
12442 write_fp_sreg(s, rd, tcg_res);
12443 } else {
12444 for (pass = 0; pass < (is_q ? 8 : 4); pass++) {
12445 TCGv_i32 tcg_op = tcg_temp_new_i32();
12446 TCGv_i32 tcg_res = tcg_temp_new_i32();
12447
12448 read_vec_element_i32(s, tcg_op, rn, pass, MO_16);
12449
12450 switch (fpop) {
12451 case 0x1a:
12452 case 0x1b:
12453 case 0x1c:
12454 case 0x3a:
12455 case 0x3b:
12456 gen_helper_advsimd_f16tosinth(tcg_res, tcg_op, tcg_fpstatus);
12457 break;
12458 case 0x3d:
12459 gen_helper_recpe_f16(tcg_res, tcg_op, tcg_fpstatus);
12460 break;
12461 case 0x5a:
12462 case 0x5b:
12463 case 0x5c:
12464 case 0x7a:
12465 case 0x7b:
12466 gen_helper_advsimd_f16touinth(tcg_res, tcg_op, tcg_fpstatus);
12467 break;
12468 case 0x18:
12469 case 0x19:
12470 case 0x38:
12471 case 0x39:
12472 case 0x58:
12473 case 0x79:
12474 gen_helper_advsimd_rinth(tcg_res, tcg_op, tcg_fpstatus);
12475 break;
12476 case 0x59:
12477 gen_helper_advsimd_rinth_exact(tcg_res, tcg_op, tcg_fpstatus);
12478 break;
12479 case 0x2f:
12480 tcg_gen_andi_i32(tcg_res, tcg_op, 0x7fff);
12481 break;
12482 case 0x6f:
12483 tcg_gen_xori_i32(tcg_res, tcg_op, 0x8000);
12484 break;
12485 case 0x7d:
12486 gen_helper_rsqrte_f16(tcg_res, tcg_op, tcg_fpstatus);
12487 break;
12488 case 0x7f:
12489 gen_helper_sqrt_f16(tcg_res, tcg_op, tcg_fpstatus);
12490 break;
12491 default:
12492 g_assert_not_reached();
12493 }
12494
12495 write_vec_element_i32(s, tcg_res, rd, pass, MO_16);
12496 }
12497
12498 clear_vec_high(s, is_q, rd);
12499 }
12500
12501 if (tcg_rmode) {
12502 gen_restore_rmode(tcg_rmode, tcg_fpstatus);
12503 }
12504}
12505
12506
12507
12508
12509
12510
12511
12512
12513
12514
12515
12516
12517static void disas_simd_indexed(DisasContext *s, uint32_t insn)
12518{
12519
12520
12521
12522
12523
12524
12525
12526 bool is_scalar = extract32(insn, 28, 1);
12527 bool is_q = extract32(insn, 30, 1);
12528 bool u = extract32(insn, 29, 1);
12529 int size = extract32(insn, 22, 2);
12530 int l = extract32(insn, 21, 1);
12531 int m = extract32(insn, 20, 1);
12532
12533 int rm = extract32(insn, 16, 4);
12534 int opcode = extract32(insn, 12, 4);
12535 int h = extract32(insn, 11, 1);
12536 int rn = extract32(insn, 5, 5);
12537 int rd = extract32(insn, 0, 5);
12538 bool is_long = false;
12539 int is_fp = 0;
12540 bool is_fp16 = false;
12541 int index;
12542 TCGv_ptr fpst;
12543
12544 switch (16 * u + opcode) {
12545 case 0x08:
12546 case 0x10:
12547 case 0x14:
12548 if (is_scalar) {
12549 unallocated_encoding(s);
12550 return;
12551 }
12552 break;
12553 case 0x02:
12554 case 0x12:
12555 case 0x06:
12556 case 0x16:
12557 case 0x0a:
12558 case 0x1a:
12559 if (is_scalar) {
12560 unallocated_encoding(s);
12561 return;
12562 }
12563 is_long = true;
12564 break;
12565 case 0x03:
12566 case 0x07:
12567 case 0x0b:
12568 is_long = true;
12569 break;
12570 case 0x0c:
12571 case 0x0d:
12572 break;
12573 case 0x01:
12574 case 0x05:
12575 case 0x09:
12576 case 0x19:
12577 is_fp = 1;
12578 break;
12579 case 0x1d:
12580 case 0x1f:
12581 if (!dc_isar_feature(aa64_rdm, s)) {
12582 unallocated_encoding(s);
12583 return;
12584 }
12585 break;
12586 case 0x0e:
12587 case 0x1e:
12588 if (is_scalar || size != MO_32 || !dc_isar_feature(aa64_dp, s)) {
12589 unallocated_encoding(s);
12590 return;
12591 }
12592 break;
12593 case 0x0f:
12594 switch (size) {
12595 case 0:
12596 case 2:
12597 if (is_scalar || !dc_isar_feature(aa64_i8mm, s)) {
12598 unallocated_encoding(s);
12599 return;
12600 }
12601 size = MO_32;
12602 break;
12603 case 1:
12604 if (is_scalar || !dc_isar_feature(aa64_bf16, s)) {
12605 unallocated_encoding(s);
12606 return;
12607 }
12608 size = MO_32;
12609 break;
12610 case 3:
12611 if (is_scalar || !dc_isar_feature(aa64_bf16, s)) {
12612 unallocated_encoding(s);
12613 return;
12614 }
12615
12616 size = MO_16;
12617 break;
12618 default:
12619 unallocated_encoding(s);
12620 return;
12621 }
12622 break;
12623 case 0x11:
12624 case 0x13:
12625 case 0x15:
12626 case 0x17:
12627 if (is_scalar || !dc_isar_feature(aa64_fcma, s)) {
12628 unallocated_encoding(s);
12629 return;
12630 }
12631 is_fp = 2;
12632 break;
12633 case 0x00:
12634 case 0x04:
12635 case 0x18:
12636 case 0x1c:
12637 if (is_scalar || size != MO_32 || !dc_isar_feature(aa64_fhm, s)) {
12638 unallocated_encoding(s);
12639 return;
12640 }
12641 size = MO_16;
12642
12643 break;
12644 default:
12645 unallocated_encoding(s);
12646 return;
12647 }
12648
12649 switch (is_fp) {
12650 case 1:
12651
12652 switch (size) {
12653 case 0:
12654 size = MO_16;
12655 is_fp16 = true;
12656 break;
12657 case MO_32:
12658 case MO_64:
12659 break;
12660 default:
12661 unallocated_encoding(s);
12662 return;
12663 }
12664 break;
12665
12666 case 2:
12667
12668 size += 1;
12669 switch (size) {
12670 case MO_32:
12671 if (h && !is_q) {
12672 unallocated_encoding(s);
12673 return;
12674 }
12675 is_fp16 = true;
12676 break;
12677 case MO_64:
12678 break;
12679 default:
12680 unallocated_encoding(s);
12681 return;
12682 }
12683 break;
12684
12685 default:
12686 switch (size) {
12687 case MO_8:
12688 case MO_64:
12689 unallocated_encoding(s);
12690 return;
12691 }
12692 break;
12693 }
12694 if (is_fp16 && !dc_isar_feature(aa64_fp16, s)) {
12695 unallocated_encoding(s);
12696 return;
12697 }
12698
12699
12700 switch (size) {
12701 case MO_16:
12702 index = h << 2 | l << 1 | m;
12703 break;
12704 case MO_32:
12705 index = h << 1 | l;
12706 rm |= m << 4;
12707 break;
12708 case MO_64:
12709 if (l || !is_q) {
12710 unallocated_encoding(s);
12711 return;
12712 }
12713 index = h;
12714 rm |= m << 4;
12715 break;
12716 default:
12717 g_assert_not_reached();
12718 }
12719
12720 if (!fp_access_check(s)) {
12721 return;
12722 }
12723
12724 if (is_fp) {
12725 fpst = fpstatus_ptr(is_fp16 ? FPST_FPCR_F16 : FPST_FPCR);
12726 } else {
12727 fpst = NULL;
12728 }
12729
12730 switch (16 * u + opcode) {
12731 case 0x0e:
12732 case 0x1e:
12733 gen_gvec_op4_ool(s, is_q, rd, rn, rm, rd, index,
12734 u ? gen_helper_gvec_udot_idx_b
12735 : gen_helper_gvec_sdot_idx_b);
12736 return;
12737 case 0x0f:
12738 switch (extract32(insn, 22, 2)) {
12739 case 0:
12740 gen_gvec_op4_ool(s, is_q, rd, rn, rm, rd, index,
12741 gen_helper_gvec_sudot_idx_b);
12742 return;
12743 case 1:
12744 gen_gvec_op4_ool(s, is_q, rd, rn, rm, rd, index,
12745 gen_helper_gvec_bfdot_idx);
12746 return;
12747 case 2:
12748 gen_gvec_op4_ool(s, is_q, rd, rn, rm, rd, index,
12749 gen_helper_gvec_usdot_idx_b);
12750 return;
12751 case 3:
12752 gen_gvec_op4_fpst(s, 1, rd, rn, rm, rd, 0, (index << 1) | is_q,
12753 gen_helper_gvec_bfmlal_idx);
12754 return;
12755 }
12756 g_assert_not_reached();
12757 case 0x11:
12758 case 0x13:
12759 case 0x15:
12760 case 0x17:
12761 {
12762 int rot = extract32(insn, 13, 2);
12763 int data = (index << 2) | rot;
12764 tcg_gen_gvec_4_ptr(vec_full_reg_offset(s, rd),
12765 vec_full_reg_offset(s, rn),
12766 vec_full_reg_offset(s, rm),
12767 vec_full_reg_offset(s, rd), fpst,
12768 is_q ? 16 : 8, vec_full_reg_size(s), data,
12769 size == MO_64
12770 ? gen_helper_gvec_fcmlas_idx
12771 : gen_helper_gvec_fcmlah_idx);
12772 }
12773 return;
12774
12775 case 0x00:
12776 case 0x04:
12777 case 0x18:
12778 case 0x1c:
12779 {
12780 int is_s = extract32(opcode, 2, 1);
12781 int is_2 = u;
12782 int data = (index << 2) | (is_2 << 1) | is_s;
12783 tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd),
12784 vec_full_reg_offset(s, rn),
12785 vec_full_reg_offset(s, rm), cpu_env,
12786 is_q ? 16 : 8, vec_full_reg_size(s),
12787 data, gen_helper_gvec_fmlal_idx_a64);
12788 }
12789 return;
12790
12791 case 0x08:
12792 if (!is_long && !is_scalar) {
12793 static gen_helper_gvec_3 * const fns[3] = {
12794 gen_helper_gvec_mul_idx_h,
12795 gen_helper_gvec_mul_idx_s,
12796 gen_helper_gvec_mul_idx_d,
12797 };
12798 tcg_gen_gvec_3_ool(vec_full_reg_offset(s, rd),
12799 vec_full_reg_offset(s, rn),
12800 vec_full_reg_offset(s, rm),
12801 is_q ? 16 : 8, vec_full_reg_size(s),
12802 index, fns[size - 1]);
12803 return;
12804 }
12805 break;
12806
12807 case 0x10:
12808 if (!is_long && !is_scalar) {
12809 static gen_helper_gvec_4 * const fns[3] = {
12810 gen_helper_gvec_mla_idx_h,
12811 gen_helper_gvec_mla_idx_s,
12812 gen_helper_gvec_mla_idx_d,
12813 };
12814 tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd),
12815 vec_full_reg_offset(s, rn),
12816 vec_full_reg_offset(s, rm),
12817 vec_full_reg_offset(s, rd),
12818 is_q ? 16 : 8, vec_full_reg_size(s),
12819 index, fns[size - 1]);
12820 return;
12821 }
12822 break;
12823
12824 case 0x14:
12825 if (!is_long && !is_scalar) {
12826 static gen_helper_gvec_4 * const fns[3] = {
12827 gen_helper_gvec_mls_idx_h,
12828 gen_helper_gvec_mls_idx_s,
12829 gen_helper_gvec_mls_idx_d,
12830 };
12831 tcg_gen_gvec_4_ool(vec_full_reg_offset(s, rd),
12832 vec_full_reg_offset(s, rn),
12833 vec_full_reg_offset(s, rm),
12834 vec_full_reg_offset(s, rd),
12835 is_q ? 16 : 8, vec_full_reg_size(s),
12836 index, fns[size - 1]);
12837 return;
12838 }
12839 break;
12840 }
12841
12842 if (size == 3) {
12843 TCGv_i64 tcg_idx = tcg_temp_new_i64();
12844 int pass;
12845
12846 assert(is_fp && is_q && !is_long);
12847
12848 read_vec_element(s, tcg_idx, rm, index, MO_64);
12849
12850 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
12851 TCGv_i64 tcg_op = tcg_temp_new_i64();
12852 TCGv_i64 tcg_res = tcg_temp_new_i64();
12853
12854 read_vec_element(s, tcg_op, rn, pass, MO_64);
12855
12856 switch (16 * u + opcode) {
12857 case 0x05:
12858
12859 gen_helper_vfp_negd(tcg_op, tcg_op);
12860
12861 case 0x01:
12862 read_vec_element(s, tcg_res, rd, pass, MO_64);
12863 gen_helper_vfp_muladdd(tcg_res, tcg_op, tcg_idx, tcg_res, fpst);
12864 break;
12865 case 0x09:
12866 gen_helper_vfp_muld(tcg_res, tcg_op, tcg_idx, fpst);
12867 break;
12868 case 0x19:
12869 gen_helper_vfp_mulxd(tcg_res, tcg_op, tcg_idx, fpst);
12870 break;
12871 default:
12872 g_assert_not_reached();
12873 }
12874
12875 write_vec_element(s, tcg_res, rd, pass, MO_64);
12876 }
12877
12878 clear_vec_high(s, !is_scalar, rd);
12879 } else if (!is_long) {
12880
12881
12882
12883
12884 TCGv_i32 tcg_idx = tcg_temp_new_i32();
12885 int pass, maxpasses;
12886
12887 if (is_scalar) {
12888 maxpasses = 1;
12889 } else {
12890 maxpasses = is_q ? 4 : 2;
12891 }
12892
12893 read_vec_element_i32(s, tcg_idx, rm, index, size);
12894
12895 if (size == 1 && !is_scalar) {
12896
12897
12898
12899
12900 tcg_gen_deposit_i32(tcg_idx, tcg_idx, tcg_idx, 16, 16);
12901 }
12902
12903 for (pass = 0; pass < maxpasses; pass++) {
12904 TCGv_i32 tcg_op = tcg_temp_new_i32();
12905 TCGv_i32 tcg_res = tcg_temp_new_i32();
12906
12907 read_vec_element_i32(s, tcg_op, rn, pass, is_scalar ? size : MO_32);
12908
12909 switch (16 * u + opcode) {
12910 case 0x08:
12911 case 0x10:
12912 case 0x14:
12913 {
12914 static NeonGenTwoOpFn * const fns[2][2] = {
12915 { gen_helper_neon_add_u16, gen_helper_neon_sub_u16 },
12916 { tcg_gen_add_i32, tcg_gen_sub_i32 },
12917 };
12918 NeonGenTwoOpFn *genfn;
12919 bool is_sub = opcode == 0x4;
12920
12921 if (size == 1) {
12922 gen_helper_neon_mul_u16(tcg_res, tcg_op, tcg_idx);
12923 } else {
12924 tcg_gen_mul_i32(tcg_res, tcg_op, tcg_idx);
12925 }
12926 if (opcode == 0x8) {
12927 break;
12928 }
12929 read_vec_element_i32(s, tcg_op, rd, pass, MO_32);
12930 genfn = fns[size - 1][is_sub];
12931 genfn(tcg_res, tcg_op, tcg_res);
12932 break;
12933 }
12934 case 0x05:
12935 case 0x01:
12936 read_vec_element_i32(s, tcg_res, rd, pass,
12937 is_scalar ? size : MO_32);
12938 switch (size) {
12939 case 1:
12940 if (opcode == 0x5) {
12941
12942
12943 tcg_gen_xori_i32(tcg_op, tcg_op, 0x80008000);
12944 }
12945 if (is_scalar) {
12946 gen_helper_advsimd_muladdh(tcg_res, tcg_op, tcg_idx,
12947 tcg_res, fpst);
12948 } else {
12949 gen_helper_advsimd_muladd2h(tcg_res, tcg_op, tcg_idx,
12950 tcg_res, fpst);
12951 }
12952 break;
12953 case 2:
12954 if (opcode == 0x5) {
12955
12956
12957 tcg_gen_xori_i32(tcg_op, tcg_op, 0x80000000);
12958 }
12959 gen_helper_vfp_muladds(tcg_res, tcg_op, tcg_idx,
12960 tcg_res, fpst);
12961 break;
12962 default:
12963 g_assert_not_reached();
12964 }
12965 break;
12966 case 0x09:
12967 switch (size) {
12968 case 1:
12969 if (is_scalar) {
12970 gen_helper_advsimd_mulh(tcg_res, tcg_op,
12971 tcg_idx, fpst);
12972 } else {
12973 gen_helper_advsimd_mul2h(tcg_res, tcg_op,
12974 tcg_idx, fpst);
12975 }
12976 break;
12977 case 2:
12978 gen_helper_vfp_muls(tcg_res, tcg_op, tcg_idx, fpst);
12979 break;
12980 default:
12981 g_assert_not_reached();
12982 }
12983 break;
12984 case 0x19:
12985 switch (size) {
12986 case 1:
12987 if (is_scalar) {
12988 gen_helper_advsimd_mulxh(tcg_res, tcg_op,
12989 tcg_idx, fpst);
12990 } else {
12991 gen_helper_advsimd_mulx2h(tcg_res, tcg_op,
12992 tcg_idx, fpst);
12993 }
12994 break;
12995 case 2:
12996 gen_helper_vfp_mulxs(tcg_res, tcg_op, tcg_idx, fpst);
12997 break;
12998 default:
12999 g_assert_not_reached();
13000 }
13001 break;
13002 case 0x0c:
13003 if (size == 1) {
13004 gen_helper_neon_qdmulh_s16(tcg_res, cpu_env,
13005 tcg_op, tcg_idx);
13006 } else {
13007 gen_helper_neon_qdmulh_s32(tcg_res, cpu_env,
13008 tcg_op, tcg_idx);
13009 }
13010 break;
13011 case 0x0d:
13012 if (size == 1) {
13013 gen_helper_neon_qrdmulh_s16(tcg_res, cpu_env,
13014 tcg_op, tcg_idx);
13015 } else {
13016 gen_helper_neon_qrdmulh_s32(tcg_res, cpu_env,
13017 tcg_op, tcg_idx);
13018 }
13019 break;
13020 case 0x1d:
13021 read_vec_element_i32(s, tcg_res, rd, pass,
13022 is_scalar ? size : MO_32);
13023 if (size == 1) {
13024 gen_helper_neon_qrdmlah_s16(tcg_res, cpu_env,
13025 tcg_op, tcg_idx, tcg_res);
13026 } else {
13027 gen_helper_neon_qrdmlah_s32(tcg_res, cpu_env,
13028 tcg_op, tcg_idx, tcg_res);
13029 }
13030 break;
13031 case 0x1f:
13032 read_vec_element_i32(s, tcg_res, rd, pass,
13033 is_scalar ? size : MO_32);
13034 if (size == 1) {
13035 gen_helper_neon_qrdmlsh_s16(tcg_res, cpu_env,
13036 tcg_op, tcg_idx, tcg_res);
13037 } else {
13038 gen_helper_neon_qrdmlsh_s32(tcg_res, cpu_env,
13039 tcg_op, tcg_idx, tcg_res);
13040 }
13041 break;
13042 default:
13043 g_assert_not_reached();
13044 }
13045
13046 if (is_scalar) {
13047 write_fp_sreg(s, rd, tcg_res);
13048 } else {
13049 write_vec_element_i32(s, tcg_res, rd, pass, MO_32);
13050 }
13051 }
13052
13053 clear_vec_high(s, is_q, rd);
13054 } else {
13055
13056 TCGv_i64 tcg_res[2];
13057 int pass;
13058 bool satop = extract32(opcode, 0, 1);
13059 MemOp memop = MO_32;
13060
13061 if (satop || !u) {
13062 memop |= MO_SIGN;
13063 }
13064
13065 if (size == 2) {
13066 TCGv_i64 tcg_idx = tcg_temp_new_i64();
13067
13068 read_vec_element(s, tcg_idx, rm, index, memop);
13069
13070 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
13071 TCGv_i64 tcg_op = tcg_temp_new_i64();
13072 TCGv_i64 tcg_passres;
13073 int passelt;
13074
13075 if (is_scalar) {
13076 passelt = 0;
13077 } else {
13078 passelt = pass + (is_q * 2);
13079 }
13080
13081 read_vec_element(s, tcg_op, rn, passelt, memop);
13082
13083 tcg_res[pass] = tcg_temp_new_i64();
13084
13085 if (opcode == 0xa || opcode == 0xb) {
13086
13087 tcg_passres = tcg_res[pass];
13088 } else {
13089 tcg_passres = tcg_temp_new_i64();
13090 }
13091
13092 tcg_gen_mul_i64(tcg_passres, tcg_op, tcg_idx);
13093
13094 if (satop) {
13095
13096 gen_helper_neon_addl_saturate_s64(tcg_passres, cpu_env,
13097 tcg_passres, tcg_passres);
13098 }
13099
13100 if (opcode == 0xa || opcode == 0xb) {
13101 continue;
13102 }
13103
13104
13105 read_vec_element(s, tcg_res[pass], rd, pass, MO_64);
13106
13107 switch (opcode) {
13108 case 0x2:
13109 tcg_gen_add_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
13110 break;
13111 case 0x6:
13112 tcg_gen_sub_i64(tcg_res[pass], tcg_res[pass], tcg_passres);
13113 break;
13114 case 0x7:
13115 tcg_gen_neg_i64(tcg_passres, tcg_passres);
13116
13117 case 0x3:
13118 gen_helper_neon_addl_saturate_s64(tcg_res[pass], cpu_env,
13119 tcg_res[pass],
13120 tcg_passres);
13121 break;
13122 default:
13123 g_assert_not_reached();
13124 }
13125 }
13126
13127 clear_vec_high(s, !is_scalar, rd);
13128 } else {
13129 TCGv_i32 tcg_idx = tcg_temp_new_i32();
13130
13131 assert(size == 1);
13132 read_vec_element_i32(s, tcg_idx, rm, index, size);
13133
13134 if (!is_scalar) {
13135
13136
13137
13138
13139 tcg_gen_deposit_i32(tcg_idx, tcg_idx, tcg_idx, 16, 16);
13140 }
13141
13142 for (pass = 0; pass < (is_scalar ? 1 : 2); pass++) {
13143 TCGv_i32 tcg_op = tcg_temp_new_i32();
13144 TCGv_i64 tcg_passres;
13145
13146 if (is_scalar) {
13147 read_vec_element_i32(s, tcg_op, rn, pass, size);
13148 } else {
13149 read_vec_element_i32(s, tcg_op, rn,
13150 pass + (is_q * 2), MO_32);
13151 }
13152
13153 tcg_res[pass] = tcg_temp_new_i64();
13154
13155 if (opcode == 0xa || opcode == 0xb) {
13156
13157 tcg_passres = tcg_res[pass];
13158 } else {
13159 tcg_passres = tcg_temp_new_i64();
13160 }
13161
13162 if (memop & MO_SIGN) {
13163 gen_helper_neon_mull_s16(tcg_passres, tcg_op, tcg_idx);
13164 } else {
13165 gen_helper_neon_mull_u16(tcg_passres, tcg_op, tcg_idx);
13166 }
13167 if (satop) {
13168 gen_helper_neon_addl_saturate_s32(tcg_passres, cpu_env,
13169 tcg_passres, tcg_passres);
13170 }
13171
13172 if (opcode == 0xa || opcode == 0xb) {
13173 continue;
13174 }
13175
13176
13177 read_vec_element(s, tcg_res[pass], rd, pass, MO_64);
13178
13179 switch (opcode) {
13180 case 0x2:
13181 gen_helper_neon_addl_u32(tcg_res[pass], tcg_res[pass],
13182 tcg_passres);
13183 break;
13184 case 0x6:
13185 gen_helper_neon_subl_u32(tcg_res[pass], tcg_res[pass],
13186 tcg_passres);
13187 break;
13188 case 0x7:
13189 gen_helper_neon_negl_u32(tcg_passres, tcg_passres);
13190
13191 case 0x3:
13192 gen_helper_neon_addl_saturate_s32(tcg_res[pass], cpu_env,
13193 tcg_res[pass],
13194 tcg_passres);
13195 break;
13196 default:
13197 g_assert_not_reached();
13198 }
13199 }
13200
13201 if (is_scalar) {
13202 tcg_gen_ext32u_i64(tcg_res[0], tcg_res[0]);
13203 }
13204 }
13205
13206 if (is_scalar) {
13207 tcg_res[1] = tcg_constant_i64(0);
13208 }
13209
13210 for (pass = 0; pass < 2; pass++) {
13211 write_vec_element(s, tcg_res[pass], rd, pass, MO_64);
13212 }
13213 }
13214}
13215
13216
13217
13218
13219
13220
13221
13222static void disas_crypto_aes(DisasContext *s, uint32_t insn)
13223{
13224 int size = extract32(insn, 22, 2);
13225 int opcode = extract32(insn, 12, 5);
13226 int rn = extract32(insn, 5, 5);
13227 int rd = extract32(insn, 0, 5);
13228 gen_helper_gvec_2 *genfn2 = NULL;
13229 gen_helper_gvec_3 *genfn3 = NULL;
13230
13231 if (!dc_isar_feature(aa64_aes, s) || size != 0) {
13232 unallocated_encoding(s);
13233 return;
13234 }
13235
13236 switch (opcode) {
13237 case 0x4:
13238 genfn3 = gen_helper_crypto_aese;
13239 break;
13240 case 0x6:
13241 genfn2 = gen_helper_crypto_aesmc;
13242 break;
13243 case 0x5:
13244 genfn3 = gen_helper_crypto_aesd;
13245 break;
13246 case 0x7:
13247 genfn2 = gen_helper_crypto_aesimc;
13248 break;
13249 default:
13250 unallocated_encoding(s);
13251 return;
13252 }
13253
13254 if (!fp_access_check(s)) {
13255 return;
13256 }
13257 if (genfn2) {
13258 gen_gvec_op2_ool(s, true, rd, rn, 0, genfn2);
13259 } else {
13260 gen_gvec_op3_ool(s, true, rd, rd, rn, 0, genfn3);
13261 }
13262}
13263
13264
13265
13266
13267
13268
13269
13270static void disas_crypto_three_reg_sha(DisasContext *s, uint32_t insn)
13271{
13272 int size = extract32(insn, 22, 2);
13273 int opcode = extract32(insn, 12, 3);
13274 int rm = extract32(insn, 16, 5);
13275 int rn = extract32(insn, 5, 5);
13276 int rd = extract32(insn, 0, 5);
13277 gen_helper_gvec_3 *genfn;
13278 bool feature;
13279
13280 if (size != 0) {
13281 unallocated_encoding(s);
13282 return;
13283 }
13284
13285 switch (opcode) {
13286 case 0:
13287 genfn = gen_helper_crypto_sha1c;
13288 feature = dc_isar_feature(aa64_sha1, s);
13289 break;
13290 case 1:
13291 genfn = gen_helper_crypto_sha1p;
13292 feature = dc_isar_feature(aa64_sha1, s);
13293 break;
13294 case 2:
13295 genfn = gen_helper_crypto_sha1m;
13296 feature = dc_isar_feature(aa64_sha1, s);
13297 break;
13298 case 3:
13299 genfn = gen_helper_crypto_sha1su0;
13300 feature = dc_isar_feature(aa64_sha1, s);
13301 break;
13302 case 4:
13303 genfn = gen_helper_crypto_sha256h;
13304 feature = dc_isar_feature(aa64_sha256, s);
13305 break;
13306 case 5:
13307 genfn = gen_helper_crypto_sha256h2;
13308 feature = dc_isar_feature(aa64_sha256, s);
13309 break;
13310 case 6:
13311 genfn = gen_helper_crypto_sha256su1;
13312 feature = dc_isar_feature(aa64_sha256, s);
13313 break;
13314 default:
13315 unallocated_encoding(s);
13316 return;
13317 }
13318
13319 if (!feature) {
13320 unallocated_encoding(s);
13321 return;
13322 }
13323
13324 if (!fp_access_check(s)) {
13325 return;
13326 }
13327 gen_gvec_op3_ool(s, true, rd, rn, rm, 0, genfn);
13328}
13329
13330
13331
13332
13333
13334
13335
13336static void disas_crypto_two_reg_sha(DisasContext *s, uint32_t insn)
13337{
13338 int size = extract32(insn, 22, 2);
13339 int opcode = extract32(insn, 12, 5);
13340 int rn = extract32(insn, 5, 5);
13341 int rd = extract32(insn, 0, 5);
13342 gen_helper_gvec_2 *genfn;
13343 bool feature;
13344
13345 if (size != 0) {
13346 unallocated_encoding(s);
13347 return;
13348 }
13349
13350 switch (opcode) {
13351 case 0:
13352 feature = dc_isar_feature(aa64_sha1, s);
13353 genfn = gen_helper_crypto_sha1h;
13354 break;
13355 case 1:
13356 feature = dc_isar_feature(aa64_sha1, s);
13357 genfn = gen_helper_crypto_sha1su1;
13358 break;
13359 case 2:
13360 feature = dc_isar_feature(aa64_sha256, s);
13361 genfn = gen_helper_crypto_sha256su0;
13362 break;
13363 default:
13364 unallocated_encoding(s);
13365 return;
13366 }
13367
13368 if (!feature) {
13369 unallocated_encoding(s);
13370 return;
13371 }
13372
13373 if (!fp_access_check(s)) {
13374 return;
13375 }
13376 gen_gvec_op2_ool(s, true, rd, rn, 0, genfn);
13377}
13378
13379static void gen_rax1_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m)
13380{
13381 tcg_gen_rotli_i64(d, m, 1);
13382 tcg_gen_xor_i64(d, d, n);
13383}
13384
13385static void gen_rax1_vec(unsigned vece, TCGv_vec d, TCGv_vec n, TCGv_vec m)
13386{
13387 tcg_gen_rotli_vec(vece, d, m, 1);
13388 tcg_gen_xor_vec(vece, d, d, n);
13389}
13390
13391void gen_gvec_rax1(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs,
13392 uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz)
13393{
13394 static const TCGOpcode vecop_list[] = { INDEX_op_rotli_vec, 0 };
13395 static const GVecGen3 op = {
13396 .fni8 = gen_rax1_i64,
13397 .fniv = gen_rax1_vec,
13398 .opt_opc = vecop_list,
13399 .fno = gen_helper_crypto_rax1,
13400 .vece = MO_64,
13401 };
13402 tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &op);
13403}
13404
13405
13406
13407
13408
13409
13410
13411static void disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn)
13412{
13413 int opcode = extract32(insn, 10, 2);
13414 int o = extract32(insn, 14, 1);
13415 int rm = extract32(insn, 16, 5);
13416 int rn = extract32(insn, 5, 5);
13417 int rd = extract32(insn, 0, 5);
13418 bool feature;
13419 gen_helper_gvec_3 *oolfn = NULL;
13420 GVecGen3Fn *gvecfn = NULL;
13421
13422 if (o == 0) {
13423 switch (opcode) {
13424 case 0:
13425 feature = dc_isar_feature(aa64_sha512, s);
13426 oolfn = gen_helper_crypto_sha512h;
13427 break;
13428 case 1:
13429 feature = dc_isar_feature(aa64_sha512, s);
13430 oolfn = gen_helper_crypto_sha512h2;
13431 break;
13432 case 2:
13433 feature = dc_isar_feature(aa64_sha512, s);
13434 oolfn = gen_helper_crypto_sha512su1;
13435 break;
13436 case 3:
13437 feature = dc_isar_feature(aa64_sha3, s);
13438 gvecfn = gen_gvec_rax1;
13439 break;
13440 default:
13441 g_assert_not_reached();
13442 }
13443 } else {
13444 switch (opcode) {
13445 case 0:
13446 feature = dc_isar_feature(aa64_sm3, s);
13447 oolfn = gen_helper_crypto_sm3partw1;
13448 break;
13449 case 1:
13450 feature = dc_isar_feature(aa64_sm3, s);
13451 oolfn = gen_helper_crypto_sm3partw2;
13452 break;
13453 case 2:
13454 feature = dc_isar_feature(aa64_sm4, s);
13455 oolfn = gen_helper_crypto_sm4ekey;
13456 break;
13457 default:
13458 unallocated_encoding(s);
13459 return;
13460 }
13461 }
13462
13463 if (!feature) {
13464 unallocated_encoding(s);
13465 return;
13466 }
13467
13468 if (!fp_access_check(s)) {
13469 return;
13470 }
13471
13472 if (oolfn) {
13473 gen_gvec_op3_ool(s, true, rd, rn, rm, 0, oolfn);
13474 } else {
13475 gen_gvec_fn3(s, true, rd, rn, rm, gvecfn, MO_64);
13476 }
13477}
13478
13479
13480
13481
13482
13483
13484
13485static void disas_crypto_two_reg_sha512(DisasContext *s, uint32_t insn)
13486{
13487 int opcode = extract32(insn, 10, 2);
13488 int rn = extract32(insn, 5, 5);
13489 int rd = extract32(insn, 0, 5);
13490 bool feature;
13491
13492 switch (opcode) {
13493 case 0:
13494 feature = dc_isar_feature(aa64_sha512, s);
13495 break;
13496 case 1:
13497 feature = dc_isar_feature(aa64_sm4, s);
13498 break;
13499 default:
13500 unallocated_encoding(s);
13501 return;
13502 }
13503
13504 if (!feature) {
13505 unallocated_encoding(s);
13506 return;
13507 }
13508
13509 if (!fp_access_check(s)) {
13510 return;
13511 }
13512
13513 switch (opcode) {
13514 case 0:
13515 gen_gvec_op2_ool(s, true, rd, rn, 0, gen_helper_crypto_sha512su0);
13516 break;
13517 case 1:
13518 gen_gvec_op3_ool(s, true, rd, rd, rn, 0, gen_helper_crypto_sm4e);
13519 break;
13520 default:
13521 g_assert_not_reached();
13522 }
13523}
13524
13525
13526
13527
13528
13529
13530
13531static void disas_crypto_four_reg(DisasContext *s, uint32_t insn)
13532{
13533 int op0 = extract32(insn, 21, 2);
13534 int rm = extract32(insn, 16, 5);
13535 int ra = extract32(insn, 10, 5);
13536 int rn = extract32(insn, 5, 5);
13537 int rd = extract32(insn, 0, 5);
13538 bool feature;
13539
13540 switch (op0) {
13541 case 0:
13542 case 1:
13543 feature = dc_isar_feature(aa64_sha3, s);
13544 break;
13545 case 2:
13546 feature = dc_isar_feature(aa64_sm3, s);
13547 break;
13548 default:
13549 unallocated_encoding(s);
13550 return;
13551 }
13552
13553 if (!feature) {
13554 unallocated_encoding(s);
13555 return;
13556 }
13557
13558 if (!fp_access_check(s)) {
13559 return;
13560 }
13561
13562 if (op0 < 2) {
13563 TCGv_i64 tcg_op1, tcg_op2, tcg_op3, tcg_res[2];
13564 int pass;
13565
13566 tcg_op1 = tcg_temp_new_i64();
13567 tcg_op2 = tcg_temp_new_i64();
13568 tcg_op3 = tcg_temp_new_i64();
13569 tcg_res[0] = tcg_temp_new_i64();
13570 tcg_res[1] = tcg_temp_new_i64();
13571
13572 for (pass = 0; pass < 2; pass++) {
13573 read_vec_element(s, tcg_op1, rn, pass, MO_64);
13574 read_vec_element(s, tcg_op2, rm, pass, MO_64);
13575 read_vec_element(s, tcg_op3, ra, pass, MO_64);
13576
13577 if (op0 == 0) {
13578
13579 tcg_gen_xor_i64(tcg_res[pass], tcg_op2, tcg_op3);
13580 } else {
13581
13582 tcg_gen_andc_i64(tcg_res[pass], tcg_op2, tcg_op3);
13583 }
13584 tcg_gen_xor_i64(tcg_res[pass], tcg_res[pass], tcg_op1);
13585 }
13586 write_vec_element(s, tcg_res[0], rd, 0, MO_64);
13587 write_vec_element(s, tcg_res[1], rd, 1, MO_64);
13588 } else {
13589 TCGv_i32 tcg_op1, tcg_op2, tcg_op3, tcg_res, tcg_zero;
13590
13591 tcg_op1 = tcg_temp_new_i32();
13592 tcg_op2 = tcg_temp_new_i32();
13593 tcg_op3 = tcg_temp_new_i32();
13594 tcg_res = tcg_temp_new_i32();
13595 tcg_zero = tcg_constant_i32(0);
13596
13597 read_vec_element_i32(s, tcg_op1, rn, 3, MO_32);
13598 read_vec_element_i32(s, tcg_op2, rm, 3, MO_32);
13599 read_vec_element_i32(s, tcg_op3, ra, 3, MO_32);
13600
13601 tcg_gen_rotri_i32(tcg_res, tcg_op1, 20);
13602 tcg_gen_add_i32(tcg_res, tcg_res, tcg_op2);
13603 tcg_gen_add_i32(tcg_res, tcg_res, tcg_op3);
13604 tcg_gen_rotri_i32(tcg_res, tcg_res, 25);
13605
13606 write_vec_element_i32(s, tcg_zero, rd, 0, MO_32);
13607 write_vec_element_i32(s, tcg_zero, rd, 1, MO_32);
13608 write_vec_element_i32(s, tcg_zero, rd, 2, MO_32);
13609 write_vec_element_i32(s, tcg_res, rd, 3, MO_32);
13610 }
13611}
13612
13613
13614
13615
13616
13617
13618
13619static void disas_crypto_xar(DisasContext *s, uint32_t insn)
13620{
13621 int rm = extract32(insn, 16, 5);
13622 int imm6 = extract32(insn, 10, 6);
13623 int rn = extract32(insn, 5, 5);
13624 int rd = extract32(insn, 0, 5);
13625
13626 if (!dc_isar_feature(aa64_sha3, s)) {
13627 unallocated_encoding(s);
13628 return;
13629 }
13630
13631 if (!fp_access_check(s)) {
13632 return;
13633 }
13634
13635 gen_gvec_xar(MO_64, vec_full_reg_offset(s, rd),
13636 vec_full_reg_offset(s, rn),
13637 vec_full_reg_offset(s, rm), imm6, 16,
13638 vec_full_reg_size(s));
13639}
13640
13641
13642
13643
13644
13645
13646
13647static void disas_crypto_three_reg_imm2(DisasContext *s, uint32_t insn)
13648{
13649 static gen_helper_gvec_3 * const fns[4] = {
13650 gen_helper_crypto_sm3tt1a, gen_helper_crypto_sm3tt1b,
13651 gen_helper_crypto_sm3tt2a, gen_helper_crypto_sm3tt2b,
13652 };
13653 int opcode = extract32(insn, 10, 2);
13654 int imm2 = extract32(insn, 12, 2);
13655 int rm = extract32(insn, 16, 5);
13656 int rn = extract32(insn, 5, 5);
13657 int rd = extract32(insn, 0, 5);
13658
13659 if (!dc_isar_feature(aa64_sm3, s)) {
13660 unallocated_encoding(s);
13661 return;
13662 }
13663
13664 if (!fp_access_check(s)) {
13665 return;
13666 }
13667
13668 gen_gvec_op3_ool(s, true, rd, rn, rm, imm2, fns[opcode]);
13669}
13670
13671
13672
13673
13674
13675
13676static const AArch64DecodeTable data_proc_simd[] = {
13677
13678 { 0x0e200400, 0x9f200400, disas_simd_three_reg_same },
13679 { 0x0e008400, 0x9f208400, disas_simd_three_reg_same_extra },
13680 { 0x0e200000, 0x9f200c00, disas_simd_three_reg_diff },
13681 { 0x0e200800, 0x9f3e0c00, disas_simd_two_reg_misc },
13682 { 0x0e300800, 0x9f3e0c00, disas_simd_across_lanes },
13683 { 0x0e000400, 0x9fe08400, disas_simd_copy },
13684 { 0x0f000000, 0x9f000400, disas_simd_indexed },
13685
13686 { 0x0f000400, 0x9ff80400, disas_simd_mod_imm },
13687 { 0x0f000400, 0x9f800400, disas_simd_shift_imm },
13688 { 0x0e000000, 0xbf208c00, disas_simd_tb },
13689 { 0x0e000800, 0xbf208c00, disas_simd_zip_trn },
13690 { 0x2e000000, 0xbf208400, disas_simd_ext },
13691 { 0x5e200400, 0xdf200400, disas_simd_scalar_three_reg_same },
13692 { 0x5e008400, 0xdf208400, disas_simd_scalar_three_reg_same_extra },
13693 { 0x5e200000, 0xdf200c00, disas_simd_scalar_three_reg_diff },
13694 { 0x5e200800, 0xdf3e0c00, disas_simd_scalar_two_reg_misc },
13695 { 0x5e300800, 0xdf3e0c00, disas_simd_scalar_pairwise },
13696 { 0x5e000400, 0xdfe08400, disas_simd_scalar_copy },
13697 { 0x5f000000, 0xdf000400, disas_simd_indexed },
13698 { 0x5f000400, 0xdf800400, disas_simd_scalar_shift_imm },
13699 { 0x4e280800, 0xff3e0c00, disas_crypto_aes },
13700 { 0x5e000000, 0xff208c00, disas_crypto_three_reg_sha },
13701 { 0x5e280800, 0xff3e0c00, disas_crypto_two_reg_sha },
13702 { 0xce608000, 0xffe0b000, disas_crypto_three_reg_sha512 },
13703 { 0xcec08000, 0xfffff000, disas_crypto_two_reg_sha512 },
13704 { 0xce000000, 0xff808000, disas_crypto_four_reg },
13705 { 0xce800000, 0xffe00000, disas_crypto_xar },
13706 { 0xce408000, 0xffe0c000, disas_crypto_three_reg_imm2 },
13707 { 0x0e400400, 0x9f60c400, disas_simd_three_reg_same_fp16 },
13708 { 0x0e780800, 0x8f7e0c00, disas_simd_two_reg_misc_fp16 },
13709 { 0x5e400400, 0xdf60c400, disas_simd_scalar_three_reg_same_fp16 },
13710 { 0x00000000, 0x00000000, NULL }
13711};
13712
13713static void disas_data_proc_simd(DisasContext *s, uint32_t insn)
13714{
13715
13716
13717
13718
13719 AArch64DecodeFn *fn = lookup_disas_fn(&data_proc_simd[0], insn);
13720 if (fn) {
13721 fn(s, insn);
13722 } else {
13723 unallocated_encoding(s);
13724 }
13725}
13726
13727
13728static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
13729{
13730 if (extract32(insn, 28, 1) == 1 && extract32(insn, 30, 1) == 0) {
13731 disas_data_proc_fp(s, insn);
13732 } else {
13733
13734 disas_data_proc_simd(s, insn);
13735 }
13736}
13737
13738static bool trans_OK(DisasContext *s, arg_OK *a)
13739{
13740 return true;
13741}
13742
13743static bool trans_FAIL(DisasContext *s, arg_OK *a)
13744{
13745 s->is_nonstreaming = true;
13746 return true;
13747}
13748
13749
13750
13751
13752
13753
13754
13755
13756static bool is_guarded_page(CPUARMState *env, DisasContext *s)
13757{
13758 uint64_t addr = s->base.pc_first;
13759#ifdef CONFIG_USER_ONLY
13760 return page_get_flags(addr) & PAGE_BTI;
13761#else
13762 CPUTLBEntryFull *full;
13763 void *host;
13764 int mmu_idx = arm_to_core_mmu_idx(s->mmu_idx);
13765 int flags;
13766
13767
13768
13769
13770
13771
13772 flags = probe_access_full(env, addr, 0, MMU_INST_FETCH, mmu_idx,
13773 false, &host, &full, 0);
13774 assert(!(flags & TLB_INVALID_MASK));
13775
13776 return full->guarded;
13777#endif
13778}
13779
13780
13781
13782
13783
13784
13785
13786
13787
13788
13789
13790
13791
13792
13793
13794
13795
13796static bool btype_destination_ok(uint32_t insn, bool bt, int btype)
13797{
13798 if ((insn & 0xfffff01fu) == 0xd503201fu) {
13799
13800 switch (extract32(insn, 5, 7)) {
13801 case 0b011001:
13802 case 0b011011:
13803
13804
13805
13806
13807 return !bt || btype != 3;
13808 case 0b100000:
13809
13810 return false;
13811 case 0b100010:
13812
13813 return btype != 3;
13814 case 0b100100:
13815
13816 return btype != 2;
13817 case 0b100110:
13818
13819 return true;
13820 }
13821 } else {
13822 switch (insn & 0xffe0001fu) {
13823 case 0xd4200000u:
13824 case 0xd4400000u:
13825
13826 return true;
13827 }
13828 }
13829 return false;
13830}
13831
13832
13833static void disas_a64_legacy(DisasContext *s, uint32_t insn)
13834{
13835 switch (extract32(insn, 25, 4)) {
13836 case 0x5:
13837 case 0xd:
13838 disas_data_proc_reg(s, insn);
13839 break;
13840 case 0x7:
13841 case 0xf:
13842 disas_data_proc_simd_fp(s, insn);
13843 break;
13844 default:
13845 unallocated_encoding(s);
13846 break;
13847 }
13848}
13849
13850static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
13851 CPUState *cpu)
13852{
13853 DisasContext *dc = container_of(dcbase, DisasContext, base);
13854 CPUARMState *env = cpu->env_ptr;
13855 ARMCPU *arm_cpu = env_archcpu(env);
13856 CPUARMTBFlags tb_flags = arm_tbflags_from_tb(dc->base.tb);
13857 int bound, core_mmu_idx;
13858
13859 dc->isar = &arm_cpu->isar;
13860 dc->condjmp = 0;
13861 dc->pc_save = dc->base.pc_first;
13862 dc->aarch64 = true;
13863 dc->thumb = false;
13864 dc->sctlr_b = 0;
13865 dc->be_data = EX_TBFLAG_ANY(tb_flags, BE_DATA) ? MO_BE : MO_LE;
13866 dc->condexec_mask = 0;
13867 dc->condexec_cond = 0;
13868 core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX);
13869 dc->mmu_idx = core_to_aa64_mmu_idx(core_mmu_idx);
13870 dc->tbii = EX_TBFLAG_A64(tb_flags, TBII);
13871 dc->tbid = EX_TBFLAG_A64(tb_flags, TBID);
13872 dc->tcma = EX_TBFLAG_A64(tb_flags, TCMA);
13873 dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
13874#if !defined(CONFIG_USER_ONLY)
13875 dc->user = (dc->current_el == 0);
13876#endif
13877 dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
13878 dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
13879 dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
13880 dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE);
13881 dc->fgt_svc = EX_TBFLAG_ANY(tb_flags, FGT_SVC);
13882 dc->fgt_eret = EX_TBFLAG_A64(tb_flags, FGT_ERET);
13883 dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL);
13884 dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL);
13885 dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16;
13886 dc->svl = (EX_TBFLAG_A64(tb_flags, SVL) + 1) * 16;
13887 dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE);
13888 dc->bt = EX_TBFLAG_A64(tb_flags, BT);
13889 dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE);
13890 dc->unpriv = EX_TBFLAG_A64(tb_flags, UNPRIV);
13891 dc->ata = EX_TBFLAG_A64(tb_flags, ATA);
13892 dc->mte_active[0] = EX_TBFLAG_A64(tb_flags, MTE_ACTIVE);
13893 dc->mte_active[1] = EX_TBFLAG_A64(tb_flags, MTE0_ACTIVE);
13894 dc->pstate_sm = EX_TBFLAG_A64(tb_flags, PSTATE_SM);
13895 dc->pstate_za = EX_TBFLAG_A64(tb_flags, PSTATE_ZA);
13896 dc->sme_trap_nonstreaming = EX_TBFLAG_A64(tb_flags, SME_TRAP_NONSTREAMING);
13897 dc->naa = EX_TBFLAG_A64(tb_flags, NAA);
13898 dc->vec_len = 0;
13899 dc->vec_stride = 0;
13900 dc->cp_regs = arm_cpu->cp_regs;
13901 dc->features = env->features;
13902 dc->dcz_blocksize = arm_cpu->dcz_blocksize;
13903
13904#ifdef CONFIG_USER_ONLY
13905
13906 tcg_debug_assert(dc->tbid & 1);
13907#endif
13908
13909 dc->lse2 = dc_isar_feature(aa64_lse2, dc);
13910
13911
13912
13913
13914
13915
13916
13917
13918
13919
13920
13921
13922
13923
13924
13925
13926 dc->ss_active = EX_TBFLAG_ANY(tb_flags, SS_ACTIVE);
13927 dc->pstate_ss = EX_TBFLAG_ANY(tb_flags, PSTATE__SS);
13928 dc->is_ldex = false;
13929
13930
13931 bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
13932
13933
13934 if (dc->ss_active) {
13935 bound = 1;
13936 }
13937 dc->base.max_insns = MIN(dc->base.max_insns, bound);
13938}
13939
13940static void aarch64_tr_tb_start(DisasContextBase *db, CPUState *cpu)
13941{
13942}
13943
13944static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
13945{
13946 DisasContext *dc = container_of(dcbase, DisasContext, base);
13947 target_ulong pc_arg = dc->base.pc_next;
13948
13949 if (tb_cflags(dcbase->tb) & CF_PCREL) {
13950 pc_arg &= ~TARGET_PAGE_MASK;
13951 }
13952 tcg_gen_insn_start(pc_arg, 0, 0);
13953 dc->insn_start = tcg_last_op();
13954}
13955
13956static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
13957{
13958 DisasContext *s = container_of(dcbase, DisasContext, base);
13959 CPUARMState *env = cpu->env_ptr;
13960 uint64_t pc = s->base.pc_next;
13961 uint32_t insn;
13962
13963
13964 if (s->ss_active && !s->pstate_ss) {
13965
13966
13967
13968
13969
13970
13971
13972
13973
13974
13975 assert(s->base.num_insns == 1);
13976 gen_swstep_exception(s, 0, 0);
13977 s->base.is_jmp = DISAS_NORETURN;
13978 s->base.pc_next = pc + 4;
13979 return;
13980 }
13981
13982 if (pc & 3) {
13983
13984
13985
13986
13987
13988
13989 assert(s->base.num_insns == 1);
13990 gen_helper_exception_pc_alignment(cpu_env, tcg_constant_tl(pc));
13991 s->base.is_jmp = DISAS_NORETURN;
13992 s->base.pc_next = QEMU_ALIGN_UP(pc, 4);
13993 return;
13994 }
13995
13996 s->pc_curr = pc;
13997 insn = arm_ldl_code(env, &s->base, pc, s->sctlr_b);
13998 s->insn = insn;
13999 s->base.pc_next = pc + 4;
14000
14001 s->fp_access_checked = false;
14002 s->sve_access_checked = false;
14003
14004 if (s->pstate_il) {
14005
14006
14007
14008
14009 gen_exception_insn(s, 0, EXCP_UDEF, syn_illegalstate());
14010 return;
14011 }
14012
14013 if (dc_isar_feature(aa64_bti, s)) {
14014 if (s->base.num_insns == 1) {
14015
14016
14017
14018
14019
14020
14021
14022
14023
14024
14025
14026 s->guarded_page = is_guarded_page(env, s);
14027
14028
14029 tcg_debug_assert(s->btype >= 0);
14030
14031
14032
14033
14034
14035
14036
14037 if (s->btype != 0
14038 && s->guarded_page
14039 && !btype_destination_ok(insn, s->bt, s->btype)) {
14040 gen_exception_insn(s, 0, EXCP_UDEF, syn_btitrap(s->btype));
14041 return;
14042 }
14043 } else {
14044
14045 tcg_debug_assert(s->btype == 0);
14046 }
14047 }
14048
14049 s->is_nonstreaming = false;
14050 if (s->sme_trap_nonstreaming) {
14051 disas_sme_fa64(s, insn);
14052 }
14053
14054 if (!disas_a64(s, insn) &&
14055 !disas_sme(s, insn) &&
14056 !disas_sve(s, insn)) {
14057 disas_a64_legacy(s, insn);
14058 }
14059
14060
14061
14062
14063
14064 if (s->btype > 0 && s->base.is_jmp != DISAS_NORETURN) {
14065 reset_btype(s);
14066 }
14067}
14068
14069static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
14070{
14071 DisasContext *dc = container_of(dcbase, DisasContext, base);
14072
14073 if (unlikely(dc->ss_active)) {
14074
14075
14076
14077
14078
14079 switch (dc->base.is_jmp) {
14080 default:
14081 gen_a64_update_pc(dc, 4);
14082
14083 case DISAS_EXIT:
14084 case DISAS_JUMP:
14085 gen_step_complete_exception(dc);
14086 break;
14087 case DISAS_NORETURN:
14088 break;
14089 }
14090 } else {
14091 switch (dc->base.is_jmp) {
14092 case DISAS_NEXT:
14093 case DISAS_TOO_MANY:
14094 gen_goto_tb(dc, 1, 4);
14095 break;
14096 default:
14097 case DISAS_UPDATE_EXIT:
14098 gen_a64_update_pc(dc, 4);
14099
14100 case DISAS_EXIT:
14101 tcg_gen_exit_tb(NULL, 0);
14102 break;
14103 case DISAS_UPDATE_NOCHAIN:
14104 gen_a64_update_pc(dc, 4);
14105
14106 case DISAS_JUMP:
14107 tcg_gen_lookup_and_goto_ptr();
14108 break;
14109 case DISAS_NORETURN:
14110 case DISAS_SWI:
14111 break;
14112 case DISAS_WFE:
14113 gen_a64_update_pc(dc, 4);
14114 gen_helper_wfe(cpu_env);
14115 break;
14116 case DISAS_YIELD:
14117 gen_a64_update_pc(dc, 4);
14118 gen_helper_yield(cpu_env);
14119 break;
14120 case DISAS_WFI:
14121
14122
14123
14124
14125 gen_a64_update_pc(dc, 4);
14126 gen_helper_wfi(cpu_env, tcg_constant_i32(4));
14127
14128
14129
14130
14131 tcg_gen_exit_tb(NULL, 0);
14132 break;
14133 }
14134 }
14135}
14136
14137static void aarch64_tr_disas_log(const DisasContextBase *dcbase,
14138 CPUState *cpu, FILE *logfile)
14139{
14140 DisasContext *dc = container_of(dcbase, DisasContext, base);
14141
14142 fprintf(logfile, "IN: %s\n", lookup_symbol(dc->base.pc_first));
14143 target_disas(logfile, cpu, dc->base.pc_first, dc->base.tb->size);
14144}
14145
14146const TranslatorOps aarch64_translator_ops = {
14147 .init_disas_context = aarch64_tr_init_disas_context,
14148 .tb_start = aarch64_tr_tb_start,
14149 .insn_start = aarch64_tr_insn_start,
14150 .translate_insn = aarch64_tr_translate_insn,
14151 .tb_stop = aarch64_tr_tb_stop,
14152 .disas_log = aarch64_tr_disas_log,
14153};
14154