160d1180bSTaylor Simpson /* 23fd49e22SMarco 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 uint16_t def_opcode; 3260d1180bSTaylor Simpson 3360d1180bSTaylor Simpson for (i = 1; i < pkt->num_insns; i++) { 3460d1180bSTaylor Simpson uint16_t use_opcode = pkt->insn[i].opcode; 3560d1180bSTaylor Simpson if (GET_ATTRIB(use_opcode, A_DOTNEWVALUE) && 3660d1180bSTaylor Simpson GET_ATTRIB(use_opcode, A_CVI) && 3760d1180bSTaylor Simpson GET_ATTRIB(use_opcode, A_STORE)) { 38*09a7e7dbSTaylor Simpson int use_regidx = pkt->insn[i].new_read_idx; 39*09a7e7dbSTaylor Simpson g_assert(pkt->insn[i].new_read_idx != -1); 4060d1180bSTaylor Simpson /* 4160d1180bSTaylor Simpson * What's encoded at the N-field is the offset to who's producing 4260d1180bSTaylor Simpson * the value. 4360d1180bSTaylor Simpson * Shift off the LSB which indicates odd/even register. 4460d1180bSTaylor Simpson */ 4560d1180bSTaylor Simpson int def_off = ((pkt->insn[i].regno[use_regidx]) >> 1); 4660d1180bSTaylor Simpson int def_oreg = pkt->insn[i].regno[use_regidx] & 1; 4760d1180bSTaylor Simpson int def_idx = -1; 4860d1180bSTaylor Simpson for (j = i - 1; (j >= 0) && (def_off >= 0); j--) { 4960d1180bSTaylor Simpson if (!GET_ATTRIB(pkt->insn[j].opcode, A_CVI)) { 5060d1180bSTaylor Simpson continue; 5160d1180bSTaylor Simpson } 5260d1180bSTaylor Simpson def_off--; 5360d1180bSTaylor Simpson if (def_off == 0) { 5460d1180bSTaylor Simpson def_idx = j; 5560d1180bSTaylor Simpson break; 5660d1180bSTaylor Simpson } 5760d1180bSTaylor Simpson } 5860d1180bSTaylor Simpson /* 5960d1180bSTaylor Simpson * Check for a badly encoded N-field which points to an instruction 6060d1180bSTaylor Simpson * out-of-range 6160d1180bSTaylor Simpson */ 6260d1180bSTaylor Simpson g_assert(!((def_off != 0) || (def_idx < 0) || 6360d1180bSTaylor Simpson (def_idx > (pkt->num_insns - 1)))); 6460d1180bSTaylor Simpson 6560d1180bSTaylor Simpson /* def_idx is the index of the producer */ 6660d1180bSTaylor Simpson def_opcode = pkt->insn[def_idx].opcode; 67*09a7e7dbSTaylor Simpson if ((pkt->insn[def_idx].dest_idx == -1) && 68*09a7e7dbSTaylor Simpson GET_ATTRIB(def_opcode, A_CVI_GATHER)) { 6960d1180bSTaylor Simpson pkt->insn[i].regno[use_regidx] = def_oreg; 7060d1180bSTaylor Simpson pkt->insn[i].new_value_producer_slot = pkt->insn[def_idx].slot; 7160d1180bSTaylor Simpson } else { 72*09a7e7dbSTaylor Simpson if (pkt->insn[def_idx].dest_idx == -1) { 7360d1180bSTaylor Simpson /* still not there, we have a bad packet */ 7460d1180bSTaylor Simpson g_assert_not_reached(); 7560d1180bSTaylor Simpson } 76*09a7e7dbSTaylor Simpson int def_regnum = 77*09a7e7dbSTaylor Simpson pkt->insn[def_idx].regno[pkt->insn[def_idx].dest_idx]; 7860d1180bSTaylor Simpson /* Now patch up the consumer with the register number */ 7960d1180bSTaylor Simpson pkt->insn[i].regno[use_regidx] = def_regnum ^ def_oreg; 8060d1180bSTaylor Simpson /* 8160d1180bSTaylor Simpson * We need to remember who produces this value to later 8260d1180bSTaylor Simpson * check if it was dynamically cancelled 8360d1180bSTaylor Simpson */ 8460d1180bSTaylor Simpson pkt->insn[i].new_value_producer_slot = pkt->insn[def_idx].slot; 8560d1180bSTaylor Simpson } 8660d1180bSTaylor Simpson } 8760d1180bSTaylor Simpson } 8860d1180bSTaylor Simpson } 8960d1180bSTaylor Simpson 9060d1180bSTaylor Simpson /* 9160d1180bSTaylor Simpson * We don't want to reorder slot1/slot0 with respect to each other. 9260d1180bSTaylor Simpson * So in our shuffling, we don't want to move the .cur / .tmp vmem earlier 9360d1180bSTaylor Simpson * Instead, we should move the producing instruction later 9460d1180bSTaylor Simpson * But the producing instruction might feed a .new store! 9560d1180bSTaylor Simpson * So we may need to move that even later. 9660d1180bSTaylor Simpson */ 9760d1180bSTaylor Simpson 9860d1180bSTaylor Simpson static void 9960d1180bSTaylor Simpson decode_mmvec_move_cvi_to_end(Packet *pkt, int max) 10060d1180bSTaylor Simpson { 10160d1180bSTaylor Simpson int i; 10260d1180bSTaylor Simpson for (i = 0; i < max; i++) { 10360d1180bSTaylor Simpson if (GET_ATTRIB(pkt->insn[i].opcode, A_CVI)) { 10460d1180bSTaylor Simpson int last_inst = pkt->num_insns - 1; 10560d1180bSTaylor Simpson uint16_t last_opcode = pkt->insn[last_inst].opcode; 10660d1180bSTaylor Simpson 10760d1180bSTaylor Simpson /* 10860d1180bSTaylor Simpson * If the last instruction is an endloop, move to the one before it 10960d1180bSTaylor Simpson * Keep endloop as the last thing always 11060d1180bSTaylor Simpson */ 11160d1180bSTaylor Simpson if ((last_opcode == J2_endloop0) || 11260d1180bSTaylor Simpson (last_opcode == J2_endloop1) || 11360d1180bSTaylor Simpson (last_opcode == J2_endloop01)) { 11460d1180bSTaylor Simpson last_inst--; 11560d1180bSTaylor Simpson } 11660d1180bSTaylor Simpson 11760d1180bSTaylor Simpson decode_send_insn_to(pkt, i, last_inst); 11860d1180bSTaylor Simpson max--; 11960d1180bSTaylor Simpson i--; /* Retry this index now that packet has rotated */ 12060d1180bSTaylor Simpson } 12160d1180bSTaylor Simpson } 12260d1180bSTaylor Simpson } 12360d1180bSTaylor Simpson 12460d1180bSTaylor Simpson static void 12560d1180bSTaylor Simpson decode_shuffle_for_execution_vops(Packet *pkt) 12660d1180bSTaylor Simpson { 12760d1180bSTaylor Simpson /* 12860d1180bSTaylor Simpson * Sort for .new 12960d1180bSTaylor Simpson */ 13060d1180bSTaylor Simpson int i; 13160d1180bSTaylor Simpson for (i = 0; i < pkt->num_insns; i++) { 13260d1180bSTaylor Simpson uint16_t opcode = pkt->insn[i].opcode; 1333fd49e22SMarco Liebel if ((GET_ATTRIB(opcode, A_LOAD) && 1343fd49e22SMarco Liebel GET_ATTRIB(opcode, A_CVI_NEW)) || 1353fd49e22SMarco Liebel GET_ATTRIB(opcode, A_CVI_TMP)) { 13660d1180bSTaylor Simpson /* 13760d1180bSTaylor Simpson * Find prior consuming vector instructions 13860d1180bSTaylor Simpson * Move to end of packet 13960d1180bSTaylor Simpson */ 14060d1180bSTaylor Simpson decode_mmvec_move_cvi_to_end(pkt, i); 14160d1180bSTaylor Simpson break; 14260d1180bSTaylor Simpson } 14360d1180bSTaylor Simpson } 14460d1180bSTaylor Simpson 14560d1180bSTaylor Simpson /* Move HVX new value stores to the end of the packet */ 14660d1180bSTaylor Simpson for (i = 0; i < pkt->num_insns - 1; i++) { 14760d1180bSTaylor Simpson uint16_t opcode = pkt->insn[i].opcode; 14860d1180bSTaylor Simpson if (GET_ATTRIB(opcode, A_STORE) && 14960d1180bSTaylor Simpson GET_ATTRIB(opcode, A_CVI_NEW) && 15060d1180bSTaylor Simpson !GET_ATTRIB(opcode, A_CVI_SCATTER_RELEASE)) { 15160d1180bSTaylor Simpson int last_inst = pkt->num_insns - 1; 15260d1180bSTaylor Simpson uint16_t last_opcode = pkt->insn[last_inst].opcode; 15360d1180bSTaylor Simpson 15460d1180bSTaylor Simpson /* 15560d1180bSTaylor Simpson * If the last instruction is an endloop, move to the one before it 15660d1180bSTaylor Simpson * Keep endloop as the last thing always 15760d1180bSTaylor Simpson */ 15860d1180bSTaylor Simpson if ((last_opcode == J2_endloop0) || 15960d1180bSTaylor Simpson (last_opcode == J2_endloop1) || 16060d1180bSTaylor Simpson (last_opcode == J2_endloop01)) { 16160d1180bSTaylor Simpson last_inst--; 16260d1180bSTaylor Simpson } 16360d1180bSTaylor Simpson 16460d1180bSTaylor Simpson decode_send_insn_to(pkt, i, last_inst); 16560d1180bSTaylor Simpson break; 16660d1180bSTaylor Simpson } 16760d1180bSTaylor Simpson } 16860d1180bSTaylor Simpson } 16960d1180bSTaylor Simpson 17060d1180bSTaylor Simpson static void 17160d1180bSTaylor Simpson check_for_vhist(Packet *pkt) 17260d1180bSTaylor Simpson { 17360d1180bSTaylor Simpson pkt->vhist_insn = NULL; 17460d1180bSTaylor Simpson for (int i = 0; i < pkt->num_insns; i++) { 17560d1180bSTaylor Simpson Insn *insn = &pkt->insn[i]; 17660d1180bSTaylor Simpson int opcode = insn->opcode; 17760d1180bSTaylor Simpson if (GET_ATTRIB(opcode, A_CVI) && GET_ATTRIB(opcode, A_CVI_4SLOT)) { 17860d1180bSTaylor Simpson pkt->vhist_insn = insn; 17960d1180bSTaylor Simpson return; 18060d1180bSTaylor Simpson } 18160d1180bSTaylor Simpson } 18260d1180bSTaylor Simpson } 18360d1180bSTaylor Simpson 18460d1180bSTaylor Simpson /* 18560d1180bSTaylor Simpson * Public Functions 18660d1180bSTaylor Simpson */ 18760d1180bSTaylor Simpson 18860d1180bSTaylor Simpson SlotMask mmvec_ext_decode_find_iclass_slots(int opcode) 18960d1180bSTaylor Simpson { 19060d1180bSTaylor Simpson if (GET_ATTRIB(opcode, A_CVI_VM)) { 19160d1180bSTaylor Simpson /* HVX memory instruction */ 19260d1180bSTaylor Simpson if (GET_ATTRIB(opcode, A_RESTRICT_SLOT0ONLY)) { 19360d1180bSTaylor Simpson return SLOTS_0; 19460d1180bSTaylor Simpson } else if (GET_ATTRIB(opcode, A_RESTRICT_SLOT1ONLY)) { 19560d1180bSTaylor Simpson return SLOTS_1; 19660d1180bSTaylor Simpson } 19760d1180bSTaylor Simpson return SLOTS_01; 19860d1180bSTaylor Simpson } else if (GET_ATTRIB(opcode, A_RESTRICT_SLOT2ONLY)) { 19960d1180bSTaylor Simpson return SLOTS_2; 20060d1180bSTaylor Simpson } else if (GET_ATTRIB(opcode, A_CVI_VX)) { 20160d1180bSTaylor Simpson /* HVX multiply instruction */ 20260d1180bSTaylor Simpson return SLOTS_23; 20360d1180bSTaylor Simpson } else if (GET_ATTRIB(opcode, A_CVI_VS_VX)) { 20460d1180bSTaylor Simpson /* HVX permute/shift instruction */ 20560d1180bSTaylor Simpson return SLOTS_23; 20660d1180bSTaylor Simpson } else { 20760d1180bSTaylor Simpson return SLOTS_0123; 20860d1180bSTaylor Simpson } 20960d1180bSTaylor Simpson } 21060d1180bSTaylor Simpson 21160d1180bSTaylor Simpson void mmvec_ext_decode_checks(Packet *pkt, bool disas_only) 21260d1180bSTaylor Simpson { 21360d1180bSTaylor Simpson check_new_value(pkt); 21460d1180bSTaylor Simpson if (!disas_only) { 21560d1180bSTaylor Simpson decode_shuffle_for_execution_vops(pkt); 21660d1180bSTaylor Simpson } 21760d1180bSTaylor Simpson check_for_vhist(pkt); 21860d1180bSTaylor Simpson } 219