ip2k.opc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. /* IP2K opcode support. -*- C -*-
  2. Copyright 2002, 2005, 2011 Free Software Foundation, Inc.
  3. Contributed by Red Hat Inc;
  4. This file is part of the GNU Binutils.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  16. MA 02110-1301, USA. */
  17. /*
  18. Each section is delimited with start and end markers.
  19. <arch>-opc.h additions use: "-- opc.h"
  20. <arch>-opc.c additions use: "-- opc.c"
  21. <arch>-asm.c additions use: "-- asm.c"
  22. <arch>-dis.c additions use: "-- dis.c"
  23. <arch>-ibd.h additions use: "-- ibd.h". */
  24. /* -- opc.h */
  25. /* Check applicability of instructions against machines. */
  26. #define CGEN_VALIDATE_INSN_SUPPORTED
  27. /* Allows reason codes to be output when assembler errors occur. */
  28. #define CGEN_VERBOSE_ASSEMBLER_ERRORS
  29. /* Override disassembly hashing - there are variable bits in the top
  30. byte of these instructions. */
  31. #define CGEN_DIS_HASH_SIZE 8
  32. #define CGEN_DIS_HASH(buf, value) \
  33. (((* (unsigned char*) (buf)) >> 5) % CGEN_DIS_HASH_SIZE)
  34. #define CGEN_ASM_HASH_SIZE 127
  35. #define CGEN_ASM_HASH(insn) ip2k_asm_hash (insn)
  36. extern unsigned int ip2k_asm_hash (const char *);
  37. extern int ip2k_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
  38. /* -- opc.c */
  39. #include "safe-ctype.h"
  40. /* A better hash function for instruction mnemonics. */
  41. unsigned int
  42. ip2k_asm_hash (const char* insn)
  43. {
  44. unsigned int hash;
  45. const char* m = insn;
  46. for (hash = 0; *m && ! ISSPACE (*m); m++)
  47. hash = (hash * 23) ^ (0x1F & TOLOWER (*m));
  48. /* printf ("%s %d\n", insn, (hash % CGEN_ASM_HASH_SIZE)); */
  49. return hash % CGEN_ASM_HASH_SIZE;
  50. }
  51. /* Special check to ensure that instruction exists for given machine. */
  52. int
  53. ip2k_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
  54. {
  55. int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
  56. /* No mach attribute? Assume it's supported for all machs. */
  57. if (machs == 0)
  58. return 1;
  59. return (machs & cd->machs) != 0;
  60. }
  61. /* -- asm.c */
  62. static const char *
  63. parse_fr (CGEN_CPU_DESC cd,
  64. const char **strp,
  65. int opindex,
  66. unsigned long *valuep)
  67. {
  68. const char *errmsg;
  69. const char *old_strp;
  70. char *afteroffset;
  71. enum cgen_parse_operand_result result_type;
  72. bfd_vma value;
  73. extern CGEN_KEYWORD ip2k_cgen_opval_register_names;
  74. bfd_vma tempvalue;
  75. old_strp = *strp;
  76. afteroffset = NULL;
  77. /* Check here to see if you're about to try parsing a w as the first arg
  78. and return an error if you are. */
  79. if ((strncmp (*strp, "w", 1) == 0) || (strncmp (*strp, "W", 1) == 0))
  80. {
  81. (*strp)++;
  82. if ((strncmp (*strp, ",", 1) == 0) || ISSPACE (**strp))
  83. {
  84. /* We've been passed a w. Return with an error message so that
  85. cgen will try the next parsing option. */
  86. errmsg = _("W keyword invalid in FR operand slot.");
  87. return errmsg;
  88. }
  89. *strp = old_strp;
  90. }
  91. /* Attempt parse as register keyword. */
  92. errmsg = cgen_parse_keyword (cd, strp, & ip2k_cgen_opval_register_names,
  93. (long *) valuep);
  94. if (*strp != NULL
  95. && errmsg == NULL)
  96. return errmsg;
  97. /* Attempt to parse for "(IP)". */
  98. afteroffset = strstr (*strp, "(IP)");
  99. if (afteroffset == NULL)
  100. /* Make sure it's not in lower case. */
  101. afteroffset = strstr (*strp, "(ip)");
  102. if (afteroffset != NULL)
  103. {
  104. if (afteroffset != *strp)
  105. {
  106. /* Invalid offset present. */
  107. errmsg = _("offset(IP) is not a valid form");
  108. return errmsg;
  109. }
  110. else
  111. {
  112. *strp += 4;
  113. *valuep = 0;
  114. errmsg = NULL;
  115. return errmsg;
  116. }
  117. }
  118. /* Attempt to parse for DP. ex: mov w, offset(DP)
  119. mov offset(DP),w */
  120. /* Try parsing it as an address and see what comes back. */
  121. afteroffset = strstr (*strp, "(DP)");
  122. if (afteroffset == NULL)
  123. /* Maybe it's in lower case. */
  124. afteroffset = strstr (*strp, "(dp)");
  125. if (afteroffset != NULL)
  126. {
  127. if (afteroffset == *strp)
  128. {
  129. /* No offset present. Use 0 by default. */
  130. tempvalue = 0;
  131. errmsg = NULL;
  132. }
  133. else
  134. errmsg = cgen_parse_address (cd, strp, opindex,
  135. BFD_RELOC_IP2K_FR_OFFSET,
  136. & result_type, & tempvalue);
  137. if (errmsg == NULL)
  138. {
  139. if (tempvalue <= 127)
  140. {
  141. /* Value is ok. Fix up the first 2 bits and return. */
  142. *valuep = 0x0100 | tempvalue;
  143. *strp += 4; /* Skip over the (DP) in *strp. */
  144. return errmsg;
  145. }
  146. else
  147. {
  148. /* Found something there in front of (DP) but it's out
  149. of range. */
  150. errmsg = _("(DP) offset out of range.");
  151. return errmsg;
  152. }
  153. }
  154. }
  155. /* Attempt to parse for SP. ex: mov w, offset(SP)
  156. mov offset(SP), w. */
  157. afteroffset = strstr (*strp, "(SP)");
  158. if (afteroffset == NULL)
  159. /* Maybe it's in lower case. */
  160. afteroffset = strstr (*strp, "(sp)");
  161. if (afteroffset != NULL)
  162. {
  163. if (afteroffset == *strp)
  164. {
  165. /* No offset present. Use 0 by default. */
  166. tempvalue = 0;
  167. errmsg = NULL;
  168. }
  169. else
  170. errmsg = cgen_parse_address (cd, strp, opindex,
  171. BFD_RELOC_IP2K_FR_OFFSET,
  172. & result_type, & tempvalue);
  173. if (errmsg == NULL)
  174. {
  175. if (tempvalue <= 127)
  176. {
  177. /* Value is ok. Fix up the first 2 bits and return. */
  178. *valuep = 0x0180 | tempvalue;
  179. *strp += 4; /* Skip over the (SP) in *strp. */
  180. return errmsg;
  181. }
  182. else
  183. {
  184. /* Found something there in front of (SP) but it's out
  185. of range. */
  186. errmsg = _("(SP) offset out of range.");
  187. return errmsg;
  188. }
  189. }
  190. }
  191. /* Attempt to parse as an address. */
  192. *strp = old_strp;
  193. errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IP2K_FR9,
  194. & result_type, & value);
  195. if (errmsg == NULL)
  196. {
  197. *valuep = value;
  198. /* If a parenthesis is found, warn about invalid form. */
  199. if (**strp == '(')
  200. errmsg = _("illegal use of parentheses");
  201. /* If a numeric value is specified, ensure that it is between
  202. 1 and 255. */
  203. else if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
  204. {
  205. if (value < 0x1 || value > 0xff)
  206. errmsg = _("operand out of range (not between 1 and 255)");
  207. }
  208. }
  209. return errmsg;
  210. }
  211. static const char *
  212. parse_addr16 (CGEN_CPU_DESC cd,
  213. const char **strp,
  214. int opindex,
  215. unsigned long *valuep)
  216. {
  217. const char *errmsg;
  218. enum cgen_parse_operand_result result_type;
  219. bfd_reloc_code_real_type code = BFD_RELOC_NONE;
  220. bfd_vma value;
  221. if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16H)
  222. code = BFD_RELOC_IP2K_HI8DATA;
  223. else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16L)
  224. code = BFD_RELOC_IP2K_LO8DATA;
  225. else
  226. {
  227. /* Something is very wrong. opindex has to be one of the above. */
  228. errmsg = _("parse_addr16: invalid opindex.");
  229. return errmsg;
  230. }
  231. errmsg = cgen_parse_address (cd, strp, opindex, code,
  232. & result_type, & value);
  233. if (errmsg == NULL)
  234. {
  235. /* We either have a relocation or a number now. */
  236. if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
  237. {
  238. /* We got a number back. */
  239. if (code == BFD_RELOC_IP2K_HI8DATA)
  240. value >>= 8;
  241. else
  242. /* code = BFD_RELOC_IP2K_LOW8DATA. */
  243. value &= 0x00FF;
  244. }
  245. *valuep = value;
  246. }
  247. return errmsg;
  248. }
  249. static const char *
  250. parse_addr16_cjp (CGEN_CPU_DESC cd,
  251. const char **strp,
  252. int opindex,
  253. unsigned long *valuep)
  254. {
  255. const char *errmsg;
  256. enum cgen_parse_operand_result result_type;
  257. bfd_reloc_code_real_type code = BFD_RELOC_NONE;
  258. bfd_vma value;
  259. if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16CJP)
  260. code = BFD_RELOC_IP2K_ADDR16CJP;
  261. else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16P)
  262. code = BFD_RELOC_IP2K_PAGE3;
  263. errmsg = cgen_parse_address (cd, strp, opindex, code,
  264. & result_type, & value);
  265. if (errmsg == NULL)
  266. {
  267. if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
  268. {
  269. if ((value & 0x1) == 0) /* If the address is even .... */
  270. {
  271. if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16CJP)
  272. *valuep = (value >> 1) & 0x1FFF; /* Should mask be 1FFF? */
  273. else if (opindex == (CGEN_OPERAND_TYPE) IP2K_OPERAND_ADDR16P)
  274. *valuep = (value >> 14) & 0x7;
  275. }
  276. else
  277. errmsg = _("Byte address required. - must be even.");
  278. }
  279. else if (result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED)
  280. {
  281. /* This will happen for things like (s2-s1) where s2 and s1
  282. are labels. */
  283. *valuep = value;
  284. }
  285. else
  286. errmsg = _("cgen_parse_address returned a symbol. Literal required.");
  287. }
  288. return errmsg;
  289. }
  290. static const char *
  291. parse_lit8 (CGEN_CPU_DESC cd,
  292. const char **strp,
  293. int opindex,
  294. long *valuep)
  295. {
  296. const char *errmsg;
  297. enum cgen_parse_operand_result result_type;
  298. bfd_reloc_code_real_type code = BFD_RELOC_NONE;
  299. bfd_vma value;
  300. /* Parse %OP relocating operators. */
  301. if (strncmp (*strp, "%bank", 5) == 0)
  302. {
  303. *strp += 5;
  304. code = BFD_RELOC_IP2K_BANK;
  305. }
  306. else if (strncmp (*strp, "%lo8data", 8) == 0)
  307. {
  308. *strp += 8;
  309. code = BFD_RELOC_IP2K_LO8DATA;
  310. }
  311. else if (strncmp (*strp, "%hi8data", 8) == 0)
  312. {
  313. *strp += 8;
  314. code = BFD_RELOC_IP2K_HI8DATA;
  315. }
  316. else if (strncmp (*strp, "%ex8data", 8) == 0)
  317. {
  318. *strp += 8;
  319. code = BFD_RELOC_IP2K_EX8DATA;
  320. }
  321. else if (strncmp (*strp, "%lo8insn", 8) == 0)
  322. {
  323. *strp += 8;
  324. code = BFD_RELOC_IP2K_LO8INSN;
  325. }
  326. else if (strncmp (*strp, "%hi8insn", 8) == 0)
  327. {
  328. *strp += 8;
  329. code = BFD_RELOC_IP2K_HI8INSN;
  330. }
  331. /* Parse %op operand. */
  332. if (code != BFD_RELOC_NONE)
  333. {
  334. errmsg = cgen_parse_address (cd, strp, opindex, code,
  335. & result_type, & value);
  336. if ((errmsg == NULL) &&
  337. (result_type != CGEN_PARSE_OPERAND_RESULT_QUEUED))
  338. errmsg = _("percent-operator operand is not a symbol");
  339. *valuep = value;
  340. }
  341. /* Parse as a number. */
  342. else
  343. {
  344. errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
  345. /* Truncate to eight bits to accept both signed and unsigned input. */
  346. if (errmsg == NULL)
  347. *valuep &= 0xFF;
  348. }
  349. return errmsg;
  350. }
  351. static const char *
  352. parse_bit3 (CGEN_CPU_DESC cd,
  353. const char **strp,
  354. int opindex,
  355. unsigned long *valuep)
  356. {
  357. const char *errmsg;
  358. char mode = 0;
  359. long count = 0;
  360. unsigned long value;
  361. if (strncmp (*strp, "%bit", 4) == 0)
  362. {
  363. *strp += 4;
  364. mode = 1;
  365. }
  366. else if (strncmp (*strp, "%msbbit", 7) == 0)
  367. {
  368. *strp += 7;
  369. mode = 1;
  370. }
  371. else if (strncmp (*strp, "%lsbbit", 7) == 0)
  372. {
  373. *strp += 7;
  374. mode = 2;
  375. }
  376. errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
  377. if (errmsg)
  378. return errmsg;
  379. if (mode)
  380. {
  381. value = * valuep;
  382. if (value == 0)
  383. {
  384. errmsg = _("Attempt to find bit index of 0");
  385. return errmsg;
  386. }
  387. if (mode == 1)
  388. {
  389. count = 31;
  390. while ((value & 0x80000000) == 0)
  391. {
  392. count--;
  393. value <<= 1;
  394. }
  395. }
  396. else if (mode == 2)
  397. {
  398. count = 0;
  399. while ((value & 0x00000001) == 0)
  400. {
  401. count++;
  402. value >>= 1;
  403. }
  404. }
  405. *valuep = count;
  406. }
  407. return errmsg;
  408. }
  409. /* -- dis.c */
  410. static void
  411. print_fr (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
  412. void * dis_info,
  413. long value,
  414. unsigned int attrs ATTRIBUTE_UNUSED,
  415. bfd_vma pc ATTRIBUTE_UNUSED,
  416. int length ATTRIBUTE_UNUSED)
  417. {
  418. disassemble_info *info = (disassemble_info *) dis_info;
  419. const CGEN_KEYWORD_ENTRY *ke;
  420. extern CGEN_KEYWORD ip2k_cgen_opval_register_names;
  421. long offsettest;
  422. long offsetvalue;
  423. if (value == 0) /* This is (IP). */
  424. {
  425. (*info->fprintf_func) (info->stream, "%s", "(IP)");
  426. return;
  427. }
  428. offsettest = value >> 7;
  429. offsetvalue = value & 0x7F;
  430. /* Check to see if first two bits are 10 -> (DP). */
  431. if (offsettest == 2)
  432. {
  433. if (offsetvalue == 0)
  434. (*info->fprintf_func) (info->stream, "%s","(DP)");
  435. else
  436. (*info->fprintf_func) (info->stream, "$%lx%s", offsetvalue, "(DP)");
  437. return;
  438. }
  439. /* Check to see if first two bits are 11 -> (SP). */
  440. if (offsettest == 3)
  441. {
  442. if (offsetvalue == 0)
  443. (*info->fprintf_func) (info->stream, "%s", "(SP)");
  444. else
  445. (*info->fprintf_func) (info->stream, "$%lx%s", offsetvalue,"(SP)");
  446. return;
  447. }
  448. /* Attempt to print as a register keyword. */
  449. ke = cgen_keyword_lookup_value (& ip2k_cgen_opval_register_names, value);
  450. if (ke != NULL)
  451. (*info->fprintf_func) (info->stream, "%s", ke->name);
  452. else
  453. /* Print as an address literal. */
  454. (*info->fprintf_func) (info->stream, "$%02lx", value);
  455. }
  456. static void
  457. print_dollarhex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
  458. void * dis_info,
  459. long value,
  460. unsigned int attrs ATTRIBUTE_UNUSED,
  461. bfd_vma pc ATTRIBUTE_UNUSED,
  462. int length ATTRIBUTE_UNUSED)
  463. {
  464. disassemble_info *info = (disassemble_info *) dis_info;
  465. (*info->fprintf_func) (info->stream, "$%lx", value);
  466. }
  467. static void
  468. print_dollarhex8 (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
  469. void * dis_info,
  470. long value,
  471. unsigned int attrs ATTRIBUTE_UNUSED,
  472. bfd_vma pc ATTRIBUTE_UNUSED,
  473. int length ATTRIBUTE_UNUSED)
  474. {
  475. disassemble_info *info = (disassemble_info *) dis_info;
  476. (*info->fprintf_func) (info->stream, "$%02lx", value);
  477. }
  478. static void
  479. print_dollarhex_addr16h (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
  480. void * dis_info,
  481. long value,
  482. unsigned int attrs ATTRIBUTE_UNUSED,
  483. bfd_vma pc ATTRIBUTE_UNUSED,
  484. int length ATTRIBUTE_UNUSED)
  485. {
  486. disassemble_info *info = (disassemble_info *) dis_info;
  487. /* This is a loadh instruction. Shift the value to the left
  488. by 8 bits so that disassembled code will reassemble properly. */
  489. value = ((value << 8) & 0xFF00);
  490. (*info->fprintf_func) (info->stream, "$%04lx", value);
  491. }
  492. static void
  493. print_dollarhex_addr16l (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
  494. void * dis_info,
  495. long value,
  496. unsigned int attrs ATTRIBUTE_UNUSED,
  497. bfd_vma pc ATTRIBUTE_UNUSED,
  498. int length ATTRIBUTE_UNUSED)
  499. {
  500. disassemble_info *info = (disassemble_info *) dis_info;
  501. (*info->fprintf_func) (info->stream, "$%04lx", value);
  502. }
  503. static void
  504. print_dollarhex_p (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
  505. void * dis_info,
  506. long value,
  507. unsigned int attrs ATTRIBUTE_UNUSED,
  508. bfd_vma pc ATTRIBUTE_UNUSED,
  509. int length ATTRIBUTE_UNUSED)
  510. {
  511. disassemble_info *info = (disassemble_info *) dis_info;
  512. value = ((value << 14) & 0x1C000);
  513. ;value = (value & 0x1FFFF);
  514. (*info->fprintf_func) (info->stream, "$%05lx", value);
  515. }
  516. static void
  517. print_dollarhex_cj (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
  518. void * dis_info,
  519. long value,
  520. unsigned int attrs ATTRIBUTE_UNUSED,
  521. bfd_vma pc ATTRIBUTE_UNUSED,
  522. int length ATTRIBUTE_UNUSED)
  523. {
  524. disassemble_info *info = (disassemble_info *) dis_info;
  525. value = ((value << 1) & 0x1FFFF);
  526. (*info->fprintf_func) (info->stream, "$%05lx", value);
  527. }
  528. static void
  529. print_decimal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
  530. void * dis_info,
  531. long value,
  532. unsigned int attrs ATTRIBUTE_UNUSED,
  533. bfd_vma pc ATTRIBUTE_UNUSED,
  534. int length ATTRIBUTE_UNUSED)
  535. {
  536. disassemble_info *info = (disassemble_info *) dis_info;
  537. (*info->fprintf_func) (info->stream, "%ld", value);
  538. }
  539. /* -- */