12a6b7db3Sskrll/* M32R opcode support. -*- C -*- 22a6b7db3Sskrll 3*be12b8bcSchristos Copyright 1998, 1999, 2000, 2001, 2004, 2005, 2007, 2009 42a6b7db3Sskrll Free Software Foundation, Inc. 52a6b7db3Sskrll 62a6b7db3Sskrll Contributed by Red Hat Inc; developed under contract from 72a6b7db3Sskrll Mitsubishi Electric Corporation. 82a6b7db3Sskrll 92a6b7db3Sskrll This file is part of the GNU Binutils. 102a6b7db3Sskrll 112a6b7db3Sskrll This program is free software; you can redistribute it and/or modify 122a6b7db3Sskrll it under the terms of the GNU General Public License as published by 132a6b7db3Sskrll the Free Software Foundation; either version 3 of the License, or 142a6b7db3Sskrll (at your option) any later version. 152a6b7db3Sskrll 162a6b7db3Sskrll This program is distributed in the hope that it will be useful, 172a6b7db3Sskrll but WITHOUT ANY WARRANTY; without even the implied warranty of 182a6b7db3Sskrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 192a6b7db3Sskrll GNU General Public License for more details. 202a6b7db3Sskrll 212a6b7db3Sskrll You should have received a copy of the GNU General Public License 222a6b7db3Sskrll along with this program; if not, write to the Free Software 232a6b7db3Sskrll Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 242a6b7db3Sskrll MA 02110-1301, USA. */ 252a6b7db3Sskrll 262a6b7db3Sskrll 272a6b7db3Sskrll/* This file is an addendum to m32r.cpu. Heavy use of C code isn't 282a6b7db3Sskrll appropriate in .cpu files, so it resides here. This especially applies 292a6b7db3Sskrll to assembly/disassembly where parsing/printing can be quite involved. 302a6b7db3Sskrll Such things aren't really part of the specification of the cpu, per se, 312a6b7db3Sskrll so .cpu files provide the general framework and .opc files handle the 322a6b7db3Sskrll nitty-gritty details as necessary. 332a6b7db3Sskrll 342a6b7db3Sskrll Each section is delimited with start and end markers. 352a6b7db3Sskrll 362a6b7db3Sskrll <arch>-opc.h additions use: "-- opc.h" 372a6b7db3Sskrll <arch>-opc.c additions use: "-- opc.c" 382a6b7db3Sskrll <arch>-asm.c additions use: "-- asm.c" 392a6b7db3Sskrll <arch>-dis.c additions use: "-- dis.c" 402a6b7db3Sskrll <arch>-ibd.h additions use: "-- ibd.h" */ 412a6b7db3Sskrll 422a6b7db3Sskrll/* -- opc.h */ 432a6b7db3Sskrll 442a6b7db3Sskrll#undef CGEN_DIS_HASH_SIZE 452a6b7db3Sskrll#define CGEN_DIS_HASH_SIZE 256 462a6b7db3Sskrll#undef CGEN_DIS_HASH 472a6b7db3Sskrll#if 0 482a6b7db3Sskrll#define X(b) (((unsigned char *) (b))[0] & 0xf0) 492a6b7db3Sskrll#define CGEN_DIS_HASH(buffer, value) \ 502a6b7db3Sskrll(X (buffer) | \ 512a6b7db3Sskrll (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \ 522a6b7db3Sskrll : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \ 532a6b7db3Sskrll : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \ 542a6b7db3Sskrll : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4))) 552a6b7db3Sskrll#else 562a6b7db3Sskrll#define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value) 572a6b7db3Sskrllextern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT); 582a6b7db3Sskrll#endif 592a6b7db3Sskrll 602a6b7db3Sskrll/* -- */ 612a6b7db3Sskrll 622a6b7db3Sskrll/* -- opc.c */ 632a6b7db3Sskrllunsigned int 642a6b7db3Sskrllm32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value) 652a6b7db3Sskrll{ 662a6b7db3Sskrll unsigned int x; 672a6b7db3Sskrll 682a6b7db3Sskrll if (value & 0xffff0000) /* 32bit instructions. */ 692a6b7db3Sskrll value = (value >> 16) & 0xffff; 702a6b7db3Sskrll 712a6b7db3Sskrll x = (value >> 8) & 0xf0; 722a6b7db3Sskrll if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50) 732a6b7db3Sskrll return x; 742a6b7db3Sskrll 752a6b7db3Sskrll if (x == 0x70 || x == 0xf0) 762a6b7db3Sskrll return x | ((value >> 8) & 0x0f); 772a6b7db3Sskrll 782a6b7db3Sskrll if (x == 0x30) 792a6b7db3Sskrll return x | ((value & 0x70) >> 4); 802a6b7db3Sskrll else 812a6b7db3Sskrll return x | ((value & 0xf0) >> 4); 822a6b7db3Sskrll} 832a6b7db3Sskrll 842a6b7db3Sskrll/* -- */ 852a6b7db3Sskrll 862a6b7db3Sskrll/* -- asm.c */ 872a6b7db3Sskrllstatic const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'"); 882a6b7db3Sskrll 892a6b7db3Sskrll/* Handle '#' prefixes (i.e. skip over them). */ 902a6b7db3Sskrll 912a6b7db3Sskrllstatic const char * 922a6b7db3Sskrllparse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 932a6b7db3Sskrll const char **strp, 942a6b7db3Sskrll int opindex ATTRIBUTE_UNUSED, 952a6b7db3Sskrll long *valuep ATTRIBUTE_UNUSED) 962a6b7db3Sskrll{ 972a6b7db3Sskrll if (**strp == '#') 982a6b7db3Sskrll ++*strp; 992a6b7db3Sskrll return NULL; 1002a6b7db3Sskrll} 1012a6b7db3Sskrll 1022a6b7db3Sskrll/* Handle shigh(), high(). */ 1032a6b7db3Sskrll 1042a6b7db3Sskrllstatic const char * 1052a6b7db3Sskrllparse_hi16 (CGEN_CPU_DESC cd, 1062a6b7db3Sskrll const char **strp, 1072a6b7db3Sskrll int opindex, 1082a6b7db3Sskrll unsigned long *valuep) 1092a6b7db3Sskrll{ 1102a6b7db3Sskrll const char *errmsg; 1112a6b7db3Sskrll enum cgen_parse_operand_result result_type; 1122a6b7db3Sskrll bfd_vma value; 1132a6b7db3Sskrll 1142a6b7db3Sskrll if (**strp == '#') 1152a6b7db3Sskrll ++*strp; 1162a6b7db3Sskrll 1172a6b7db3Sskrll if (strncasecmp (*strp, "high(", 5) == 0) 1182a6b7db3Sskrll { 1192a6b7db3Sskrll *strp += 5; 1202a6b7db3Sskrll errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO, 1212a6b7db3Sskrll & result_type, & value); 1222a6b7db3Sskrll if (**strp != ')') 1232a6b7db3Sskrll return MISSING_CLOSING_PARENTHESIS; 1242a6b7db3Sskrll ++*strp; 1252a6b7db3Sskrll if (errmsg == NULL 1262a6b7db3Sskrll && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 1272a6b7db3Sskrll { 1282a6b7db3Sskrll value >>= 16; 1292a6b7db3Sskrll value &= 0xffff; 1302a6b7db3Sskrll } 1312a6b7db3Sskrll *valuep = value; 1322a6b7db3Sskrll return errmsg; 1332a6b7db3Sskrll } 1342a6b7db3Sskrll else if (strncasecmp (*strp, "shigh(", 6) == 0) 1352a6b7db3Sskrll { 1362a6b7db3Sskrll *strp += 6; 1372a6b7db3Sskrll errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO, 1382a6b7db3Sskrll & result_type, & value); 1392a6b7db3Sskrll if (**strp != ')') 1402a6b7db3Sskrll return MISSING_CLOSING_PARENTHESIS; 1412a6b7db3Sskrll ++*strp; 1422a6b7db3Sskrll if (errmsg == NULL 1432a6b7db3Sskrll && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 1442a6b7db3Sskrll { 1452a6b7db3Sskrll value += 0x8000; 1462a6b7db3Sskrll value >>= 16; 1472a6b7db3Sskrll value &= 0xffff; 1482a6b7db3Sskrll } 1492a6b7db3Sskrll *valuep = value; 1502a6b7db3Sskrll return errmsg; 1512a6b7db3Sskrll } 1522a6b7db3Sskrll 1532a6b7db3Sskrll return cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 1542a6b7db3Sskrll} 1552a6b7db3Sskrll 1562a6b7db3Sskrll/* Handle low() in a signed context. Also handle sda(). 1572a6b7db3Sskrll The signedness of the value doesn't matter to low(), but this also 1582a6b7db3Sskrll handles the case where low() isn't present. */ 1592a6b7db3Sskrll 1602a6b7db3Sskrllstatic const char * 1612a6b7db3Sskrllparse_slo16 (CGEN_CPU_DESC cd, 1622a6b7db3Sskrll const char ** strp, 1632a6b7db3Sskrll int opindex, 1642a6b7db3Sskrll long * valuep) 1652a6b7db3Sskrll{ 1662a6b7db3Sskrll const char *errmsg; 1672a6b7db3Sskrll enum cgen_parse_operand_result result_type; 1682a6b7db3Sskrll bfd_vma value; 1692a6b7db3Sskrll 1702a6b7db3Sskrll if (**strp == '#') 1712a6b7db3Sskrll ++*strp; 1722a6b7db3Sskrll 1732a6b7db3Sskrll if (strncasecmp (*strp, "low(", 4) == 0) 1742a6b7db3Sskrll { 1752a6b7db3Sskrll *strp += 4; 1762a6b7db3Sskrll errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16, 1772a6b7db3Sskrll & result_type, & value); 1782a6b7db3Sskrll if (**strp != ')') 1792a6b7db3Sskrll return MISSING_CLOSING_PARENTHESIS; 1802a6b7db3Sskrll ++*strp; 1812a6b7db3Sskrll if (errmsg == NULL 1822a6b7db3Sskrll && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 1832a6b7db3Sskrll value = ((value & 0xffff) ^ 0x8000) - 0x8000; 1842a6b7db3Sskrll *valuep = value; 1852a6b7db3Sskrll return errmsg; 1862a6b7db3Sskrll } 1872a6b7db3Sskrll 1882a6b7db3Sskrll if (strncasecmp (*strp, "sda(", 4) == 0) 1892a6b7db3Sskrll { 1902a6b7db3Sskrll *strp += 4; 1912a6b7db3Sskrll errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16, 1922a6b7db3Sskrll NULL, & value); 1932a6b7db3Sskrll if (**strp != ')') 1942a6b7db3Sskrll return MISSING_CLOSING_PARENTHESIS; 1952a6b7db3Sskrll ++*strp; 1962a6b7db3Sskrll *valuep = value; 1972a6b7db3Sskrll return errmsg; 1982a6b7db3Sskrll } 1992a6b7db3Sskrll 2002a6b7db3Sskrll return cgen_parse_signed_integer (cd, strp, opindex, valuep); 2012a6b7db3Sskrll} 2022a6b7db3Sskrll 2032a6b7db3Sskrll/* Handle low() in an unsigned context. 2042a6b7db3Sskrll The signedness of the value doesn't matter to low(), but this also 2052a6b7db3Sskrll handles the case where low() isn't present. */ 2062a6b7db3Sskrll 2072a6b7db3Sskrllstatic const char * 2082a6b7db3Sskrllparse_ulo16 (CGEN_CPU_DESC cd, 2092a6b7db3Sskrll const char **strp, 2102a6b7db3Sskrll int opindex, 2112a6b7db3Sskrll unsigned long *valuep) 2122a6b7db3Sskrll{ 2132a6b7db3Sskrll const char *errmsg; 2142a6b7db3Sskrll enum cgen_parse_operand_result result_type; 2152a6b7db3Sskrll bfd_vma value; 2162a6b7db3Sskrll 2172a6b7db3Sskrll if (**strp == '#') 2182a6b7db3Sskrll ++*strp; 2192a6b7db3Sskrll 2202a6b7db3Sskrll if (strncasecmp (*strp, "low(", 4) == 0) 2212a6b7db3Sskrll { 2222a6b7db3Sskrll *strp += 4; 2232a6b7db3Sskrll errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16, 2242a6b7db3Sskrll & result_type, & value); 2252a6b7db3Sskrll if (**strp != ')') 2262a6b7db3Sskrll return MISSING_CLOSING_PARENTHESIS; 2272a6b7db3Sskrll ++*strp; 2282a6b7db3Sskrll if (errmsg == NULL 2292a6b7db3Sskrll && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 2302a6b7db3Sskrll value &= 0xffff; 2312a6b7db3Sskrll *valuep = value; 2322a6b7db3Sskrll return errmsg; 2332a6b7db3Sskrll } 2342a6b7db3Sskrll 2352a6b7db3Sskrll return cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 2362a6b7db3Sskrll} 2372a6b7db3Sskrll 2382a6b7db3Sskrll/* -- */ 2392a6b7db3Sskrll 2402a6b7db3Sskrll/* -- dis.c */ 2412a6b7db3Sskrll 242*be12b8bcSchristos/* Print signed operands with '#' prefixes. */ 243*be12b8bcSchristos 244*be12b8bcSchristosstatic void 245*be12b8bcSchristosprint_signed_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 246*be12b8bcSchristos void * dis_info, 247*be12b8bcSchristos long value, 248*be12b8bcSchristos unsigned int attrs ATTRIBUTE_UNUSED, 249*be12b8bcSchristos bfd_vma pc ATTRIBUTE_UNUSED, 250*be12b8bcSchristos int length ATTRIBUTE_UNUSED) 251*be12b8bcSchristos{ 252*be12b8bcSchristos disassemble_info *info = (disassemble_info *) dis_info; 253*be12b8bcSchristos 254*be12b8bcSchristos (*info->fprintf_func) (info->stream, "#"); 255*be12b8bcSchristos (*info->fprintf_func) (info->stream, "%ld", value); 256*be12b8bcSchristos} 257*be12b8bcSchristos 258*be12b8bcSchristos/* Print unsigned operands with '#' prefixes. */ 259*be12b8bcSchristos 260*be12b8bcSchristosstatic void 261*be12b8bcSchristosprint_unsigned_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 262*be12b8bcSchristos void * dis_info, 263*be12b8bcSchristos long value, 264*be12b8bcSchristos unsigned int attrs ATTRIBUTE_UNUSED, 265*be12b8bcSchristos bfd_vma pc ATTRIBUTE_UNUSED, 266*be12b8bcSchristos int length ATTRIBUTE_UNUSED) 267*be12b8bcSchristos{ 268*be12b8bcSchristos disassemble_info *info = (disassemble_info *) dis_info; 269*be12b8bcSchristos 270*be12b8bcSchristos (*info->fprintf_func) (info->stream, "#"); 271*be12b8bcSchristos (*info->fprintf_func) (info->stream, "0x%lx", value); 272*be12b8bcSchristos} 2732a6b7db3Sskrll 2742a6b7db3Sskrll/* Handle '#' prefixes as operands. */ 2752a6b7db3Sskrll 2762a6b7db3Sskrllstatic void 2772a6b7db3Sskrllprint_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 2782a6b7db3Sskrll void * dis_info, 2792a6b7db3Sskrll long value ATTRIBUTE_UNUSED, 2802a6b7db3Sskrll unsigned int attrs ATTRIBUTE_UNUSED, 2812a6b7db3Sskrll bfd_vma pc ATTRIBUTE_UNUSED, 2822a6b7db3Sskrll int length ATTRIBUTE_UNUSED) 2832a6b7db3Sskrll{ 2842a6b7db3Sskrll disassemble_info *info = (disassemble_info *) dis_info; 2852a6b7db3Sskrll 2862a6b7db3Sskrll (*info->fprintf_func) (info->stream, "#"); 2872a6b7db3Sskrll} 2882a6b7db3Sskrll 2892a6b7db3Sskrll#undef CGEN_PRINT_INSN 2902a6b7db3Sskrll#define CGEN_PRINT_INSN my_print_insn 2912a6b7db3Sskrll 2922a6b7db3Sskrllstatic int 2932a6b7db3Sskrllmy_print_insn (CGEN_CPU_DESC cd, 2942a6b7db3Sskrll bfd_vma pc, 2952a6b7db3Sskrll disassemble_info *info) 2962a6b7db3Sskrll{ 2972a6b7db3Sskrll bfd_byte buffer[CGEN_MAX_INSN_SIZE]; 2982a6b7db3Sskrll bfd_byte *buf = buffer; 2992a6b7db3Sskrll int status; 3002a6b7db3Sskrll int buflen = (pc & 3) == 0 ? 4 : 2; 3012a6b7db3Sskrll int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG; 3022a6b7db3Sskrll bfd_byte *x; 3032a6b7db3Sskrll 3042a6b7db3Sskrll /* Read the base part of the insn. */ 3052a6b7db3Sskrll 3062a6b7db3Sskrll status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0), 3072a6b7db3Sskrll buf, buflen, info); 3082a6b7db3Sskrll if (status != 0) 3092a6b7db3Sskrll { 3102a6b7db3Sskrll (*info->memory_error_func) (status, pc, info); 3112a6b7db3Sskrll return -1; 3122a6b7db3Sskrll } 3132a6b7db3Sskrll 3142a6b7db3Sskrll /* 32 bit insn? */ 3152a6b7db3Sskrll x = (big_p ? &buf[0] : &buf[3]); 3162a6b7db3Sskrll if ((pc & 3) == 0 && (*x & 0x80) != 0) 3172a6b7db3Sskrll return print_insn (cd, pc, info, buf, buflen); 3182a6b7db3Sskrll 3192a6b7db3Sskrll /* Print the first insn. */ 3202a6b7db3Sskrll if ((pc & 3) == 0) 3212a6b7db3Sskrll { 3222a6b7db3Sskrll buf += (big_p ? 0 : 2); 3232a6b7db3Sskrll if (print_insn (cd, pc, info, buf, 2) == 0) 3242a6b7db3Sskrll (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); 3252a6b7db3Sskrll buf += (big_p ? 2 : -2); 3262a6b7db3Sskrll } 3272a6b7db3Sskrll 3282a6b7db3Sskrll x = (big_p ? &buf[0] : &buf[1]); 3292a6b7db3Sskrll if (*x & 0x80) 3302a6b7db3Sskrll { 3312a6b7db3Sskrll /* Parallel. */ 3322a6b7db3Sskrll (*info->fprintf_func) (info->stream, " || "); 3332a6b7db3Sskrll *x &= 0x7f; 3342a6b7db3Sskrll } 3352a6b7db3Sskrll else 3362a6b7db3Sskrll (*info->fprintf_func) (info->stream, " -> "); 3372a6b7db3Sskrll 3382a6b7db3Sskrll /* The "& 3" is to pass a consistent address. 3392a6b7db3Sskrll Parallel insns arguably both begin on the word boundary. 3402a6b7db3Sskrll Also, branch insns are calculated relative to the word boundary. */ 3412a6b7db3Sskrll if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0) 3422a6b7db3Sskrll (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); 3432a6b7db3Sskrll 3442a6b7db3Sskrll return (pc & 3) ? 2 : 4; 3452a6b7db3Sskrll} 3462a6b7db3Sskrll 3472a6b7db3Sskrll/* -- */ 348