spu-dis.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /* Disassemble SPU instructions
  3. Copyright 2006 Free Software Foundation, Inc.
  4. This file is part of GDB, GAS, and the GNU binutils.
  5. */
  6. #include <linux/string.h>
  7. #include "nonstdio.h"
  8. #include "ansidecl.h"
  9. #include "spu.h"
  10. #include "dis-asm.h"
  11. /* This file provides a disassembler function which uses
  12. the disassembler interface defined in dis-asm.h. */
  13. extern const struct spu_opcode spu_opcodes[];
  14. extern const int spu_num_opcodes;
  15. #define SPU_DISASM_TBL_SIZE (1 << 11)
  16. static const struct spu_opcode *spu_disassemble_table[SPU_DISASM_TBL_SIZE];
  17. static void
  18. init_spu_disassemble (void)
  19. {
  20. int i;
  21. /* If two instructions have the same opcode then we prefer the first
  22. * one. In most cases it is just an alternate mnemonic. */
  23. for (i = 0; i < spu_num_opcodes; i++)
  24. {
  25. int o = spu_opcodes[i].opcode;
  26. if (o >= SPU_DISASM_TBL_SIZE)
  27. continue; /* abort (); */
  28. if (spu_disassemble_table[o] == 0)
  29. spu_disassemble_table[o] = &spu_opcodes[i];
  30. }
  31. }
  32. /* Determine the instruction from the 10 least significant bits. */
  33. static const struct spu_opcode *
  34. get_index_for_opcode (unsigned int insn)
  35. {
  36. const struct spu_opcode *index;
  37. unsigned int opcode = insn >> (32-11);
  38. /* Init the table. This assumes that element 0/opcode 0 (currently
  39. * NOP) is always used */
  40. if (spu_disassemble_table[0] == 0)
  41. init_spu_disassemble ();
  42. if ((index = spu_disassemble_table[opcode & 0x780]) != 0
  43. && index->insn_type == RRR)
  44. return index;
  45. if ((index = spu_disassemble_table[opcode & 0x7f0]) != 0
  46. && (index->insn_type == RI18 || index->insn_type == LBT))
  47. return index;
  48. if ((index = spu_disassemble_table[opcode & 0x7f8]) != 0
  49. && index->insn_type == RI10)
  50. return index;
  51. if ((index = spu_disassemble_table[opcode & 0x7fc]) != 0
  52. && (index->insn_type == RI16))
  53. return index;
  54. if ((index = spu_disassemble_table[opcode & 0x7fe]) != 0
  55. && (index->insn_type == RI8))
  56. return index;
  57. if ((index = spu_disassemble_table[opcode & 0x7ff]) != 0)
  58. return index;
  59. return NULL;
  60. }
  61. /* Print a Spu instruction. */
  62. int
  63. print_insn_spu (unsigned long insn, unsigned long memaddr)
  64. {
  65. int value;
  66. int hex_value;
  67. const struct spu_opcode *index;
  68. enum spu_insns tag;
  69. index = get_index_for_opcode (insn);
  70. if (index == 0)
  71. {
  72. printf(".long 0x%lx", insn);
  73. }
  74. else
  75. {
  76. int i;
  77. int paren = 0;
  78. tag = (enum spu_insns)(index - spu_opcodes);
  79. printf("%s", index->mnemonic);
  80. if (tag == M_BI || tag == M_BISL || tag == M_IRET || tag == M_BISLED
  81. || tag == M_BIHNZ || tag == M_BIHZ || tag == M_BINZ || tag == M_BIZ
  82. || tag == M_SYNC || tag == M_HBR)
  83. {
  84. int fb = (insn >> (32-18)) & 0x7f;
  85. if (fb & 0x40)
  86. printf(tag == M_SYNC ? "c" : "p");
  87. if (fb & 0x20)
  88. printf("d");
  89. if (fb & 0x10)
  90. printf("e");
  91. }
  92. if (index->arg[0] != 0)
  93. printf("\t");
  94. hex_value = 0;
  95. for (i = 1; i <= index->arg[0]; i++)
  96. {
  97. int arg = index->arg[i];
  98. if (arg != A_P && !paren && i > 1)
  99. printf(",");
  100. switch (arg)
  101. {
  102. case A_T:
  103. printf("$%lu",
  104. DECODE_INSN_RT (insn));
  105. break;
  106. case A_A:
  107. printf("$%lu",
  108. DECODE_INSN_RA (insn));
  109. break;
  110. case A_B:
  111. printf("$%lu",
  112. DECODE_INSN_RB (insn));
  113. break;
  114. case A_C:
  115. printf("$%lu",
  116. DECODE_INSN_RC (insn));
  117. break;
  118. case A_S:
  119. printf("$sp%lu",
  120. DECODE_INSN_RA (insn));
  121. break;
  122. case A_H:
  123. printf("$ch%lu",
  124. DECODE_INSN_RA (insn));
  125. break;
  126. case A_P:
  127. paren++;
  128. printf("(");
  129. break;
  130. case A_U7A:
  131. printf("%lu",
  132. 173 - DECODE_INSN_U8 (insn));
  133. break;
  134. case A_U7B:
  135. printf("%lu",
  136. 155 - DECODE_INSN_U8 (insn));
  137. break;
  138. case A_S3:
  139. case A_S6:
  140. case A_S7:
  141. case A_S7N:
  142. case A_U3:
  143. case A_U5:
  144. case A_U6:
  145. case A_U7:
  146. hex_value = DECODE_INSN_I7 (insn);
  147. printf("%d", hex_value);
  148. break;
  149. case A_S11:
  150. print_address(memaddr + DECODE_INSN_I9a (insn) * 4);
  151. break;
  152. case A_S11I:
  153. print_address(memaddr + DECODE_INSN_I9b (insn) * 4);
  154. break;
  155. case A_S10:
  156. case A_S10B:
  157. hex_value = DECODE_INSN_I10 (insn);
  158. printf("%d", hex_value);
  159. break;
  160. case A_S14:
  161. hex_value = DECODE_INSN_I10 (insn) * 16;
  162. printf("%d", hex_value);
  163. break;
  164. case A_S16:
  165. hex_value = DECODE_INSN_I16 (insn);
  166. printf("%d", hex_value);
  167. break;
  168. case A_X16:
  169. hex_value = DECODE_INSN_U16 (insn);
  170. printf("%u", hex_value);
  171. break;
  172. case A_R18:
  173. value = DECODE_INSN_I16 (insn) * 4;
  174. if (value == 0)
  175. printf("%d", value);
  176. else
  177. {
  178. hex_value = memaddr + value;
  179. print_address(hex_value & 0x3ffff);
  180. }
  181. break;
  182. case A_S18:
  183. value = DECODE_INSN_U16 (insn) * 4;
  184. if (value == 0)
  185. printf("%d", value);
  186. else
  187. print_address(value);
  188. break;
  189. case A_U18:
  190. value = DECODE_INSN_U18 (insn);
  191. if (value == 0 || 1)
  192. {
  193. hex_value = value;
  194. printf("%u", value);
  195. }
  196. else
  197. print_address(value);
  198. break;
  199. case A_U14:
  200. hex_value = DECODE_INSN_U14 (insn);
  201. printf("%u", hex_value);
  202. break;
  203. }
  204. if (arg != A_P && paren)
  205. {
  206. printf(")");
  207. paren--;
  208. }
  209. }
  210. if (hex_value > 16)
  211. printf("\t# %x", hex_value);
  212. }
  213. return 4;
  214. }