microblaze-dis.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /* Disassemble Xilinx microblaze instructions.
  2. Copyright (C) 2009-2015 Free Software Foundation, Inc.
  3. This file is part of the GNU opcodes library.
  4. This library 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 3, or (at your option)
  7. any later version.
  8. It is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  11. License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this file; see the file COPYING. If not, write to the
  14. Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
  15. MA 02110-1301, USA. */
  16. #include "sysdep.h"
  17. #define STATIC_TABLE
  18. #define DEFINE_TABLE
  19. #include "dis-asm.h"
  20. #include <strings.h>
  21. #include "microblaze-opc.h"
  22. #include "microblaze-dis.h"
  23. #define get_field_rd(instr) get_field (instr, RD_MASK, RD_LOW)
  24. #define get_field_r1(instr) get_field (instr, RA_MASK, RA_LOW)
  25. #define get_field_r2(instr) get_field (instr, RB_MASK, RB_LOW)
  26. #define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW)
  27. #define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW)
  28. static char *
  29. get_field (long instr, long mask, unsigned short low)
  30. {
  31. char tmpstr[25];
  32. sprintf (tmpstr, "%s%d", register_prefix, (int)((instr & mask) >> low));
  33. return (strdup (tmpstr));
  34. }
  35. static char *
  36. get_field_imm (long instr)
  37. {
  38. char tmpstr[25];
  39. sprintf (tmpstr, "%d", (short)((instr & IMM_MASK) >> IMM_LOW));
  40. return (strdup (tmpstr));
  41. }
  42. static char *
  43. get_field_imm5 (long instr)
  44. {
  45. char tmpstr[25];
  46. sprintf (tmpstr, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW));
  47. return (strdup (tmpstr));
  48. }
  49. static char *
  50. get_field_imm5_mbar (long instr)
  51. {
  52. char tmpstr[25];
  53. sprintf(tmpstr, "%d", (short)((instr & IMM5_MBAR_MASK) >> IMM_MBAR));
  54. return(strdup(tmpstr));
  55. }
  56. static char *
  57. get_field_rfsl (long instr)
  58. {
  59. char tmpstr[25];
  60. sprintf (tmpstr, "%s%d", fsl_register_prefix,
  61. (short)((instr & RFSL_MASK) >> IMM_LOW));
  62. return (strdup (tmpstr));
  63. }
  64. static char *
  65. get_field_imm15 (long instr)
  66. {
  67. char tmpstr[25];
  68. sprintf (tmpstr, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW));
  69. return (strdup (tmpstr));
  70. }
  71. static char *
  72. get_field_special (long instr, struct op_code_struct * op)
  73. {
  74. char tmpstr[25];
  75. char spr[6];
  76. switch ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask))
  77. {
  78. case REG_MSR_MASK :
  79. strcpy (spr, "msr");
  80. break;
  81. case REG_PC_MASK :
  82. strcpy (spr, "pc");
  83. break;
  84. case REG_EAR_MASK :
  85. strcpy (spr, "ear");
  86. break;
  87. case REG_ESR_MASK :
  88. strcpy (spr, "esr");
  89. break;
  90. case REG_FSR_MASK :
  91. strcpy (spr, "fsr");
  92. break;
  93. case REG_BTR_MASK :
  94. strcpy (spr, "btr");
  95. break;
  96. case REG_EDR_MASK :
  97. strcpy (spr, "edr");
  98. break;
  99. case REG_PID_MASK :
  100. strcpy (spr, "pid");
  101. break;
  102. case REG_ZPR_MASK :
  103. strcpy (spr, "zpr");
  104. break;
  105. case REG_TLBX_MASK :
  106. strcpy (spr, "tlbx");
  107. break;
  108. case REG_TLBLO_MASK :
  109. strcpy (spr, "tlblo");
  110. break;
  111. case REG_TLBHI_MASK :
  112. strcpy (spr, "tlbhi");
  113. break;
  114. case REG_TLBSX_MASK :
  115. strcpy (spr, "tlbsx");
  116. break;
  117. case REG_SHR_MASK :
  118. strcpy (spr, "shr");
  119. break;
  120. case REG_SLR_MASK :
  121. strcpy (spr, "slr");
  122. break;
  123. default :
  124. if (((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000)
  125. == REG_PVR_MASK)
  126. {
  127. sprintf (tmpstr, "%spvr%d", register_prefix,
  128. (unsigned short)(((instr & IMM_MASK) >> IMM_LOW)
  129. ^ op->immval_mask) ^ REG_PVR_MASK);
  130. return (strdup (tmpstr));
  131. }
  132. else
  133. strcpy (spr, "pc");
  134. break;
  135. }
  136. sprintf (tmpstr, "%s%s", register_prefix, spr);
  137. return (strdup (tmpstr));
  138. }
  139. static unsigned long
  140. read_insn_microblaze (bfd_vma memaddr,
  141. struct disassemble_info *info,
  142. struct op_code_struct **opr)
  143. {
  144. unsigned char ibytes[4];
  145. int status;
  146. struct op_code_struct * op;
  147. unsigned long inst;
  148. status = info->read_memory_func (memaddr, ibytes, 4, info);
  149. if (status != 0)
  150. {
  151. info->memory_error_func (status, memaddr, info);
  152. return 0;
  153. }
  154. if (info->endian == BFD_ENDIAN_BIG)
  155. inst = (ibytes[0] << 24) | (ibytes[1] << 16) | (ibytes[2] << 8) | ibytes[3];
  156. else if (info->endian == BFD_ENDIAN_LITTLE)
  157. inst = (ibytes[3] << 24) | (ibytes[2] << 16) | (ibytes[1] << 8) | ibytes[0];
  158. else
  159. abort ();
  160. /* Just a linear search of the table. */
  161. for (op = opcodes; op->name != 0; op ++)
  162. if (op->bit_sequence == (inst & op->opcode_mask))
  163. break;
  164. *opr = op;
  165. return inst;
  166. }
  167. int
  168. print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
  169. {
  170. fprintf_ftype print_func = info->fprintf_func;
  171. void * stream = info->stream;
  172. unsigned long inst, prev_inst;
  173. struct op_code_struct * op, *pop;
  174. int immval = 0;
  175. bfd_boolean immfound = FALSE;
  176. static bfd_vma prev_insn_addr = -1; /* Init the prev insn addr. */
  177. static int prev_insn_vma = -1; /* Init the prev insn vma. */
  178. int curr_insn_vma = info->buffer_vma;
  179. info->bytes_per_chunk = 4;
  180. inst = read_insn_microblaze (memaddr, info, &op);
  181. if (inst == 0)
  182. return -1;
  183. if (prev_insn_vma == curr_insn_vma)
  184. {
  185. if (memaddr-(info->bytes_per_chunk) == prev_insn_addr)
  186. {
  187. prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop);
  188. if (prev_inst == 0)
  189. return -1;
  190. if (pop->instr == imm)
  191. {
  192. immval = (get_int_field_imm (prev_inst) << 16) & 0xffff0000;
  193. immfound = TRUE;
  194. }
  195. else
  196. {
  197. immval = 0;
  198. immfound = FALSE;
  199. }
  200. }
  201. }
  202. /* Make curr insn as prev insn. */
  203. prev_insn_addr = memaddr;
  204. prev_insn_vma = curr_insn_vma;
  205. if (op->name == NULL)
  206. print_func (stream, ".short 0x%04x", (unsigned int) inst);
  207. else
  208. {
  209. print_func (stream, "%s", op->name);
  210. switch (op->inst_type)
  211. {
  212. case INST_TYPE_RD_R1_R2:
  213. print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
  214. get_field_r1(inst), get_field_r2 (inst));
  215. break;
  216. case INST_TYPE_RD_R1_IMM:
  217. print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
  218. get_field_r1(inst), get_field_imm (inst));
  219. if (info->print_address_func && get_int_field_r1 (inst) == 0
  220. && info->symbol_at_address_func)
  221. {
  222. if (immfound)
  223. immval |= (get_int_field_imm (inst) & 0x0000ffff);
  224. else
  225. {
  226. immval = get_int_field_imm (inst);
  227. if (immval & 0x8000)
  228. immval |= 0xFFFF0000;
  229. }
  230. if (immval > 0 && info->symbol_at_address_func (immval, info))
  231. {
  232. print_func (stream, "\t// ");
  233. info->print_address_func (immval, info);
  234. }
  235. }
  236. break;
  237. case INST_TYPE_RD_R1_IMM5:
  238. print_func (stream, "\t%s, %s, %s", get_field_rd (inst),
  239. get_field_r1(inst), get_field_imm5 (inst));
  240. break;
  241. case INST_TYPE_RD_RFSL:
  242. print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_rfsl (inst));
  243. break;
  244. case INST_TYPE_R1_RFSL:
  245. print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_rfsl (inst));
  246. break;
  247. case INST_TYPE_RD_SPECIAL:
  248. print_func (stream, "\t%s, %s", get_field_rd (inst),
  249. get_field_special (inst, op));
  250. break;
  251. case INST_TYPE_SPECIAL_R1:
  252. print_func (stream, "\t%s, %s", get_field_special (inst, op),
  253. get_field_r1(inst));
  254. break;
  255. case INST_TYPE_RD_R1:
  256. print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_r1 (inst));
  257. break;
  258. case INST_TYPE_R1_R2:
  259. print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_r2 (inst));
  260. break;
  261. case INST_TYPE_R1_IMM:
  262. print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_imm (inst));
  263. /* The non-pc relative instructions are returns, which shouldn't
  264. have a label printed. */
  265. if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET
  266. && info->symbol_at_address_func)
  267. {
  268. if (immfound)
  269. immval |= (get_int_field_imm (inst) & 0x0000ffff);
  270. else
  271. {
  272. immval = get_int_field_imm (inst);
  273. if (immval & 0x8000)
  274. immval |= 0xFFFF0000;
  275. }
  276. immval += memaddr;
  277. if (immval > 0 && info->symbol_at_address_func (immval, info))
  278. {
  279. print_func (stream, "\t// ");
  280. info->print_address_func (immval, info);
  281. }
  282. else
  283. {
  284. print_func (stream, "\t\t// ");
  285. print_func (stream, "%x", immval);
  286. }
  287. }
  288. break;
  289. case INST_TYPE_RD_IMM:
  290. print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_imm (inst));
  291. if (info->print_address_func && info->symbol_at_address_func)
  292. {
  293. if (immfound)
  294. immval |= (get_int_field_imm (inst) & 0x0000ffff);
  295. else
  296. {
  297. immval = get_int_field_imm (inst);
  298. if (immval & 0x8000)
  299. immval |= 0xFFFF0000;
  300. }
  301. if (op->inst_offset_type == INST_PC_OFFSET)
  302. immval += (int) memaddr;
  303. if (info->symbol_at_address_func (immval, info))
  304. {
  305. print_func (stream, "\t// ");
  306. info->print_address_func (immval, info);
  307. }
  308. }
  309. break;
  310. case INST_TYPE_IMM:
  311. print_func (stream, "\t%s", get_field_imm (inst));
  312. if (info->print_address_func && info->symbol_at_address_func
  313. && op->instr != imm)
  314. {
  315. if (immfound)
  316. immval |= (get_int_field_imm (inst) & 0x0000ffff);
  317. else
  318. {
  319. immval = get_int_field_imm (inst);
  320. if (immval & 0x8000)
  321. immval |= 0xFFFF0000;
  322. }
  323. if (op->inst_offset_type == INST_PC_OFFSET)
  324. immval += (int) memaddr;
  325. if (immval > 0 && info->symbol_at_address_func (immval, info))
  326. {
  327. print_func (stream, "\t// ");
  328. info->print_address_func (immval, info);
  329. }
  330. else if (op->inst_offset_type == INST_PC_OFFSET)
  331. {
  332. print_func (stream, "\t\t// ");
  333. print_func (stream, "%x", immval);
  334. }
  335. }
  336. break;
  337. case INST_TYPE_RD_R2:
  338. print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_r2 (inst));
  339. break;
  340. case INST_TYPE_R2:
  341. print_func (stream, "\t%s", get_field_r2 (inst));
  342. break;
  343. case INST_TYPE_R1:
  344. print_func (stream, "\t%s", get_field_r1 (inst));
  345. break;
  346. case INST_TYPE_R1_R2_SPECIAL:
  347. print_func (stream, "\t%s, %s", get_field_r1 (inst), get_field_r2 (inst));
  348. break;
  349. case INST_TYPE_RD_IMM15:
  350. print_func (stream, "\t%s, %s", get_field_rd (inst), get_field_imm15 (inst));
  351. break;
  352. /* For mbar insn. */
  353. case INST_TYPE_IMM5:
  354. print_func (stream, "\t%s", get_field_imm5_mbar (inst));
  355. break;
  356. /* For mbar 16 or sleep insn. */
  357. case INST_TYPE_NONE:
  358. break;
  359. /* For tuqula instruction */
  360. case INST_TYPE_RD:
  361. print_func (stream, "\t%s", get_field_rd (inst));
  362. break;
  363. case INST_TYPE_RFSL:
  364. print_func (stream, "\t%s", get_field_rfsl (inst));
  365. break;
  366. default:
  367. /* If the disassembler lags the instruction set. */
  368. print_func (stream, "\tundecoded operands, inst is 0x%04x", (unsigned int) inst);
  369. break;
  370. }
  371. }
  372. /* Say how many bytes we consumed. */
  373. return 4;
  374. }
  375. enum microblaze_instr
  376. get_insn_microblaze (long inst,
  377. bfd_boolean *isunsignedimm,
  378. enum microblaze_instr_type *insn_type,
  379. short *delay_slots)
  380. {
  381. struct op_code_struct * op;
  382. *isunsignedimm = FALSE;
  383. /* Just a linear search of the table. */
  384. for (op = opcodes; op->name != 0; op ++)
  385. if (op->bit_sequence == (inst & op->opcode_mask))
  386. break;
  387. if (op->name == 0)
  388. return invalid_inst;
  389. else
  390. {
  391. *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM);
  392. *insn_type = op->instr_type;
  393. *delay_slots = op->delay_slots;
  394. return op->instr;
  395. }
  396. }
  397. enum microblaze_instr
  398. microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *immed)
  399. {
  400. enum microblaze_instr op;
  401. bfd_boolean t1;
  402. enum microblaze_instr_type t2;
  403. short t3;
  404. op = get_insn_microblaze (insn, &t1, &t2, &t3);
  405. *rd = (insn & RD_MASK) >> RD_LOW;
  406. *ra = (insn & RA_MASK) >> RA_LOW;
  407. *rb = (insn & RB_MASK) >> RB_LOW;
  408. t3 = (insn & IMM_MASK) >> IMM_LOW;
  409. *immed = (int) t3;
  410. return (op);
  411. }
  412. unsigned long
  413. microblaze_get_target_address (long inst, bfd_boolean immfound, int immval,
  414. long pcval, long r1val, long r2val,
  415. bfd_boolean *targetvalid,
  416. bfd_boolean *unconditionalbranch)
  417. {
  418. struct op_code_struct * op;
  419. long targetaddr = 0;
  420. *unconditionalbranch = FALSE;
  421. /* Just a linear search of the table. */
  422. for (op = opcodes; op->name != 0; op ++)
  423. if (op->bit_sequence == (inst & op->opcode_mask))
  424. break;
  425. if (op->name == 0)
  426. {
  427. *targetvalid = FALSE;
  428. }
  429. else if (op->instr_type == branch_inst)
  430. {
  431. switch (op->inst_type)
  432. {
  433. case INST_TYPE_R2:
  434. *unconditionalbranch = TRUE;
  435. /* Fall through. */
  436. case INST_TYPE_RD_R2:
  437. case INST_TYPE_R1_R2:
  438. targetaddr = r2val;
  439. *targetvalid = TRUE;
  440. if (op->inst_offset_type == INST_PC_OFFSET)
  441. targetaddr += pcval;
  442. break;
  443. case INST_TYPE_IMM:
  444. *unconditionalbranch = TRUE;
  445. /* Fall through. */
  446. case INST_TYPE_RD_IMM:
  447. case INST_TYPE_R1_IMM:
  448. if (immfound)
  449. {
  450. targetaddr = (immval << 16) & 0xffff0000;
  451. targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
  452. }
  453. else
  454. {
  455. targetaddr = get_int_field_imm (inst);
  456. if (targetaddr & 0x8000)
  457. targetaddr |= 0xFFFF0000;
  458. }
  459. if (op->inst_offset_type == INST_PC_OFFSET)
  460. targetaddr += pcval;
  461. *targetvalid = TRUE;
  462. break;
  463. default:
  464. *targetvalid = FALSE;
  465. break;
  466. }
  467. }
  468. else if (op->instr_type == return_inst)
  469. {
  470. if (immfound)
  471. {
  472. targetaddr = (immval << 16) & 0xffff0000;
  473. targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
  474. }
  475. else
  476. {
  477. targetaddr = get_int_field_imm (inst);
  478. if (targetaddr & 0x8000)
  479. targetaddr |= 0xFFFF0000;
  480. }
  481. targetaddr += r1val;
  482. *targetvalid = TRUE;
  483. }
  484. else
  485. *targetvalid = FALSE;
  486. return targetaddr;
  487. }