Add-in development tools for fx-9860G and fx-CG 50, to use with GCC and gint.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

269 lines
5.9 KiB

  1. #include <fxos.h>
  2. #include <errors.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. /* Architecture we are disassembling for */
  6. static enum mpu mpu = MPU_GUESS;
  7. /* Current program counter */
  8. static uint32_t pc = 0;
  9. /* Data chunk under disassembly (whole file) */
  10. static uint8_t *data;
  11. static size_t len;
  12. /* Non-NULL when disassembling an OS */
  13. static struct os const *os = NULL;
  14. /* pcdisp(): Compute the address of a PC-relative displacement
  15. @pc Current PC value
  16. @disp Displacement value (from opcode)
  17. @unit Number of bytes per step (1, 2 or 4), depends on instruction
  18. Returns the pointed location. */
  19. static uint32_t pcdisp(uint32_t pc, uint32_t disp, int unit)
  20. {
  21. pc += 4;
  22. if(unit == 4) pc &= ~3;
  23. return pc + disp * unit;
  24. }
  25. /* pcread(): Read data pointed through a PC-relative displacement
  26. @pc Current PC value
  27. @disp Displacement value (from opcode)
  28. @unit Number of bytes per set (also number of bytes read)
  29. @out If non-NULL, set to 1 if pointed address is out of the file
  30. Returns the value pointed at, an undefined value if out of bounds. */
  31. static uint32_t pcread(uint32_t pc, uint32_t disp, int unit, int *out)
  32. {
  33. /* Take physical addresses */
  34. uint32_t addr = pcdisp(pc, disp, unit) & 0x1fffffff;
  35. if(out) *out = (addr + unit > len);
  36. uint32_t value = 0;
  37. while(unit--) value = (value << 8) | data[addr++];
  38. return value;
  39. }
  40. /* matches(): Count number of matches for a single instruction
  41. @opcode 16-bit opcode value
  42. Returns the number of matching instructions in the database. */
  43. static int matches(uint16_t opcode)
  44. {
  45. struct asm_match match;
  46. int count = 0;
  47. while(!asm_decode(opcode, &match, count))
  48. {
  49. count++;
  50. }
  51. return count;
  52. }
  53. static void arg_output(int type, char const *literal,
  54. struct asm_match const *match, int opsize)
  55. {
  56. int n = match->n;
  57. int m = match->m;
  58. int d = match->d;
  59. int i = match->i;
  60. /* Sign extensions of d to 8 and 12 bits */
  61. int32_t d8 = (int8_t)d;
  62. int32_t d12 = (d & 0x800) ? (int32_t)(d | 0xfffff000) : (d);
  63. /* Sign extension of i to 8 bits */
  64. int32_t i8 = (int8_t)i;
  65. int out_of_bounds;
  66. uint32_t addr;
  67. uint32_t value;
  68. switch(type)
  69. {
  70. case LITERAL:
  71. printf("%s", literal);
  72. break;
  73. case IMM:
  74. printf("#%d", i8);
  75. break;
  76. case RN:
  77. printf("r%d", n);
  78. break;
  79. case RM:
  80. printf("r%d", m);
  81. break;
  82. case JUMP8:
  83. value = pcdisp(pc, d8, 2);
  84. printf("<%x", value);
  85. if(os) analysis_short(os, value | 0x80000000);
  86. printf(">");
  87. break;
  88. case JUMP12:
  89. value = pcdisp(pc, d12, 2);
  90. printf("<%x", value);
  91. if(os) analysis_short(os, value | 0x80000000);
  92. printf(">");
  93. break;
  94. case PCDISP:
  95. addr = pcdisp(pc, d, opsize);
  96. value = pcread(pc, d, opsize, &out_of_bounds);
  97. printf("<%x>", addr);
  98. if(out_of_bounds) printf("(out of bounds)");
  99. else
  100. {
  101. printf("(#0x%0*x", opsize * 2, value);
  102. if(os) analysis_short(os, value);
  103. printf(")");
  104. }
  105. break;
  106. case AT_RN:
  107. printf("@r%d", n);
  108. break;
  109. case AT_RM:
  110. printf("@r%d", m);
  111. break;
  112. case AT_RMP:
  113. printf("@r%d+", m);
  114. break;
  115. case AT_RNP:
  116. printf("@r%d+", n);
  117. break;
  118. case AT_MRN:
  119. printf("@-r%d", n);
  120. break;
  121. case AT_DRN:
  122. printf("@(%d, r%d)", d * opsize, n);
  123. break;
  124. case AT_DRM:
  125. printf("@(%d, r%d)", d * opsize, m);
  126. break;
  127. case AT_R0RN:
  128. printf("@(r0, r%d)", n);
  129. break;
  130. case AT_R0RM:
  131. printf("@(r0, r%d)", m);
  132. break;
  133. case AT_DGBR:
  134. printf("@(%d, gbr)", d * opsize);
  135. break;
  136. }
  137. }
  138. static void instruction_output(uint16_t opcode, struct asm_match const *match)
  139. {
  140. char const *mnemonic = match->insn->mnemonic;
  141. printf(" %5x: %04x %s", pc, opcode, mnemonic);
  142. /* Find out operation size */
  143. size_t n = strlen(mnemonic);
  144. int opsize = 0;
  145. if(n >= 3 && mnemonic[n-2] == '.')
  146. {
  147. int c = mnemonic[n-1];
  148. opsize = (c == 'b') + 2 * (c == 'w') + 4 * (c == 'l');
  149. }
  150. /* Output arguments */
  151. if(!match->insn->arg1) return;
  152. printf("%*s", (int)(8-n), "");
  153. arg_output(match->insn->arg1, match->insn->literal1, match, opsize);
  154. if(!match->insn->arg2) return;
  155. printf(", ");
  156. arg_output(match->insn->arg2, match->insn->literal2, match, opsize);
  157. }
  158. static void instruction_single(uint16_t opcode)
  159. {
  160. struct asm_match match;
  161. asm_decode(opcode, &match, 0);
  162. instruction_output(opcode, &match);
  163. printf("\n");
  164. }
  165. static void instruction_conflicts(uint16_t opcode, int count)
  166. {
  167. struct asm_match match;
  168. printf("\n # conflicts[%d] on <%x>(%04x)\n", count, pc, opcode);
  169. for(int i = 0; i < count; i++)
  170. {
  171. asm_decode(opcode, &match, i);
  172. instruction_output(opcode, &match);
  173. printf(" # table '%s'\n", match.table);
  174. }
  175. printf("\n");
  176. }
  177. /* disassembly_os(): Disassemble an address or a syscall */
  178. void disassembly_os(struct os const *src, struct disassembly const *opt)
  179. {
  180. /* Initialize this file's global state */
  181. mpu = src->mpu;
  182. pc = opt->start;
  183. data = src->data;
  184. len = src->len;
  185. os = src;
  186. /* Override MPU guesses if user requested a specific platform */
  187. if(opt->mpu != MPU_GUESS) mpu = opt->mpu;
  188. /* Handle situations where the start address is a syscall */
  189. if(opt->syscall)
  190. {
  191. pc = os_syscall(os, opt->start);
  192. if(pc == (uint32_t)-1)
  193. {
  194. err("syscall 0x%04x does not exist", opt->start);
  195. return;
  196. }
  197. }
  198. /* Take physical addresses */
  199. pc &= 0x1fffffff;
  200. /* Cut the length if it reaches past the end of the file */
  201. uint32_t limit = (pc + opt->len) & ~1;
  202. if(limit > os->len) limit = os->len;
  203. /* Enforce alignment of PC */
  204. if(pc & 1)
  205. {
  206. err("address is not 2-aligned, skipping 1 byte");
  207. pc += 1;
  208. }
  209. uint8_t *data = os->data;
  210. while(pc < limit)
  211. {
  212. if(os)
  213. {
  214. int syscall = os_syscall_find(os, pc | 0x80000000);
  215. if(syscall == -1)
  216. syscall = os_syscall_find(os, pc | 0xa0000000);
  217. if(syscall != -1)
  218. {
  219. struct sys_call const *s = sys_find(syscall);
  220. printf("\n<%x %%%03x", pc, syscall);
  221. if(s) printf(" %s", s->name);
  222. printf(">\n");
  223. }
  224. }
  225. uint16_t opcode = (data[pc] << 8) | data[pc + 1];
  226. int count = matches(opcode);
  227. if(count == 0) printf(" %5x: %04x\n", pc, opcode);
  228. else if(count == 1) instruction_single(opcode);
  229. else instruction_conflicts(opcode, count);
  230. pc += 2;
  231. }
  232. }