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