1 /* M32R opcode support. -*- C -*- 2 3 Copyright 1998, 1999, 2000, 2001, 2004, 2005, 2007, 2009 4 Free Software Foundation, Inc. 5 6 Contributed by Red Hat Inc; developed under contract from 7 Mitsubishi Electric Corporation. 8 9 This file is part of the GNU Binutils. 10 11 This program is free software; you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation; either version 3 of the License, or 14 (at your option) any later version. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program; if not, write to the Free Software 23 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 24 MA 02110-1301, USA. */ 25 26 27 /* This file is an addendum to m32r.cpu. Heavy use of C code isn't 28 appropriate in .cpu files, so it resides here. This especially applies 29 to assembly/disassembly where parsing/printing can be quite involved. 30 Such things aren't really part of the specification of the cpu, per se, 31 so .cpu files provide the general framework and .opc files handle the 32 nitty-gritty details as necessary. 33 34 Each section is delimited with start and end markers. 35 36 <arch>-opc.h additions use: "-- opc.h" 37 <arch>-opc.c additions use: "-- opc.c" 38 <arch>-asm.c additions use: "-- asm.c" 39 <arch>-dis.c additions use: "-- dis.c" 40 <arch>-ibd.h additions use: "-- ibd.h" */ 41 42 /* -- opc.h */ 44 45 #undef CGEN_DIS_HASH_SIZE 46 #define CGEN_DIS_HASH_SIZE 256 47 #undef CGEN_DIS_HASH 48 #if 0 49 #define X(b) (((unsigned char *) (b))[0] & 0xf0) 50 #define CGEN_DIS_HASH(buffer, value) \ 51 (X (buffer) | \ 52 (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \ 53 : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \ 54 : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \ 55 : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4))) 56 #else 57 #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value) 58 extern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT); 59 #endif 60 61 /* -- */ 62 63 /* -- opc.c */ 65 unsigned int 66 m32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value) 67 { 68 unsigned int x; 69 70 if (value & 0xffff0000) /* 32bit instructions. */ 71 value = (value >> 16) & 0xffff; 72 73 x = (value >> 8) & 0xf0; 74 if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50) 75 return x; 76 77 if (x == 0x70 || x == 0xf0) 78 return x | ((value >> 8) & 0x0f); 79 80 if (x == 0x30) 81 return x | ((value & 0x70) >> 4); 82 else 83 return x | ((value & 0xf0) >> 4); 84 } 85 86 /* -- */ 87 88 /* -- asm.c */ 90 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'"); 91 92 /* Handle '#' prefixes (i.e. skip over them). */ 93 94 static const char * 95 parse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 96 const char **strp, 97 int opindex ATTRIBUTE_UNUSED, 98 long *valuep ATTRIBUTE_UNUSED) 99 { 100 if (**strp == '#') 101 ++*strp; 102 return NULL; 103 } 104 105 /* Handle shigh(), high(). */ 106 107 static const char * 108 parse_hi16 (CGEN_CPU_DESC cd, 109 const char **strp, 110 int opindex, 111 unsigned long *valuep) 112 { 113 const char *errmsg; 114 enum cgen_parse_operand_result result_type; 115 bfd_vma value; 116 117 if (**strp == '#') 118 ++*strp; 119 120 if (strncasecmp (*strp, "high(", 5) == 0) 121 { 122 *strp += 5; 123 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO, 124 & result_type, & value); 125 if (**strp != ')') 126 return MISSING_CLOSING_PARENTHESIS; 127 ++*strp; 128 if (errmsg == NULL 129 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 130 { 131 value >>= 16; 132 value &= 0xffff; 133 } 134 *valuep = value; 135 return errmsg; 136 } 137 else if (strncasecmp (*strp, "shigh(", 6) == 0) 138 { 139 *strp += 6; 140 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO, 141 & result_type, & value); 142 if (**strp != ')') 143 return MISSING_CLOSING_PARENTHESIS; 144 ++*strp; 145 if (errmsg == NULL 146 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 147 { 148 value += 0x8000; 149 value >>= 16; 150 value &= 0xffff; 151 } 152 *valuep = value; 153 return errmsg; 154 } 155 156 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 157 } 158 159 /* Handle low() in a signed context. Also handle sda(). 160 The signedness of the value doesn't matter to low(), but this also 161 handles the case where low() isn't present. */ 162 163 static const char * 164 parse_slo16 (CGEN_CPU_DESC cd, 165 const char ** strp, 166 int opindex, 167 long * valuep) 168 { 169 const char *errmsg; 170 enum cgen_parse_operand_result result_type; 171 bfd_vma value; 172 173 if (**strp == '#') 174 ++*strp; 175 176 if (strncasecmp (*strp, "low(", 4) == 0) 177 { 178 *strp += 4; 179 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16, 180 & result_type, & value); 181 if (**strp != ')') 182 return MISSING_CLOSING_PARENTHESIS; 183 ++*strp; 184 if (errmsg == NULL 185 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 186 value = ((value & 0xffff) ^ 0x8000) - 0x8000; 187 *valuep = value; 188 return errmsg; 189 } 190 191 if (strncasecmp (*strp, "sda(", 4) == 0) 192 { 193 *strp += 4; 194 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16, 195 NULL, & value); 196 if (**strp != ')') 197 return MISSING_CLOSING_PARENTHESIS; 198 ++*strp; 199 *valuep = value; 200 return errmsg; 201 } 202 203 return cgen_parse_signed_integer (cd, strp, opindex, valuep); 204 } 205 206 /* Handle low() in an unsigned context. 207 The signedness of the value doesn't matter to low(), but this also 208 handles the case where low() isn't present. */ 209 210 static const char * 211 parse_ulo16 (CGEN_CPU_DESC cd, 212 const char **strp, 213 int opindex, 214 unsigned long *valuep) 215 { 216 const char *errmsg; 217 enum cgen_parse_operand_result result_type; 218 bfd_vma value; 219 220 if (**strp == '#') 221 ++*strp; 222 223 if (strncasecmp (*strp, "low(", 4) == 0) 224 { 225 *strp += 4; 226 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16, 227 & result_type, & value); 228 if (**strp != ')') 229 return MISSING_CLOSING_PARENTHESIS; 230 ++*strp; 231 if (errmsg == NULL 232 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 233 value &= 0xffff; 234 *valuep = value; 235 return errmsg; 236 } 237 238 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 239 } 240 241 /* -- */ 242 243 /* -- dis.c */ 245 246 /* Print signed operands with '#' prefixes. */ 247 248 static void 249 print_signed_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 250 void * dis_info, 251 long value, 252 unsigned int attrs ATTRIBUTE_UNUSED, 253 bfd_vma pc ATTRIBUTE_UNUSED, 254 int length ATTRIBUTE_UNUSED) 255 { 256 disassemble_info *info = (disassemble_info *) dis_info; 257 258 (*info->fprintf_func) (info->stream, "#"); 259 (*info->fprintf_func) (info->stream, "%ld", value); 260 } 261 262 /* Print unsigned operands with '#' prefixes. */ 263 264 static void 265 print_unsigned_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 266 void * dis_info, 267 long value, 268 unsigned int attrs ATTRIBUTE_UNUSED, 269 bfd_vma pc ATTRIBUTE_UNUSED, 270 int length ATTRIBUTE_UNUSED) 271 { 272 disassemble_info *info = (disassemble_info *) dis_info; 273 274 (*info->fprintf_func) (info->stream, "#"); 275 (*info->fprintf_func) (info->stream, "0x%lx", value); 276 } 277 278 /* Handle '#' prefixes as operands. */ 279 280 static void 281 print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 282 void * dis_info, 283 long value ATTRIBUTE_UNUSED, 284 unsigned int attrs ATTRIBUTE_UNUSED, 285 bfd_vma pc ATTRIBUTE_UNUSED, 286 int length ATTRIBUTE_UNUSED) 287 { 288 disassemble_info *info = (disassemble_info *) dis_info; 289 290 (*info->fprintf_func) (info->stream, "#"); 291 } 292 293 #undef CGEN_PRINT_INSN 294 #define CGEN_PRINT_INSN my_print_insn 295 296 static int 297 my_print_insn (CGEN_CPU_DESC cd, 298 bfd_vma pc, 299 disassemble_info *info) 300 { 301 bfd_byte buffer[CGEN_MAX_INSN_SIZE]; 302 bfd_byte *buf = buffer; 303 int status; 304 int buflen = (pc & 3) == 0 ? 4 : 2; 305 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG; 306 bfd_byte *x; 307 308 /* Read the base part of the insn. */ 309 310 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0), 311 buf, buflen, info); 312 if (status != 0) 313 { 314 (*info->memory_error_func) (status, pc, info); 315 return -1; 316 } 317 318 /* 32 bit insn? */ 319 x = (big_p ? &buf[0] : &buf[3]); 320 if ((pc & 3) == 0 && (*x & 0x80) != 0) 321 return print_insn (cd, pc, info, buf, buflen); 322 323 /* Print the first insn. */ 324 if ((pc & 3) == 0) 325 { 326 buf += (big_p ? 0 : 2); 327 if (print_insn (cd, pc, info, buf, 2) == 0) 328 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); 329 buf += (big_p ? 2 : -2); 330 } 331 332 x = (big_p ? &buf[0] : &buf[1]); 333 if (*x & 0x80) 334 { 335 /* Parallel. */ 336 (*info->fprintf_func) (info->stream, " || "); 337 *x &= 0x7f; 338 } 339 else 340 (*info->fprintf_func) (info->stream, " -> "); 341 342 /* The "& 3" is to pass a consistent address. 343 Parallel insns arguably both begin on the word boundary. 344 Also, branch insns are calculated relative to the word boundary. */ 345 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0) 346 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); 347 348 return (pc & 3) ? 2 : 4; 349 } 350 351 /* -- */ 352