162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* Disassemble SPU instructions 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci Copyright 2006 Free Software Foundation, Inc. 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci This file is part of GDB, GAS, and the GNU binutils. 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/string.h> 1162306a36Sopenharmony_ci#include "nonstdio.h" 1262306a36Sopenharmony_ci#include "ansidecl.h" 1362306a36Sopenharmony_ci#include "spu.h" 1462306a36Sopenharmony_ci#include "dis-asm.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* This file provides a disassembler function which uses 1762306a36Sopenharmony_ci the disassembler interface defined in dis-asm.h. */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciextern const struct spu_opcode spu_opcodes[]; 2062306a36Sopenharmony_ciextern const int spu_num_opcodes; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define SPU_DISASM_TBL_SIZE (1 << 11) 2362306a36Sopenharmony_cistatic const struct spu_opcode *spu_disassemble_table[SPU_DISASM_TBL_SIZE]; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic void 2662306a36Sopenharmony_ciinit_spu_disassemble (void) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci int i; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci /* If two instructions have the same opcode then we prefer the first 3162306a36Sopenharmony_ci * one. In most cases it is just an alternate mnemonic. */ 3262306a36Sopenharmony_ci for (i = 0; i < spu_num_opcodes; i++) 3362306a36Sopenharmony_ci { 3462306a36Sopenharmony_ci int o = spu_opcodes[i].opcode; 3562306a36Sopenharmony_ci if (o >= SPU_DISASM_TBL_SIZE) 3662306a36Sopenharmony_ci continue; /* abort (); */ 3762306a36Sopenharmony_ci if (spu_disassemble_table[o] == 0) 3862306a36Sopenharmony_ci spu_disassemble_table[o] = &spu_opcodes[i]; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Determine the instruction from the 10 least significant bits. */ 4362306a36Sopenharmony_cistatic const struct spu_opcode * 4462306a36Sopenharmony_ciget_index_for_opcode (unsigned int insn) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci const struct spu_opcode *index; 4762306a36Sopenharmony_ci unsigned int opcode = insn >> (32-11); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* Init the table. This assumes that element 0/opcode 0 (currently 5062306a36Sopenharmony_ci * NOP) is always used */ 5162306a36Sopenharmony_ci if (spu_disassemble_table[0] == 0) 5262306a36Sopenharmony_ci init_spu_disassemble (); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x780]) != 0 5562306a36Sopenharmony_ci && index->insn_type == RRR) 5662306a36Sopenharmony_ci return index; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x7f0]) != 0 5962306a36Sopenharmony_ci && (index->insn_type == RI18 || index->insn_type == LBT)) 6062306a36Sopenharmony_ci return index; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x7f8]) != 0 6362306a36Sopenharmony_ci && index->insn_type == RI10) 6462306a36Sopenharmony_ci return index; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x7fc]) != 0 6762306a36Sopenharmony_ci && (index->insn_type == RI16)) 6862306a36Sopenharmony_ci return index; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x7fe]) != 0 7162306a36Sopenharmony_ci && (index->insn_type == RI8)) 7262306a36Sopenharmony_ci return index; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0) 7562306a36Sopenharmony_ci return index; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return NULL; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* Print a Spu instruction. */ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciint 8362306a36Sopenharmony_ciprint_insn_spu (unsigned long insn, unsigned long memaddr) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci int value; 8662306a36Sopenharmony_ci int hex_value; 8762306a36Sopenharmony_ci const struct spu_opcode *index; 8862306a36Sopenharmony_ci enum spu_insns tag; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci index = get_index_for_opcode (insn); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (index == 0) 9362306a36Sopenharmony_ci { 9462306a36Sopenharmony_ci printf(".long 0x%lx", insn); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci else 9762306a36Sopenharmony_ci { 9862306a36Sopenharmony_ci int i; 9962306a36Sopenharmony_ci int paren = 0; 10062306a36Sopenharmony_ci tag = (enum spu_insns)(index - spu_opcodes); 10162306a36Sopenharmony_ci printf("%s", index->mnemonic); 10262306a36Sopenharmony_ci if (tag == M_BI || tag == M_BISL || tag == M_IRET || tag == M_BISLED 10362306a36Sopenharmony_ci || tag == M_BIHNZ || tag == M_BIHZ || tag == M_BINZ || tag == M_BIZ 10462306a36Sopenharmony_ci || tag == M_SYNC || tag == M_HBR) 10562306a36Sopenharmony_ci { 10662306a36Sopenharmony_ci int fb = (insn >> (32-18)) & 0x7f; 10762306a36Sopenharmony_ci if (fb & 0x40) 10862306a36Sopenharmony_ci printf(tag == M_SYNC ? "c" : "p"); 10962306a36Sopenharmony_ci if (fb & 0x20) 11062306a36Sopenharmony_ci printf("d"); 11162306a36Sopenharmony_ci if (fb & 0x10) 11262306a36Sopenharmony_ci printf("e"); 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci if (index->arg[0] != 0) 11562306a36Sopenharmony_ci printf("\t"); 11662306a36Sopenharmony_ci hex_value = 0; 11762306a36Sopenharmony_ci for (i = 1; i <= index->arg[0]; i++) 11862306a36Sopenharmony_ci { 11962306a36Sopenharmony_ci int arg = index->arg[i]; 12062306a36Sopenharmony_ci if (arg != A_P && !paren && i > 1) 12162306a36Sopenharmony_ci printf(","); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci switch (arg) 12462306a36Sopenharmony_ci { 12562306a36Sopenharmony_ci case A_T: 12662306a36Sopenharmony_ci printf("$%lu", 12762306a36Sopenharmony_ci DECODE_INSN_RT (insn)); 12862306a36Sopenharmony_ci break; 12962306a36Sopenharmony_ci case A_A: 13062306a36Sopenharmony_ci printf("$%lu", 13162306a36Sopenharmony_ci DECODE_INSN_RA (insn)); 13262306a36Sopenharmony_ci break; 13362306a36Sopenharmony_ci case A_B: 13462306a36Sopenharmony_ci printf("$%lu", 13562306a36Sopenharmony_ci DECODE_INSN_RB (insn)); 13662306a36Sopenharmony_ci break; 13762306a36Sopenharmony_ci case A_C: 13862306a36Sopenharmony_ci printf("$%lu", 13962306a36Sopenharmony_ci DECODE_INSN_RC (insn)); 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci case A_S: 14262306a36Sopenharmony_ci printf("$sp%lu", 14362306a36Sopenharmony_ci DECODE_INSN_RA (insn)); 14462306a36Sopenharmony_ci break; 14562306a36Sopenharmony_ci case A_H: 14662306a36Sopenharmony_ci printf("$ch%lu", 14762306a36Sopenharmony_ci DECODE_INSN_RA (insn)); 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci case A_P: 15062306a36Sopenharmony_ci paren++; 15162306a36Sopenharmony_ci printf("("); 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci case A_U7A: 15462306a36Sopenharmony_ci printf("%lu", 15562306a36Sopenharmony_ci 173 - DECODE_INSN_U8 (insn)); 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci case A_U7B: 15862306a36Sopenharmony_ci printf("%lu", 15962306a36Sopenharmony_ci 155 - DECODE_INSN_U8 (insn)); 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci case A_S3: 16262306a36Sopenharmony_ci case A_S6: 16362306a36Sopenharmony_ci case A_S7: 16462306a36Sopenharmony_ci case A_S7N: 16562306a36Sopenharmony_ci case A_U3: 16662306a36Sopenharmony_ci case A_U5: 16762306a36Sopenharmony_ci case A_U6: 16862306a36Sopenharmony_ci case A_U7: 16962306a36Sopenharmony_ci hex_value = DECODE_INSN_I7 (insn); 17062306a36Sopenharmony_ci printf("%d", hex_value); 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci case A_S11: 17362306a36Sopenharmony_ci print_address(memaddr + DECODE_INSN_I9a (insn) * 4); 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci case A_S11I: 17662306a36Sopenharmony_ci print_address(memaddr + DECODE_INSN_I9b (insn) * 4); 17762306a36Sopenharmony_ci break; 17862306a36Sopenharmony_ci case A_S10: 17962306a36Sopenharmony_ci case A_S10B: 18062306a36Sopenharmony_ci hex_value = DECODE_INSN_I10 (insn); 18162306a36Sopenharmony_ci printf("%d", hex_value); 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci case A_S14: 18462306a36Sopenharmony_ci hex_value = DECODE_INSN_I10 (insn) * 16; 18562306a36Sopenharmony_ci printf("%d", hex_value); 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci case A_S16: 18862306a36Sopenharmony_ci hex_value = DECODE_INSN_I16 (insn); 18962306a36Sopenharmony_ci printf("%d", hex_value); 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci case A_X16: 19262306a36Sopenharmony_ci hex_value = DECODE_INSN_U16 (insn); 19362306a36Sopenharmony_ci printf("%u", hex_value); 19462306a36Sopenharmony_ci break; 19562306a36Sopenharmony_ci case A_R18: 19662306a36Sopenharmony_ci value = DECODE_INSN_I16 (insn) * 4; 19762306a36Sopenharmony_ci if (value == 0) 19862306a36Sopenharmony_ci printf("%d", value); 19962306a36Sopenharmony_ci else 20062306a36Sopenharmony_ci { 20162306a36Sopenharmony_ci hex_value = memaddr + value; 20262306a36Sopenharmony_ci print_address(hex_value & 0x3ffff); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci break; 20562306a36Sopenharmony_ci case A_S18: 20662306a36Sopenharmony_ci value = DECODE_INSN_U16 (insn) * 4; 20762306a36Sopenharmony_ci if (value == 0) 20862306a36Sopenharmony_ci printf("%d", value); 20962306a36Sopenharmony_ci else 21062306a36Sopenharmony_ci print_address(value); 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci case A_U18: 21362306a36Sopenharmony_ci value = DECODE_INSN_U18 (insn); 21462306a36Sopenharmony_ci if (value == 0 || 1) 21562306a36Sopenharmony_ci { 21662306a36Sopenharmony_ci hex_value = value; 21762306a36Sopenharmony_ci printf("%u", value); 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci else 22062306a36Sopenharmony_ci print_address(value); 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci case A_U14: 22362306a36Sopenharmony_ci hex_value = DECODE_INSN_U14 (insn); 22462306a36Sopenharmony_ci printf("%u", hex_value); 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci if (arg != A_P && paren) 22862306a36Sopenharmony_ci { 22962306a36Sopenharmony_ci printf(")"); 23062306a36Sopenharmony_ci paren--; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci if (hex_value > 16) 23462306a36Sopenharmony_ci printf("\t# %x", hex_value); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci return 4; 23762306a36Sopenharmony_ci} 238