18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Disassemble SPU instructions 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci Copyright 2006 Free Software Foundation, Inc. 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci This file is part of GDB, GAS, and the GNU binutils. 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/string.h> 118c2ecf20Sopenharmony_ci#include "nonstdio.h" 128c2ecf20Sopenharmony_ci#include "ansidecl.h" 138c2ecf20Sopenharmony_ci#include "spu.h" 148c2ecf20Sopenharmony_ci#include "dis-asm.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* This file provides a disassembler function which uses 178c2ecf20Sopenharmony_ci the disassembler interface defined in dis-asm.h. */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciextern const struct spu_opcode spu_opcodes[]; 208c2ecf20Sopenharmony_ciextern const int spu_num_opcodes; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define SPU_DISASM_TBL_SIZE (1 << 11) 238c2ecf20Sopenharmony_cistatic const struct spu_opcode *spu_disassemble_table[SPU_DISASM_TBL_SIZE]; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic void 268c2ecf20Sopenharmony_ciinit_spu_disassemble (void) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci int i; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci /* If two instructions have the same opcode then we prefer the first 318c2ecf20Sopenharmony_ci * one. In most cases it is just an alternate mnemonic. */ 328c2ecf20Sopenharmony_ci for (i = 0; i < spu_num_opcodes; i++) 338c2ecf20Sopenharmony_ci { 348c2ecf20Sopenharmony_ci int o = spu_opcodes[i].opcode; 358c2ecf20Sopenharmony_ci if (o >= SPU_DISASM_TBL_SIZE) 368c2ecf20Sopenharmony_ci continue; /* abort (); */ 378c2ecf20Sopenharmony_ci if (spu_disassemble_table[o] == 0) 388c2ecf20Sopenharmony_ci spu_disassemble_table[o] = &spu_opcodes[i]; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Determine the instruction from the 10 least significant bits. */ 438c2ecf20Sopenharmony_cistatic const struct spu_opcode * 448c2ecf20Sopenharmony_ciget_index_for_opcode (unsigned int insn) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci const struct spu_opcode *index; 478c2ecf20Sopenharmony_ci unsigned int opcode = insn >> (32-11); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Init the table. This assumes that element 0/opcode 0 (currently 508c2ecf20Sopenharmony_ci * NOP) is always used */ 518c2ecf20Sopenharmony_ci if (spu_disassemble_table[0] == 0) 528c2ecf20Sopenharmony_ci init_spu_disassemble (); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x780]) != 0 558c2ecf20Sopenharmony_ci && index->insn_type == RRR) 568c2ecf20Sopenharmony_ci return index; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x7f0]) != 0 598c2ecf20Sopenharmony_ci && (index->insn_type == RI18 || index->insn_type == LBT)) 608c2ecf20Sopenharmony_ci return index; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x7f8]) != 0 638c2ecf20Sopenharmony_ci && index->insn_type == RI10) 648c2ecf20Sopenharmony_ci return index; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x7fc]) != 0 678c2ecf20Sopenharmony_ci && (index->insn_type == RI16)) 688c2ecf20Sopenharmony_ci return index; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x7fe]) != 0 718c2ecf20Sopenharmony_ci && (index->insn_type == RI8)) 728c2ecf20Sopenharmony_ci return index; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0) 758c2ecf20Sopenharmony_ci return index; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return NULL; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* Print a Spu instruction. */ 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciint 838c2ecf20Sopenharmony_ciprint_insn_spu (unsigned long insn, unsigned long memaddr) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci int value; 868c2ecf20Sopenharmony_ci int hex_value; 878c2ecf20Sopenharmony_ci const struct spu_opcode *index; 888c2ecf20Sopenharmony_ci enum spu_insns tag; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci index = get_index_for_opcode (insn); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (index == 0) 938c2ecf20Sopenharmony_ci { 948c2ecf20Sopenharmony_ci printf(".long 0x%lx", insn); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci { 988c2ecf20Sopenharmony_ci int i; 998c2ecf20Sopenharmony_ci int paren = 0; 1008c2ecf20Sopenharmony_ci tag = (enum spu_insns)(index - spu_opcodes); 1018c2ecf20Sopenharmony_ci printf("%s", index->mnemonic); 1028c2ecf20Sopenharmony_ci if (tag == M_BI || tag == M_BISL || tag == M_IRET || tag == M_BISLED 1038c2ecf20Sopenharmony_ci || tag == M_BIHNZ || tag == M_BIHZ || tag == M_BINZ || tag == M_BIZ 1048c2ecf20Sopenharmony_ci || tag == M_SYNC || tag == M_HBR) 1058c2ecf20Sopenharmony_ci { 1068c2ecf20Sopenharmony_ci int fb = (insn >> (32-18)) & 0x7f; 1078c2ecf20Sopenharmony_ci if (fb & 0x40) 1088c2ecf20Sopenharmony_ci printf(tag == M_SYNC ? "c" : "p"); 1098c2ecf20Sopenharmony_ci if (fb & 0x20) 1108c2ecf20Sopenharmony_ci printf("d"); 1118c2ecf20Sopenharmony_ci if (fb & 0x10) 1128c2ecf20Sopenharmony_ci printf("e"); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci if (index->arg[0] != 0) 1158c2ecf20Sopenharmony_ci printf("\t"); 1168c2ecf20Sopenharmony_ci hex_value = 0; 1178c2ecf20Sopenharmony_ci for (i = 1; i <= index->arg[0]; i++) 1188c2ecf20Sopenharmony_ci { 1198c2ecf20Sopenharmony_ci int arg = index->arg[i]; 1208c2ecf20Sopenharmony_ci if (arg != A_P && !paren && i > 1) 1218c2ecf20Sopenharmony_ci printf(","); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci switch (arg) 1248c2ecf20Sopenharmony_ci { 1258c2ecf20Sopenharmony_ci case A_T: 1268c2ecf20Sopenharmony_ci printf("$%lu", 1278c2ecf20Sopenharmony_ci DECODE_INSN_RT (insn)); 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci case A_A: 1308c2ecf20Sopenharmony_ci printf("$%lu", 1318c2ecf20Sopenharmony_ci DECODE_INSN_RA (insn)); 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case A_B: 1348c2ecf20Sopenharmony_ci printf("$%lu", 1358c2ecf20Sopenharmony_ci DECODE_INSN_RB (insn)); 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci case A_C: 1388c2ecf20Sopenharmony_ci printf("$%lu", 1398c2ecf20Sopenharmony_ci DECODE_INSN_RC (insn)); 1408c2ecf20Sopenharmony_ci break; 1418c2ecf20Sopenharmony_ci case A_S: 1428c2ecf20Sopenharmony_ci printf("$sp%lu", 1438c2ecf20Sopenharmony_ci DECODE_INSN_RA (insn)); 1448c2ecf20Sopenharmony_ci break; 1458c2ecf20Sopenharmony_ci case A_H: 1468c2ecf20Sopenharmony_ci printf("$ch%lu", 1478c2ecf20Sopenharmony_ci DECODE_INSN_RA (insn)); 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci case A_P: 1508c2ecf20Sopenharmony_ci paren++; 1518c2ecf20Sopenharmony_ci printf("("); 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci case A_U7A: 1548c2ecf20Sopenharmony_ci printf("%lu", 1558c2ecf20Sopenharmony_ci 173 - DECODE_INSN_U8 (insn)); 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci case A_U7B: 1588c2ecf20Sopenharmony_ci printf("%lu", 1598c2ecf20Sopenharmony_ci 155 - DECODE_INSN_U8 (insn)); 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci case A_S3: 1628c2ecf20Sopenharmony_ci case A_S6: 1638c2ecf20Sopenharmony_ci case A_S7: 1648c2ecf20Sopenharmony_ci case A_S7N: 1658c2ecf20Sopenharmony_ci case A_U3: 1668c2ecf20Sopenharmony_ci case A_U5: 1678c2ecf20Sopenharmony_ci case A_U6: 1688c2ecf20Sopenharmony_ci case A_U7: 1698c2ecf20Sopenharmony_ci hex_value = DECODE_INSN_I7 (insn); 1708c2ecf20Sopenharmony_ci printf("%d", hex_value); 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci case A_S11: 1738c2ecf20Sopenharmony_ci print_address(memaddr + DECODE_INSN_I9a (insn) * 4); 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci case A_S11I: 1768c2ecf20Sopenharmony_ci print_address(memaddr + DECODE_INSN_I9b (insn) * 4); 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci case A_S10: 1798c2ecf20Sopenharmony_ci case A_S10B: 1808c2ecf20Sopenharmony_ci hex_value = DECODE_INSN_I10 (insn); 1818c2ecf20Sopenharmony_ci printf("%d", hex_value); 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case A_S14: 1848c2ecf20Sopenharmony_ci hex_value = DECODE_INSN_I10 (insn) * 16; 1858c2ecf20Sopenharmony_ci printf("%d", hex_value); 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case A_S16: 1888c2ecf20Sopenharmony_ci hex_value = DECODE_INSN_I16 (insn); 1898c2ecf20Sopenharmony_ci printf("%d", hex_value); 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci case A_X16: 1928c2ecf20Sopenharmony_ci hex_value = DECODE_INSN_U16 (insn); 1938c2ecf20Sopenharmony_ci printf("%u", hex_value); 1948c2ecf20Sopenharmony_ci break; 1958c2ecf20Sopenharmony_ci case A_R18: 1968c2ecf20Sopenharmony_ci value = DECODE_INSN_I16 (insn) * 4; 1978c2ecf20Sopenharmony_ci if (value == 0) 1988c2ecf20Sopenharmony_ci printf("%d", value); 1998c2ecf20Sopenharmony_ci else 2008c2ecf20Sopenharmony_ci { 2018c2ecf20Sopenharmony_ci hex_value = memaddr + value; 2028c2ecf20Sopenharmony_ci print_address(hex_value & 0x3ffff); 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci case A_S18: 2068c2ecf20Sopenharmony_ci value = DECODE_INSN_U16 (insn) * 4; 2078c2ecf20Sopenharmony_ci if (value == 0) 2088c2ecf20Sopenharmony_ci printf("%d", value); 2098c2ecf20Sopenharmony_ci else 2108c2ecf20Sopenharmony_ci print_address(value); 2118c2ecf20Sopenharmony_ci break; 2128c2ecf20Sopenharmony_ci case A_U18: 2138c2ecf20Sopenharmony_ci value = DECODE_INSN_U18 (insn); 2148c2ecf20Sopenharmony_ci if (value == 0 || 1) 2158c2ecf20Sopenharmony_ci { 2168c2ecf20Sopenharmony_ci hex_value = value; 2178c2ecf20Sopenharmony_ci printf("%u", value); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci else 2208c2ecf20Sopenharmony_ci print_address(value); 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci case A_U14: 2238c2ecf20Sopenharmony_ci hex_value = DECODE_INSN_U14 (insn); 2248c2ecf20Sopenharmony_ci printf("%u", hex_value); 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci if (arg != A_P && paren) 2288c2ecf20Sopenharmony_ci { 2298c2ecf20Sopenharmony_ci printf(")"); 2308c2ecf20Sopenharmony_ci paren--; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci if (hex_value > 16) 2348c2ecf20Sopenharmony_ci printf("\t# %x", hex_value); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci return 4; 2378c2ecf20Sopenharmony_ci} 238