2 * Copyright(c) 2019-2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include "qemu/osdep.h"
24 #include "printinsn.h"
25 #include "mmvec/decode_ext_mmvec.h"
27 #define fZXTN(N, M, VAL) ((VAL) & ((1LL << (N)) - 1))
31 EXT_IDX_noext_AFTER
= 4,
33 EXT_IDX_mmvec_AFTER
= 8,
38 * Certain operand types represent a non-contiguous set of values.
39 * For example, the compound compare-and-jump instruction can only access
40 * registers R0-R7 and R16-23.
41 * This table represents the mapping from the encoding to the actual values.
44 #define DEF_REGMAP(NAME, ELEMENTS, ...) \
45 static const unsigned int DECODE_REGISTER_##NAME[ELEMENTS] = \
48 DEF_REGMAP(R_16
, 16, 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23)
49 DEF_REGMAP(R__8
, 8, 0, 2, 4, 6, 16, 18, 20, 22)
50 DEF_REGMAP(R_8
, 8, 0, 1, 2, 3, 4, 5, 6, 7)
52 #define DECODE_MAPPED_REG(OPNUM, NAME) \
53 insn->regno[OPNUM] = DECODE_REGISTER_##NAME[insn->regno[OPNUM]];
56 const struct DectreeTable
*table_link
;
57 const struct DectreeTable
*table_link_b
;
60 DECTREE_ENTRY_INVALID
,
68 typedef struct DectreeTable
{
69 unsigned int (*lookup_function
)(int startbit
, int width
, uint32_t opcode
);
71 unsigned int startbit
;
73 const DectreeEntry table
[];
76 #define DECODE_NEW_TABLE(TAG, SIZE, WHATNOT) \
77 static const DectreeTable dectree_table_##TAG;
78 #define TABLE_LINK(TABLE) /* NOTHING */
79 #define TERMINAL(TAG, ENC) /* NOTHING */
80 #define SUBINSNS(TAG, CLASSA, CLASSB, ENC) /* NOTHING */
81 #define EXTSPACE(TAG, ENC) /* NOTHING */
82 #define INVALID() /* NOTHING */
83 #define DECODE_END_TABLE(...) /* NOTHING */
84 #define DECODE_MATCH_INFO(...) /* NOTHING */
85 #define DECODE_LEGACY_MATCH_INFO(...) /* NOTHING */
86 #define DECODE_OPINFO(...) /* NOTHING */
88 #include "dectree_generated.h.inc"
91 #undef DECODE_MATCH_INFO
92 #undef DECODE_LEGACY_MATCH_INFO
93 #undef DECODE_END_TABLE
99 #undef DECODE_NEW_TABLE
100 #undef DECODE_SEPARATOR_BITS
102 #define DECODE_SEPARATOR_BITS(START, WIDTH) NULL, START, WIDTH
103 #define DECODE_NEW_TABLE_HELPER(TAG, SIZE, FN, START, WIDTH) \
104 static const DectreeTable dectree_table_##TAG = { \
106 .lookup_function = FN, \
110 #define DECODE_NEW_TABLE(TAG, SIZE, WHATNOT) \
111 DECODE_NEW_TABLE_HELPER(TAG, SIZE, WHATNOT)
113 #define TABLE_LINK(TABLE) \
114 { .type = DECTREE_TABLE_LINK, .table_link = &dectree_table_##TABLE },
115 #define TERMINAL(TAG, ENC) \
116 { .type = DECTREE_TERMINAL, .opcode = TAG },
117 #define SUBINSNS(TAG, CLASSA, CLASSB, ENC) \
119 .type = DECTREE_SUBINSNS, \
120 .table_link = &dectree_table_DECODE_SUBINSN_##CLASSA, \
121 .table_link_b = &dectree_table_DECODE_SUBINSN_##CLASSB \
123 #define EXTSPACE(TAG, ENC) { .type = DECTREE_EXTSPACE },
124 #define INVALID() { .type = DECTREE_ENTRY_INVALID, .opcode = XX_LAST_OPCODE },
126 #define DECODE_END_TABLE(...) } };
128 #define DECODE_MATCH_INFO(...) /* NOTHING */
129 #define DECODE_LEGACY_MATCH_INFO(...) /* NOTHING */
130 #define DECODE_OPINFO(...) /* NOTHING */
132 #include "dectree_generated.h.inc"
135 #undef DECODE_MATCH_INFO
136 #undef DECODE_LEGACY_MATCH_INFO
137 #undef DECODE_END_TABLE
143 #undef DECODE_NEW_TABLE
144 #undef DECODE_NEW_TABLE_HELPER
145 #undef DECODE_SEPARATOR_BITS
147 static const DectreeTable dectree_table_DECODE_EXT_EXT_noext
= {
148 .size
= 1, .lookup_function
= NULL
, .startbit
= 0, .width
= 0,
150 { .type
= DECTREE_ENTRY_INVALID
, .opcode
= XX_LAST_OPCODE
},
154 static const DectreeTable
*ext_trees
[XX_LAST_EXT_IDX
];
156 static void decode_ext_init(void)
159 for (i
= EXT_IDX_noext
; i
< EXT_IDX_noext_AFTER
; i
++) {
160 ext_trees
[i
] = &dectree_table_DECODE_EXT_EXT_noext
;
162 for (i
= EXT_IDX_mmvec
; i
< EXT_IDX_mmvec_AFTER
; i
++) {
163 ext_trees
[i
] = &dectree_table_DECODE_EXT_EXT_mmvec
;
172 #define DECODE_NEW_TABLE(TAG, SIZE, WHATNOT) /* NOTHING */
173 #define TABLE_LINK(TABLE) /* NOTHING */
174 #define TERMINAL(TAG, ENC) /* NOTHING */
175 #define SUBINSNS(TAG, CLASSA, CLASSB, ENC) /* NOTHING */
176 #define EXTSPACE(TAG, ENC) /* NOTHING */
177 #define INVALID() /* NOTHING */
178 #define DECODE_END_TABLE(...) /* NOTHING */
179 #define DECODE_OPINFO(...) /* NOTHING */
181 #define DECODE_MATCH_INFO_NORMAL(TAG, MASK, MATCH) \
187 #define DECODE_MATCH_INFO_NULL(TAG, MASK, MATCH) \
188 [TAG] = { .match = ~0 },
190 #define DECODE_MATCH_INFO(...) DECODE_MATCH_INFO_NORMAL(__VA_ARGS__)
191 #define DECODE_LEGACY_MATCH_INFO(...) /* NOTHING */
193 static const DecodeITableEntry decode_itable
[XX_LAST_OPCODE
] = {
194 #include "dectree_generated.h.inc"
197 #undef DECODE_MATCH_INFO
198 #define DECODE_MATCH_INFO(...) DECODE_MATCH_INFO_NULL(__VA_ARGS__)
200 #undef DECODE_LEGACY_MATCH_INFO
201 #define DECODE_LEGACY_MATCH_INFO(...) DECODE_MATCH_INFO_NORMAL(__VA_ARGS__)
203 static const DecodeITableEntry decode_legacy_itable
[XX_LAST_OPCODE
] = {
204 #include "dectree_generated.h.inc"
208 #undef DECODE_MATCH_INFO
209 #undef DECODE_LEGACY_MATCH_INFO
210 #undef DECODE_END_TABLE
216 #undef DECODE_NEW_TABLE
217 #undef DECODE_SEPARATOR_BITS
219 void decode_init(void)
224 void decode_send_insn_to(Packet
*packet
, int start
, int newloc
)
229 if (start
== newloc
) {
232 if (start
< newloc
) {
233 /* Move towards end */
236 /* move towards beginning */
239 for (i
= start
; i
!= newloc
; i
+= direction
) {
240 tmpinsn
= packet
->insn
[i
];
241 packet
->insn
[i
] = packet
->insn
[i
+ direction
];
242 packet
->insn
[i
+ direction
] = tmpinsn
;
246 /* Fill newvalue registers with the correct regno */
248 decode_fill_newvalue_regno(Packet
*packet
)
250 int i
, use_regidx
, offset
, def_idx
, dst_idx
;
251 uint16_t def_opcode
, use_opcode
;
254 for (i
= 1; i
< packet
->num_insns
; i
++) {
255 if (GET_ATTRIB(packet
->insn
[i
].opcode
, A_DOTNEWVALUE
) &&
256 !GET_ATTRIB(packet
->insn
[i
].opcode
, A_EXTENSION
)) {
257 use_opcode
= packet
->insn
[i
].opcode
;
259 /* It's a store, so we're adjusting the Nt field */
260 if (GET_ATTRIB(use_opcode
, A_STORE
)) {
261 use_regidx
= strchr(opcode_reginfo
[use_opcode
], 't') -
262 opcode_reginfo
[use_opcode
];
263 } else { /* It's a Jump, so we're adjusting the Ns field */
264 use_regidx
= strchr(opcode_reginfo
[use_opcode
], 's') -
265 opcode_reginfo
[use_opcode
];
269 * What's encoded at the N-field is the offset to who's producing
270 * the value. Shift off the LSB which indicates odd/even register,
271 * then walk backwards and skip over the constant extenders.
273 offset
= packet
->insn
[i
].regno
[use_regidx
] >> 1;
274 def_idx
= i
- offset
;
275 for (int j
= 0; j
< offset
; j
++) {
276 if (GET_ATTRIB(packet
->insn
[i
- j
- 1].opcode
, A_IT_EXTENDER
)) {
282 * Check for a badly encoded N-field which points to an instruction
285 g_assert(!((def_idx
< 0) || (def_idx
> (packet
->num_insns
- 1))));
288 * packet->insn[def_idx] is the producer
289 * Figure out which type of destination it produces
290 * and the corresponding index in the reginfo
292 def_opcode
= packet
->insn
[def_idx
].opcode
;
293 dststr
= strstr(opcode_wregs
[def_opcode
], "Rd");
295 dststr
= strchr(opcode_reginfo
[def_opcode
], 'd');
297 dststr
= strstr(opcode_wregs
[def_opcode
], "Rx");
299 dststr
= strchr(opcode_reginfo
[def_opcode
], 'x');
301 dststr
= strstr(opcode_wregs
[def_opcode
], "Re");
303 dststr
= strchr(opcode_reginfo
[def_opcode
], 'e');
305 dststr
= strstr(opcode_wregs
[def_opcode
], "Ry");
307 dststr
= strchr(opcode_reginfo
[def_opcode
], 'y');
309 g_assert_not_reached();
314 g_assert(dststr
!= NULL
);
316 /* Now patch up the consumer with the register number */
317 dst_idx
= dststr
- opcode_reginfo
[def_opcode
];
318 packet
->insn
[i
].regno
[use_regidx
] =
319 packet
->insn
[def_idx
].regno
[dst_idx
];
321 * We need to remember who produces this value to later
322 * check if it was dynamically cancelled
324 packet
->insn
[i
].new_value_producer_slot
=
325 packet
->insn
[def_idx
].slot
;
330 /* Split CJ into a compare and a jump */
331 static void decode_split_cmpjump(Packet
*pkt
)
334 int numinsns
= pkt
->num_insns
;
337 * First, split all compare-jumps.
338 * The compare is sent to the end as a new instruction.
339 * Do it this way so we don't reorder dual jumps. Those need to stay in
342 for (i
= 0; i
< numinsns
; i
++) {
343 /* It's a cmp-jump */
344 if (GET_ATTRIB(pkt
->insn
[i
].opcode
, A_NEWCMPJUMP
)) {
345 last
= pkt
->num_insns
;
346 pkt
->insn
[last
] = pkt
->insn
[i
]; /* copy the instruction */
347 pkt
->insn
[last
].part1
= true; /* last insn does the CMP */
348 pkt
->insn
[i
].part1
= false; /* existing insn does the JUMP */
353 /* Now re-shuffle all the compares back to the beginning */
354 for (i
= 0; i
< pkt
->num_insns
; i
++) {
355 if (pkt
->insn
[i
].part1
) {
356 decode_send_insn_to(pkt
, i
, 0);
361 static bool decode_opcode_can_jump(int opcode
)
363 if ((GET_ATTRIB(opcode
, A_JUMP
)) ||
364 (GET_ATTRIB(opcode
, A_CALL
)) ||
365 (opcode
== J2_trap0
) ||
366 (opcode
== J2_pause
)) {
367 /* Exception to A_JUMP attribute */
368 if (opcode
== J4_hintjumpr
) {
377 static bool decode_opcode_ends_loop(int opcode
)
379 return GET_ATTRIB(opcode
, A_HWLOOP0_END
) ||
380 GET_ATTRIB(opcode
, A_HWLOOP1_END
);
383 /* Set the is_* fields in each instruction */
384 static void decode_set_insn_attr_fields(Packet
*pkt
)
387 int numinsns
= pkt
->num_insns
;
390 pkt
->pkt_has_cof
= false;
391 pkt
->pkt_has_multi_cof
= false;
392 pkt
->pkt_has_endloop
= false;
393 pkt
->pkt_has_dczeroa
= false;
395 for (i
= 0; i
< numinsns
; i
++) {
396 opcode
= pkt
->insn
[i
].opcode
;
397 if (pkt
->insn
[i
].part1
) {
398 continue; /* Skip compare of cmp-jumps */
401 if (GET_ATTRIB(opcode
, A_DCZEROA
)) {
402 pkt
->pkt_has_dczeroa
= true;
405 if (GET_ATTRIB(opcode
, A_STORE
)) {
406 if (GET_ATTRIB(opcode
, A_SCALAR_STORE
) &&
407 !GET_ATTRIB(opcode
, A_MEMSIZE_0B
)) {
408 if (pkt
->insn
[i
].slot
== 0) {
409 pkt
->pkt_has_store_s0
= true;
411 pkt
->pkt_has_store_s1
= true;
416 if (decode_opcode_can_jump(opcode
)) {
417 if (pkt
->pkt_has_cof
) {
418 pkt
->pkt_has_multi_cof
= true;
420 pkt
->pkt_has_cof
= true;
423 pkt
->insn
[i
].is_endloop
= decode_opcode_ends_loop(opcode
);
425 pkt
->pkt_has_endloop
|= pkt
->insn
[i
].is_endloop
;
427 if (pkt
->pkt_has_endloop
) {
428 if (pkt
->pkt_has_cof
) {
429 pkt
->pkt_has_multi_cof
= true;
431 pkt
->pkt_has_cof
= true;
437 * Shuffle for execution
438 * Move stores to end (in same order as encoding)
439 * Move compares to beginning (for use by .new insns)
441 static void decode_shuffle_for_execution(Packet
*packet
)
443 bool changed
= false;
445 bool flag
; /* flag means we've seen a non-memory instruction */
447 int last_insn
= packet
->num_insns
- 1;
450 * Skip end loops, somehow an end loop is getting in and messing
453 if (decode_opcode_ends_loop(packet
->insn
[last_insn
].opcode
)) {
460 * Stores go last, must not reorder.
461 * Cannot shuffle stores past loads, either.
462 * Iterate backwards. If we see a non-memory instruction,
463 * then a store, shuffle the store to the front. Don't shuffle
464 * stores wrt each other or a load.
466 for (flag
= false, n_mems
= 0, i
= last_insn
; i
>= 0; i
--) {
467 int opcode
= packet
->insn
[i
].opcode
;
469 if (flag
&& GET_ATTRIB(opcode
, A_STORE
)) {
470 decode_send_insn_to(packet
, i
, last_insn
- n_mems
);
473 } else if (GET_ATTRIB(opcode
, A_STORE
)) {
475 } else if (GET_ATTRIB(opcode
, A_LOAD
)) {
477 * Don't set flag, since we don't want to shuffle a
481 } else if (GET_ATTRIB(opcode
, A_DOTNEWVALUE
)) {
483 * Don't set flag, since we don't want to shuffle past
494 /* Compares go first, may be reordered wrt each other */
495 for (flag
= false, i
= 0; i
< last_insn
+ 1; i
++) {
496 int opcode
= packet
->insn
[i
].opcode
;
498 if ((strstr(opcode_wregs
[opcode
], "Pd4") ||
499 strstr(opcode_wregs
[opcode
], "Pe4")) &&
500 GET_ATTRIB(opcode
, A_STORE
) == 0) {
501 /* This should be a compare (not a store conditional) */
503 decode_send_insn_to(packet
, i
, 0);
507 } else if (GET_ATTRIB(opcode
, A_IMPLICIT_WRITES_P3
) &&
508 !decode_opcode_ends_loop(packet
->insn
[i
].opcode
)) {
510 * spNloop instruction
511 * Don't reorder endloops; they are not valid for .new uses,
512 * and we want to match HW
515 decode_send_insn_to(packet
, i
, 0);
519 } else if (GET_ATTRIB(opcode
, A_IMPLICIT_WRITES_P0
) &&
520 !GET_ATTRIB(opcode
, A_NEWCMPJUMP
)) {
522 decode_send_insn_to(packet
, i
, 0);
536 * If we have a .new register compare/branch, move that to the very
537 * very end, past stores
539 for (i
= 0; i
< last_insn
; i
++) {
540 if (GET_ATTRIB(packet
->insn
[i
].opcode
, A_DOTNEWVALUE
)) {
541 decode_send_insn_to(packet
, i
, last_insn
);
548 apply_extender(Packet
*pkt
, int i
, uint32_t extender
)
553 immed_num
= opcode_which_immediate_is_extended(pkt
->insn
[i
].opcode
);
554 base_immed
= pkt
->insn
[i
].immed
[immed_num
];
556 pkt
->insn
[i
].immed
[immed_num
] = extender
| fZXTN(6, 32, base_immed
);
559 static void decode_apply_extenders(Packet
*packet
)
562 for (i
= 0; i
< packet
->num_insns
; i
++) {
563 if (GET_ATTRIB(packet
->insn
[i
].opcode
, A_IT_EXTENDER
)) {
564 packet
->insn
[i
+ 1].extension_valid
= true;
565 apply_extender(packet
, i
+ 1, packet
->insn
[i
].immed
[0]);
570 static void decode_remove_extenders(Packet
*packet
)
573 for (i
= 0; i
< packet
->num_insns
; i
++) {
574 if (GET_ATTRIB(packet
->insn
[i
].opcode
, A_IT_EXTENDER
)) {
575 /* Remove this one by moving the remaining instructions down */
577 (j
< packet
->num_insns
- 1) && (j
< INSTRUCTIONS_MAX
- 1);
579 packet
->insn
[j
] = packet
->insn
[j
+ 1];
586 static SlotMask
get_valid_slots(const Packet
*pkt
, unsigned int slot
)
588 if (GET_ATTRIB(pkt
->insn
[slot
].opcode
, A_EXTENSION
)) {
589 return mmvec_ext_decode_find_iclass_slots(pkt
->insn
[slot
].opcode
);
591 return find_iclass_slots(pkt
->insn
[slot
].opcode
,
592 pkt
->insn
[slot
].iclass
);
596 #define DECODE_NEW_TABLE(TAG, SIZE, WHATNOT) /* NOTHING */
597 #define TABLE_LINK(TABLE) /* NOTHING */
598 #define TERMINAL(TAG, ENC) /* NOTHING */
599 #define SUBINSNS(TAG, CLASSA, CLASSB, ENC) /* NOTHING */
600 #define EXTSPACE(TAG, ENC) /* NOTHING */
601 #define INVALID() /* NOTHING */
602 #define DECODE_END_TABLE(...) /* NOTHING */
603 #define DECODE_MATCH_INFO(...) /* NOTHING */
604 #define DECODE_LEGACY_MATCH_INFO(...) /* NOTHING */
606 #define DECODE_REG(REGNO, WIDTH, STARTBIT) \
607 insn->regno[REGNO] = ((encoding >> STARTBIT) & ((1 << WIDTH) - 1));
609 #define DECODE_IMPL_REG(REGNO, VAL) \
610 insn->regno[REGNO] = VAL;
612 #define DECODE_IMM(IMMNO, WIDTH, STARTBIT, VALSTART) \
613 insn->immed[IMMNO] |= (((encoding >> STARTBIT) & ((1 << WIDTH) - 1))) << \
616 #define DECODE_IMM_SXT(IMMNO, WIDTH) \
617 insn->immed[IMMNO] = ((((int32_t)insn->immed[IMMNO]) << (32 - WIDTH)) >> \
620 #define DECODE_IMM_NEG(IMMNO, WIDTH) \
621 insn->immed[IMMNO] = -insn->immed[IMMNO];
623 #define DECODE_IMM_SHIFT(IMMNO, SHAMT) \
624 if ((!insn->extension_valid) || \
625 (insn->which_extended != IMMNO)) { \
626 insn->immed[IMMNO] <<= SHAMT; \
629 #define DECODE_OPINFO(TAG, BEH) \
635 * Fill in the operands of the instruction
636 * dectree_generated.h.inc has a DECODE_OPINFO entry for each opcode
638 * DECODE_OPINFO(A2_addi,
641 * DECODE_IMM(0,7,21,9)
642 * DECODE_IMM(0,9,5,0)
643 * DECODE_IMM_SXT(0,16)
644 * with the macros defined above, we'll fill in a switch statement
645 * where each case is an opcode tag.
648 decode_op(Insn
*insn
, Opcode tag
, uint32_t encoding
)
653 if (insn
->extension_valid
) {
654 insn
->which_extended
= opcode_which_immediate_is_extended(tag
);
658 #include "dectree_generated.h.inc"
663 insn
->generate
= opcode_genptr
[tag
];
665 insn
->iclass
= iclass_bits(encoding
);
669 #undef DECODE_IMPL_REG
671 #undef DECODE_IMM_SHIFT
673 #undef DECODE_MATCH_INFO
674 #undef DECODE_LEGACY_MATCH_INFO
675 #undef DECODE_END_TABLE
681 #undef DECODE_NEW_TABLE
682 #undef DECODE_SEPARATOR_BITS
685 decode_subinsn_tablewalk(Insn
*insn
, const DectreeTable
*table
,
690 if (table
->lookup_function
) {
691 i
= table
->lookup_function(table
->startbit
, table
->width
, encoding
);
693 i
= extract32(encoding
, table
->startbit
, table
->width
);
695 if (table
->table
[i
].type
== DECTREE_TABLE_LINK
) {
696 return decode_subinsn_tablewalk(insn
, table
->table
[i
].table_link
,
698 } else if (table
->table
[i
].type
== DECTREE_TERMINAL
) {
699 opc
= table
->table
[i
].opcode
;
700 if ((encoding
& decode_itable
[opc
].mask
) != decode_itable
[opc
].match
) {
703 decode_op(insn
, opc
, encoding
);
710 static unsigned int get_insn_a(uint32_t encoding
)
712 return extract32(encoding
, 0, 13);
715 static unsigned int get_insn_b(uint32_t encoding
)
717 return extract32(encoding
, 16, 13);
721 decode_insns_tablewalk(Insn
*insn
, const DectreeTable
*table
,
727 if (table
->lookup_function
) {
728 i
= table
->lookup_function(table
->startbit
, table
->width
, encoding
);
730 i
= extract32(encoding
, table
->startbit
, table
->width
);
732 if (table
->table
[i
].type
== DECTREE_TABLE_LINK
) {
733 return decode_insns_tablewalk(insn
, table
->table
[i
].table_link
,
735 } else if (table
->table
[i
].type
== DECTREE_SUBINSNS
) {
736 a
= get_insn_a(encoding
);
737 b
= get_insn_b(encoding
);
738 b
= decode_subinsn_tablewalk(insn
, table
->table
[i
].table_link_b
, b
);
739 a
= decode_subinsn_tablewalk(insn
+ 1, table
->table
[i
].table_link
, a
);
740 if ((a
== 0) || (b
== 0)) {
744 } else if (table
->table
[i
].type
== DECTREE_TERMINAL
) {
745 opc
= table
->table
[i
].opcode
;
746 if ((encoding
& decode_itable
[opc
].mask
) != decode_itable
[opc
].match
) {
747 if ((encoding
& decode_legacy_itable
[opc
].mask
) !=
748 decode_legacy_itable
[opc
].match
) {
752 decode_op(insn
, opc
, encoding
);
754 } else if (table
->table
[i
].type
== DECTREE_EXTSPACE
) {
756 * For now, HVX will be the only coproc
758 return decode_insns_tablewalk(insn
, ext_trees
[EXT_IDX_mmvec
], encoding
);
765 decode_insns(Insn
*insn
, uint32_t encoding
)
767 const DectreeTable
*table
;
768 if (parse_bits(encoding
) != 0) {
769 /* Start with PP table - 32 bit instructions */
770 table
= &dectree_table_DECODE_ROOT_32
;
772 /* start with EE table - duplex instructions */
773 table
= &dectree_table_DECODE_ROOT_EE
;
775 return decode_insns_tablewalk(insn
, table
, encoding
);
778 static void decode_add_endloop_insn(Insn
*insn
, int loopnum
)
781 insn
->opcode
= J2_endloop01
;
782 insn
->generate
= opcode_genptr
[J2_endloop01
];
783 } else if (loopnum
== 1) {
784 insn
->opcode
= J2_endloop1
;
785 insn
->generate
= opcode_genptr
[J2_endloop1
];
786 } else if (loopnum
== 0) {
787 insn
->opcode
= J2_endloop0
;
788 insn
->generate
= opcode_genptr
[J2_endloop0
];
790 g_assert_not_reached();
794 static bool decode_parsebits_is_loopend(uint32_t encoding32
)
796 uint32_t bits
= parse_bits(encoding32
);
801 decode_set_slot_number(Packet
*pkt
)
805 bool hit_mem_insn
= false;
806 bool hit_duplex
= false;
807 bool slot0_found
= false;
808 bool slot1_found
= false;
812 * The slots are encoded in reverse order
813 * For each instruction, count down until you find a suitable slot
815 for (i
= 0, slot
= 3; i
< pkt
->num_insns
; i
++) {
816 SlotMask valid_slots
= get_valid_slots(pkt
, i
);
818 while (!(valid_slots
& (1 << slot
))) {
821 pkt
->insn
[i
].slot
= slot
;
823 /* I've assigned the slot, now decrement it for the next insn */
828 /* Fix the exceptions - mem insns to slot 0,1 */
829 for (i
= pkt
->num_insns
- 1; i
>= 0; i
--) {
830 /* First memory instruction always goes to slot 0 */
831 if ((GET_ATTRIB(pkt
->insn
[i
].opcode
, A_MEMLIKE
) ||
832 GET_ATTRIB(pkt
->insn
[i
].opcode
, A_MEMLIKE_PACKET_RULES
)) &&
835 pkt
->insn
[i
].slot
= 0;
839 /* Next memory instruction always goes to slot 1 */
840 if ((GET_ATTRIB(pkt
->insn
[i
].opcode
, A_MEMLIKE
) ||
841 GET_ATTRIB(pkt
->insn
[i
].opcode
, A_MEMLIKE_PACKET_RULES
)) &&
843 pkt
->insn
[i
].slot
= 1;
847 /* Fix the exceptions - duplex always slot 0,1 */
848 for (i
= pkt
->num_insns
- 1; i
>= 0; i
--) {
849 /* First subinsn always goes to slot 0 */
850 if (GET_ATTRIB(pkt
->insn
[i
].opcode
, A_SUBINSN
) && !hit_duplex
) {
852 pkt
->insn
[i
].slot
= 0;
856 /* Next subinsn always goes to slot 1 */
857 if (GET_ATTRIB(pkt
->insn
[i
].opcode
, A_SUBINSN
) && hit_duplex
) {
858 pkt
->insn
[i
].slot
= 1;
862 /* Fix the exceptions - slot 1 is never empty, always aligns to slot 0 */
863 for (i
= pkt
->num_insns
- 1; i
>= 0; i
--) {
865 if (pkt
->insn
[i
].slot
== 0) {
866 bool is_endloop
= (pkt
->insn
[i
].opcode
== J2_endloop01
);
867 is_endloop
|= (pkt
->insn
[i
].opcode
== J2_endloop0
);
868 is_endloop
|= (pkt
->insn
[i
].opcode
== J2_endloop1
);
871 * Make sure it's not endloop since, we're overloading
879 if (pkt
->insn
[i
].slot
== 1) {
884 /* Is slot0 empty and slot1 used? */
885 if ((!slot0_found
) && slot1_found
) {
886 /* Then push it to slot0 */
887 pkt
->insn
[slot1_iidx
].slot
= 0;
893 * Decodes packet with given words
894 * Returns 0 on insufficient words,
895 * or number of words used on success
898 int decode_packet(int max_words
, const uint32_t *words
, Packet
*pkt
,
903 bool end_of_packet
= false;
909 memset(pkt
, 0, sizeof(*pkt
));
910 /* Try to build packet */
911 while (!end_of_packet
&& (words_read
< max_words
)) {
912 encoding32
= words
[words_read
];
913 end_of_packet
= is_packet_end(encoding32
);
914 new_insns
= decode_insns(&pkt
->insn
[num_insns
], encoding32
);
915 g_assert(new_insns
> 0);
917 * If we saw an extender, mark next word extended so immediate
920 if (pkt
->insn
[num_insns
].opcode
== A4_ext
) {
921 pkt
->insn
[num_insns
+ 1].extension_valid
= true;
923 num_insns
+= new_insns
;
927 pkt
->num_insns
= num_insns
;
928 if (!end_of_packet
) {
929 /* Ran out of words! */
932 pkt
->encod_pkt_size_in_bytes
= words_read
* 4;
933 pkt
->pkt_has_hvx
= false;
934 for (i
= 0; i
< num_insns
; i
++) {
936 GET_ATTRIB(pkt
->insn
[i
].opcode
, A_CVI
);
940 * Check for :endloop in the parse bits
941 * Section 10.6 of the Programmer's Reference describes the encoding
942 * The end of hardware loop 0 can be encoded with 2 words
943 * The end of hardware loop 1 needs 3 words
945 if ((words_read
== 2) && (decode_parsebits_is_loopend(words
[0]))) {
946 decode_add_endloop_insn(&pkt
->insn
[pkt
->num_insns
++], 0);
948 if (words_read
>= 3) {
949 bool has_loop0
, has_loop1
;
950 has_loop0
= decode_parsebits_is_loopend(words
[0]);
951 has_loop1
= decode_parsebits_is_loopend(words
[1]);
952 if (has_loop0
&& has_loop1
) {
953 decode_add_endloop_insn(&pkt
->insn
[pkt
->num_insns
++], 10);
954 } else if (has_loop1
) {
955 decode_add_endloop_insn(&pkt
->insn
[pkt
->num_insns
++], 1);
956 } else if (has_loop0
) {
957 decode_add_endloop_insn(&pkt
->insn
[pkt
->num_insns
++], 0);
961 decode_apply_extenders(pkt
);
963 decode_remove_extenders(pkt
);
965 decode_set_slot_number(pkt
);
966 decode_fill_newvalue_regno(pkt
);
968 if (pkt
->pkt_has_hvx
) {
969 mmvec_ext_decode_checks(pkt
, disas_only
);
973 decode_shuffle_for_execution(pkt
);
974 decode_split_cmpjump(pkt
);
975 decode_set_insn_attr_fields(pkt
);
981 /* Used for "-d in_asm" logging */
982 int disassemble_hexagon(uint32_t *words
, int nwords
, bfd_vma pc
,
987 if (decode_packet(nwords
, words
, &pkt
, true) > 0) {
988 snprint_a_pkt_disas(buf
, &pkt
, words
, pc
);
989 return pkt
.encod_pkt_size_in_bytes
;
991 g_string_assign(buf
, "<invalid>");