1/* M32R opcode support. -*- C -*- 2 3 Copyright 1998, 1999, 2000, 2001, 2004, 2005 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 Contributed by Red Hat Inc; developed under contract from Fujitsu. 12 13 This file is part of the GNU Binutils. 14 15 This program is free software; you can redistribute it and/or modify 16 it under the terms of the GNU General Public License as published by 17 the Free Software Foundation; either version 2 of the License, or 18 (at your option) any later version. 19 20 This program is distributed in the hope that it will be useful, 21 but WITHOUT ANY WARRANTY; without even the implied warranty of 22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 GNU General Public License for more details. 24 25 You should have received a copy of the GNU General Public License 26 along with this program; if not, write to the Free Software 27 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 28 MA 02110-1301, USA. */ 29 30/* This file is an addendum to m32r.cpu. Heavy use of C code isn't 31 appropriate in .cpu files, so it resides here. This especially applies 32 to assembly/disassembly where parsing/printing can be quite involved. 33 Such things aren't really part of the specification of the cpu, per se, 34 so .cpu files provide the general framework and .opc files handle the 35 nitty-gritty details as necessary. 36 37 Each section is delimited with start and end markers. 38 39 <arch>-opc.h additions use: "-- opc.h" 40 <arch>-opc.c additions use: "-- opc.c" 41 <arch>-asm.c additions use: "-- asm.c" 42 <arch>-dis.c additions use: "-- dis.c" 43 <arch>-ibd.h additions use: "-- ibd.h" */ 44 45/* -- opc.h */ 46 47#undef CGEN_DIS_HASH_SIZE 48#define CGEN_DIS_HASH_SIZE 256 49#undef CGEN_DIS_HASH 50#if 0 51#define X(b) (((unsigned char *) (b))[0] & 0xf0) 52#define CGEN_DIS_HASH(buffer, value) \ 53(X (buffer) | \ 54 (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \ 55 : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \ 56 : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \ 57 : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4))) 58#else 59#define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value) 60extern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT); 61#endif 62 63/* -- */ 64 65/* -- opc.c */ 66unsigned int 67m32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value) 68{ 69 unsigned int x; 70 71 if (value & 0xffff0000) /* 32bit instructions. */ 72 value = (value >> 16) & 0xffff; 73 74 x = (value >> 8) & 0xf0; 75 if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50) 76 return x; 77 78 if (x == 0x70 || x == 0xf0) 79 return x | ((value >> 8) & 0x0f); 80 81 if (x == 0x30) 82 return x | ((value & 0x70) >> 4); 83 else 84 return x | ((value & 0xf0) >> 4); 85} 86 87/* -- */ 88 89/* -- asm.c */ 90static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'"); 91 92/* Handle '#' prefixes (i.e. skip over them). */ 93 94static const char * 95parse_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 107static const char * 108parse_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 163static const char * 164parse_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 210static const char * 211parse_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 */ 244/* Immediate values are prefixed with '#'. */ 245 246#define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length) \ 247 do \ 248 { \ 249 if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX)) \ 250 (*info->fprintf_func) (info->stream, "#"); \ 251 } \ 252 while (0) 253 254/* Handle '#' prefixes as operands. */ 255 256static void 257print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 258 void * dis_info, 259 long value ATTRIBUTE_UNUSED, 260 unsigned int attrs ATTRIBUTE_UNUSED, 261 bfd_vma pc ATTRIBUTE_UNUSED, 262 int length ATTRIBUTE_UNUSED) 263{ 264 disassemble_info *info = (disassemble_info *) dis_info; 265 266 (*info->fprintf_func) (info->stream, "#"); 267} 268 269#undef CGEN_PRINT_INSN 270#define CGEN_PRINT_INSN my_print_insn 271 272static int 273my_print_insn (CGEN_CPU_DESC cd, 274 bfd_vma pc, 275 disassemble_info *info) 276{ 277 bfd_byte buffer[CGEN_MAX_INSN_SIZE]; 278 bfd_byte *buf = buffer; 279 int status; 280 int buflen = (pc & 3) == 0 ? 4 : 2; 281 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG; 282 bfd_byte *x; 283 284 /* Read the base part of the insn. */ 285 286 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0), 287 buf, buflen, info); 288 if (status != 0) 289 { 290 (*info->memory_error_func) (status, pc, info); 291 return -1; 292 } 293 294 /* 32 bit insn? */ 295 x = (big_p ? &buf[0] : &buf[3]); 296 if ((pc & 3) == 0 && (*x & 0x80) != 0) 297 return print_insn (cd, pc, info, buf, buflen); 298 299 /* Print the first insn. */ 300 if ((pc & 3) == 0) 301 { 302 buf += (big_p ? 0 : 2); 303 if (print_insn (cd, pc, info, buf, 2) == 0) 304 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); 305 buf += (big_p ? 2 : -2); 306 } 307 308 x = (big_p ? &buf[0] : &buf[1]); 309 if (*x & 0x80) 310 { 311 /* Parallel. */ 312 (*info->fprintf_func) (info->stream, " || "); 313 *x &= 0x7f; 314 } 315 else 316 (*info->fprintf_func) (info->stream, " -> "); 317 318 /* The "& 3" is to pass a consistent address. 319 Parallel insns arguably both begin on the word boundary. 320 Also, branch insns are calculated relative to the word boundary. */ 321 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0) 322 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); 323 324 return (pc & 3) ? 2 : 4; 325} 326 327/* -- */ 328