1*60d1180bSTaylor Simpson /*
2*60d1180bSTaylor Simpson  *  Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
3*60d1180bSTaylor Simpson  *
4*60d1180bSTaylor Simpson  *  This program is free software; you can redistribute it and/or modify
5*60d1180bSTaylor Simpson  *  it under the terms of the GNU General Public License as published by
6*60d1180bSTaylor Simpson  *  the Free Software Foundation; either version 2 of the License, or
7*60d1180bSTaylor Simpson  *  (at your option) any later version.
8*60d1180bSTaylor Simpson  *
9*60d1180bSTaylor Simpson  *  This program is distributed in the hope that it will be useful,
10*60d1180bSTaylor Simpson  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11*60d1180bSTaylor Simpson  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*60d1180bSTaylor Simpson  *  GNU General Public License for more details.
13*60d1180bSTaylor Simpson  *
14*60d1180bSTaylor Simpson  *  You should have received a copy of the GNU General Public License
15*60d1180bSTaylor Simpson  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
16*60d1180bSTaylor Simpson  */
17*60d1180bSTaylor Simpson 
18*60d1180bSTaylor Simpson #include "qemu/osdep.h"
19*60d1180bSTaylor Simpson #include "decode.h"
20*60d1180bSTaylor Simpson #include "opcodes.h"
21*60d1180bSTaylor Simpson #include "insn.h"
22*60d1180bSTaylor Simpson #include "iclass.h"
23*60d1180bSTaylor Simpson #include "mmvec/mmvec.h"
24*60d1180bSTaylor Simpson #include "mmvec/decode_ext_mmvec.h"
25*60d1180bSTaylor Simpson 
26*60d1180bSTaylor Simpson static void
27*60d1180bSTaylor Simpson check_new_value(Packet *pkt)
28*60d1180bSTaylor Simpson {
29*60d1180bSTaylor Simpson     /* .new value for a MMVector store */
30*60d1180bSTaylor Simpson     int i, j;
31*60d1180bSTaylor Simpson     const char *reginfo;
32*60d1180bSTaylor Simpson     const char *destletters;
33*60d1180bSTaylor Simpson     const char *dststr = NULL;
34*60d1180bSTaylor Simpson     uint16_t def_opcode;
35*60d1180bSTaylor Simpson     char letter;
36*60d1180bSTaylor Simpson     int def_regnum;
37*60d1180bSTaylor Simpson 
38*60d1180bSTaylor Simpson     for (i = 1; i < pkt->num_insns; i++) {
39*60d1180bSTaylor Simpson         uint16_t use_opcode = pkt->insn[i].opcode;
40*60d1180bSTaylor Simpson         if (GET_ATTRIB(use_opcode, A_DOTNEWVALUE) &&
41*60d1180bSTaylor Simpson             GET_ATTRIB(use_opcode, A_CVI) &&
42*60d1180bSTaylor Simpson             GET_ATTRIB(use_opcode, A_STORE)) {
43*60d1180bSTaylor Simpson             int use_regidx = strchr(opcode_reginfo[use_opcode], 's') -
44*60d1180bSTaylor Simpson                 opcode_reginfo[use_opcode];
45*60d1180bSTaylor Simpson             /*
46*60d1180bSTaylor Simpson              * What's encoded at the N-field is the offset to who's producing
47*60d1180bSTaylor Simpson              * the value.
48*60d1180bSTaylor Simpson              * Shift off the LSB which indicates odd/even register.
49*60d1180bSTaylor Simpson              */
50*60d1180bSTaylor Simpson             int def_off = ((pkt->insn[i].regno[use_regidx]) >> 1);
51*60d1180bSTaylor Simpson             int def_oreg = pkt->insn[i].regno[use_regidx] & 1;
52*60d1180bSTaylor Simpson             int def_idx = -1;
53*60d1180bSTaylor Simpson             for (j = i - 1; (j >= 0) && (def_off >= 0); j--) {
54*60d1180bSTaylor Simpson                 if (!GET_ATTRIB(pkt->insn[j].opcode, A_CVI)) {
55*60d1180bSTaylor Simpson                     continue;
56*60d1180bSTaylor Simpson                 }
57*60d1180bSTaylor Simpson                 def_off--;
58*60d1180bSTaylor Simpson                 if (def_off == 0) {
59*60d1180bSTaylor Simpson                     def_idx = j;
60*60d1180bSTaylor Simpson                     break;
61*60d1180bSTaylor Simpson                 }
62*60d1180bSTaylor Simpson             }
63*60d1180bSTaylor Simpson             /*
64*60d1180bSTaylor Simpson              * Check for a badly encoded N-field which points to an instruction
65*60d1180bSTaylor Simpson              * out-of-range
66*60d1180bSTaylor Simpson              */
67*60d1180bSTaylor Simpson             g_assert(!((def_off != 0) || (def_idx < 0) ||
68*60d1180bSTaylor Simpson                        (def_idx > (pkt->num_insns - 1))));
69*60d1180bSTaylor Simpson 
70*60d1180bSTaylor Simpson             /* def_idx is the index of the producer */
71*60d1180bSTaylor Simpson             def_opcode = pkt->insn[def_idx].opcode;
72*60d1180bSTaylor Simpson             reginfo = opcode_reginfo[def_opcode];
73*60d1180bSTaylor Simpson             destletters = "dexy";
74*60d1180bSTaylor Simpson             for (j = 0; (letter = destletters[j]) != 0; j++) {
75*60d1180bSTaylor Simpson                 dststr = strchr(reginfo, letter);
76*60d1180bSTaylor Simpson                 if (dststr != NULL) {
77*60d1180bSTaylor Simpson                     break;
78*60d1180bSTaylor Simpson                 }
79*60d1180bSTaylor Simpson             }
80*60d1180bSTaylor Simpson             if ((dststr == NULL)  && GET_ATTRIB(def_opcode, A_CVI_GATHER)) {
81*60d1180bSTaylor Simpson                 def_regnum = 0;
82*60d1180bSTaylor Simpson                 pkt->insn[i].regno[use_regidx] = def_oreg;
83*60d1180bSTaylor Simpson                 pkt->insn[i].new_value_producer_slot = pkt->insn[def_idx].slot;
84*60d1180bSTaylor Simpson             } else {
85*60d1180bSTaylor Simpson                 if (dststr == NULL) {
86*60d1180bSTaylor Simpson                     /* still not there, we have a bad packet */
87*60d1180bSTaylor Simpson                     g_assert_not_reached();
88*60d1180bSTaylor Simpson                 }
89*60d1180bSTaylor Simpson                 def_regnum = pkt->insn[def_idx].regno[dststr - reginfo];
90*60d1180bSTaylor Simpson                 /* Now patch up the consumer with the register number */
91*60d1180bSTaylor Simpson                 pkt->insn[i].regno[use_regidx] = def_regnum ^ def_oreg;
92*60d1180bSTaylor Simpson                 /* special case for (Vx,Vy) */
93*60d1180bSTaylor Simpson                 dststr = strchr(reginfo, 'y');
94*60d1180bSTaylor Simpson                 if (def_oreg && strchr(reginfo, 'x') && dststr) {
95*60d1180bSTaylor Simpson                     def_regnum = pkt->insn[def_idx].regno[dststr - reginfo];
96*60d1180bSTaylor Simpson                     pkt->insn[i].regno[use_regidx] = def_regnum;
97*60d1180bSTaylor Simpson                 }
98*60d1180bSTaylor Simpson                 /*
99*60d1180bSTaylor Simpson                  * We need to remember who produces this value to later
100*60d1180bSTaylor Simpson                  * check if it was dynamically cancelled
101*60d1180bSTaylor Simpson                  */
102*60d1180bSTaylor Simpson                 pkt->insn[i].new_value_producer_slot = pkt->insn[def_idx].slot;
103*60d1180bSTaylor Simpson             }
104*60d1180bSTaylor Simpson         }
105*60d1180bSTaylor Simpson     }
106*60d1180bSTaylor Simpson }
107*60d1180bSTaylor Simpson 
108*60d1180bSTaylor Simpson /*
109*60d1180bSTaylor Simpson  * We don't want to reorder slot1/slot0 with respect to each other.
110*60d1180bSTaylor Simpson  * So in our shuffling, we don't want to move the .cur / .tmp vmem earlier
111*60d1180bSTaylor Simpson  * Instead, we should move the producing instruction later
112*60d1180bSTaylor Simpson  * But the producing instruction might feed a .new store!
113*60d1180bSTaylor Simpson  * So we may need to move that even later.
114*60d1180bSTaylor Simpson  */
115*60d1180bSTaylor Simpson 
116*60d1180bSTaylor Simpson static void
117*60d1180bSTaylor Simpson decode_mmvec_move_cvi_to_end(Packet *pkt, int max)
118*60d1180bSTaylor Simpson {
119*60d1180bSTaylor Simpson     int i;
120*60d1180bSTaylor Simpson     for (i = 0; i < max; i++) {
121*60d1180bSTaylor Simpson         if (GET_ATTRIB(pkt->insn[i].opcode, A_CVI)) {
122*60d1180bSTaylor Simpson             int last_inst = pkt->num_insns - 1;
123*60d1180bSTaylor Simpson             uint16_t last_opcode = pkt->insn[last_inst].opcode;
124*60d1180bSTaylor Simpson 
125*60d1180bSTaylor Simpson             /*
126*60d1180bSTaylor Simpson              * If the last instruction is an endloop, move to the one before it
127*60d1180bSTaylor Simpson              * Keep endloop as the last thing always
128*60d1180bSTaylor Simpson              */
129*60d1180bSTaylor Simpson             if ((last_opcode == J2_endloop0) ||
130*60d1180bSTaylor Simpson                 (last_opcode == J2_endloop1) ||
131*60d1180bSTaylor Simpson                 (last_opcode == J2_endloop01)) {
132*60d1180bSTaylor Simpson                 last_inst--;
133*60d1180bSTaylor Simpson             }
134*60d1180bSTaylor Simpson 
135*60d1180bSTaylor Simpson             decode_send_insn_to(pkt, i, last_inst);
136*60d1180bSTaylor Simpson             max--;
137*60d1180bSTaylor Simpson             i--;    /* Retry this index now that packet has rotated */
138*60d1180bSTaylor Simpson         }
139*60d1180bSTaylor Simpson     }
140*60d1180bSTaylor Simpson }
141*60d1180bSTaylor Simpson 
142*60d1180bSTaylor Simpson static void
143*60d1180bSTaylor Simpson decode_shuffle_for_execution_vops(Packet *pkt)
144*60d1180bSTaylor Simpson {
145*60d1180bSTaylor Simpson     /*
146*60d1180bSTaylor Simpson      * Sort for .new
147*60d1180bSTaylor Simpson      */
148*60d1180bSTaylor Simpson     int i;
149*60d1180bSTaylor Simpson     for (i = 0; i < pkt->num_insns; i++) {
150*60d1180bSTaylor Simpson         uint16_t opcode = pkt->insn[i].opcode;
151*60d1180bSTaylor Simpson         if (GET_ATTRIB(opcode, A_LOAD) &&
152*60d1180bSTaylor Simpson             (GET_ATTRIB(opcode, A_CVI_NEW) ||
153*60d1180bSTaylor Simpson              GET_ATTRIB(opcode, A_CVI_TMP))) {
154*60d1180bSTaylor Simpson             /*
155*60d1180bSTaylor Simpson              * Find prior consuming vector instructions
156*60d1180bSTaylor Simpson              * Move to end of packet
157*60d1180bSTaylor Simpson              */
158*60d1180bSTaylor Simpson             decode_mmvec_move_cvi_to_end(pkt, i);
159*60d1180bSTaylor Simpson             break;
160*60d1180bSTaylor Simpson         }
161*60d1180bSTaylor Simpson     }
162*60d1180bSTaylor Simpson 
163*60d1180bSTaylor Simpson     /* Move HVX new value stores to the end of the packet */
164*60d1180bSTaylor Simpson     for (i = 0; i < pkt->num_insns - 1; i++) {
165*60d1180bSTaylor Simpson         uint16_t opcode = pkt->insn[i].opcode;
166*60d1180bSTaylor Simpson         if (GET_ATTRIB(opcode, A_STORE) &&
167*60d1180bSTaylor Simpson             GET_ATTRIB(opcode, A_CVI_NEW) &&
168*60d1180bSTaylor Simpson             !GET_ATTRIB(opcode, A_CVI_SCATTER_RELEASE)) {
169*60d1180bSTaylor Simpson             int last_inst = pkt->num_insns - 1;
170*60d1180bSTaylor Simpson             uint16_t last_opcode = pkt->insn[last_inst].opcode;
171*60d1180bSTaylor Simpson 
172*60d1180bSTaylor Simpson             /*
173*60d1180bSTaylor Simpson              * If the last instruction is an endloop, move to the one before it
174*60d1180bSTaylor Simpson              * Keep endloop as the last thing always
175*60d1180bSTaylor Simpson              */
176*60d1180bSTaylor Simpson             if ((last_opcode == J2_endloop0) ||
177*60d1180bSTaylor Simpson                 (last_opcode == J2_endloop1) ||
178*60d1180bSTaylor Simpson                 (last_opcode == J2_endloop01)) {
179*60d1180bSTaylor Simpson                 last_inst--;
180*60d1180bSTaylor Simpson             }
181*60d1180bSTaylor Simpson 
182*60d1180bSTaylor Simpson             decode_send_insn_to(pkt, i, last_inst);
183*60d1180bSTaylor Simpson             break;
184*60d1180bSTaylor Simpson         }
185*60d1180bSTaylor Simpson     }
186*60d1180bSTaylor Simpson }
187*60d1180bSTaylor Simpson 
188*60d1180bSTaylor Simpson static void
189*60d1180bSTaylor Simpson check_for_vhist(Packet *pkt)
190*60d1180bSTaylor Simpson {
191*60d1180bSTaylor Simpson     pkt->vhist_insn = NULL;
192*60d1180bSTaylor Simpson     for (int i = 0; i < pkt->num_insns; i++) {
193*60d1180bSTaylor Simpson         Insn *insn = &pkt->insn[i];
194*60d1180bSTaylor Simpson         int opcode = insn->opcode;
195*60d1180bSTaylor Simpson         if (GET_ATTRIB(opcode, A_CVI) && GET_ATTRIB(opcode, A_CVI_4SLOT)) {
196*60d1180bSTaylor Simpson                 pkt->vhist_insn = insn;
197*60d1180bSTaylor Simpson                 return;
198*60d1180bSTaylor Simpson         }
199*60d1180bSTaylor Simpson     }
200*60d1180bSTaylor Simpson }
201*60d1180bSTaylor Simpson 
202*60d1180bSTaylor Simpson /*
203*60d1180bSTaylor Simpson  * Public Functions
204*60d1180bSTaylor Simpson  */
205*60d1180bSTaylor Simpson 
206*60d1180bSTaylor Simpson SlotMask mmvec_ext_decode_find_iclass_slots(int opcode)
207*60d1180bSTaylor Simpson {
208*60d1180bSTaylor Simpson     if (GET_ATTRIB(opcode, A_CVI_VM)) {
209*60d1180bSTaylor Simpson         /* HVX memory instruction */
210*60d1180bSTaylor Simpson         if (GET_ATTRIB(opcode, A_RESTRICT_SLOT0ONLY)) {
211*60d1180bSTaylor Simpson             return SLOTS_0;
212*60d1180bSTaylor Simpson         } else if (GET_ATTRIB(opcode, A_RESTRICT_SLOT1ONLY)) {
213*60d1180bSTaylor Simpson             return SLOTS_1;
214*60d1180bSTaylor Simpson         }
215*60d1180bSTaylor Simpson         return SLOTS_01;
216*60d1180bSTaylor Simpson     } else if (GET_ATTRIB(opcode, A_RESTRICT_SLOT2ONLY)) {
217*60d1180bSTaylor Simpson         return SLOTS_2;
218*60d1180bSTaylor Simpson     } else if (GET_ATTRIB(opcode, A_CVI_VX)) {
219*60d1180bSTaylor Simpson         /* HVX multiply instruction */
220*60d1180bSTaylor Simpson         return SLOTS_23;
221*60d1180bSTaylor Simpson     } else if (GET_ATTRIB(opcode, A_CVI_VS_VX)) {
222*60d1180bSTaylor Simpson         /* HVX permute/shift instruction */
223*60d1180bSTaylor Simpson         return SLOTS_23;
224*60d1180bSTaylor Simpson     } else {
225*60d1180bSTaylor Simpson         return SLOTS_0123;
226*60d1180bSTaylor Simpson     }
227*60d1180bSTaylor Simpson }
228*60d1180bSTaylor Simpson 
229*60d1180bSTaylor Simpson void mmvec_ext_decode_checks(Packet *pkt, bool disas_only)
230*60d1180bSTaylor Simpson {
231*60d1180bSTaylor Simpson     check_new_value(pkt);
232*60d1180bSTaylor Simpson     if (!disas_only) {
233*60d1180bSTaylor Simpson         decode_shuffle_for_execution_vops(pkt);
234*60d1180bSTaylor Simpson     }
235*60d1180bSTaylor Simpson     check_for_vhist(pkt);
236*60d1180bSTaylor Simpson }
237