xref: /qemu/target/arm/tcg/translate-mve.c (revision 507b6a500c2f0f6cf6182aa69efac4c20eb3e97b)
16390eed4SPeter Maydell /*
26390eed4SPeter Maydell  *  ARM translation: M-profile MVE instructions
36390eed4SPeter Maydell  *
46390eed4SPeter Maydell  *  Copyright (c) 2021 Linaro, Ltd.
56390eed4SPeter Maydell  *
66390eed4SPeter Maydell  * This library is free software; you can redistribute it and/or
76390eed4SPeter Maydell  * modify it under the terms of the GNU Lesser General Public
86390eed4SPeter Maydell  * License as published by the Free Software Foundation; either
96390eed4SPeter Maydell  * version 2.1 of the License, or (at your option) any later version.
106390eed4SPeter Maydell  *
116390eed4SPeter Maydell  * This library is distributed in the hope that it will be useful,
126390eed4SPeter Maydell  * but WITHOUT ANY WARRANTY; without even the implied warranty of
136390eed4SPeter Maydell  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
146390eed4SPeter Maydell  * Lesser General Public License for more details.
156390eed4SPeter Maydell  *
166390eed4SPeter Maydell  * You should have received a copy of the GNU Lesser General Public
176390eed4SPeter Maydell  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
186390eed4SPeter Maydell  */
196390eed4SPeter Maydell 
206390eed4SPeter Maydell #include "qemu/osdep.h"
216390eed4SPeter Maydell #include "tcg/tcg-op.h"
226390eed4SPeter Maydell #include "tcg/tcg-op-gvec.h"
236390eed4SPeter Maydell #include "exec/exec-all.h"
246390eed4SPeter Maydell #include "exec/gen-icount.h"
256390eed4SPeter Maydell #include "translate.h"
266390eed4SPeter Maydell #include "translate-a32.h"
276390eed4SPeter Maydell 
286390eed4SPeter Maydell /* Include the generated decoder */
296390eed4SPeter Maydell #include "decode-mve.c.inc"
30*507b6a50SPeter Maydell 
31*507b6a50SPeter Maydell typedef void MVEGenLdStFn(TCGv_ptr, TCGv_ptr, TCGv_i32);
32*507b6a50SPeter Maydell 
33*507b6a50SPeter Maydell /* Return the offset of a Qn register (same semantics as aa32_vfp_qreg()) */
34*507b6a50SPeter Maydell static inline long mve_qreg_offset(unsigned reg)
35*507b6a50SPeter Maydell {
36*507b6a50SPeter Maydell     return offsetof(CPUARMState, vfp.zregs[reg].d[0]);
37*507b6a50SPeter Maydell }
38*507b6a50SPeter Maydell 
39*507b6a50SPeter Maydell static TCGv_ptr mve_qreg_ptr(unsigned reg)
40*507b6a50SPeter Maydell {
41*507b6a50SPeter Maydell     TCGv_ptr ret = tcg_temp_new_ptr();
42*507b6a50SPeter Maydell     tcg_gen_addi_ptr(ret, cpu_env, mve_qreg_offset(reg));
43*507b6a50SPeter Maydell     return ret;
44*507b6a50SPeter Maydell }
45*507b6a50SPeter Maydell 
46*507b6a50SPeter Maydell static bool mve_check_qreg_bank(DisasContext *s, int qmask)
47*507b6a50SPeter Maydell {
48*507b6a50SPeter Maydell     /*
49*507b6a50SPeter Maydell      * Check whether Qregs are in range. For v8.1M only Q0..Q7
50*507b6a50SPeter Maydell      * are supported, see VFPSmallRegisterBank().
51*507b6a50SPeter Maydell      */
52*507b6a50SPeter Maydell     return qmask < 8;
53*507b6a50SPeter Maydell }
54*507b6a50SPeter Maydell 
55*507b6a50SPeter Maydell static bool mve_eci_check(DisasContext *s)
56*507b6a50SPeter Maydell {
57*507b6a50SPeter Maydell     /*
58*507b6a50SPeter Maydell      * This is a beatwise insn: check that ECI is valid (not a
59*507b6a50SPeter Maydell      * reserved value) and note that we are handling it.
60*507b6a50SPeter Maydell      * Return true if OK, false if we generated an exception.
61*507b6a50SPeter Maydell      */
62*507b6a50SPeter Maydell     s->eci_handled = true;
63*507b6a50SPeter Maydell     switch (s->eci) {
64*507b6a50SPeter Maydell     case ECI_NONE:
65*507b6a50SPeter Maydell     case ECI_A0:
66*507b6a50SPeter Maydell     case ECI_A0A1:
67*507b6a50SPeter Maydell     case ECI_A0A1A2:
68*507b6a50SPeter Maydell     case ECI_A0A1A2B0:
69*507b6a50SPeter Maydell         return true;
70*507b6a50SPeter Maydell     default:
71*507b6a50SPeter Maydell         /* Reserved value: INVSTATE UsageFault */
72*507b6a50SPeter Maydell         gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized(),
73*507b6a50SPeter Maydell                            default_exception_el(s));
74*507b6a50SPeter Maydell         return false;
75*507b6a50SPeter Maydell     }
76*507b6a50SPeter Maydell }
77*507b6a50SPeter Maydell 
78*507b6a50SPeter Maydell static void mve_update_eci(DisasContext *s)
79*507b6a50SPeter Maydell {
80*507b6a50SPeter Maydell     /*
81*507b6a50SPeter Maydell      * The helper function will always update the CPUState field,
82*507b6a50SPeter Maydell      * so we only need to update the DisasContext field.
83*507b6a50SPeter Maydell      */
84*507b6a50SPeter Maydell     if (s->eci) {
85*507b6a50SPeter Maydell         s->eci = (s->eci == ECI_A0A1A2B0) ? ECI_A0 : ECI_NONE;
86*507b6a50SPeter Maydell     }
87*507b6a50SPeter Maydell }
88*507b6a50SPeter Maydell 
89*507b6a50SPeter Maydell static bool do_ldst(DisasContext *s, arg_VLDR_VSTR *a, MVEGenLdStFn *fn)
90*507b6a50SPeter Maydell {
91*507b6a50SPeter Maydell     TCGv_i32 addr;
92*507b6a50SPeter Maydell     uint32_t offset;
93*507b6a50SPeter Maydell     TCGv_ptr qreg;
94*507b6a50SPeter Maydell 
95*507b6a50SPeter Maydell     if (!dc_isar_feature(aa32_mve, s) ||
96*507b6a50SPeter Maydell         !mve_check_qreg_bank(s, a->qd) ||
97*507b6a50SPeter Maydell         !fn) {
98*507b6a50SPeter Maydell         return false;
99*507b6a50SPeter Maydell     }
100*507b6a50SPeter Maydell 
101*507b6a50SPeter Maydell     /* CONSTRAINED UNPREDICTABLE: we choose to UNDEF */
102*507b6a50SPeter Maydell     if (a->rn == 15 || (a->rn == 13 && a->w)) {
103*507b6a50SPeter Maydell         return false;
104*507b6a50SPeter Maydell     }
105*507b6a50SPeter Maydell 
106*507b6a50SPeter Maydell     if (!mve_eci_check(s) || !vfp_access_check(s)) {
107*507b6a50SPeter Maydell         return true;
108*507b6a50SPeter Maydell     }
109*507b6a50SPeter Maydell 
110*507b6a50SPeter Maydell     offset = a->imm << a->size;
111*507b6a50SPeter Maydell     if (!a->a) {
112*507b6a50SPeter Maydell         offset = -offset;
113*507b6a50SPeter Maydell     }
114*507b6a50SPeter Maydell     addr = load_reg(s, a->rn);
115*507b6a50SPeter Maydell     if (a->p) {
116*507b6a50SPeter Maydell         tcg_gen_addi_i32(addr, addr, offset);
117*507b6a50SPeter Maydell     }
118*507b6a50SPeter Maydell 
119*507b6a50SPeter Maydell     qreg = mve_qreg_ptr(a->qd);
120*507b6a50SPeter Maydell     fn(cpu_env, qreg, addr);
121*507b6a50SPeter Maydell     tcg_temp_free_ptr(qreg);
122*507b6a50SPeter Maydell 
123*507b6a50SPeter Maydell     /*
124*507b6a50SPeter Maydell      * Writeback always happens after the last beat of the insn,
125*507b6a50SPeter Maydell      * regardless of predication
126*507b6a50SPeter Maydell      */
127*507b6a50SPeter Maydell     if (a->w) {
128*507b6a50SPeter Maydell         if (!a->p) {
129*507b6a50SPeter Maydell             tcg_gen_addi_i32(addr, addr, offset);
130*507b6a50SPeter Maydell         }
131*507b6a50SPeter Maydell         store_reg(s, a->rn, addr);
132*507b6a50SPeter Maydell     } else {
133*507b6a50SPeter Maydell         tcg_temp_free_i32(addr);
134*507b6a50SPeter Maydell     }
135*507b6a50SPeter Maydell     mve_update_eci(s);
136*507b6a50SPeter Maydell     return true;
137*507b6a50SPeter Maydell }
138*507b6a50SPeter Maydell 
139*507b6a50SPeter Maydell static bool trans_VLDR_VSTR(DisasContext *s, arg_VLDR_VSTR *a)
140*507b6a50SPeter Maydell {
141*507b6a50SPeter Maydell     static MVEGenLdStFn * const ldstfns[4][2] = {
142*507b6a50SPeter Maydell         { gen_helper_mve_vstrb, gen_helper_mve_vldrb },
143*507b6a50SPeter Maydell         { gen_helper_mve_vstrh, gen_helper_mve_vldrh },
144*507b6a50SPeter Maydell         { gen_helper_mve_vstrw, gen_helper_mve_vldrw },
145*507b6a50SPeter Maydell         { NULL, NULL }
146*507b6a50SPeter Maydell     };
147*507b6a50SPeter Maydell     return do_ldst(s, a, ldstfns[a->size][a->l]);
148*507b6a50SPeter Maydell }
149