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
check_new_value(Packet * pkt)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
decode_mmvec_move_cvi_to_end(Packet * pkt,int max)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
decode_shuffle_for_execution_vops(Packet * pkt)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
check_for_vhist(Packet * pkt)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
mmvec_ext_decode_find_iclass_slots(int opcode)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
mmvec_ext_decode_checks(Packet * pkt,bool disas_only)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