160d1180bSTaylor Simpson /* 2*3fd49e22SMarco Liebel * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved. 360d1180bSTaylor Simpson * 460d1180bSTaylor Simpson * This program is free software; you can redistribute it and/or modify 560d1180bSTaylor Simpson * it under the terms of the GNU General Public License as published by 660d1180bSTaylor Simpson * the Free Software Foundation; either version 2 of the License, or 760d1180bSTaylor Simpson * (at your option) any later version. 860d1180bSTaylor Simpson * 960d1180bSTaylor Simpson * This program is distributed in the hope that it will be useful, 1060d1180bSTaylor Simpson * but WITHOUT ANY WARRANTY; without even the implied warranty of 1160d1180bSTaylor Simpson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1260d1180bSTaylor Simpson * GNU General Public License for more details. 1360d1180bSTaylor Simpson * 1460d1180bSTaylor Simpson * You should have received a copy of the GNU General Public License 1560d1180bSTaylor Simpson * along with this program; if not, see <http://www.gnu.org/licenses/>. 1660d1180bSTaylor Simpson */ 1760d1180bSTaylor Simpson 1860d1180bSTaylor Simpson #include "qemu/osdep.h" 1960d1180bSTaylor Simpson #include "decode.h" 2060d1180bSTaylor Simpson #include "opcodes.h" 2160d1180bSTaylor Simpson #include "insn.h" 2260d1180bSTaylor Simpson #include "iclass.h" 2360d1180bSTaylor Simpson #include "mmvec/mmvec.h" 2460d1180bSTaylor Simpson #include "mmvec/decode_ext_mmvec.h" 2560d1180bSTaylor Simpson 2660d1180bSTaylor Simpson static void 2760d1180bSTaylor Simpson check_new_value(Packet *pkt) 2860d1180bSTaylor Simpson { 2960d1180bSTaylor Simpson /* .new value for a MMVector store */ 3060d1180bSTaylor Simpson int i, j; 3160d1180bSTaylor Simpson const char *reginfo; 3260d1180bSTaylor Simpson const char *destletters; 3360d1180bSTaylor Simpson const char *dststr = NULL; 3460d1180bSTaylor Simpson uint16_t def_opcode; 3560d1180bSTaylor Simpson char letter; 3660d1180bSTaylor Simpson int def_regnum; 3760d1180bSTaylor Simpson 3860d1180bSTaylor Simpson for (i = 1; i < pkt->num_insns; i++) { 3960d1180bSTaylor Simpson uint16_t use_opcode = pkt->insn[i].opcode; 4060d1180bSTaylor Simpson if (GET_ATTRIB(use_opcode, A_DOTNEWVALUE) && 4160d1180bSTaylor Simpson GET_ATTRIB(use_opcode, A_CVI) && 4260d1180bSTaylor Simpson GET_ATTRIB(use_opcode, A_STORE)) { 4360d1180bSTaylor Simpson int use_regidx = strchr(opcode_reginfo[use_opcode], 's') - 4460d1180bSTaylor Simpson opcode_reginfo[use_opcode]; 4560d1180bSTaylor Simpson /* 4660d1180bSTaylor Simpson * What's encoded at the N-field is the offset to who's producing 4760d1180bSTaylor Simpson * the value. 4860d1180bSTaylor Simpson * Shift off the LSB which indicates odd/even register. 4960d1180bSTaylor Simpson */ 5060d1180bSTaylor Simpson int def_off = ((pkt->insn[i].regno[use_regidx]) >> 1); 5160d1180bSTaylor Simpson int def_oreg = pkt->insn[i].regno[use_regidx] & 1; 5260d1180bSTaylor Simpson int def_idx = -1; 5360d1180bSTaylor Simpson for (j = i - 1; (j >= 0) && (def_off >= 0); j--) { 5460d1180bSTaylor Simpson if (!GET_ATTRIB(pkt->insn[j].opcode, A_CVI)) { 5560d1180bSTaylor Simpson continue; 5660d1180bSTaylor Simpson } 5760d1180bSTaylor Simpson def_off--; 5860d1180bSTaylor Simpson if (def_off == 0) { 5960d1180bSTaylor Simpson def_idx = j; 6060d1180bSTaylor Simpson break; 6160d1180bSTaylor Simpson } 6260d1180bSTaylor Simpson } 6360d1180bSTaylor Simpson /* 6460d1180bSTaylor Simpson * Check for a badly encoded N-field which points to an instruction 6560d1180bSTaylor Simpson * out-of-range 6660d1180bSTaylor Simpson */ 6760d1180bSTaylor Simpson g_assert(!((def_off != 0) || (def_idx < 0) || 6860d1180bSTaylor Simpson (def_idx > (pkt->num_insns - 1)))); 6960d1180bSTaylor Simpson 7060d1180bSTaylor Simpson /* def_idx is the index of the producer */ 7160d1180bSTaylor Simpson def_opcode = pkt->insn[def_idx].opcode; 7260d1180bSTaylor Simpson reginfo = opcode_reginfo[def_opcode]; 7360d1180bSTaylor Simpson destletters = "dexy"; 7460d1180bSTaylor Simpson for (j = 0; (letter = destletters[j]) != 0; j++) { 7560d1180bSTaylor Simpson dststr = strchr(reginfo, letter); 7660d1180bSTaylor Simpson if (dststr != NULL) { 7760d1180bSTaylor Simpson break; 7860d1180bSTaylor Simpson } 7960d1180bSTaylor Simpson } 8060d1180bSTaylor Simpson if ((dststr == NULL) && GET_ATTRIB(def_opcode, A_CVI_GATHER)) { 8160d1180bSTaylor Simpson def_regnum = 0; 8260d1180bSTaylor Simpson pkt->insn[i].regno[use_regidx] = def_oreg; 8360d1180bSTaylor Simpson pkt->insn[i].new_value_producer_slot = pkt->insn[def_idx].slot; 8460d1180bSTaylor Simpson } else { 8560d1180bSTaylor Simpson if (dststr == NULL) { 8660d1180bSTaylor Simpson /* still not there, we have a bad packet */ 8760d1180bSTaylor Simpson g_assert_not_reached(); 8860d1180bSTaylor Simpson } 8960d1180bSTaylor Simpson def_regnum = pkt->insn[def_idx].regno[dststr - reginfo]; 9060d1180bSTaylor Simpson /* Now patch up the consumer with the register number */ 9160d1180bSTaylor Simpson pkt->insn[i].regno[use_regidx] = def_regnum ^ def_oreg; 9260d1180bSTaylor Simpson /* special case for (Vx,Vy) */ 9360d1180bSTaylor Simpson dststr = strchr(reginfo, 'y'); 9460d1180bSTaylor Simpson if (def_oreg && strchr(reginfo, 'x') && dststr) { 9560d1180bSTaylor Simpson def_regnum = pkt->insn[def_idx].regno[dststr - reginfo]; 9660d1180bSTaylor Simpson pkt->insn[i].regno[use_regidx] = def_regnum; 9760d1180bSTaylor Simpson } 9860d1180bSTaylor Simpson /* 9960d1180bSTaylor Simpson * We need to remember who produces this value to later 10060d1180bSTaylor Simpson * check if it was dynamically cancelled 10160d1180bSTaylor Simpson */ 10260d1180bSTaylor Simpson pkt->insn[i].new_value_producer_slot = pkt->insn[def_idx].slot; 10360d1180bSTaylor Simpson } 10460d1180bSTaylor Simpson } 10560d1180bSTaylor Simpson } 10660d1180bSTaylor Simpson } 10760d1180bSTaylor Simpson 10860d1180bSTaylor Simpson /* 10960d1180bSTaylor Simpson * We don't want to reorder slot1/slot0 with respect to each other. 11060d1180bSTaylor Simpson * So in our shuffling, we don't want to move the .cur / .tmp vmem earlier 11160d1180bSTaylor Simpson * Instead, we should move the producing instruction later 11260d1180bSTaylor Simpson * But the producing instruction might feed a .new store! 11360d1180bSTaylor Simpson * So we may need to move that even later. 11460d1180bSTaylor Simpson */ 11560d1180bSTaylor Simpson 11660d1180bSTaylor Simpson static void 11760d1180bSTaylor Simpson decode_mmvec_move_cvi_to_end(Packet *pkt, int max) 11860d1180bSTaylor Simpson { 11960d1180bSTaylor Simpson int i; 12060d1180bSTaylor Simpson for (i = 0; i < max; i++) { 12160d1180bSTaylor Simpson if (GET_ATTRIB(pkt->insn[i].opcode, A_CVI)) { 12260d1180bSTaylor Simpson int last_inst = pkt->num_insns - 1; 12360d1180bSTaylor Simpson uint16_t last_opcode = pkt->insn[last_inst].opcode; 12460d1180bSTaylor Simpson 12560d1180bSTaylor Simpson /* 12660d1180bSTaylor Simpson * If the last instruction is an endloop, move to the one before it 12760d1180bSTaylor Simpson * Keep endloop as the last thing always 12860d1180bSTaylor Simpson */ 12960d1180bSTaylor Simpson if ((last_opcode == J2_endloop0) || 13060d1180bSTaylor Simpson (last_opcode == J2_endloop1) || 13160d1180bSTaylor Simpson (last_opcode == J2_endloop01)) { 13260d1180bSTaylor Simpson last_inst--; 13360d1180bSTaylor Simpson } 13460d1180bSTaylor Simpson 13560d1180bSTaylor Simpson decode_send_insn_to(pkt, i, last_inst); 13660d1180bSTaylor Simpson max--; 13760d1180bSTaylor Simpson i--; /* Retry this index now that packet has rotated */ 13860d1180bSTaylor Simpson } 13960d1180bSTaylor Simpson } 14060d1180bSTaylor Simpson } 14160d1180bSTaylor Simpson 14260d1180bSTaylor Simpson static void 14360d1180bSTaylor Simpson decode_shuffle_for_execution_vops(Packet *pkt) 14460d1180bSTaylor Simpson { 14560d1180bSTaylor Simpson /* 14660d1180bSTaylor Simpson * Sort for .new 14760d1180bSTaylor Simpson */ 14860d1180bSTaylor Simpson int i; 14960d1180bSTaylor Simpson for (i = 0; i < pkt->num_insns; i++) { 15060d1180bSTaylor Simpson uint16_t opcode = pkt->insn[i].opcode; 151*3fd49e22SMarco Liebel if ((GET_ATTRIB(opcode, A_LOAD) && 152*3fd49e22SMarco Liebel GET_ATTRIB(opcode, A_CVI_NEW)) || 153*3fd49e22SMarco Liebel GET_ATTRIB(opcode, A_CVI_TMP)) { 15460d1180bSTaylor Simpson /* 15560d1180bSTaylor Simpson * Find prior consuming vector instructions 15660d1180bSTaylor Simpson * Move to end of packet 15760d1180bSTaylor Simpson */ 15860d1180bSTaylor Simpson decode_mmvec_move_cvi_to_end(pkt, i); 15960d1180bSTaylor Simpson break; 16060d1180bSTaylor Simpson } 16160d1180bSTaylor Simpson } 16260d1180bSTaylor Simpson 16360d1180bSTaylor Simpson /* Move HVX new value stores to the end of the packet */ 16460d1180bSTaylor Simpson for (i = 0; i < pkt->num_insns - 1; i++) { 16560d1180bSTaylor Simpson uint16_t opcode = pkt->insn[i].opcode; 16660d1180bSTaylor Simpson if (GET_ATTRIB(opcode, A_STORE) && 16760d1180bSTaylor Simpson GET_ATTRIB(opcode, A_CVI_NEW) && 16860d1180bSTaylor Simpson !GET_ATTRIB(opcode, A_CVI_SCATTER_RELEASE)) { 16960d1180bSTaylor Simpson int last_inst = pkt->num_insns - 1; 17060d1180bSTaylor Simpson uint16_t last_opcode = pkt->insn[last_inst].opcode; 17160d1180bSTaylor Simpson 17260d1180bSTaylor Simpson /* 17360d1180bSTaylor Simpson * If the last instruction is an endloop, move to the one before it 17460d1180bSTaylor Simpson * Keep endloop as the last thing always 17560d1180bSTaylor Simpson */ 17660d1180bSTaylor Simpson if ((last_opcode == J2_endloop0) || 17760d1180bSTaylor Simpson (last_opcode == J2_endloop1) || 17860d1180bSTaylor Simpson (last_opcode == J2_endloop01)) { 17960d1180bSTaylor Simpson last_inst--; 18060d1180bSTaylor Simpson } 18160d1180bSTaylor Simpson 18260d1180bSTaylor Simpson decode_send_insn_to(pkt, i, last_inst); 18360d1180bSTaylor Simpson break; 18460d1180bSTaylor Simpson } 18560d1180bSTaylor Simpson } 18660d1180bSTaylor Simpson } 18760d1180bSTaylor Simpson 18860d1180bSTaylor Simpson static void 18960d1180bSTaylor Simpson check_for_vhist(Packet *pkt) 19060d1180bSTaylor Simpson { 19160d1180bSTaylor Simpson pkt->vhist_insn = NULL; 19260d1180bSTaylor Simpson for (int i = 0; i < pkt->num_insns; i++) { 19360d1180bSTaylor Simpson Insn *insn = &pkt->insn[i]; 19460d1180bSTaylor Simpson int opcode = insn->opcode; 19560d1180bSTaylor Simpson if (GET_ATTRIB(opcode, A_CVI) && GET_ATTRIB(opcode, A_CVI_4SLOT)) { 19660d1180bSTaylor Simpson pkt->vhist_insn = insn; 19760d1180bSTaylor Simpson return; 19860d1180bSTaylor Simpson } 19960d1180bSTaylor Simpson } 20060d1180bSTaylor Simpson } 20160d1180bSTaylor Simpson 20260d1180bSTaylor Simpson /* 20360d1180bSTaylor Simpson * Public Functions 20460d1180bSTaylor Simpson */ 20560d1180bSTaylor Simpson 20660d1180bSTaylor Simpson SlotMask mmvec_ext_decode_find_iclass_slots(int opcode) 20760d1180bSTaylor Simpson { 20860d1180bSTaylor Simpson if (GET_ATTRIB(opcode, A_CVI_VM)) { 20960d1180bSTaylor Simpson /* HVX memory instruction */ 21060d1180bSTaylor Simpson if (GET_ATTRIB(opcode, A_RESTRICT_SLOT0ONLY)) { 21160d1180bSTaylor Simpson return SLOTS_0; 21260d1180bSTaylor Simpson } else if (GET_ATTRIB(opcode, A_RESTRICT_SLOT1ONLY)) { 21360d1180bSTaylor Simpson return SLOTS_1; 21460d1180bSTaylor Simpson } 21560d1180bSTaylor Simpson return SLOTS_01; 21660d1180bSTaylor Simpson } else if (GET_ATTRIB(opcode, A_RESTRICT_SLOT2ONLY)) { 21760d1180bSTaylor Simpson return SLOTS_2; 21860d1180bSTaylor Simpson } else if (GET_ATTRIB(opcode, A_CVI_VX)) { 21960d1180bSTaylor Simpson /* HVX multiply instruction */ 22060d1180bSTaylor Simpson return SLOTS_23; 22160d1180bSTaylor Simpson } else if (GET_ATTRIB(opcode, A_CVI_VS_VX)) { 22260d1180bSTaylor Simpson /* HVX permute/shift instruction */ 22360d1180bSTaylor Simpson return SLOTS_23; 22460d1180bSTaylor Simpson } else { 22560d1180bSTaylor Simpson return SLOTS_0123; 22660d1180bSTaylor Simpson } 22760d1180bSTaylor Simpson } 22860d1180bSTaylor Simpson 22960d1180bSTaylor Simpson void mmvec_ext_decode_checks(Packet *pkt, bool disas_only) 23060d1180bSTaylor Simpson { 23160d1180bSTaylor Simpson check_new_value(pkt); 23260d1180bSTaylor Simpson if (!disas_only) { 23360d1180bSTaylor Simpson decode_shuffle_for_execution_vops(pkt); 23460d1180bSTaylor Simpson } 23560d1180bSTaylor Simpson check_for_vhist(pkt); 23660d1180bSTaylor Simpson } 237