| 1 | /* |
| 2 | * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. |
| 3 | * |
| 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. |
| 8 | * |
| 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. |
| 13 | * |
| 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/>. |
| 16 | */ |
| 17 | |
| 18 | #include "qemu/osdep.h" |
| 19 | #include "attribs.h" |
| 20 | #include "printinsn.h" |
| 21 | #include "insn.h" |
| 22 | #include "reg_fields.h" |
| 23 | #include "internal.h" |
| 24 | #include "decode.h" |
| 25 | |
| 26 | /* |
| 27 | * Used when there is some sort of error and we can't figure out the real |
| 28 | * system register name |
| 29 | */ |
| 30 | static const char *const generic_sreg_names[256] = { |
| 31 | "S000", "S001", "S002", "S003", "S004", "S005", "S006", "S007", |
| 32 | "S008", "S009", "S010", "S011", "S012", "S013", "S014", "S015", |
| 33 | "S016", "S017", "S018", "S019", "S020", "S021", "S022", "S023", |
| 34 | "S024", "S025", "S026", "S027", "S028", "S029", "S030", "S031", |
| 35 | "S032", "S033", "S034", "S035", "S036", "S037", "S038", "S039", |
| 36 | "S040", "S041", "S042", "S043", "S044", "S045", "S046", "S047", |
| 37 | "S048", "S049", "S050", "S051", "S052", "S053", "S054", "S055", |
| 38 | "S056", "S057", "S058", "S059", "S060", "S061", "S062", "S063", |
| 39 | "S064", "S065", "S066", "S067", "S068", "S069", "S070", "S071", |
| 40 | "S072", "S073", "S074", "S075", "S076", "S077", "S078", "S079", |
| 41 | "S080", "S081", "S082", "S083", "S084", "S085", "S086", "S087", |
| 42 | "S088", "S089", "S090", "S091", "S092", "S093", "S094", "S095", |
| 43 | "S096", "S097", "S098", "S099", "S100", "S101", "S102", "S103", |
| 44 | "S104", "S105", "S106", "S107", "S108", "S109", "S110", "S111", |
| 45 | "S112", "S113", "S114", "S115", "S116", "S117", "S118", "S119", |
| 46 | "S120", "S121", "S122", "S123", "S124", "S125", "S126", "S127", |
| 47 | "S128", "S129", "S130", "S131", "S132", "S133", "S134", "S135", |
| 48 | "S136", "S137", "S138", "S139", "S140", "S141", "S142", "S143", |
| 49 | "S144", "S145", "S146", "S147", "S148", "S149", "S150", "S151", |
| 50 | "S152", "S153", "S154", "S155", "S156", "S157", "S158", "S159", |
| 51 | "S160", "S161", "S162", "S163", "S164", "S165", "S166", "S167", |
| 52 | "S168", "S169", "S170", "S171", "S172", "S173", "S174", "S175", |
| 53 | "S176", "S177", "S178", "S179", "S180", "S181", "S182", "S183", |
| 54 | "S184", "S185", "S186", "S187", "S188", "S189", "S190", "S191", |
| 55 | "S192", "S193", "S194", "S195", "S196", "S197", "S198", "S199", |
| 56 | "S200", "S201", "S202", "S203", "S204", "S205", "S206", "S207", |
| 57 | "S208", "S209", "S210", "S211", "S212", "S213", "S214", "S215", |
| 58 | "S216", "S217", "S218", "S219", "S220", "S221", "S222", "S223", |
| 59 | "S224", "S225", "S226", "S227", "S228", "S229", "S230", "S231", |
| 60 | "S232", "S233", "S234", "S235", "S236", "S237", "S238", "S239", |
| 61 | "S240", "S241", "S242", "S243", "S244", "S245", "S246", "S247", |
| 62 | "S248", "S249", "S250", "S251", "S252", "S253", "S254", "S255", |
| 63 | }; |
| 64 | |
| 65 | static const char *sreg2str(uint8_t reg) |
| 66 | { |
| 67 | #ifndef CONFIG_USER_ONLY |
| 68 | if (reg < NUM_SREGS) { |
| 69 | return hexagon_sregnames[reg]; |
| 70 | } else { |
| 71 | return generic_sreg_names[reg]; |
| 72 | } |
| 73 | #else |
| 74 | return generic_sreg_names[reg]; |
| 75 | #endif |
| 76 | } |
| 77 | |
| 78 | /* |
| 79 | * Used when there is some sort of error and we can't figure out the real |
| 80 | * control register name |
| 81 | */ |
| 82 | static const char *const generic_creg_names[256] = { |
| 83 | "C000", "C001", "C002", "C003", "C004", "C005", "C006", "C007", |
| 84 | "C008", "C009", "C010", "C011", "C012", "C013", "C014", "C015", |
| 85 | "C016", "C017", "C018", "C019", "C020", "C021", "C022", "C023", |
| 86 | "C024", "C025", "C026", "C027", "C028", "C029", "C030", "C031", |
| 87 | "C032", "C033", "C034", "C035", "C036", "C037", "C038", "C039", |
| 88 | "C040", "C041", "C042", "C043", "C044", "C045", "C046", "C047", |
| 89 | "C048", "C049", "C050", "C051", "C052", "C053", "C054", "C055", |
| 90 | "C056", "C057", "C058", "C059", "C060", "C061", "C062", "C063", |
| 91 | "C064", "C065", "C066", "C067", "C068", "C069", "C070", "C071", |
| 92 | "C072", "C073", "C074", "C075", "C076", "C077", "C078", "C079", |
| 93 | "C080", "C081", "C082", "C083", "C084", "C085", "C086", "C087", |
| 94 | "C088", "C089", "C090", "C091", "C092", "C093", "C094", "C095", |
| 95 | "C096", "C097", "C098", "C099", "C100", "C101", "C102", "C103", |
| 96 | "C104", "C105", "C106", "C107", "C108", "C109", "C110", "C111", |
| 97 | "C112", "C113", "C114", "C115", "C116", "C117", "C118", "C119", |
| 98 | "C120", "C121", "C122", "C123", "C124", "C125", "C126", "C127", |
| 99 | "C128", "C129", "C130", "C131", "C132", "C133", "C134", "C135", |
| 100 | "C136", "C137", "C138", "C139", "C140", "C141", "C142", "C143", |
| 101 | "C144", "C145", "C146", "C147", "C148", "C149", "C150", "C151", |
| 102 | "C152", "C153", "C154", "C155", "C156", "C157", "C158", "C159", |
| 103 | "C160", "C161", "C162", "C163", "C164", "C165", "C166", "C167", |
| 104 | "C168", "C169", "C170", "C171", "C172", "C173", "C174", "C175", |
| 105 | "C176", "C177", "C178", "C179", "C180", "C181", "C182", "C183", |
| 106 | "C184", "C185", "C186", "C187", "C188", "C189", "C190", "C191", |
| 107 | "C192", "C193", "C194", "C195", "C196", "C197", "C198", "C199", |
| 108 | "C200", "C201", "C202", "C203", "C204", "C205", "C206", "C207", |
| 109 | "C208", "C209", "C210", "C211", "C212", "C213", "C214", "C215", |
| 110 | "C216", "C217", "C218", "C219", "C220", "C221", "C222", "C223", |
| 111 | "C224", "C225", "C226", "C227", "C228", "C229", "C230", "C231", |
| 112 | "C232", "C233", "C234", "C235", "C236", "C237", "C238", "C239", |
| 113 | "C240", "C241", "C242", "C243", "C244", "C245", "C246", "C247", |
| 114 | "C248", "C249", "C250", "C251", "C252", "C253", "C254", "C255", |
| 115 | }; |
| 116 | |
| 117 | static const char *creg2str(uint8_t reg) |
| 118 | { |
| 119 | uint8_t gpr = reg + HEX_REG_SA0; |
| 120 | if (gpr < TOTAL_PER_THREAD_REGS) { |
| 121 | return hexagon_regnames[gpr]; |
| 122 | } else { |
| 123 | return generic_creg_names[reg]; |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | static void snprintinsn(GString *buf, Insn *insn) |
| 128 | { |
| 129 | switch (insn->opcode) { |
| 130 | #define DEF_VECX_PRINTINFO(TAG, FMT, ...) DEF_PRINTINFO(TAG, FMT, __VA_ARGS__) |
| 131 | #define DEF_PRINTINFO(TAG, FMT, ...) \ |
| 132 | case TAG: \ |
| 133 | g_string_append_printf(buf, FMT, __VA_ARGS__); \ |
| 134 | break; |
| 135 | #include "printinsn_generated.h.inc" |
| 136 | #undef DEF_VECX_PRINTINFO |
| 137 | #undef DEF_PRINTINFO |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | void snprint_a_pkt_disas(GString *buf, Packet *pkt, uint32_t *words, |
| 142 | target_ulong pc, const HexagonCPUConfig *cfg) |
| 143 | { |
| 144 | bool has_endloop0 = false; |
| 145 | bool has_endloop1 = false; |
| 146 | bool has_endloop01 = false; |
| 147 | |
| 148 | for (int i = 0; i < pkt->num_insns; i++) { |
| 149 | if (pkt->insn[i].part1) { |
| 150 | continue; |
| 151 | } |
| 152 | |
| 153 | /* We'll print the endloop's at the end of the packet */ |
| 154 | if (pkt->insn[i].opcode == J2_endloop0) { |
| 155 | has_endloop0 = true; |
| 156 | continue; |
| 157 | } |
| 158 | if (pkt->insn[i].opcode == J2_endloop1) { |
| 159 | has_endloop1 = true; |
| 160 | continue; |
| 161 | } |
| 162 | if (pkt->insn[i].opcode == J2_endloop01) { |
| 163 | has_endloop01 = true; |
| 164 | continue; |
| 165 | } |
| 166 | |
| 167 | g_string_append_printf(buf, "0x" TARGET_FMT_lx "\t", words[i]); |
| 168 | |
| 169 | if (i == 0) { |
| 170 | g_string_append(buf, "{"); |
| 171 | } |
| 172 | |
| 173 | g_string_append(buf, "\t"); |
| 174 | if (opcode_supported(pkt->insn[i].opcode, cfg->hex_def)) { |
| 175 | snprintinsn(buf, &(pkt->insn[i])); |
| 176 | } else { |
| 177 | g_string_append(buf, "<invalid>"); |
| 178 | } |
| 179 | |
| 180 | if (!cfg->ieee_fp_extension && |
| 181 | GET_ATTRIB(pkt->insn[i].opcode, A_HVX_IEEE_FP)) { |
| 182 | g_string_append(buf, " (disabled: no ieee_fp)"); |
| 183 | } |
| 184 | |
| 185 | if (i < pkt->num_insns - 1) { |
| 186 | /* |
| 187 | * Subinstructions are two instructions encoded |
| 188 | * in the same word. Print them on the same line. |
| 189 | */ |
| 190 | if (GET_ATTRIB(pkt->insn[i].opcode, A_SUBINSN)) { |
| 191 | g_string_append(buf, "; "); |
| 192 | snprintinsn(buf, &(pkt->insn[i + 1])); |
| 193 | i++; |
| 194 | } else if (pkt->insn[i + 1].opcode != J2_endloop0 && |
| 195 | pkt->insn[i + 1].opcode != J2_endloop1 && |
| 196 | pkt->insn[i + 1].opcode != J2_endloop01) { |
| 197 | pc += 4; |
| 198 | g_string_append_printf(buf, "\n0x" TARGET_FMT_lx ": ", pc); |
| 199 | } |
| 200 | } |
| 201 | } |
| 202 | g_string_append(buf, " }"); |
| 203 | if (has_endloop0) { |
| 204 | g_string_append(buf, " :endloop0"); |
| 205 | } |
| 206 | if (has_endloop1) { |
| 207 | g_string_append(buf, " :endloop1"); |
| 208 | } |
| 209 | if (has_endloop01) { |
| 210 | g_string_append(buf, " :endloop01"); |
| 211 | } |
| 212 | } |