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