xref: /openbmc/qemu/target/arm/tcg/translate-m-nocp.c (revision f0984d4040c328d1c021ae6680479cbbe13c485b)
1*f0984d40SFabiano Rosas /*
2*f0984d40SFabiano Rosas  *  ARM translation: M-profile NOCP special-case instructions
3*f0984d40SFabiano Rosas  *
4*f0984d40SFabiano Rosas  *  Copyright (c) 2020 Linaro, Ltd.
5*f0984d40SFabiano Rosas  *
6*f0984d40SFabiano Rosas  * This library is free software; you can redistribute it and/or
7*f0984d40SFabiano Rosas  * modify it under the terms of the GNU Lesser General Public
8*f0984d40SFabiano Rosas  * License as published by the Free Software Foundation; either
9*f0984d40SFabiano Rosas  * version 2.1 of the License, or (at your option) any later version.
10*f0984d40SFabiano Rosas  *
11*f0984d40SFabiano Rosas  * This library is distributed in the hope that it will be useful,
12*f0984d40SFabiano Rosas  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*f0984d40SFabiano Rosas  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*f0984d40SFabiano Rosas  * Lesser General Public License for more details.
15*f0984d40SFabiano Rosas  *
16*f0984d40SFabiano Rosas  * You should have received a copy of the GNU Lesser General Public
17*f0984d40SFabiano Rosas  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*f0984d40SFabiano Rosas  */
19*f0984d40SFabiano Rosas 
20*f0984d40SFabiano Rosas #include "qemu/osdep.h"
21*f0984d40SFabiano Rosas #include "tcg/tcg-op.h"
22*f0984d40SFabiano Rosas #include "tcg/tcg-op-gvec.h"
23*f0984d40SFabiano Rosas #include "translate.h"
24*f0984d40SFabiano Rosas #include "translate-a32.h"
25*f0984d40SFabiano Rosas 
26*f0984d40SFabiano Rosas #include "decode-m-nocp.c.inc"
27*f0984d40SFabiano Rosas 
28*f0984d40SFabiano Rosas /*
29*f0984d40SFabiano Rosas  * Decode VLLDM and VLSTM are nonstandard because:
30*f0984d40SFabiano Rosas  *  * if there is no FPU then these insns must NOP in
31*f0984d40SFabiano Rosas  *    Secure state and UNDEF in Nonsecure state
32*f0984d40SFabiano Rosas  *  * if there is an FPU then these insns do not have
33*f0984d40SFabiano Rosas  *    the usual behaviour that vfp_access_check() provides of
34*f0984d40SFabiano Rosas  *    being controlled by CPACR/NSACR enable bits or the
35*f0984d40SFabiano Rosas  *    lazy-stacking logic.
36*f0984d40SFabiano Rosas  */
37*f0984d40SFabiano Rosas static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
38*f0984d40SFabiano Rosas {
39*f0984d40SFabiano Rosas     TCGv_i32 fptr;
40*f0984d40SFabiano Rosas 
41*f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_M) ||
42*f0984d40SFabiano Rosas         !arm_dc_feature(s, ARM_FEATURE_V8)) {
43*f0984d40SFabiano Rosas         return false;
44*f0984d40SFabiano Rosas     }
45*f0984d40SFabiano Rosas 
46*f0984d40SFabiano Rosas     if (a->op) {
47*f0984d40SFabiano Rosas         /*
48*f0984d40SFabiano Rosas          * T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not
49*f0984d40SFabiano Rosas          * to take the IMPDEF option to make memory accesses to the stack
50*f0984d40SFabiano Rosas          * slots that correspond to the D16-D31 registers (discarding
51*f0984d40SFabiano Rosas          * read data and writing UNKNOWN values), so for us the T2
52*f0984d40SFabiano Rosas          * encoding behaves identically to the T1 encoding.
53*f0984d40SFabiano Rosas          */
54*f0984d40SFabiano Rosas         if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
55*f0984d40SFabiano Rosas             return false;
56*f0984d40SFabiano Rosas         }
57*f0984d40SFabiano Rosas     } else {
58*f0984d40SFabiano Rosas         /*
59*f0984d40SFabiano Rosas          * T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs.
60*f0984d40SFabiano Rosas          * This is currently architecturally impossible, but we add the
61*f0984d40SFabiano Rosas          * check to stay in line with the pseudocode. Note that we must
62*f0984d40SFabiano Rosas          * emit code for the UNDEF so it takes precedence over the NOCP.
63*f0984d40SFabiano Rosas          */
64*f0984d40SFabiano Rosas         if (dc_isar_feature(aa32_simd_r32, s)) {
65*f0984d40SFabiano Rosas             unallocated_encoding(s);
66*f0984d40SFabiano Rosas             return true;
67*f0984d40SFabiano Rosas         }
68*f0984d40SFabiano Rosas     }
69*f0984d40SFabiano Rosas 
70*f0984d40SFabiano Rosas     /*
71*f0984d40SFabiano Rosas      * If not secure, UNDEF. We must emit code for this
72*f0984d40SFabiano Rosas      * rather than returning false so that this takes
73*f0984d40SFabiano Rosas      * precedence over the m-nocp.decode NOCP fallback.
74*f0984d40SFabiano Rosas      */
75*f0984d40SFabiano Rosas     if (!s->v8m_secure) {
76*f0984d40SFabiano Rosas         unallocated_encoding(s);
77*f0984d40SFabiano Rosas         return true;
78*f0984d40SFabiano Rosas     }
79*f0984d40SFabiano Rosas 
80*f0984d40SFabiano Rosas     s->eci_handled = true;
81*f0984d40SFabiano Rosas 
82*f0984d40SFabiano Rosas     /* If no fpu, NOP. */
83*f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_vfp, s)) {
84*f0984d40SFabiano Rosas         clear_eci_state(s);
85*f0984d40SFabiano Rosas         return true;
86*f0984d40SFabiano Rosas     }
87*f0984d40SFabiano Rosas 
88*f0984d40SFabiano Rosas     fptr = load_reg(s, a->rn);
89*f0984d40SFabiano Rosas     if (a->l) {
90*f0984d40SFabiano Rosas         gen_helper_v7m_vlldm(cpu_env, fptr);
91*f0984d40SFabiano Rosas     } else {
92*f0984d40SFabiano Rosas         gen_helper_v7m_vlstm(cpu_env, fptr);
93*f0984d40SFabiano Rosas     }
94*f0984d40SFabiano Rosas     tcg_temp_free_i32(fptr);
95*f0984d40SFabiano Rosas 
96*f0984d40SFabiano Rosas     clear_eci_state(s);
97*f0984d40SFabiano Rosas 
98*f0984d40SFabiano Rosas     /*
99*f0984d40SFabiano Rosas      * End the TB, because we have updated FP control bits,
100*f0984d40SFabiano Rosas      * and possibly VPR or LTPSIZE.
101*f0984d40SFabiano Rosas      */
102*f0984d40SFabiano Rosas     s->base.is_jmp = DISAS_UPDATE_EXIT;
103*f0984d40SFabiano Rosas     return true;
104*f0984d40SFabiano Rosas }
105*f0984d40SFabiano Rosas 
106*f0984d40SFabiano Rosas static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a)
107*f0984d40SFabiano Rosas {
108*f0984d40SFabiano Rosas     int btmreg, topreg;
109*f0984d40SFabiano Rosas     TCGv_i64 zero;
110*f0984d40SFabiano Rosas     TCGv_i32 aspen, sfpa;
111*f0984d40SFabiano Rosas 
112*f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_m_sec_state, s)) {
113*f0984d40SFabiano Rosas         /* Before v8.1M, fall through in decode to NOCP check */
114*f0984d40SFabiano Rosas         return false;
115*f0984d40SFabiano Rosas     }
116*f0984d40SFabiano Rosas 
117*f0984d40SFabiano Rosas     /* Explicitly UNDEF because this takes precedence over NOCP */
118*f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) {
119*f0984d40SFabiano Rosas         unallocated_encoding(s);
120*f0984d40SFabiano Rosas         return true;
121*f0984d40SFabiano Rosas     }
122*f0984d40SFabiano Rosas 
123*f0984d40SFabiano Rosas     s->eci_handled = true;
124*f0984d40SFabiano Rosas 
125*f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_vfp_simd, s)) {
126*f0984d40SFabiano Rosas         /* NOP if we have neither FP nor MVE */
127*f0984d40SFabiano Rosas         clear_eci_state(s);
128*f0984d40SFabiano Rosas         return true;
129*f0984d40SFabiano Rosas     }
130*f0984d40SFabiano Rosas 
131*f0984d40SFabiano Rosas     /*
132*f0984d40SFabiano Rosas      * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no
133*f0984d40SFabiano Rosas      * active floating point context so we must NOP (without doing
134*f0984d40SFabiano Rosas      * any lazy state preservation or the NOCP check).
135*f0984d40SFabiano Rosas      */
136*f0984d40SFabiano Rosas     aspen = load_cpu_field(v7m.fpccr[M_REG_S]);
137*f0984d40SFabiano Rosas     sfpa = load_cpu_field(v7m.control[M_REG_S]);
138*f0984d40SFabiano Rosas     tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
139*f0984d40SFabiano Rosas     tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
140*f0984d40SFabiano Rosas     tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK);
141*f0984d40SFabiano Rosas     tcg_gen_or_i32(sfpa, sfpa, aspen);
142*f0984d40SFabiano Rosas     arm_gen_condlabel(s);
143*f0984d40SFabiano Rosas     tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel.label);
144*f0984d40SFabiano Rosas 
145*f0984d40SFabiano Rosas     if (s->fp_excp_el != 0) {
146*f0984d40SFabiano Rosas         gen_exception_insn_el(s, 0, EXCP_NOCP,
147*f0984d40SFabiano Rosas                               syn_uncategorized(), s->fp_excp_el);
148*f0984d40SFabiano Rosas         return true;
149*f0984d40SFabiano Rosas     }
150*f0984d40SFabiano Rosas 
151*f0984d40SFabiano Rosas     topreg = a->vd + a->imm - 1;
152*f0984d40SFabiano Rosas     btmreg = a->vd;
153*f0984d40SFabiano Rosas 
154*f0984d40SFabiano Rosas     /* Convert to Sreg numbers if the insn specified in Dregs */
155*f0984d40SFabiano Rosas     if (a->size == 3) {
156*f0984d40SFabiano Rosas         topreg = topreg * 2 + 1;
157*f0984d40SFabiano Rosas         btmreg *= 2;
158*f0984d40SFabiano Rosas     }
159*f0984d40SFabiano Rosas 
160*f0984d40SFabiano Rosas     if (topreg > 63 || (topreg > 31 && !(topreg & 1))) {
161*f0984d40SFabiano Rosas         /* UNPREDICTABLE: we choose to undef */
162*f0984d40SFabiano Rosas         unallocated_encoding(s);
163*f0984d40SFabiano Rosas         return true;
164*f0984d40SFabiano Rosas     }
165*f0984d40SFabiano Rosas 
166*f0984d40SFabiano Rosas     /* Silently ignore requests to clear D16-D31 if they don't exist */
167*f0984d40SFabiano Rosas     if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) {
168*f0984d40SFabiano Rosas         topreg = 31;
169*f0984d40SFabiano Rosas     }
170*f0984d40SFabiano Rosas 
171*f0984d40SFabiano Rosas     if (!vfp_access_check(s)) {
172*f0984d40SFabiano Rosas         return true;
173*f0984d40SFabiano Rosas     }
174*f0984d40SFabiano Rosas 
175*f0984d40SFabiano Rosas     /* Zero the Sregs from btmreg to topreg inclusive. */
176*f0984d40SFabiano Rosas     zero = tcg_constant_i64(0);
177*f0984d40SFabiano Rosas     if (btmreg & 1) {
178*f0984d40SFabiano Rosas         write_neon_element64(zero, btmreg >> 1, 1, MO_32);
179*f0984d40SFabiano Rosas         btmreg++;
180*f0984d40SFabiano Rosas     }
181*f0984d40SFabiano Rosas     for (; btmreg + 1 <= topreg; btmreg += 2) {
182*f0984d40SFabiano Rosas         write_neon_element64(zero, btmreg >> 1, 0, MO_64);
183*f0984d40SFabiano Rosas     }
184*f0984d40SFabiano Rosas     if (btmreg == topreg) {
185*f0984d40SFabiano Rosas         write_neon_element64(zero, btmreg >> 1, 0, MO_32);
186*f0984d40SFabiano Rosas         btmreg++;
187*f0984d40SFabiano Rosas     }
188*f0984d40SFabiano Rosas     assert(btmreg == topreg + 1);
189*f0984d40SFabiano Rosas     if (dc_isar_feature(aa32_mve, s)) {
190*f0984d40SFabiano Rosas         store_cpu_field(tcg_constant_i32(0), v7m.vpr);
191*f0984d40SFabiano Rosas     }
192*f0984d40SFabiano Rosas 
193*f0984d40SFabiano Rosas     clear_eci_state(s);
194*f0984d40SFabiano Rosas     return true;
195*f0984d40SFabiano Rosas }
196*f0984d40SFabiano Rosas 
197*f0984d40SFabiano Rosas /*
198*f0984d40SFabiano Rosas  * M-profile provides two different sets of instructions that can
199*f0984d40SFabiano Rosas  * access floating point system registers: VMSR/VMRS (which move
200*f0984d40SFabiano Rosas  * to/from a general purpose register) and VLDR/VSTR sysreg (which
201*f0984d40SFabiano Rosas  * move directly to/from memory). In some cases there are also side
202*f0984d40SFabiano Rosas  * effects which must happen after any write to memory (which could
203*f0984d40SFabiano Rosas  * cause an exception). So we implement the common logic for the
204*f0984d40SFabiano Rosas  * sysreg access in gen_M_fp_sysreg_write() and gen_M_fp_sysreg_read(),
205*f0984d40SFabiano Rosas  * which take pointers to callback functions which will perform the
206*f0984d40SFabiano Rosas  * actual "read/write general purpose register" and "read/write
207*f0984d40SFabiano Rosas  * memory" operations.
208*f0984d40SFabiano Rosas  */
209*f0984d40SFabiano Rosas 
210*f0984d40SFabiano Rosas /*
211*f0984d40SFabiano Rosas  * Emit code to store the sysreg to its final destination; frees the
212*f0984d40SFabiano Rosas  * TCG temp 'value' it is passed. do_access is true to do the store,
213*f0984d40SFabiano Rosas  * and false to skip it and only perform side-effects like base
214*f0984d40SFabiano Rosas  * register writeback.
215*f0984d40SFabiano Rosas  */
216*f0984d40SFabiano Rosas typedef void fp_sysreg_storefn(DisasContext *s, void *opaque, TCGv_i32 value,
217*f0984d40SFabiano Rosas                                bool do_access);
218*f0984d40SFabiano Rosas /*
219*f0984d40SFabiano Rosas  * Emit code to load the value to be copied to the sysreg; returns
220*f0984d40SFabiano Rosas  * a new TCG temporary. do_access is true to do the store,
221*f0984d40SFabiano Rosas  * and false to skip it and only perform side-effects like base
222*f0984d40SFabiano Rosas  * register writeback.
223*f0984d40SFabiano Rosas  */
224*f0984d40SFabiano Rosas typedef TCGv_i32 fp_sysreg_loadfn(DisasContext *s, void *opaque,
225*f0984d40SFabiano Rosas                                   bool do_access);
226*f0984d40SFabiano Rosas 
227*f0984d40SFabiano Rosas /* Common decode/access checks for fp sysreg read/write */
228*f0984d40SFabiano Rosas typedef enum FPSysRegCheckResult {
229*f0984d40SFabiano Rosas     FPSysRegCheckFailed, /* caller should return false */
230*f0984d40SFabiano Rosas     FPSysRegCheckDone, /* caller should return true */
231*f0984d40SFabiano Rosas     FPSysRegCheckContinue, /* caller should continue generating code */
232*f0984d40SFabiano Rosas } FPSysRegCheckResult;
233*f0984d40SFabiano Rosas 
234*f0984d40SFabiano Rosas static FPSysRegCheckResult fp_sysreg_checks(DisasContext *s, int regno)
235*f0984d40SFabiano Rosas {
236*f0984d40SFabiano Rosas     if (!dc_isar_feature(aa32_fpsp_v2, s) && !dc_isar_feature(aa32_mve, s)) {
237*f0984d40SFabiano Rosas         return FPSysRegCheckFailed;
238*f0984d40SFabiano Rosas     }
239*f0984d40SFabiano Rosas 
240*f0984d40SFabiano Rosas     switch (regno) {
241*f0984d40SFabiano Rosas     case ARM_VFP_FPSCR:
242*f0984d40SFabiano Rosas     case QEMU_VFP_FPSCR_NZCV:
243*f0984d40SFabiano Rosas         break;
244*f0984d40SFabiano Rosas     case ARM_VFP_FPSCR_NZCVQC:
245*f0984d40SFabiano Rosas         if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
246*f0984d40SFabiano Rosas             return FPSysRegCheckFailed;
247*f0984d40SFabiano Rosas         }
248*f0984d40SFabiano Rosas         break;
249*f0984d40SFabiano Rosas     case ARM_VFP_FPCXT_S:
250*f0984d40SFabiano Rosas     case ARM_VFP_FPCXT_NS:
251*f0984d40SFabiano Rosas         if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
252*f0984d40SFabiano Rosas             return FPSysRegCheckFailed;
253*f0984d40SFabiano Rosas         }
254*f0984d40SFabiano Rosas         if (!s->v8m_secure) {
255*f0984d40SFabiano Rosas             return FPSysRegCheckFailed;
256*f0984d40SFabiano Rosas         }
257*f0984d40SFabiano Rosas         break;
258*f0984d40SFabiano Rosas     case ARM_VFP_VPR:
259*f0984d40SFabiano Rosas     case ARM_VFP_P0:
260*f0984d40SFabiano Rosas         if (!dc_isar_feature(aa32_mve, s)) {
261*f0984d40SFabiano Rosas             return FPSysRegCheckFailed;
262*f0984d40SFabiano Rosas         }
263*f0984d40SFabiano Rosas         break;
264*f0984d40SFabiano Rosas     default:
265*f0984d40SFabiano Rosas         return FPSysRegCheckFailed;
266*f0984d40SFabiano Rosas     }
267*f0984d40SFabiano Rosas 
268*f0984d40SFabiano Rosas     /*
269*f0984d40SFabiano Rosas      * FPCXT_NS is a special case: it has specific handling for
270*f0984d40SFabiano Rosas      * "current FP state is inactive", and must do the PreserveFPState()
271*f0984d40SFabiano Rosas      * but not the usual full set of actions done by ExecuteFPCheck().
272*f0984d40SFabiano Rosas      * So we don't call vfp_access_check() and the callers must handle this.
273*f0984d40SFabiano Rosas      */
274*f0984d40SFabiano Rosas     if (regno != ARM_VFP_FPCXT_NS && !vfp_access_check(s)) {
275*f0984d40SFabiano Rosas         return FPSysRegCheckDone;
276*f0984d40SFabiano Rosas     }
277*f0984d40SFabiano Rosas     return FPSysRegCheckContinue;
278*f0984d40SFabiano Rosas }
279*f0984d40SFabiano Rosas 
280*f0984d40SFabiano Rosas static void gen_branch_fpInactive(DisasContext *s, TCGCond cond,
281*f0984d40SFabiano Rosas                                   TCGLabel *label)
282*f0984d40SFabiano Rosas {
283*f0984d40SFabiano Rosas     /*
284*f0984d40SFabiano Rosas      * FPCXT_NS is a special case: it has specific handling for
285*f0984d40SFabiano Rosas      * "current FP state is inactive", and must do the PreserveFPState()
286*f0984d40SFabiano Rosas      * but not the usual full set of actions done by ExecuteFPCheck().
287*f0984d40SFabiano Rosas      * We don't have a TB flag that matches the fpInactive check, so we
288*f0984d40SFabiano Rosas      * do it at runtime as we don't expect FPCXT_NS accesses to be frequent.
289*f0984d40SFabiano Rosas      *
290*f0984d40SFabiano Rosas      * Emit code that checks fpInactive and does a conditional
291*f0984d40SFabiano Rosas      * branch to label based on it:
292*f0984d40SFabiano Rosas      *  if cond is TCG_COND_NE then branch if fpInactive != 0 (ie if inactive)
293*f0984d40SFabiano Rosas      *  if cond is TCG_COND_EQ then branch if fpInactive == 0 (ie if active)
294*f0984d40SFabiano Rosas      */
295*f0984d40SFabiano Rosas     assert(cond == TCG_COND_EQ || cond == TCG_COND_NE);
296*f0984d40SFabiano Rosas 
297*f0984d40SFabiano Rosas     /* fpInactive = FPCCR_NS.ASPEN == 1 && CONTROL.FPCA == 0 */
298*f0984d40SFabiano Rosas     TCGv_i32 aspen, fpca;
299*f0984d40SFabiano Rosas     aspen = load_cpu_field(v7m.fpccr[M_REG_NS]);
300*f0984d40SFabiano Rosas     fpca = load_cpu_field(v7m.control[M_REG_S]);
301*f0984d40SFabiano Rosas     tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
302*f0984d40SFabiano Rosas     tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
303*f0984d40SFabiano Rosas     tcg_gen_andi_i32(fpca, fpca, R_V7M_CONTROL_FPCA_MASK);
304*f0984d40SFabiano Rosas     tcg_gen_or_i32(fpca, fpca, aspen);
305*f0984d40SFabiano Rosas     tcg_gen_brcondi_i32(tcg_invert_cond(cond), fpca, 0, label);
306*f0984d40SFabiano Rosas     tcg_temp_free_i32(aspen);
307*f0984d40SFabiano Rosas     tcg_temp_free_i32(fpca);
308*f0984d40SFabiano Rosas }
309*f0984d40SFabiano Rosas 
310*f0984d40SFabiano Rosas static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
311*f0984d40SFabiano Rosas                                   fp_sysreg_loadfn *loadfn,
312*f0984d40SFabiano Rosas                                   void *opaque)
313*f0984d40SFabiano Rosas {
314*f0984d40SFabiano Rosas     /* Do a write to an M-profile floating point system register */
315*f0984d40SFabiano Rosas     TCGv_i32 tmp;
316*f0984d40SFabiano Rosas     TCGLabel *lab_end = NULL;
317*f0984d40SFabiano Rosas 
318*f0984d40SFabiano Rosas     switch (fp_sysreg_checks(s, regno)) {
319*f0984d40SFabiano Rosas     case FPSysRegCheckFailed:
320*f0984d40SFabiano Rosas         return false;
321*f0984d40SFabiano Rosas     case FPSysRegCheckDone:
322*f0984d40SFabiano Rosas         return true;
323*f0984d40SFabiano Rosas     case FPSysRegCheckContinue:
324*f0984d40SFabiano Rosas         break;
325*f0984d40SFabiano Rosas     }
326*f0984d40SFabiano Rosas 
327*f0984d40SFabiano Rosas     switch (regno) {
328*f0984d40SFabiano Rosas     case ARM_VFP_FPSCR:
329*f0984d40SFabiano Rosas         tmp = loadfn(s, opaque, true);
330*f0984d40SFabiano Rosas         gen_helper_vfp_set_fpscr(cpu_env, tmp);
331*f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
332*f0984d40SFabiano Rosas         gen_lookup_tb(s);
333*f0984d40SFabiano Rosas         break;
334*f0984d40SFabiano Rosas     case ARM_VFP_FPSCR_NZCVQC:
335*f0984d40SFabiano Rosas     {
336*f0984d40SFabiano Rosas         TCGv_i32 fpscr;
337*f0984d40SFabiano Rosas         tmp = loadfn(s, opaque, true);
338*f0984d40SFabiano Rosas         if (dc_isar_feature(aa32_mve, s)) {
339*f0984d40SFabiano Rosas             /* QC is only present for MVE; otherwise RES0 */
340*f0984d40SFabiano Rosas             TCGv_i32 qc = tcg_temp_new_i32();
341*f0984d40SFabiano Rosas             tcg_gen_andi_i32(qc, tmp, FPCR_QC);
342*f0984d40SFabiano Rosas             /*
343*f0984d40SFabiano Rosas              * The 4 vfp.qc[] fields need only be "zero" vs "non-zero";
344*f0984d40SFabiano Rosas              * here writing the same value into all elements is simplest.
345*f0984d40SFabiano Rosas              */
346*f0984d40SFabiano Rosas             tcg_gen_gvec_dup_i32(MO_32, offsetof(CPUARMState, vfp.qc),
347*f0984d40SFabiano Rosas                                  16, 16, qc);
348*f0984d40SFabiano Rosas         }
349*f0984d40SFabiano Rosas         tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK);
350*f0984d40SFabiano Rosas         fpscr = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
351*f0984d40SFabiano Rosas         tcg_gen_andi_i32(fpscr, fpscr, ~FPCR_NZCV_MASK);
352*f0984d40SFabiano Rosas         tcg_gen_or_i32(fpscr, fpscr, tmp);
353*f0984d40SFabiano Rosas         store_cpu_field(fpscr, vfp.xregs[ARM_VFP_FPSCR]);
354*f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
355*f0984d40SFabiano Rosas         break;
356*f0984d40SFabiano Rosas     }
357*f0984d40SFabiano Rosas     case ARM_VFP_FPCXT_NS:
358*f0984d40SFabiano Rosas     {
359*f0984d40SFabiano Rosas         TCGLabel *lab_active = gen_new_label();
360*f0984d40SFabiano Rosas 
361*f0984d40SFabiano Rosas         lab_end = gen_new_label();
362*f0984d40SFabiano Rosas         gen_branch_fpInactive(s, TCG_COND_EQ, lab_active);
363*f0984d40SFabiano Rosas         /*
364*f0984d40SFabiano Rosas          * fpInactive case: write is a NOP, so only do side effects
365*f0984d40SFabiano Rosas          * like register writeback before we branch to end
366*f0984d40SFabiano Rosas          */
367*f0984d40SFabiano Rosas         loadfn(s, opaque, false);
368*f0984d40SFabiano Rosas         tcg_gen_br(lab_end);
369*f0984d40SFabiano Rosas 
370*f0984d40SFabiano Rosas         gen_set_label(lab_active);
371*f0984d40SFabiano Rosas         /*
372*f0984d40SFabiano Rosas          * !fpInactive: if FPU disabled, take NOCP exception;
373*f0984d40SFabiano Rosas          * otherwise PreserveFPState(), and then FPCXT_NS writes
374*f0984d40SFabiano Rosas          * behave the same as FPCXT_S writes.
375*f0984d40SFabiano Rosas          */
376*f0984d40SFabiano Rosas         if (!vfp_access_check_m(s, true)) {
377*f0984d40SFabiano Rosas             /*
378*f0984d40SFabiano Rosas              * This was only a conditional exception, so override
379*f0984d40SFabiano Rosas              * gen_exception_insn_el()'s default to DISAS_NORETURN
380*f0984d40SFabiano Rosas              */
381*f0984d40SFabiano Rosas             s->base.is_jmp = DISAS_NEXT;
382*f0984d40SFabiano Rosas             break;
383*f0984d40SFabiano Rosas         }
384*f0984d40SFabiano Rosas     }
385*f0984d40SFabiano Rosas     /* fall through */
386*f0984d40SFabiano Rosas     case ARM_VFP_FPCXT_S:
387*f0984d40SFabiano Rosas     {
388*f0984d40SFabiano Rosas         TCGv_i32 sfpa, control;
389*f0984d40SFabiano Rosas         /*
390*f0984d40SFabiano Rosas          * Set FPSCR and CONTROL.SFPA from value; the new FPSCR takes
391*f0984d40SFabiano Rosas          * bits [27:0] from value and zeroes bits [31:28].
392*f0984d40SFabiano Rosas          */
393*f0984d40SFabiano Rosas         tmp = loadfn(s, opaque, true);
394*f0984d40SFabiano Rosas         sfpa = tcg_temp_new_i32();
395*f0984d40SFabiano Rosas         tcg_gen_shri_i32(sfpa, tmp, 31);
396*f0984d40SFabiano Rosas         control = load_cpu_field(v7m.control[M_REG_S]);
397*f0984d40SFabiano Rosas         tcg_gen_deposit_i32(control, control, sfpa,
398*f0984d40SFabiano Rosas                             R_V7M_CONTROL_SFPA_SHIFT, 1);
399*f0984d40SFabiano Rosas         store_cpu_field(control, v7m.control[M_REG_S]);
400*f0984d40SFabiano Rosas         tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK);
401*f0984d40SFabiano Rosas         gen_helper_vfp_set_fpscr(cpu_env, tmp);
402*f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
403*f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
404*f0984d40SFabiano Rosas         tcg_temp_free_i32(sfpa);
405*f0984d40SFabiano Rosas         break;
406*f0984d40SFabiano Rosas     }
407*f0984d40SFabiano Rosas     case ARM_VFP_VPR:
408*f0984d40SFabiano Rosas         /* Behaves as NOP if not privileged */
409*f0984d40SFabiano Rosas         if (IS_USER(s)) {
410*f0984d40SFabiano Rosas             loadfn(s, opaque, false);
411*f0984d40SFabiano Rosas             break;
412*f0984d40SFabiano Rosas         }
413*f0984d40SFabiano Rosas         tmp = loadfn(s, opaque, true);
414*f0984d40SFabiano Rosas         store_cpu_field(tmp, v7m.vpr);
415*f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
416*f0984d40SFabiano Rosas         break;
417*f0984d40SFabiano Rosas     case ARM_VFP_P0:
418*f0984d40SFabiano Rosas     {
419*f0984d40SFabiano Rosas         TCGv_i32 vpr;
420*f0984d40SFabiano Rosas         tmp = loadfn(s, opaque, true);
421*f0984d40SFabiano Rosas         vpr = load_cpu_field(v7m.vpr);
422*f0984d40SFabiano Rosas         tcg_gen_deposit_i32(vpr, vpr, tmp,
423*f0984d40SFabiano Rosas                             R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH);
424*f0984d40SFabiano Rosas         store_cpu_field(vpr, v7m.vpr);
425*f0984d40SFabiano Rosas         s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
426*f0984d40SFabiano Rosas         tcg_temp_free_i32(tmp);
427*f0984d40SFabiano Rosas         break;
428*f0984d40SFabiano Rosas     }
429*f0984d40SFabiano Rosas     default:
430*f0984d40SFabiano Rosas         g_assert_not_reached();
431*f0984d40SFabiano Rosas     }
432*f0984d40SFabiano Rosas     if (lab_end) {
433*f0984d40SFabiano Rosas         gen_set_label(lab_end);
434*f0984d40SFabiano Rosas     }
435*f0984d40SFabiano Rosas     return true;
436*f0984d40SFabiano Rosas }
437*f0984d40SFabiano Rosas 
438*f0984d40SFabiano Rosas static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
439*f0984d40SFabiano Rosas                                  fp_sysreg_storefn *storefn,
440*f0984d40SFabiano Rosas                                  void *opaque)
441*f0984d40SFabiano Rosas {
442*f0984d40SFabiano Rosas     /* Do a read from an M-profile floating point system register */
443*f0984d40SFabiano Rosas     TCGv_i32 tmp;
444*f0984d40SFabiano Rosas     TCGLabel *lab_end = NULL;
445*f0984d40SFabiano Rosas     bool lookup_tb = false;
446*f0984d40SFabiano Rosas 
447*f0984d40SFabiano Rosas     switch (fp_sysreg_checks(s, regno)) {
448*f0984d40SFabiano Rosas     case FPSysRegCheckFailed:
449*f0984d40SFabiano Rosas         return false;
450*f0984d40SFabiano Rosas     case FPSysRegCheckDone:
451*f0984d40SFabiano Rosas         return true;
452*f0984d40SFabiano Rosas     case FPSysRegCheckContinue:
453*f0984d40SFabiano Rosas         break;
454*f0984d40SFabiano Rosas     }
455*f0984d40SFabiano Rosas 
456*f0984d40SFabiano Rosas     if (regno == ARM_VFP_FPSCR_NZCVQC && !dc_isar_feature(aa32_mve, s)) {
457*f0984d40SFabiano Rosas         /* QC is RES0 without MVE, so NZCVQC simplifies to NZCV */
458*f0984d40SFabiano Rosas         regno = QEMU_VFP_FPSCR_NZCV;
459*f0984d40SFabiano Rosas     }
460*f0984d40SFabiano Rosas 
461*f0984d40SFabiano Rosas     switch (regno) {
462*f0984d40SFabiano Rosas     case ARM_VFP_FPSCR:
463*f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
464*f0984d40SFabiano Rosas         gen_helper_vfp_get_fpscr(tmp, cpu_env);
465*f0984d40SFabiano Rosas         storefn(s, opaque, tmp, true);
466*f0984d40SFabiano Rosas         break;
467*f0984d40SFabiano Rosas     case ARM_VFP_FPSCR_NZCVQC:
468*f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
469*f0984d40SFabiano Rosas         gen_helper_vfp_get_fpscr(tmp, cpu_env);
470*f0984d40SFabiano Rosas         tcg_gen_andi_i32(tmp, tmp, FPCR_NZCVQC_MASK);
471*f0984d40SFabiano Rosas         storefn(s, opaque, tmp, true);
472*f0984d40SFabiano Rosas         break;
473*f0984d40SFabiano Rosas     case QEMU_VFP_FPSCR_NZCV:
474*f0984d40SFabiano Rosas         /*
475*f0984d40SFabiano Rosas          * Read just NZCV; this is a special case to avoid the
476*f0984d40SFabiano Rosas          * helper call for the "VMRS to CPSR.NZCV" insn.
477*f0984d40SFabiano Rosas          */
478*f0984d40SFabiano Rosas         tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
479*f0984d40SFabiano Rosas         tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK);
480*f0984d40SFabiano Rosas         storefn(s, opaque, tmp, true);
481*f0984d40SFabiano Rosas         break;
482*f0984d40SFabiano Rosas     case ARM_VFP_FPCXT_S:
483*f0984d40SFabiano Rosas     {
484*f0984d40SFabiano Rosas         TCGv_i32 control, sfpa, fpscr;
485*f0984d40SFabiano Rosas         /* Bits [27:0] from FPSCR, bit [31] from CONTROL.SFPA */
486*f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
487*f0984d40SFabiano Rosas         sfpa = tcg_temp_new_i32();
488*f0984d40SFabiano Rosas         gen_helper_vfp_get_fpscr(tmp, cpu_env);
489*f0984d40SFabiano Rosas         tcg_gen_andi_i32(tmp, tmp, ~FPCR_NZCV_MASK);
490*f0984d40SFabiano Rosas         control = load_cpu_field(v7m.control[M_REG_S]);
491*f0984d40SFabiano Rosas         tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK);
492*f0984d40SFabiano Rosas         tcg_gen_shli_i32(sfpa, sfpa, 31 - R_V7M_CONTROL_SFPA_SHIFT);
493*f0984d40SFabiano Rosas         tcg_gen_or_i32(tmp, tmp, sfpa);
494*f0984d40SFabiano Rosas         tcg_temp_free_i32(sfpa);
495*f0984d40SFabiano Rosas         /*
496*f0984d40SFabiano Rosas          * Store result before updating FPSCR etc, in case
497*f0984d40SFabiano Rosas          * it is a memory write which causes an exception.
498*f0984d40SFabiano Rosas          */
499*f0984d40SFabiano Rosas         storefn(s, opaque, tmp, true);
500*f0984d40SFabiano Rosas         /*
501*f0984d40SFabiano Rosas          * Now we must reset FPSCR from FPDSCR_NS, and clear
502*f0984d40SFabiano Rosas          * CONTROL.SFPA; so we'll end the TB here.
503*f0984d40SFabiano Rosas          */
504*f0984d40SFabiano Rosas         tcg_gen_andi_i32(control, control, ~R_V7M_CONTROL_SFPA_MASK);
505*f0984d40SFabiano Rosas         store_cpu_field(control, v7m.control[M_REG_S]);
506*f0984d40SFabiano Rosas         fpscr = load_cpu_field(v7m.fpdscr[M_REG_NS]);
507*f0984d40SFabiano Rosas         gen_helper_vfp_set_fpscr(cpu_env, fpscr);
508*f0984d40SFabiano Rosas         tcg_temp_free_i32(fpscr);
509*f0984d40SFabiano Rosas         lookup_tb = true;
510*f0984d40SFabiano Rosas         break;
511*f0984d40SFabiano Rosas     }
512*f0984d40SFabiano Rosas     case ARM_VFP_FPCXT_NS:
513*f0984d40SFabiano Rosas     {
514*f0984d40SFabiano Rosas         TCGv_i32 control, sfpa, fpscr, fpdscr;
515*f0984d40SFabiano Rosas         TCGLabel *lab_active = gen_new_label();
516*f0984d40SFabiano Rosas 
517*f0984d40SFabiano Rosas         lookup_tb = true;
518*f0984d40SFabiano Rosas 
519*f0984d40SFabiano Rosas         gen_branch_fpInactive(s, TCG_COND_EQ, lab_active);
520*f0984d40SFabiano Rosas         /* fpInactive case: reads as FPDSCR_NS */
521*f0984d40SFabiano Rosas         TCGv_i32 tmp = load_cpu_field(v7m.fpdscr[M_REG_NS]);
522*f0984d40SFabiano Rosas         storefn(s, opaque, tmp, true);
523*f0984d40SFabiano Rosas         lab_end = gen_new_label();
524*f0984d40SFabiano Rosas         tcg_gen_br(lab_end);
525*f0984d40SFabiano Rosas 
526*f0984d40SFabiano Rosas         gen_set_label(lab_active);
527*f0984d40SFabiano Rosas         /*
528*f0984d40SFabiano Rosas          * !fpInactive: if FPU disabled, take NOCP exception;
529*f0984d40SFabiano Rosas          * otherwise PreserveFPState(), and then FPCXT_NS
530*f0984d40SFabiano Rosas          * reads the same as FPCXT_S.
531*f0984d40SFabiano Rosas          */
532*f0984d40SFabiano Rosas         if (!vfp_access_check_m(s, true)) {
533*f0984d40SFabiano Rosas             /*
534*f0984d40SFabiano Rosas              * This was only a conditional exception, so override
535*f0984d40SFabiano Rosas              * gen_exception_insn_el()'s default to DISAS_NORETURN
536*f0984d40SFabiano Rosas              */
537*f0984d40SFabiano Rosas             s->base.is_jmp = DISAS_NEXT;
538*f0984d40SFabiano Rosas             break;
539*f0984d40SFabiano Rosas         }
540*f0984d40SFabiano Rosas         tmp = tcg_temp_new_i32();
541*f0984d40SFabiano Rosas         sfpa = tcg_temp_new_i32();
542*f0984d40SFabiano Rosas         fpscr = tcg_temp_new_i32();
543*f0984d40SFabiano Rosas         gen_helper_vfp_get_fpscr(fpscr, cpu_env);
544*f0984d40SFabiano Rosas         tcg_gen_andi_i32(tmp, fpscr, ~FPCR_NZCV_MASK);
545*f0984d40SFabiano Rosas         control = load_cpu_field(v7m.control[M_REG_S]);
546*f0984d40SFabiano Rosas         tcg_gen_andi_i32(sfpa, control, R_V7M_CONTROL_SFPA_MASK);
547*f0984d40SFabiano Rosas         tcg_gen_shli_i32(sfpa, sfpa, 31 - R_V7M_CONTROL_SFPA_SHIFT);
548*f0984d40SFabiano Rosas         tcg_gen_or_i32(tmp, tmp, sfpa);
549*f0984d40SFabiano Rosas         tcg_temp_free_i32(control);
550*f0984d40SFabiano Rosas         /* Store result before updating FPSCR, in case it faults */
551*f0984d40SFabiano Rosas         storefn(s, opaque, tmp, true);
552*f0984d40SFabiano Rosas         /* If SFPA is zero then set FPSCR from FPDSCR_NS */
553*f0984d40SFabiano Rosas         fpdscr = load_cpu_field(v7m.fpdscr[M_REG_NS]);
554*f0984d40SFabiano Rosas         tcg_gen_movcond_i32(TCG_COND_EQ, fpscr, sfpa, tcg_constant_i32(0),
555*f0984d40SFabiano Rosas                             fpdscr, fpscr);
556*f0984d40SFabiano Rosas         gen_helper_vfp_set_fpscr(cpu_env, fpscr);
557*f0984d40SFabiano Rosas         tcg_temp_free_i32(sfpa);
558*f0984d40SFabiano Rosas         tcg_temp_free_i32(fpdscr);
559*f0984d40SFabiano Rosas         tcg_temp_free_i32(fpscr);
560*f0984d40SFabiano Rosas         break;
561*f0984d40SFabiano Rosas     }
562*f0984d40SFabiano Rosas     case ARM_VFP_VPR:
563*f0984d40SFabiano Rosas         /* Behaves as NOP if not privileged */
564*f0984d40SFabiano Rosas         if (IS_USER(s)) {
565*f0984d40SFabiano Rosas             storefn(s, opaque, NULL, false);
566*f0984d40SFabiano Rosas             break;
567*f0984d40SFabiano Rosas         }
568*f0984d40SFabiano Rosas         tmp = load_cpu_field(v7m.vpr);
569*f0984d40SFabiano Rosas         storefn(s, opaque, tmp, true);
570*f0984d40SFabiano Rosas         break;
571*f0984d40SFabiano Rosas     case ARM_VFP_P0:
572*f0984d40SFabiano Rosas         tmp = load_cpu_field(v7m.vpr);
573*f0984d40SFabiano Rosas         tcg_gen_extract_i32(tmp, tmp, R_V7M_VPR_P0_SHIFT, R_V7M_VPR_P0_LENGTH);
574*f0984d40SFabiano Rosas         storefn(s, opaque, tmp, true);
575*f0984d40SFabiano Rosas         break;
576*f0984d40SFabiano Rosas     default:
577*f0984d40SFabiano Rosas         g_assert_not_reached();
578*f0984d40SFabiano Rosas     }
579*f0984d40SFabiano Rosas 
580*f0984d40SFabiano Rosas     if (lab_end) {
581*f0984d40SFabiano Rosas         gen_set_label(lab_end);
582*f0984d40SFabiano Rosas     }
583*f0984d40SFabiano Rosas     if (lookup_tb) {
584*f0984d40SFabiano Rosas         gen_lookup_tb(s);
585*f0984d40SFabiano Rosas     }
586*f0984d40SFabiano Rosas     return true;
587*f0984d40SFabiano Rosas }
588*f0984d40SFabiano Rosas 
589*f0984d40SFabiano Rosas static void fp_sysreg_to_gpr(DisasContext *s, void *opaque, TCGv_i32 value,
590*f0984d40SFabiano Rosas                              bool do_access)
591*f0984d40SFabiano Rosas {
592*f0984d40SFabiano Rosas     arg_VMSR_VMRS *a = opaque;
593*f0984d40SFabiano Rosas 
594*f0984d40SFabiano Rosas     if (!do_access) {
595*f0984d40SFabiano Rosas         return;
596*f0984d40SFabiano Rosas     }
597*f0984d40SFabiano Rosas 
598*f0984d40SFabiano Rosas     if (a->rt == 15) {
599*f0984d40SFabiano Rosas         /* Set the 4 flag bits in the CPSR */
600*f0984d40SFabiano Rosas         gen_set_nzcv(value);
601*f0984d40SFabiano Rosas         tcg_temp_free_i32(value);
602*f0984d40SFabiano Rosas     } else {
603*f0984d40SFabiano Rosas         store_reg(s, a->rt, value);
604*f0984d40SFabiano Rosas     }
605*f0984d40SFabiano Rosas }
606*f0984d40SFabiano Rosas 
607*f0984d40SFabiano Rosas static TCGv_i32 gpr_to_fp_sysreg(DisasContext *s, void *opaque, bool do_access)
608*f0984d40SFabiano Rosas {
609*f0984d40SFabiano Rosas     arg_VMSR_VMRS *a = opaque;
610*f0984d40SFabiano Rosas 
611*f0984d40SFabiano Rosas     if (!do_access) {
612*f0984d40SFabiano Rosas         return NULL;
613*f0984d40SFabiano Rosas     }
614*f0984d40SFabiano Rosas     return load_reg(s, a->rt);
615*f0984d40SFabiano Rosas }
616*f0984d40SFabiano Rosas 
617*f0984d40SFabiano Rosas static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
618*f0984d40SFabiano Rosas {
619*f0984d40SFabiano Rosas     /*
620*f0984d40SFabiano Rosas      * Accesses to R15 are UNPREDICTABLE; we choose to undef.
621*f0984d40SFabiano Rosas      * FPSCR -> r15 is a special case which writes to the PSR flags;
622*f0984d40SFabiano Rosas      * set a->reg to a special value to tell gen_M_fp_sysreg_read()
623*f0984d40SFabiano Rosas      * we only care about the top 4 bits of FPSCR there.
624*f0984d40SFabiano Rosas      */
625*f0984d40SFabiano Rosas     if (a->rt == 15) {
626*f0984d40SFabiano Rosas         if (a->l && a->reg == ARM_VFP_FPSCR) {
627*f0984d40SFabiano Rosas             a->reg = QEMU_VFP_FPSCR_NZCV;
628*f0984d40SFabiano Rosas         } else {
629*f0984d40SFabiano Rosas             return false;
630*f0984d40SFabiano Rosas         }
631*f0984d40SFabiano Rosas     }
632*f0984d40SFabiano Rosas 
633*f0984d40SFabiano Rosas     if (a->l) {
634*f0984d40SFabiano Rosas         /* VMRS, move FP system register to gp register */
635*f0984d40SFabiano Rosas         return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_gpr, a);
636*f0984d40SFabiano Rosas     } else {
637*f0984d40SFabiano Rosas         /* VMSR, move gp register to FP system register */
638*f0984d40SFabiano Rosas         return gen_M_fp_sysreg_write(s, a->reg, gpr_to_fp_sysreg, a);
639*f0984d40SFabiano Rosas     }
640*f0984d40SFabiano Rosas }
641*f0984d40SFabiano Rosas 
642*f0984d40SFabiano Rosas static void fp_sysreg_to_memory(DisasContext *s, void *opaque, TCGv_i32 value,
643*f0984d40SFabiano Rosas                                 bool do_access)
644*f0984d40SFabiano Rosas {
645*f0984d40SFabiano Rosas     arg_vldr_sysreg *a = opaque;
646*f0984d40SFabiano Rosas     uint32_t offset = a->imm;
647*f0984d40SFabiano Rosas     TCGv_i32 addr;
648*f0984d40SFabiano Rosas 
649*f0984d40SFabiano Rosas     if (!a->a) {
650*f0984d40SFabiano Rosas         offset = -offset;
651*f0984d40SFabiano Rosas     }
652*f0984d40SFabiano Rosas 
653*f0984d40SFabiano Rosas     if (!do_access && !a->w) {
654*f0984d40SFabiano Rosas         return;
655*f0984d40SFabiano Rosas     }
656*f0984d40SFabiano Rosas 
657*f0984d40SFabiano Rosas     addr = load_reg(s, a->rn);
658*f0984d40SFabiano Rosas     if (a->p) {
659*f0984d40SFabiano Rosas         tcg_gen_addi_i32(addr, addr, offset);
660*f0984d40SFabiano Rosas     }
661*f0984d40SFabiano Rosas 
662*f0984d40SFabiano Rosas     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
663*f0984d40SFabiano Rosas         gen_helper_v8m_stackcheck(cpu_env, addr);
664*f0984d40SFabiano Rosas     }
665*f0984d40SFabiano Rosas 
666*f0984d40SFabiano Rosas     if (do_access) {
667*f0984d40SFabiano Rosas         gen_aa32_st_i32(s, value, addr, get_mem_index(s),
668*f0984d40SFabiano Rosas                         MO_UL | MO_ALIGN | s->be_data);
669*f0984d40SFabiano Rosas         tcg_temp_free_i32(value);
670*f0984d40SFabiano Rosas     }
671*f0984d40SFabiano Rosas 
672*f0984d40SFabiano Rosas     if (a->w) {
673*f0984d40SFabiano Rosas         /* writeback */
674*f0984d40SFabiano Rosas         if (!a->p) {
675*f0984d40SFabiano Rosas             tcg_gen_addi_i32(addr, addr, offset);
676*f0984d40SFabiano Rosas         }
677*f0984d40SFabiano Rosas         store_reg(s, a->rn, addr);
678*f0984d40SFabiano Rosas     } else {
679*f0984d40SFabiano Rosas         tcg_temp_free_i32(addr);
680*f0984d40SFabiano Rosas     }
681*f0984d40SFabiano Rosas }
682*f0984d40SFabiano Rosas 
683*f0984d40SFabiano Rosas static TCGv_i32 memory_to_fp_sysreg(DisasContext *s, void *opaque,
684*f0984d40SFabiano Rosas                                     bool do_access)
685*f0984d40SFabiano Rosas {
686*f0984d40SFabiano Rosas     arg_vldr_sysreg *a = opaque;
687*f0984d40SFabiano Rosas     uint32_t offset = a->imm;
688*f0984d40SFabiano Rosas     TCGv_i32 addr;
689*f0984d40SFabiano Rosas     TCGv_i32 value = NULL;
690*f0984d40SFabiano Rosas 
691*f0984d40SFabiano Rosas     if (!a->a) {
692*f0984d40SFabiano Rosas         offset = -offset;
693*f0984d40SFabiano Rosas     }
694*f0984d40SFabiano Rosas 
695*f0984d40SFabiano Rosas     if (!do_access && !a->w) {
696*f0984d40SFabiano Rosas         return NULL;
697*f0984d40SFabiano Rosas     }
698*f0984d40SFabiano Rosas 
699*f0984d40SFabiano Rosas     addr = load_reg(s, a->rn);
700*f0984d40SFabiano Rosas     if (a->p) {
701*f0984d40SFabiano Rosas         tcg_gen_addi_i32(addr, addr, offset);
702*f0984d40SFabiano Rosas     }
703*f0984d40SFabiano Rosas 
704*f0984d40SFabiano Rosas     if (s->v8m_stackcheck && a->rn == 13 && a->w) {
705*f0984d40SFabiano Rosas         gen_helper_v8m_stackcheck(cpu_env, addr);
706*f0984d40SFabiano Rosas     }
707*f0984d40SFabiano Rosas 
708*f0984d40SFabiano Rosas     if (do_access) {
709*f0984d40SFabiano Rosas         value = tcg_temp_new_i32();
710*f0984d40SFabiano Rosas         gen_aa32_ld_i32(s, value, addr, get_mem_index(s),
711*f0984d40SFabiano Rosas                         MO_UL | MO_ALIGN | s->be_data);
712*f0984d40SFabiano Rosas     }
713*f0984d40SFabiano Rosas 
714*f0984d40SFabiano Rosas     if (a->w) {
715*f0984d40SFabiano Rosas         /* writeback */
716*f0984d40SFabiano Rosas         if (!a->p) {
717*f0984d40SFabiano Rosas             tcg_gen_addi_i32(addr, addr, offset);
718*f0984d40SFabiano Rosas         }
719*f0984d40SFabiano Rosas         store_reg(s, a->rn, addr);
720*f0984d40SFabiano Rosas     } else {
721*f0984d40SFabiano Rosas         tcg_temp_free_i32(addr);
722*f0984d40SFabiano Rosas     }
723*f0984d40SFabiano Rosas     return value;
724*f0984d40SFabiano Rosas }
725*f0984d40SFabiano Rosas 
726*f0984d40SFabiano Rosas static bool trans_VLDR_sysreg(DisasContext *s, arg_vldr_sysreg *a)
727*f0984d40SFabiano Rosas {
728*f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
729*f0984d40SFabiano Rosas         return false;
730*f0984d40SFabiano Rosas     }
731*f0984d40SFabiano Rosas     if (a->rn == 15) {
732*f0984d40SFabiano Rosas         return false;
733*f0984d40SFabiano Rosas     }
734*f0984d40SFabiano Rosas     return gen_M_fp_sysreg_write(s, a->reg, memory_to_fp_sysreg, a);
735*f0984d40SFabiano Rosas }
736*f0984d40SFabiano Rosas 
737*f0984d40SFabiano Rosas static bool trans_VSTR_sysreg(DisasContext *s, arg_vldr_sysreg *a)
738*f0984d40SFabiano Rosas {
739*f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
740*f0984d40SFabiano Rosas         return false;
741*f0984d40SFabiano Rosas     }
742*f0984d40SFabiano Rosas     if (a->rn == 15) {
743*f0984d40SFabiano Rosas         return false;
744*f0984d40SFabiano Rosas     }
745*f0984d40SFabiano Rosas     return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_memory, a);
746*f0984d40SFabiano Rosas }
747*f0984d40SFabiano Rosas 
748*f0984d40SFabiano Rosas static bool trans_NOCP(DisasContext *s, arg_nocp *a)
749*f0984d40SFabiano Rosas {
750*f0984d40SFabiano Rosas     /*
751*f0984d40SFabiano Rosas      * Handle M-profile early check for disabled coprocessor:
752*f0984d40SFabiano Rosas      * all we need to do here is emit the NOCP exception if
753*f0984d40SFabiano Rosas      * the coprocessor is disabled. Otherwise we return false
754*f0984d40SFabiano Rosas      * and the real VFP/etc decode will handle the insn.
755*f0984d40SFabiano Rosas      */
756*f0984d40SFabiano Rosas     assert(arm_dc_feature(s, ARM_FEATURE_M));
757*f0984d40SFabiano Rosas 
758*f0984d40SFabiano Rosas     if (a->cp == 11) {
759*f0984d40SFabiano Rosas         a->cp = 10;
760*f0984d40SFabiano Rosas     }
761*f0984d40SFabiano Rosas     if (arm_dc_feature(s, ARM_FEATURE_V8_1M) &&
762*f0984d40SFabiano Rosas         (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) {
763*f0984d40SFabiano Rosas         /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
764*f0984d40SFabiano Rosas         a->cp = 10;
765*f0984d40SFabiano Rosas     }
766*f0984d40SFabiano Rosas 
767*f0984d40SFabiano Rosas     if (a->cp != 10) {
768*f0984d40SFabiano Rosas         gen_exception_insn(s, 0, EXCP_NOCP, syn_uncategorized());
769*f0984d40SFabiano Rosas         return true;
770*f0984d40SFabiano Rosas     }
771*f0984d40SFabiano Rosas 
772*f0984d40SFabiano Rosas     if (s->fp_excp_el != 0) {
773*f0984d40SFabiano Rosas         gen_exception_insn_el(s, 0, EXCP_NOCP,
774*f0984d40SFabiano Rosas                               syn_uncategorized(), s->fp_excp_el);
775*f0984d40SFabiano Rosas         return true;
776*f0984d40SFabiano Rosas     }
777*f0984d40SFabiano Rosas 
778*f0984d40SFabiano Rosas     return false;
779*f0984d40SFabiano Rosas }
780*f0984d40SFabiano Rosas 
781*f0984d40SFabiano Rosas static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a)
782*f0984d40SFabiano Rosas {
783*f0984d40SFabiano Rosas     /* This range needs a coprocessor check for v8.1M and later only */
784*f0984d40SFabiano Rosas     if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
785*f0984d40SFabiano Rosas         return false;
786*f0984d40SFabiano Rosas     }
787*f0984d40SFabiano Rosas     return trans_NOCP(s, a);
788*f0984d40SFabiano Rosas }
789