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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 28 29/* This file is an addendum to m32r.cpu. Heavy use of C code isn't 30 appropriate in .cpu files, so it resides here. This especially applies 31 to assembly/disassembly where parsing/printing can be quite involved. 32 Such things aren't really part of the specification of the cpu, per se, 33 so .cpu files provide the general framework and .opc files handle the 34 nitty-gritty details as necessary. 35 36 Each section is delimited with start and end markers. 37 38 <arch>-opc.h additions use: "-- opc.h" 39 <arch>-opc.c additions use: "-- opc.c" 40 <arch>-asm.c additions use: "-- asm.c" 41 <arch>-dis.c additions use: "-- dis.c" 42 <arch>-ibd.h additions use: "-- ibd.h" */ 43 44/* -- opc.h */ 45 46#undef CGEN_DIS_HASH_SIZE 47#define CGEN_DIS_HASH_SIZE 256 48#undef CGEN_DIS_HASH 49#if 0 50#define X(b) (((unsigned char *) (b))[0] & 0xf0) 51#define CGEN_DIS_HASH(buffer, value) \ 52(X (buffer) | \ 53 (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \ 54 : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \ 55 : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \ 56 : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4))) 57#else 58#define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash(buffer, value) 59extern unsigned int m32r_cgen_dis_hash(const char *, CGEN_INSN_INT); 60#endif 61 62/* -- */ 63 64/* -- opc.c */ 65unsigned int 66m32r_cgen_dis_hash (buf, value) 67 const char * buf ATTRIBUTE_UNUSED; 68 CGEN_INSN_INT value; 69{ 70 unsigned int x; 71 72 if (value & 0xffff0000) /* 32bit instructions */ 73 value = (value >> 16) & 0xffff; 74 75 x = (value>>8) & 0xf0; 76 if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50) 77 return x; 78 79 if (x == 0x70 || x == 0xf0) 80 return x | ((value>>8) & 0x0f); 81 82 if (x == 0x30) 83 return x | ((value & 0x70) >> 4); 84 else 85 return x | ((value & 0xf0) >> 4); 86} 87 88/* -- */ 89 90/* -- asm.c */ 91static const char * parse_hash 92 PARAMS ((CGEN_CPU_DESC, const char **, int, long *)); 93static const char * parse_hi16 94 PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *)); 95static const char * parse_slo16 96 PARAMS ((CGEN_CPU_DESC, const char **, int, long *)); 97static const char * parse_ulo16 98 PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *)); 99 100/* Handle '#' prefixes (i.e. skip over them). */ 101 102static const char * 103parse_hash (cd, strp, opindex, valuep) 104 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; 105 const char **strp; 106 int opindex ATTRIBUTE_UNUSED; 107 long *valuep ATTRIBUTE_UNUSED; 108{ 109 if (**strp == '#') 110 ++*strp; 111 return NULL; 112} 113 114/* Handle shigh(), high(). */ 115 116static const char * 117parse_hi16 (cd, strp, opindex, valuep) 118 CGEN_CPU_DESC cd; 119 const char **strp; 120 int opindex; 121 unsigned long *valuep; 122{ 123 const char *errmsg; 124 enum cgen_parse_operand_result result_type; 125 bfd_vma value; 126 127 if (**strp == '#') 128 ++*strp; 129 130 if (strncasecmp (*strp, "high(", 5) == 0) 131 { 132 *strp += 5; 133 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO, 134 &result_type, &value); 135 if (**strp != ')') 136 return "missing `)'"; 137 ++*strp; 138 if (errmsg == NULL 139 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 140 value >>= 16; 141 *valuep = value; 142 return errmsg; 143 } 144 else if (strncasecmp (*strp, "shigh(", 6) == 0) 145 { 146 *strp += 6; 147 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO, 148 &result_type, &value); 149 if (**strp != ')') 150 return "missing `)'"; 151 ++*strp; 152 if (errmsg == NULL 153 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 154 { 155 value = value + (value & 0x8000 ? 0x10000 : 0); 156 value >>= 16; 157 } 158 *valuep = value; 159 return errmsg; 160 } 161 162 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 163} 164 165/* Handle low() in a signed context. Also handle sda(). 166 The signedness of the value doesn't matter to low(), but this also 167 handles the case where low() isn't present. */ 168 169static const char * 170parse_slo16 (cd, strp, opindex, valuep) 171 CGEN_CPU_DESC cd; 172 const char **strp; 173 int opindex; 174 long *valuep; 175{ 176 const char *errmsg; 177 enum cgen_parse_operand_result result_type; 178 bfd_vma value; 179 180 if (**strp == '#') 181 ++*strp; 182 183 if (strncasecmp (*strp, "low(", 4) == 0) 184 { 185 *strp += 4; 186 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16, 187 &result_type, &value); 188 if (**strp != ')') 189 return "missing `)'"; 190 ++*strp; 191 if (errmsg == NULL 192 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 193 { 194 value &= 0xffff; 195 if (value & 0x8000) 196 value |= 0xffff0000; 197 } 198 *valuep = value; 199 return errmsg; 200 } 201 202 if (strncasecmp (*strp, "sda(", 4) == 0) 203 { 204 *strp += 4; 205 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16, 206 NULL, &value); 207 if (**strp != ')') 208 return "missing `)'"; 209 ++*strp; 210 *valuep = value; 211 return errmsg; 212 } 213 214 return cgen_parse_signed_integer (cd, strp, opindex, valuep); 215} 216 217/* Handle low() in an unsigned context. 218 The signedness of the value doesn't matter to low(), but this also 219 handles the case where low() isn't present. */ 220 221static const char * 222parse_ulo16 (cd, strp, opindex, valuep) 223 CGEN_CPU_DESC cd; 224 const char **strp; 225 int opindex; 226 unsigned long *valuep; 227{ 228 const char *errmsg; 229 enum cgen_parse_operand_result result_type; 230 bfd_vma value; 231 232 if (**strp == '#') 233 ++*strp; 234 235 if (strncasecmp (*strp, "low(", 4) == 0) 236 { 237 *strp += 4; 238 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16, 239 &result_type, &value); 240 if (**strp != ')') 241 return "missing `)'"; 242 ++*strp; 243 if (errmsg == NULL 244 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 245 value &= 0xffff; 246 *valuep = value; 247 return errmsg; 248 } 249 250 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 251} 252 253/* -- */ 254 255/* -- dis.c */ 256static void print_hash PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int)); 257static int my_print_insn PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *)); 258 259/* Immediate values are prefixed with '#'. */ 260 261#define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length) \ 262 do \ 263 { \ 264 if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX)) \ 265 (*info->fprintf_func) (info->stream, "#"); \ 266 } \ 267 while (0) 268 269/* Handle '#' prefixes as operands. */ 270 271static void 272print_hash (cd, dis_info, value, attrs, pc, length) 273 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; 274 PTR dis_info; 275 long value ATTRIBUTE_UNUSED; 276 unsigned int attrs ATTRIBUTE_UNUSED; 277 bfd_vma pc ATTRIBUTE_UNUSED; 278 int length ATTRIBUTE_UNUSED; 279{ 280 disassemble_info *info = (disassemble_info *) dis_info; 281 (*info->fprintf_func) (info->stream, "#"); 282} 283 284#undef CGEN_PRINT_INSN 285#define CGEN_PRINT_INSN my_print_insn 286 287static int 288my_print_insn (cd, pc, info) 289 CGEN_CPU_DESC cd; 290 bfd_vma pc; 291 disassemble_info *info; 292{ 293 char buffer[CGEN_MAX_INSN_SIZE]; 294 char *buf = buffer; 295 int status; 296 int buflen = (pc & 3) == 0 ? 4 : 2; 297 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG; 298 char *x; 299 300 /* Read the base part of the insn. */ 301 302 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0), 303 buf, buflen, info); 304 if (status != 0) 305 { 306 (*info->memory_error_func) (status, pc, info); 307 return -1; 308 } 309 310 /* 32 bit insn? */ 311 x = (big_p ? &buf[0] : &buf[3]); 312 if ((pc & 3) == 0 && (*x & 0x80) != 0) 313 return print_insn (cd, pc, info, buf, buflen); 314 315 /* Print the first insn. */ 316 if ((pc & 3) == 0) 317 { 318 buf += (big_p ? 0 : 2); 319 if (print_insn (cd, pc, info, buf, 2) == 0) 320 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); 321 buf += (big_p ? 2 : -2); 322 } 323 324 x = (big_p ? &buf[0] : &buf[1]); 325 if (*x & 0x80) 326 { 327 /* Parallel. */ 328 (*info->fprintf_func) (info->stream, " || "); 329 *x &= 0x7f; 330 } 331 else 332 (*info->fprintf_func) (info->stream, " -> "); 333 334 /* The "& 3" is to pass a consistent address. 335 Parallel insns arguably both begin on the word boundary. 336 Also, branch insns are calculated relative to the word boundary. */ 337 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0) 338 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); 339 340 return (pc & 3) ? 2 : 4; 341} 342 343/* -- */ 344