| 1 | /* MeP opcode support. -*- C -*- |
| 2 | Copyright 2011 Free Software Foundation, Inc. |
| 3 | |
| 4 | Contributed by Red Hat Inc; |
| 5 | |
| 6 | This file is part of the GNU Binutils. |
| 7 | |
| 8 | This program is free software; you can redistribute it and/or modify |
| 9 | it under the terms of the GNU General Public License as published by |
| 10 | the Free Software Foundation; either version 3 of the License, or |
| 11 | (at your option) any later version. |
| 12 | |
| 13 | This program is distributed in the hope that it will be useful, |
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | GNU General Public License for more details. |
| 17 | |
| 18 | You should have received a copy of the GNU General Public License |
| 19 | along with this program; if not, write to the Free Software |
| 20 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
| 21 | MA 02110-1301, USA. */ |
| 22 | |
| 23 | /* -- opc.h */ |
| 24 | |
| 25 | #undef CGEN_DIS_HASH_SIZE |
| 26 | #define CGEN_DIS_HASH_SIZE 1 |
| 27 | |
| 28 | #undef CGEN_DIS_HASH |
| 29 | #define CGEN_DIS_HASH(buffer, insn) 0 |
| 30 | |
| 31 | #define CGEN_VERBOSE_ASSEMBLER_ERRORS |
| 32 | |
| 33 | typedef struct |
| 34 | { |
| 35 | char * name; |
| 36 | int config_enum; |
| 37 | unsigned cpu_flag; |
| 38 | int big_endian; |
| 39 | int vliw_bits; |
| 40 | CGEN_ATTR_VALUE_BITSET_TYPE cop16_isa; |
| 41 | CGEN_ATTR_VALUE_BITSET_TYPE cop32_isa; |
| 42 | CGEN_ATTR_VALUE_BITSET_TYPE cop48_isa; |
| 43 | CGEN_ATTR_VALUE_BITSET_TYPE cop64_isa; |
| 44 | CGEN_ATTR_VALUE_BITSET_TYPE cop_isa; |
| 45 | CGEN_ATTR_VALUE_BITSET_TYPE core_isa; |
| 46 | unsigned int option_mask; |
| 47 | } mep_config_map_struct; |
| 48 | |
| 49 | extern mep_config_map_struct mep_config_map[]; |
| 50 | extern int mep_config_index; |
| 51 | |
| 52 | extern void init_mep_all_core_isas_mask (void); |
| 53 | extern void init_mep_all_cop_isas_mask (void); |
| 54 | extern CGEN_ATTR_VALUE_BITSET_TYPE mep_cop_isa (void); |
| 55 | |
| 56 | #define MEP_CONFIG (mep_config_map[mep_config_index].config_enum) |
| 57 | #define MEP_CPU (mep_config_map[mep_config_index].cpu_flag) |
| 58 | #define MEP_OMASK (mep_config_map[mep_config_index].option_mask) |
| 59 | #define MEP_VLIW (mep_config_map[mep_config_index].vliw_bits > 0) |
| 60 | #define MEP_VLIW32 (mep_config_map[mep_config_index].vliw_bits == 32) |
| 61 | #define MEP_VLIW64 (mep_config_map[mep_config_index].vliw_bits == 64) |
| 62 | #define MEP_COP16_ISA (mep_config_map[mep_config_index].cop16_isa) |
| 63 | #define MEP_COP32_ISA (mep_config_map[mep_config_index].cop32_isa) |
| 64 | #define MEP_COP48_ISA (mep_config_map[mep_config_index].cop48_isa) |
| 65 | #define MEP_COP64_ISA (mep_config_map[mep_config_index].cop64_isa) |
| 66 | #define MEP_COP_ISA (mep_config_map[mep_config_index].cop_isa) |
| 67 | #define MEP_CORE_ISA (mep_config_map[mep_config_index].core_isa) |
| 68 | |
| 69 | /* begin-cop-ip-supported-defines */ |
| 70 | #define MEP_IVC2_SUPPORTED 1 |
| 71 | /* end-cop-ip-supported-defines */ |
| 72 | |
| 73 | extern int mep_insn_supported_by_isa (const CGEN_INSN *, CGEN_ATTR_VALUE_BITSET_TYPE *); |
| 74 | |
| 75 | /* A mask for all ISAs executed by the core. */ |
| 76 | #define MEP_ALL_CORE_ISAS_MASK mep_all_core_isas_mask |
| 77 | extern CGEN_ATTR_VALUE_BITSET_TYPE mep_all_core_isas_mask; |
| 78 | |
| 79 | #define MEP_INSN_CORE_P(insn) ( \ |
| 80 | init_mep_all_core_isas_mask (), \ |
| 81 | mep_insn_supported_by_isa (insn, & MEP_ALL_CORE_ISAS_MASK) \ |
| 82 | ) |
| 83 | |
| 84 | /* A mask for all ISAs executed by a VLIW coprocessor. */ |
| 85 | #define MEP_ALL_COP_ISAS_MASK mep_all_cop_isas_mask |
| 86 | extern CGEN_ATTR_VALUE_BITSET_TYPE mep_all_cop_isas_mask; |
| 87 | |
| 88 | #define MEP_INSN_COP_P(insn) ( \ |
| 89 | init_mep_all_cop_isas_mask (), \ |
| 90 | mep_insn_supported_by_isa (insn, & MEP_ALL_COP_ISAS_MASK) \ |
| 91 | ) |
| 92 | |
| 93 | extern int mep_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *); |
| 94 | extern int mep_cgen_insn_supported_asm (CGEN_CPU_DESC, const CGEN_INSN *); |
| 95 | |
| 96 | /* -- asm.c */ |
| 97 | |
| 98 | #include "elf/mep.h" |
| 99 | |
| 100 | #define CGEN_VALIDATE_INSN_SUPPORTED |
| 101 | #define mep_cgen_insn_supported mep_cgen_insn_supported_asm |
| 102 | |
| 103 | const char * parse_csrn (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *); |
| 104 | const char * parse_tpreg (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *); |
| 105 | const char * parse_spreg (CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *); |
| 106 | const char * parse_mep_align (CGEN_CPU_DESC, const char **, enum cgen_operand_type, long *); |
| 107 | const char * parse_mep_alignu (CGEN_CPU_DESC, const char **, enum cgen_operand_type, unsigned long *); |
| 108 | static const char * parse_signed16 (CGEN_CPU_DESC, const char **, int, long *); |
| 109 | static const char * parse_signed16_range (CGEN_CPU_DESC, const char **, int, long *) ATTRIBUTE_UNUSED; |
| 110 | static const char * parse_unsigned16 (CGEN_CPU_DESC, const char **, int, unsigned long *); |
| 111 | static const char * parse_unsigned16_range (CGEN_CPU_DESC, const char **, int, unsigned long *) ATTRIBUTE_UNUSED; |
| 112 | static const char * parse_lo16 (CGEN_CPU_DESC, const char **, int, long *, long); |
| 113 | static const char * parse_unsigned7 (CGEN_CPU_DESC, const char **, enum cgen_operand_type, unsigned long *); |
| 114 | static const char * parse_zero (CGEN_CPU_DESC, const char **, int, long *); |
| 115 | |
| 116 | const char * |
| 117 | parse_csrn (CGEN_CPU_DESC cd, const char **strp, |
| 118 | CGEN_KEYWORD *keyword_table, long *field) |
| 119 | { |
| 120 | const char *err; |
| 121 | unsigned long value; |
| 122 | |
| 123 | err = cgen_parse_keyword (cd, strp, keyword_table, field); |
| 124 | if (!err) |
| 125 | return NULL; |
| 126 | |
| 127 | err = cgen_parse_unsigned_integer (cd, strp, MEP_OPERAND_CSRN_IDX, & value); |
| 128 | if (err) |
| 129 | return err; |
| 130 | *field = value; |
| 131 | return NULL; |
| 132 | } |
| 133 | |
| 134 | /* begin-cop-ip-parse-handlers */ |
| 135 | static const char * |
| 136 | parse_ivc2_cr (CGEN_CPU_DESC, |
| 137 | const char **, |
| 138 | CGEN_KEYWORD *, |
| 139 | long *) ATTRIBUTE_UNUSED; |
| 140 | static const char * |
| 141 | parse_ivc2_cr (CGEN_CPU_DESC cd, |
| 142 | const char **strp, |
| 143 | CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED, |
| 144 | long *field) |
| 145 | { |
| 146 | return cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_cr_ivc2, field); |
| 147 | } |
| 148 | static const char * |
| 149 | parse_ivc2_ccr (CGEN_CPU_DESC, |
| 150 | const char **, |
| 151 | CGEN_KEYWORD *, |
| 152 | long *) ATTRIBUTE_UNUSED; |
| 153 | static const char * |
| 154 | parse_ivc2_ccr (CGEN_CPU_DESC cd, |
| 155 | const char **strp, |
| 156 | CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED, |
| 157 | long *field) |
| 158 | { |
| 159 | return cgen_parse_keyword (cd, strp, & mep_cgen_opval_h_ccr_ivc2, field); |
| 160 | } |
| 161 | /* end-cop-ip-parse-handlers */ |
| 162 | |
| 163 | const char * |
| 164 | parse_tpreg (CGEN_CPU_DESC cd, const char ** strp, |
| 165 | CGEN_KEYWORD *keyword_table, long *field) |
| 166 | { |
| 167 | const char *err; |
| 168 | |
| 169 | err = cgen_parse_keyword (cd, strp, keyword_table, field); |
| 170 | if (err) |
| 171 | return err; |
| 172 | if (*field != 13) |
| 173 | return _("Only $tp or $13 allowed for this opcode"); |
| 174 | return NULL; |
| 175 | } |
| 176 | |
| 177 | const char * |
| 178 | parse_spreg (CGEN_CPU_DESC cd, const char ** strp, |
| 179 | CGEN_KEYWORD *keyword_table, long *field) |
| 180 | { |
| 181 | const char *err; |
| 182 | |
| 183 | err = cgen_parse_keyword (cd, strp, keyword_table, field); |
| 184 | if (err) |
| 185 | return err; |
| 186 | if (*field != 15) |
| 187 | return _("Only $sp or $15 allowed for this opcode"); |
| 188 | return NULL; |
| 189 | } |
| 190 | |
| 191 | const char * |
| 192 | parse_mep_align (CGEN_CPU_DESC cd, const char ** strp, |
| 193 | enum cgen_operand_type type, long *field) |
| 194 | { |
| 195 | long lsbs = 0; |
| 196 | const char *err; |
| 197 | |
| 198 | switch (type) |
| 199 | { |
| 200 | case MEP_OPERAND_PCREL8A2: |
| 201 | case MEP_OPERAND_PCREL12A2: |
| 202 | case MEP_OPERAND_PCREL17A2: |
| 203 | case MEP_OPERAND_PCREL24A2: |
| 204 | err = cgen_parse_signed_integer (cd, strp, type, field); |
| 205 | break; |
| 206 | case MEP_OPERAND_PCABS24A2: |
| 207 | case MEP_OPERAND_UDISP7: |
| 208 | case MEP_OPERAND_UDISP7A2: |
| 209 | case MEP_OPERAND_UDISP7A4: |
| 210 | case MEP_OPERAND_UIMM7A4: |
| 211 | case MEP_OPERAND_ADDR24A4: |
| 212 | err = cgen_parse_unsigned_integer (cd, strp, type, (unsigned long *) field); |
| 213 | break; |
| 214 | default: |
| 215 | abort(); |
| 216 | } |
| 217 | if (err) |
| 218 | return err; |
| 219 | switch (type) |
| 220 | { |
| 221 | case MEP_OPERAND_UDISP7: |
| 222 | lsbs = 0; |
| 223 | break; |
| 224 | case MEP_OPERAND_PCREL8A2: |
| 225 | case MEP_OPERAND_PCREL12A2: |
| 226 | case MEP_OPERAND_PCREL17A2: |
| 227 | case MEP_OPERAND_PCREL24A2: |
| 228 | case MEP_OPERAND_PCABS24A2: |
| 229 | case MEP_OPERAND_UDISP7A2: |
| 230 | lsbs = *field & 1; |
| 231 | break; |
| 232 | case MEP_OPERAND_UDISP7A4: |
| 233 | case MEP_OPERAND_UIMM7A4: |
| 234 | case MEP_OPERAND_ADDR24A4: |
| 235 | lsbs = *field & 3; |
| 236 | break; |
| 237 | lsbs = *field & 7; |
| 238 | break; |
| 239 | default: |
| 240 | /* Safe assumption? */ |
| 241 | abort (); |
| 242 | } |
| 243 | if (lsbs) |
| 244 | return "Value is not aligned enough"; |
| 245 | return NULL; |
| 246 | } |
| 247 | |
| 248 | const char * |
| 249 | parse_mep_alignu (CGEN_CPU_DESC cd, const char ** strp, |
| 250 | enum cgen_operand_type type, unsigned long *field) |
| 251 | { |
| 252 | return parse_mep_align (cd, strp, type, (long *) field); |
| 253 | } |
| 254 | |
| 255 | |
| 256 | /* Handle %lo(), %tpoff(), %sdaoff(), %hi(), and other signed |
| 257 | constants in a signed context. */ |
| 258 | |
| 259 | static const char * |
| 260 | parse_signed16 (CGEN_CPU_DESC cd, |
| 261 | const char **strp, |
| 262 | int opindex, |
| 263 | long *valuep) |
| 264 | { |
| 265 | return parse_lo16 (cd, strp, opindex, valuep, 1); |
| 266 | } |
| 267 | |
| 268 | static const char * |
| 269 | parse_lo16 (CGEN_CPU_DESC cd, |
| 270 | const char **strp, |
| 271 | int opindex, |
| 272 | long *valuep, |
| 273 | long signedp) |
| 274 | { |
| 275 | const char *errmsg; |
| 276 | enum cgen_parse_operand_result result_type; |
| 277 | bfd_vma value; |
| 278 | |
| 279 | if (strncasecmp (*strp, "%lo(", 4) == 0) |
| 280 | { |
| 281 | *strp += 4; |
| 282 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_LOW16, |
| 283 | & result_type, & value); |
| 284 | if (**strp != ')') |
| 285 | return _("missing `)'"); |
| 286 | ++*strp; |
| 287 | if (errmsg == NULL |
| 288 | && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) |
| 289 | value &= 0xffff; |
| 290 | if (signedp) |
| 291 | *valuep = (long)(short) value; |
| 292 | else |
| 293 | *valuep = value; |
| 294 | return errmsg; |
| 295 | } |
| 296 | |
| 297 | if (strncasecmp (*strp, "%hi(", 4) == 0) |
| 298 | { |
| 299 | *strp += 4; |
| 300 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16S, |
| 301 | & result_type, & value); |
| 302 | if (**strp != ')') |
| 303 | return _("missing `)'"); |
| 304 | ++*strp; |
| 305 | if (errmsg == NULL |
| 306 | && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) |
| 307 | value = (value + 0x8000) >> 16; |
| 308 | *valuep = value; |
| 309 | return errmsg; |
| 310 | } |
| 311 | |
| 312 | if (strncasecmp (*strp, "%uhi(", 5) == 0) |
| 313 | { |
| 314 | *strp += 5; |
| 315 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16U, |
| 316 | & result_type, & value); |
| 317 | if (**strp != ')') |
| 318 | return _("missing `)'"); |
| 319 | ++*strp; |
| 320 | if (errmsg == NULL |
| 321 | && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) |
| 322 | value = value >> 16; |
| 323 | *valuep = value; |
| 324 | return errmsg; |
| 325 | } |
| 326 | |
| 327 | if (strncasecmp (*strp, "%sdaoff(", 8) == 0) |
| 328 | { |
| 329 | *strp += 8; |
| 330 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_GPREL, |
| 331 | NULL, & value); |
| 332 | if (**strp != ')') |
| 333 | return _("missing `)'"); |
| 334 | ++*strp; |
| 335 | *valuep = value; |
| 336 | return errmsg; |
| 337 | } |
| 338 | |
| 339 | if (strncasecmp (*strp, "%tpoff(", 7) == 0) |
| 340 | { |
| 341 | *strp += 7; |
| 342 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_TPREL, |
| 343 | NULL, & value); |
| 344 | if (**strp != ')') |
| 345 | return _("missing `)'"); |
| 346 | ++*strp; |
| 347 | *valuep = value; |
| 348 | return errmsg; |
| 349 | } |
| 350 | |
| 351 | if (**strp == '%') |
| 352 | return _("invalid %function() here"); |
| 353 | |
| 354 | return cgen_parse_signed_integer (cd, strp, opindex, valuep); |
| 355 | } |
| 356 | |
| 357 | static const char * |
| 358 | parse_unsigned16 (CGEN_CPU_DESC cd, |
| 359 | const char **strp, |
| 360 | int opindex, |
| 361 | unsigned long *valuep) |
| 362 | { |
| 363 | return parse_lo16 (cd, strp, opindex, (long *) valuep, 0); |
| 364 | } |
| 365 | |
| 366 | static const char * |
| 367 | parse_signed16_range (CGEN_CPU_DESC cd, |
| 368 | const char **strp, |
| 369 | int opindex, |
| 370 | signed long *valuep) |
| 371 | { |
| 372 | const char *errmsg = 0; |
| 373 | signed long value; |
| 374 | |
| 375 | errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value); |
| 376 | if (errmsg) |
| 377 | return errmsg; |
| 378 | |
| 379 | if (value < -32768 || value > 32767) |
| 380 | return _("Immediate is out of range -32768 to 32767"); |
| 381 | |
| 382 | *valuep = value; |
| 383 | return 0; |
| 384 | } |
| 385 | |
| 386 | static const char * |
| 387 | parse_unsigned16_range (CGEN_CPU_DESC cd, |
| 388 | const char **strp, |
| 389 | int opindex, |
| 390 | unsigned long *valuep) |
| 391 | { |
| 392 | const char *errmsg = 0; |
| 393 | unsigned long value; |
| 394 | |
| 395 | errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, & value); |
| 396 | if (errmsg) |
| 397 | return errmsg; |
| 398 | |
| 399 | if (value > 65535) |
| 400 | return _("Immediate is out of range 0 to 65535"); |
| 401 | |
| 402 | *valuep = value; |
| 403 | return 0; |
| 404 | } |
| 405 | |
| 406 | /* A special case of parse_signed16 which accepts only the value zero. */ |
| 407 | |
| 408 | static const char * |
| 409 | parse_zero (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep) |
| 410 | { |
| 411 | const char *errmsg; |
| 412 | enum cgen_parse_operand_result result_type; |
| 413 | bfd_vma value; |
| 414 | |
| 415 | /*fprintf(stderr, "dj: signed parse opindex `%s'\n", *strp);*/ |
| 416 | |
| 417 | /* Prevent ($ry) from being attempted as an expression on 'sw $rx,($ry)'. |
| 418 | It will fail and cause ry to be listed as an undefined symbol in the |
| 419 | listing. */ |
| 420 | if (strncmp (*strp, "($", 2) == 0) |
| 421 | return "not zero"; /* any string will do -- will never be seen. */ |
| 422 | |
| 423 | if (strncasecmp (*strp, "%lo(", 4) == 0) |
| 424 | { |
| 425 | *strp += 4; |
| 426 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_LOW16, |
| 427 | &result_type, &value); |
| 428 | if (**strp != ')') |
| 429 | return "missing `)'"; |
| 430 | ++*strp; |
| 431 | if (errmsg == NULL |
| 432 | && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0)) |
| 433 | return "not zero"; /* any string will do -- will never be seen. */ |
| 434 | *valuep = value; |
| 435 | return errmsg; |
| 436 | } |
| 437 | |
| 438 | if (strncasecmp (*strp, "%hi(", 4) == 0) |
| 439 | { |
| 440 | *strp += 4; |
| 441 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16S, |
| 442 | &result_type, &value); |
| 443 | if (**strp != ')') |
| 444 | return "missing `)'"; |
| 445 | ++*strp; |
| 446 | if (errmsg == NULL |
| 447 | && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0)) |
| 448 | return "not zero"; /* any string will do -- will never be seen. */ |
| 449 | *valuep = value; |
| 450 | return errmsg; |
| 451 | } |
| 452 | |
| 453 | if (strncasecmp (*strp, "%uhi(", 5) == 0) |
| 454 | { |
| 455 | *strp += 5; |
| 456 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_HI16U, |
| 457 | &result_type, &value); |
| 458 | if (**strp != ')') |
| 459 | return "missing `)'"; |
| 460 | ++*strp; |
| 461 | if (errmsg == NULL |
| 462 | && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0)) |
| 463 | return "not zero"; /* any string will do -- will never be seen. */ |
| 464 | *valuep = value; |
| 465 | return errmsg; |
| 466 | } |
| 467 | |
| 468 | if (strncasecmp (*strp, "%sdaoff(", 8) == 0) |
| 469 | { |
| 470 | *strp += 8; |
| 471 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_GPREL, |
| 472 | &result_type, &value); |
| 473 | if (**strp != ')') |
| 474 | return "missing `)'"; |
| 475 | ++*strp; |
| 476 | if (errmsg == NULL |
| 477 | && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0)) |
| 478 | return "not zero"; /* any string will do -- will never be seen. */ |
| 479 | *valuep = value; |
| 480 | return errmsg; |
| 481 | } |
| 482 | |
| 483 | if (strncasecmp (*strp, "%tpoff(", 7) == 0) |
| 484 | { |
| 485 | *strp += 7; |
| 486 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_MEP_TPREL, |
| 487 | &result_type, &value); |
| 488 | if (**strp != ')') |
| 489 | return "missing `)'"; |
| 490 | ++*strp; |
| 491 | if (errmsg == NULL |
| 492 | && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0)) |
| 493 | return "not zero"; /* any string will do -- will never be seen. */ |
| 494 | *valuep = value; |
| 495 | return errmsg; |
| 496 | } |
| 497 | |
| 498 | if (**strp == '%') |
| 499 | return "invalid %function() here"; |
| 500 | |
| 501 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_NONE, |
| 502 | &result_type, &value); |
| 503 | if (errmsg == NULL |
| 504 | && (result_type != CGEN_PARSE_OPERAND_RESULT_NUMBER || value != 0)) |
| 505 | return "not zero"; /* any string will do -- will never be seen. */ |
| 506 | |
| 507 | return errmsg; |
| 508 | } |
| 509 | |
| 510 | static const char * |
| 511 | parse_unsigned7 (CGEN_CPU_DESC cd, const char **strp, |
| 512 | enum cgen_operand_type opindex, unsigned long *valuep) |
| 513 | { |
| 514 | const char *errmsg; |
| 515 | bfd_vma value; |
| 516 | |
| 517 | /* fprintf(stderr, "dj: unsigned7 parse `%s'\n", *strp); */ |
| 518 | |
| 519 | if (strncasecmp (*strp, "%tpoff(", 7) == 0) |
| 520 | { |
| 521 | int reloc; |
| 522 | *strp += 7; |
| 523 | switch (opindex) |
| 524 | { |
| 525 | case MEP_OPERAND_UDISP7: |
| 526 | reloc = BFD_RELOC_MEP_TPREL7; |
| 527 | break; |
| 528 | case MEP_OPERAND_UDISP7A2: |
| 529 | reloc = BFD_RELOC_MEP_TPREL7A2; |
| 530 | break; |
| 531 | case MEP_OPERAND_UDISP7A4: |
| 532 | reloc = BFD_RELOC_MEP_TPREL7A4; |
| 533 | break; |
| 534 | default: |
| 535 | /* Safe assumption? */ |
| 536 | abort (); |
| 537 | } |
| 538 | errmsg = cgen_parse_address (cd, strp, opindex, reloc, |
| 539 | NULL, &value); |
| 540 | if (**strp != ')') |
| 541 | return "missing `)'"; |
| 542 | ++*strp; |
| 543 | *valuep = value; |
| 544 | return errmsg; |
| 545 | } |
| 546 | |
| 547 | if (**strp == '%') |
| 548 | return _("invalid %function() here"); |
| 549 | |
| 550 | return parse_mep_alignu (cd, strp, opindex, valuep); |
| 551 | } |
| 552 | |
| 553 | static ATTRIBUTE_UNUSED const char * |
| 554 | parse_cdisp10 (CGEN_CPU_DESC cd, |
| 555 | const char **strp, |
| 556 | int opindex, |
| 557 | long *valuep) |
| 558 | { |
| 559 | const char *errmsg = 0; |
| 560 | signed long value; |
| 561 | long have_zero = 0; |
| 562 | int wide = 0; |
| 563 | int alignment; |
| 564 | |
| 565 | switch (opindex) |
| 566 | { |
| 567 | case MEP_OPERAND_CDISP10A4: |
| 568 | alignment = 2; |
| 569 | break; |
| 570 | case MEP_OPERAND_CDISP10A2: |
| 571 | alignment = 1; |
| 572 | break; |
| 573 | case MEP_OPERAND_CDISP10: |
| 574 | default: |
| 575 | alignment = 0; |
| 576 | break; |
| 577 | } |
| 578 | |
| 579 | if ((MEP_CPU & EF_MEP_CPU_MASK) == EF_MEP_CPU_C5) |
| 580 | wide = 1; |
| 581 | |
| 582 | if (strncmp (*strp, "0x0", 3) == 0 |
| 583 | || (**strp == '0' && *(*strp + 1) != 'x')) |
| 584 | have_zero = 1; |
| 585 | |
| 586 | errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value); |
| 587 | if (errmsg) |
| 588 | return errmsg; |
| 589 | |
| 590 | if (wide) |
| 591 | { |
| 592 | if (value < -512 || value > 511) |
| 593 | return _("Immediate is out of range -512 to 511"); |
| 594 | } |
| 595 | else |
| 596 | { |
| 597 | if (value < -128 || value > 127) |
| 598 | return _("Immediate is out of range -128 to 127"); |
| 599 | } |
| 600 | |
| 601 | if (value & ((1<<alignment)-1)) |
| 602 | return _("Value is not aligned enough"); |
| 603 | |
| 604 | /* If this field may require a relocation then use larger dsp16. */ |
| 605 | if (! have_zero && value == 0) |
| 606 | return (wide ? _("Immediate is out of range -512 to 511") |
| 607 | : _("Immediate is out of range -128 to 127")); |
| 608 | |
| 609 | *valuep = value; |
| 610 | return 0; |
| 611 | } |
| 612 | |
| 613 | /* BEGIN LIGHTWEIGHT MACRO PROCESSOR. */ |
| 614 | |
| 615 | #define MAXARGS 9 |
| 616 | |
| 617 | typedef struct |
| 618 | { |
| 619 | char *name; |
| 620 | char *expansion; |
| 621 | } macro; |
| 622 | |
| 623 | typedef struct |
| 624 | { |
| 625 | const char *start; |
| 626 | int len; |
| 627 | } arg; |
| 628 | |
| 629 | macro macros[] = |
| 630 | { |
| 631 | { "sizeof", "(`1.end + (- `1))"}, |
| 632 | { "startof", "(`1 | 0)" }, |
| 633 | { "align4", "(`1&(~3))"}, |
| 634 | /*{ "hi", "(((`1+0x8000)>>16) & 0xffff)" }, */ |
| 635 | /*{ "lo", "(`1 & 0xffff)" }, */ |
| 636 | /*{ "sdaoff", "((`1-__sdabase) & 0x7f)"}, */ |
| 637 | /*{ "tpoff", "((`1-__tpbase) & 0x7f)"}, */ |
| 638 | { 0,0 } |
| 639 | }; |
| 640 | |
| 641 | static char * expand_string (const char *, int); |
| 642 | |
| 643 | static const char * |
| 644 | mep_cgen_expand_macros_and_parse_operand |
| 645 | (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *); |
| 646 | |
| 647 | static char * |
| 648 | str_append (char *dest, const char *input, int len) |
| 649 | { |
| 650 | char *new_dest; |
| 651 | int oldlen; |
| 652 | |
| 653 | if (len == 0) |
| 654 | return dest; |
| 655 | /* printf("str_append: <<%s>>, <<%s>>, %d\n", dest, input, len); */ |
| 656 | oldlen = (dest ? strlen(dest) : 0); |
| 657 | new_dest = realloc (dest, oldlen + len + 1); |
| 658 | memset (new_dest + oldlen, 0, len + 1); |
| 659 | return strncat (new_dest, input, len); |
| 660 | } |
| 661 | |
| 662 | static macro * |
| 663 | lookup_macro (const char *name) |
| 664 | { |
| 665 | macro *m; |
| 666 | |
| 667 | for (m = macros; m->name; ++m) |
| 668 | if (strncmp (m->name, name, strlen(m->name)) == 0) |
| 669 | return m; |
| 670 | |
| 671 | return 0; |
| 672 | } |
| 673 | |
| 674 | static char * |
| 675 | expand_macro (arg *args, int narg, macro *mac) |
| 676 | { |
| 677 | char *result = 0, *rescanned_result = 0; |
| 678 | char *e = mac->expansion; |
| 679 | char *mark = e; |
| 680 | int mac_arg = 0; |
| 681 | |
| 682 | /* printf("expanding macro %s with %d args\n", mac->name, narg + 1); */ |
| 683 | while (*e) |
| 684 | { |
| 685 | if (*e == '`' && |
| 686 | (*e+1) && |
| 687 | ((*(e + 1) - '1') <= MAXARGS) && |
| 688 | ((*(e + 1) - '1') <= narg)) |
| 689 | { |
| 690 | result = str_append (result, mark, e - mark); |
| 691 | mac_arg = (*(e + 1) - '1'); |
| 692 | /* printf("replacing `%d with %s\n", mac_arg+1, args[mac_arg].start); */ |
| 693 | result = str_append (result, args[mac_arg].start, args[mac_arg].len); |
| 694 | ++e; |
| 695 | mark = e+1; |
| 696 | } |
| 697 | ++e; |
| 698 | } |
| 699 | |
| 700 | if (mark != e) |
| 701 | result = str_append (result, mark, e - mark); |
| 702 | |
| 703 | if (result) |
| 704 | { |
| 705 | rescanned_result = expand_string (result, 0); |
| 706 | free (result); |
| 707 | return rescanned_result; |
| 708 | } |
| 709 | else |
| 710 | return result; |
| 711 | } |
| 712 | |
| 713 | #define IN_TEXT 0 |
| 714 | #define IN_ARGS 1 |
| 715 | |
| 716 | static char * |
| 717 | expand_string (const char *in, int first_only) |
| 718 | { |
| 719 | int num_expansions = 0; |
| 720 | int depth = 0; |
| 721 | int narg = -1; |
| 722 | arg args[MAXARGS]; |
| 723 | int state = IN_TEXT; |
| 724 | const char *mark = in; |
| 725 | macro *pmacro = NULL; |
| 726 | char *expansion = 0; |
| 727 | char *result = 0; |
| 728 | |
| 729 | while (*in) |
| 730 | { |
| 731 | switch (state) |
| 732 | { |
| 733 | case IN_TEXT: |
| 734 | if (*in == '%' && *(in + 1) && (!first_only || num_expansions == 0)) |
| 735 | { |
| 736 | pmacro = lookup_macro (in + 1); |
| 737 | if (pmacro) |
| 738 | { |
| 739 | /* printf("entering state %d at '%s'...\n", state, in); */ |
| 740 | result = str_append (result, mark, in - mark); |
| 741 | mark = in; |
| 742 | in += 1 + strlen (pmacro->name); |
| 743 | while (*in == ' ') ++in; |
| 744 | if (*in != '(') |
| 745 | { |
| 746 | state = IN_TEXT; |
| 747 | pmacro = NULL; |
| 748 | } |
| 749 | else |
| 750 | { |
| 751 | state = IN_ARGS; |
| 752 | narg = 0; |
| 753 | args[narg].start = in + 1; |
| 754 | args[narg].len = 0; |
| 755 | mark = in + 1; |
| 756 | } |
| 757 | } |
| 758 | } |
| 759 | break; |
| 760 | case IN_ARGS: |
| 761 | if (depth == 0) |
| 762 | { |
| 763 | switch (*in) |
| 764 | { |
| 765 | case ',': |
| 766 | narg++; |
| 767 | args[narg].start = (in + 1); |
| 768 | args[narg].len = 0; |
| 769 | break; |
| 770 | case ')': |
| 771 | state = IN_TEXT; |
| 772 | /* printf("entering state %d at '%s'...\n", state, in); */ |
| 773 | if (pmacro) |
| 774 | { |
| 775 | expansion = 0; |
| 776 | expansion = expand_macro (args, narg, pmacro); |
| 777 | num_expansions++; |
| 778 | if (expansion) |
| 779 | { |
| 780 | result = str_append (result, expansion, strlen (expansion)); |
| 781 | free (expansion); |
| 782 | } |
| 783 | } |
| 784 | else |
| 785 | { |
| 786 | result = str_append (result, mark, in - mark); |
| 787 | } |
| 788 | pmacro = NULL; |
| 789 | mark = in + 1; |
| 790 | break; |
| 791 | case '(': |
| 792 | depth++; |
| 793 | /* Fall through. */ |
| 794 | default: |
| 795 | args[narg].len++; |
| 796 | break; |
| 797 | } |
| 798 | } |
| 799 | else |
| 800 | { |
| 801 | if (*in == ')') |
| 802 | depth--; |
| 803 | if (narg > -1) |
| 804 | args[narg].len++; |
| 805 | } |
| 806 | |
| 807 | } |
| 808 | ++in; |
| 809 | } |
| 810 | |
| 811 | if (mark != in) |
| 812 | result = str_append (result, mark, in - mark); |
| 813 | |
| 814 | return result; |
| 815 | } |
| 816 | |
| 817 | #undef IN_ARGS |
| 818 | #undef IN_TEXT |
| 819 | #undef MAXARGS |
| 820 | |
| 821 | |
| 822 | /* END LIGHTWEIGHT MACRO PROCESSOR. */ |
| 823 | |
| 824 | const char * mep_cgen_parse_operand |
| 825 | (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *); |
| 826 | |
| 827 | const char * |
| 828 | mep_cgen_expand_macros_and_parse_operand (CGEN_CPU_DESC cd, int opindex, |
| 829 | const char ** strp_in, CGEN_FIELDS * fields) |
| 830 | { |
| 831 | const char * errmsg = NULL; |
| 832 | char *str = 0, *hold = 0; |
| 833 | const char **strp = 0; |
| 834 | |
| 835 | /* Set up a new pointer to macro-expanded string. */ |
| 836 | str = expand_string (*strp_in, 1); |
| 837 | /* fprintf (stderr, " expanded <<%s>> to <<%s>>\n", *strp_in, str); */ |
| 838 | |
| 839 | hold = str; |
| 840 | strp = (const char **)(&str); |
| 841 | |
| 842 | errmsg = mep_cgen_parse_operand (cd, opindex, strp, fields); |
| 843 | |
| 844 | /* Now work out the advance. */ |
| 845 | if (strlen (str) == 0) |
| 846 | *strp_in += strlen (*strp_in); |
| 847 | |
| 848 | else |
| 849 | { |
| 850 | if (strstr (*strp_in, str)) |
| 851 | /* A macro-expansion was pulled off the front. */ |
| 852 | *strp_in = strstr (*strp_in, str); |
| 853 | else |
| 854 | /* A non-macro-expansion was pulled off the front. */ |
| 855 | *strp_in += (str - hold); |
| 856 | } |
| 857 | |
| 858 | if (hold) |
| 859 | free (hold); |
| 860 | |
| 861 | return errmsg; |
| 862 | } |
| 863 | |
| 864 | #define CGEN_ASM_INIT_HOOK (cd->parse_operand = mep_cgen_expand_macros_and_parse_operand); |
| 865 | |
| 866 | /* -- dis.c */ |
| 867 | |
| 868 | #include "elf/mep.h" |
| 869 | #include "elf-bfd.h" |
| 870 | |
| 871 | #define CGEN_VALIDATE_INSN_SUPPORTED |
| 872 | |
| 873 | static void print_tpreg (CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int); |
| 874 | static void print_spreg (CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int); |
| 875 | |
| 876 | static void |
| 877 | print_tpreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, PTR dis_info, |
| 878 | CGEN_KEYWORD *table ATTRIBUTE_UNUSED, long val ATTRIBUTE_UNUSED, |
| 879 | unsigned int flags ATTRIBUTE_UNUSED) |
| 880 | { |
| 881 | disassemble_info *info = (disassemble_info *) dis_info; |
| 882 | |
| 883 | (*info->fprintf_func) (info->stream, "$tp"); |
| 884 | } |
| 885 | |
| 886 | static void |
| 887 | print_spreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, PTR dis_info, |
| 888 | CGEN_KEYWORD *table ATTRIBUTE_UNUSED, long val ATTRIBUTE_UNUSED, |
| 889 | unsigned int flags ATTRIBUTE_UNUSED) |
| 890 | { |
| 891 | disassemble_info *info = (disassemble_info *) dis_info; |
| 892 | |
| 893 | (*info->fprintf_func) (info->stream, "$sp"); |
| 894 | } |
| 895 | |
| 896 | /* begin-cop-ip-print-handlers */ |
| 897 | static void |
| 898 | print_ivc2_cr (CGEN_CPU_DESC, |
| 899 | void *, |
| 900 | CGEN_KEYWORD *, |
| 901 | long, |
| 902 | unsigned int) ATTRIBUTE_UNUSED; |
| 903 | static void |
| 904 | print_ivc2_cr (CGEN_CPU_DESC cd, |
| 905 | void *dis_info, |
| 906 | CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED, |
| 907 | long value, |
| 908 | unsigned int attrs) |
| 909 | { |
| 910 | print_keyword (cd, dis_info, & mep_cgen_opval_h_cr_ivc2, value, attrs); |
| 911 | } |
| 912 | static void |
| 913 | print_ivc2_ccr (CGEN_CPU_DESC, |
| 914 | void *, |
| 915 | CGEN_KEYWORD *, |
| 916 | long, |
| 917 | unsigned int) ATTRIBUTE_UNUSED; |
| 918 | static void |
| 919 | print_ivc2_ccr (CGEN_CPU_DESC cd, |
| 920 | void *dis_info, |
| 921 | CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED, |
| 922 | long value, |
| 923 | unsigned int attrs) |
| 924 | { |
| 925 | print_keyword (cd, dis_info, & mep_cgen_opval_h_ccr_ivc2, value, attrs); |
| 926 | } |
| 927 | /* end-cop-ip-print-handlers */ |
| 928 | |
| 929 | /************************************************************\ |
| 930 | *********************** Experimental ************************* |
| 931 | \************************************************************/ |
| 932 | |
| 933 | #undef CGEN_PRINT_INSN |
| 934 | #define CGEN_PRINT_INSN mep_print_insn |
| 935 | |
| 936 | static int |
| 937 | mep_print_vliw_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info, |
| 938 | bfd_byte *buf, int corelength, int copro1length, |
| 939 | int copro2length ATTRIBUTE_UNUSED) |
| 940 | { |
| 941 | int i; |
| 942 | int status = 0; |
| 943 | /* char insnbuf[CGEN_MAX_INSN_SIZE]; */ |
| 944 | bfd_byte insnbuf[64]; |
| 945 | |
| 946 | /* If corelength > 0 then there is a core insn present. It |
| 947 | will be at the beginning of the buffer. After printing |
| 948 | the core insn, we need to print the + on the next line. */ |
| 949 | if (corelength > 0) |
| 950 | { |
| 951 | int my_status = 0; |
| 952 | |
| 953 | for (i = 0; i < corelength; i++ ) |
| 954 | insnbuf[i] = buf[i]; |
| 955 | cd->isas = & MEP_CORE_ISA; |
| 956 | |
| 957 | my_status = print_insn (cd, pc, info, insnbuf, corelength); |
| 958 | if (my_status != corelength) |
| 959 | { |
| 960 | (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); |
| 961 | my_status = corelength; |
| 962 | } |
| 963 | status += my_status; |
| 964 | |
| 965 | /* Print the + to indicate that the following copro insn is */ |
| 966 | /* part of a vliw group. */ |
| 967 | if (copro1length > 0) |
| 968 | (*info->fprintf_func) (info->stream, " + "); |
| 969 | } |
| 970 | |
| 971 | /* Now all that is left to be processed is the coprocessor insns |
| 972 | In vliw mode, there will always be one. Its positioning will |
| 973 | be from byte corelength to byte corelength+copro1length -1. |
| 974 | No need to check for existence. Also, the first vliw insn, |
| 975 | will, as spec'd, always be at least as long as the core insn |
| 976 | so we don't need to flush the buffer. */ |
| 977 | if (copro1length > 0) |
| 978 | { |
| 979 | int my_status = 0; |
| 980 | |
| 981 | for (i = corelength; i < corelength + copro1length; i++ ) |
| 982 | insnbuf[i - corelength] = buf[i]; |
| 983 | |
| 984 | switch (copro1length) |
| 985 | { |
| 986 | case 0: |
| 987 | break; |
| 988 | case 2: |
| 989 | cd->isas = & MEP_COP16_ISA; |
| 990 | break; |
| 991 | case 4: |
| 992 | cd->isas = & MEP_COP32_ISA; |
| 993 | break; |
| 994 | case 6: |
| 995 | cd->isas = & MEP_COP48_ISA; |
| 996 | break; |
| 997 | case 8: |
| 998 | cd->isas = & MEP_COP64_ISA; |
| 999 | break; |
| 1000 | default: |
| 1001 | /* Shouldn't be anything but 16,32,48,64. */ |
| 1002 | break; |
| 1003 | } |
| 1004 | |
| 1005 | my_status = print_insn (cd, pc, info, insnbuf, copro1length); |
| 1006 | |
| 1007 | if (my_status != copro1length) |
| 1008 | { |
| 1009 | (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); |
| 1010 | my_status = copro1length; |
| 1011 | } |
| 1012 | status += my_status; |
| 1013 | } |
| 1014 | |
| 1015 | #if 0 |
| 1016 | /* Now we need to process the second copro insn if it exists. We |
| 1017 | have no guarantee that the second copro insn will be longer |
| 1018 | than the first, so we have to flush the buffer if we are have |
| 1019 | a second copro insn to process. If present, this insn will |
| 1020 | be in the position from byte corelength+copro1length to byte |
| 1021 | corelength+copro1length+copro2length-1 (which better equal 8 |
| 1022 | or else we're in big trouble. */ |
| 1023 | if (copro2length > 0) |
| 1024 | { |
| 1025 | int my_status = 0; |
| 1026 | |
| 1027 | for (i = 0; i < 64 ; i++) |
| 1028 | insnbuf[i] = 0; |
| 1029 | |
| 1030 | for (i = corelength + copro1length; i < 64; i++) |
| 1031 | insnbuf[i - (corelength + copro1length)] = buf[i]; |
| 1032 | |
| 1033 | switch (copro2length) |
| 1034 | { |
| 1035 | case 2: |
| 1036 | cd->isas = 1 << ISA_EXT_COP1_16; |
| 1037 | break; |
| 1038 | case 4: |
| 1039 | cd->isas = 1 << ISA_EXT_COP1_32; |
| 1040 | break; |
| 1041 | case 6: |
| 1042 | cd->isas = 1 << ISA_EXT_COP1_48; |
| 1043 | break; |
| 1044 | case 8: |
| 1045 | cd->isas = 1 << ISA_EXT_COP1_64; |
| 1046 | break; |
| 1047 | default: |
| 1048 | /* Shouldn't be anything but 16,32,48,64. */ |
| 1049 | break; |
| 1050 | } |
| 1051 | |
| 1052 | my_status = print_insn (cd, pc, info, insnbuf, copro2length); |
| 1053 | |
| 1054 | if (my_status != copro2length) |
| 1055 | { |
| 1056 | (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG); |
| 1057 | my_status = copro2length; |
| 1058 | } |
| 1059 | |
| 1060 | status += my_status; |
| 1061 | } |
| 1062 | #endif |
| 1063 | |
| 1064 | /* Status should now be the number of bytes that were printed |
| 1065 | which should be 4 for VLIW32 mode and 64 for VLIW64 mode. */ |
| 1066 | |
| 1067 | if ((!MEP_VLIW64 && (status != 4)) || (MEP_VLIW64 && (status != 8))) |
| 1068 | return -1; |
| 1069 | else |
| 1070 | return status; |
| 1071 | } |
| 1072 | |
| 1073 | /* The two functions mep_examine_vliw[32,64]_insns are used find out |
| 1074 | which vliw combinaion (16 bit core with 48 bit copro, 32 bit core |
| 1075 | with 32 bit copro, etc.) is present. Later on, when internally |
| 1076 | parallel coprocessors are handled, only these functions should |
| 1077 | need to be changed. |
| 1078 | |
| 1079 | At this time only the following combinations are supported: |
| 1080 | |
| 1081 | VLIW32 Mode: |
| 1082 | 16 bit core insn (core) and 16 bit coprocessor insn (cop1) |
| 1083 | 32 bit core insn (core) |
| 1084 | 32 bit coprocessor insn (cop1) |
| 1085 | Note: As of this time, I do not believe we have enough information |
| 1086 | to distinguish a 32 bit core insn from a 32 bit cop insn. Also, |
| 1087 | no 16 bit coprocessor insns have been specified. |
| 1088 | |
| 1089 | VLIW64 Mode: |
| 1090 | 16 bit core insn (core) and 48 bit coprocessor insn (cop1) |
| 1091 | 32 bit core insn (core) and 32 bit coprocessor insn (cop1) |
| 1092 | 64 bit coprocessor insn (cop1) |
| 1093 | |
| 1094 | The framework for an internally parallel coprocessor is also |
| 1095 | present (2nd coprocessor insn is cop2), but at this time it |
| 1096 | is not used. This only appears to be valid in VLIW64 mode. */ |
| 1097 | |
| 1098 | static int |
| 1099 | mep_examine_vliw32_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info) |
| 1100 | { |
| 1101 | int status; |
| 1102 | int buflength; |
| 1103 | int corebuflength; |
| 1104 | int cop1buflength; |
| 1105 | int cop2buflength; |
| 1106 | bfd_byte buf[CGEN_MAX_INSN_SIZE]; |
| 1107 | char indicator16[1]; |
| 1108 | char indicatorcop32[2]; |
| 1109 | |
| 1110 | /* At this time we're not supporting internally parallel coprocessors, |
| 1111 | so cop2buflength will always be 0. */ |
| 1112 | cop2buflength = 0; |
| 1113 | |
| 1114 | /* Read in 32 bits. */ |
| 1115 | buflength = 4; /* VLIW insn spans 4 bytes. */ |
| 1116 | status = (*info->read_memory_func) (pc, buf, buflength, info); |
| 1117 | |
| 1118 | if (status != 0) |
| 1119 | { |
| 1120 | (*info->memory_error_func) (status, pc, info); |
| 1121 | return -1; |
| 1122 | } |
| 1123 | |
| 1124 | /* Put the big endian representation of the bytes to be examined |
| 1125 | in the temporary buffers for examination. */ |
| 1126 | |
| 1127 | if (info->endian == BFD_ENDIAN_BIG) |
| 1128 | { |
| 1129 | indicator16[0] = buf[0]; |
| 1130 | indicatorcop32[0] = buf[0]; |
| 1131 | indicatorcop32[1] = buf[1]; |
| 1132 | } |
| 1133 | else |
| 1134 | { |
| 1135 | indicator16[0] = buf[1]; |
| 1136 | indicatorcop32[0] = buf[1]; |
| 1137 | indicatorcop32[1] = buf[0]; |
| 1138 | } |
| 1139 | |
| 1140 | /* If the two high order bits are 00, 01 or 10, we have a 16 bit |
| 1141 | core insn and a 48 bit copro insn. */ |
| 1142 | |
| 1143 | if ((indicator16[0] & 0x80) && (indicator16[0] & 0x40)) |
| 1144 | { |
| 1145 | if ((indicatorcop32[0] & 0xf0) == 0xf0 && (indicatorcop32[1] & 0x07) == 0x07) |
| 1146 | { |
| 1147 | /* We have a 32 bit copro insn. */ |
| 1148 | corebuflength = 0; |
| 1149 | /* All 4 4ytes are one copro insn. */ |
| 1150 | cop1buflength = 4; |
| 1151 | } |
| 1152 | else |
| 1153 | { |
| 1154 | /* We have a 32 bit core. */ |
| 1155 | corebuflength = 4; |
| 1156 | cop1buflength = 0; |
| 1157 | } |
| 1158 | } |
| 1159 | else |
| 1160 | { |
| 1161 | /* We have a 16 bit core insn and a 16 bit copro insn. */ |
| 1162 | corebuflength = 2; |
| 1163 | cop1buflength = 2; |
| 1164 | } |
| 1165 | |
| 1166 | /* Now we have the distrubution set. Print them out. */ |
| 1167 | status = mep_print_vliw_insns (cd, pc, info, buf, corebuflength, |
| 1168 | cop1buflength, cop2buflength); |
| 1169 | |
| 1170 | return status; |
| 1171 | } |
| 1172 | |
| 1173 | static int |
| 1174 | mep_examine_vliw64_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info) |
| 1175 | { |
| 1176 | int status; |
| 1177 | int buflength; |
| 1178 | int corebuflength; |
| 1179 | int cop1buflength; |
| 1180 | int cop2buflength; |
| 1181 | bfd_byte buf[CGEN_MAX_INSN_SIZE]; |
| 1182 | char indicator16[1]; |
| 1183 | char indicator64[4]; |
| 1184 | |
| 1185 | /* At this time we're not supporting internally parallel |
| 1186 | coprocessors, so cop2buflength will always be 0. */ |
| 1187 | cop2buflength = 0; |
| 1188 | |
| 1189 | /* Read in 64 bits. */ |
| 1190 | buflength = 8; /* VLIW insn spans 8 bytes. */ |
| 1191 | status = (*info->read_memory_func) (pc, buf, buflength, info); |
| 1192 | |
| 1193 | if (status != 0) |
| 1194 | { |
| 1195 | (*info->memory_error_func) (status, pc, info); |
| 1196 | return -1; |
| 1197 | } |
| 1198 | |
| 1199 | /* We have all 64 bits in the buffer now. We have to figure out |
| 1200 | what combination of instruction sizes are present. The two |
| 1201 | high order bits will indicate whether or not we have a 16 bit |
| 1202 | core insn or not. If not, then we have to look at the 7,8th |
| 1203 | bytes to tell whether we have 64 bit copro insn or a 32 bit |
| 1204 | core insn with a 32 bit copro insn. Endianness will make a |
| 1205 | difference here. */ |
| 1206 | |
| 1207 | /* Put the big endian representation of the bytes to be examined |
| 1208 | in the temporary buffers for examination. */ |
| 1209 | |
| 1210 | /* indicator16[0] = buf[0]; */ |
| 1211 | if (info->endian == BFD_ENDIAN_BIG) |
| 1212 | { |
| 1213 | indicator16[0] = buf[0]; |
| 1214 | indicator64[0] = buf[0]; |
| 1215 | indicator64[1] = buf[1]; |
| 1216 | indicator64[2] = buf[2]; |
| 1217 | indicator64[3] = buf[3]; |
| 1218 | } |
| 1219 | else |
| 1220 | { |
| 1221 | indicator16[0] = buf[1]; |
| 1222 | indicator64[0] = buf[1]; |
| 1223 | indicator64[1] = buf[0]; |
| 1224 | indicator64[2] = buf[3]; |
| 1225 | indicator64[3] = buf[2]; |
| 1226 | } |
| 1227 | |
| 1228 | /* If the two high order bits are 00, 01 or 10, we have a 16 bit |
| 1229 | core insn and a 48 bit copro insn. */ |
| 1230 | |
| 1231 | if ((indicator16[0] & 0x80) && (indicator16[0] & 0x40)) |
| 1232 | { |
| 1233 | if ((indicator64[0] & 0xf0) == 0xf0 && (indicator64[1] & 0x07) == 0x07 |
| 1234 | && ((indicator64[2] & 0xfe) != 0xf0 || (indicator64[3] & 0xf4) != 0)) |
| 1235 | { |
| 1236 | /* We have a 64 bit copro insn. */ |
| 1237 | corebuflength = 0; |
| 1238 | /* All 8 bytes are one copro insn. */ |
| 1239 | cop1buflength = 8; |
| 1240 | } |
| 1241 | else |
| 1242 | { |
| 1243 | /* We have a 32 bit core insn and a 32 bit copro insn. */ |
| 1244 | corebuflength = 4; |
| 1245 | cop1buflength = 4; |
| 1246 | } |
| 1247 | } |
| 1248 | else |
| 1249 | { |
| 1250 | /* We have a 16 bit core insn and a 48 bit copro insn. */ |
| 1251 | corebuflength = 2; |
| 1252 | cop1buflength = 6; |
| 1253 | } |
| 1254 | |
| 1255 | /* Now we have the distrubution set. Print them out. */ |
| 1256 | status = mep_print_vliw_insns (cd, pc, info, buf, corebuflength, |
| 1257 | cop1buflength, cop2buflength); |
| 1258 | |
| 1259 | return status; |
| 1260 | } |
| 1261 | |
| 1262 | #ifdef MEP_IVC2_SUPPORTED |
| 1263 | |
| 1264 | static int |
| 1265 | print_slot_insn (CGEN_CPU_DESC cd, |
| 1266 | bfd_vma pc, |
| 1267 | disassemble_info *info, |
| 1268 | SLOTS_ATTR slot, |
| 1269 | bfd_byte *buf) |
| 1270 | { |
| 1271 | const CGEN_INSN_LIST *insn_list; |
| 1272 | CGEN_INSN_INT insn_value; |
| 1273 | CGEN_EXTRACT_INFO ex_info; |
| 1274 | |
| 1275 | insn_value = cgen_get_insn_value (cd, buf, 32); |
| 1276 | |
| 1277 | /* Fill in ex_info fields like read_insn would. Don't actually call |
| 1278 | read_insn, since the incoming buffer is already read (and possibly |
| 1279 | modified a la m32r). */ |
| 1280 | ex_info.valid = (1 << 8) - 1; |
| 1281 | ex_info.dis_info = info; |
| 1282 | ex_info.insn_bytes = buf; |
| 1283 | |
| 1284 | /* The instructions are stored in hash lists. |
| 1285 | Pick the first one and keep trying until we find the right one. */ |
| 1286 | |
| 1287 | insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value); |
| 1288 | while (insn_list != NULL) |
| 1289 | { |
| 1290 | const CGEN_INSN *insn = insn_list->insn; |
| 1291 | CGEN_FIELDS fields; |
| 1292 | int length; |
| 1293 | |
| 1294 | if ((CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG) |
| 1295 | && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG) != MEP_CONFIG) |
| 1296 | || ! (CGEN_ATTR_CGEN_INSN_SLOTS_VALUE (CGEN_INSN_ATTRS (insn)) & (1 << slot))) |
| 1297 | { |
| 1298 | insn_list = CGEN_DIS_NEXT_INSN (insn_list); |
| 1299 | continue; |
| 1300 | } |
| 1301 | |
| 1302 | if ((insn_value & CGEN_INSN_BASE_MASK (insn)) |
| 1303 | == CGEN_INSN_BASE_VALUE (insn)) |
| 1304 | { |
| 1305 | /* Printing is handled in two passes. The first pass parses the |
| 1306 | machine insn and extracts the fields. The second pass prints |
| 1307 | them. */ |
| 1308 | |
| 1309 | length = CGEN_EXTRACT_FN (cd, insn) |
| 1310 | (cd, insn, &ex_info, insn_value, &fields, pc); |
| 1311 | |
| 1312 | /* Length < 0 -> error. */ |
| 1313 | if (length < 0) |
| 1314 | return length; |
| 1315 | if (length > 0) |
| 1316 | { |
| 1317 | CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length); |
| 1318 | /* Length is in bits, result is in bytes. */ |
| 1319 | return length / 8; |
| 1320 | } |
| 1321 | } |
| 1322 | |
| 1323 | insn_list = CGEN_DIS_NEXT_INSN (insn_list); |
| 1324 | } |
| 1325 | |
| 1326 | if (slot == SLOTS_P0S) |
| 1327 | (*info->fprintf_func) (info->stream, "*unknown-p0s*"); |
| 1328 | else if (slot == SLOTS_P0) |
| 1329 | (*info->fprintf_func) (info->stream, "*unknown-p0*"); |
| 1330 | else if (slot == SLOTS_P1) |
| 1331 | (*info->fprintf_func) (info->stream, "*unknown-p1*"); |
| 1332 | else if (slot == SLOTS_C3) |
| 1333 | (*info->fprintf_func) (info->stream, "*unknown-c3*"); |
| 1334 | return 0; |
| 1335 | } |
| 1336 | |
| 1337 | static int |
| 1338 | mep_examine_ivc2_insns (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, bfd_vma pc ATTRIBUTE_UNUSED, disassemble_info *info ATTRIBUTE_UNUSED) |
| 1339 | { |
| 1340 | int status; |
| 1341 | int buflength; |
| 1342 | bfd_byte buf[8]; |
| 1343 | bfd_byte insn[8]; |
| 1344 | int e; |
| 1345 | |
| 1346 | /* Read in 64 bits. */ |
| 1347 | buflength = 8; /* VLIW insn spans 8 bytes. */ |
| 1348 | status = (*info->read_memory_func) (pc, buf, buflength, info); |
| 1349 | |
| 1350 | if (status != 0) |
| 1351 | { |
| 1352 | (*info->memory_error_func) (status, pc, info); |
| 1353 | return -1; |
| 1354 | } |
| 1355 | |
| 1356 | if (info->endian == BFD_ENDIAN_LITTLE) |
| 1357 | e = 1; |
| 1358 | else |
| 1359 | e = 0; |
| 1360 | |
| 1361 | if (((unsigned char)buf[0^e] & 0xf0) < 0xc0) |
| 1362 | { |
| 1363 | /* <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */ |
| 1364 | /* V1 [-----core-----][--------p0s-------][------------p1------------] */ |
| 1365 | |
| 1366 | print_insn (cd, pc, info, buf, 2); |
| 1367 | |
| 1368 | insn[0^e] = 0; |
| 1369 | insn[1^e] = buf[2^e]; |
| 1370 | insn[2^e] = buf[3^e]; |
| 1371 | insn[3^e] = buf[4^e] & 0xf0; |
| 1372 | (*info->fprintf_func) (info->stream, " + "); |
| 1373 | print_slot_insn (cd, pc, info, SLOTS_P0S, insn); |
| 1374 | |
| 1375 | insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4; |
| 1376 | insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4; |
| 1377 | insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4; |
| 1378 | insn[3^e] = buf[7^e] << 4; |
| 1379 | (*info->fprintf_func) (info->stream, " + "); |
| 1380 | print_slot_insn (cd, pc, info, SLOTS_P1, insn); |
| 1381 | } |
| 1382 | else if ((buf[0^e] & 0xf0) == 0xf0 && (buf[1^e] & 0x0f) == 0x07) |
| 1383 | { |
| 1384 | /* <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */ |
| 1385 | /* V3 1111[--p0--]0111[--------p0--------][------------p1------------] */ |
| 1386 | /* 00000000111111112222222233333333 */ |
| 1387 | |
| 1388 | insn[0^e] = buf[0^e] << 4 | buf[1^e] >> 4; |
| 1389 | insn[1^e] = buf[2^e]; |
| 1390 | insn[2^e] = buf[3^e]; |
| 1391 | insn[3^e] = buf[4^e] & 0xf0; |
| 1392 | print_slot_insn (cd, pc, info, SLOTS_P0, insn); |
| 1393 | |
| 1394 | insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4; |
| 1395 | insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4; |
| 1396 | insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4; |
| 1397 | insn[3^e] = buf[7^e] << 4; |
| 1398 | (*info->fprintf_func) (info->stream, " + "); |
| 1399 | print_slot_insn (cd, pc, info, SLOTS_P1, insn); |
| 1400 | } |
| 1401 | else |
| 1402 | { |
| 1403 | /* <--00--><--11--><--22--><--33--><--44--><--55--><--66--><--77--> */ |
| 1404 | /* V2 [-------------core-------------]xxxx[------------p1------------] */ |
| 1405 | print_insn (cd, pc, info, buf, 4); |
| 1406 | |
| 1407 | insn[0^e] = buf[4^e] << 4 | buf[5^e] >> 4; |
| 1408 | insn[1^e] = buf[5^e] << 4 | buf[6^e] >> 4; |
| 1409 | insn[2^e] = buf[6^e] << 4 | buf[7^e] >> 4; |
| 1410 | insn[3^e] = buf[7^e] << 4; |
| 1411 | (*info->fprintf_func) (info->stream, " + "); |
| 1412 | print_slot_insn (cd, pc, info, SLOTS_P1, insn); |
| 1413 | } |
| 1414 | |
| 1415 | return 8; |
| 1416 | } |
| 1417 | |
| 1418 | #endif /* MEP_IVC2_SUPPORTED */ |
| 1419 | |
| 1420 | /* This is a hack. SID calls this to update the disassembler as the |
| 1421 | CPU changes modes. */ |
| 1422 | static int mep_ivc2_disassemble_p = 0; |
| 1423 | static int mep_ivc2_vliw_disassemble_p = 0; |
| 1424 | |
| 1425 | void |
| 1426 | mep_print_insn_set_ivc2_mode (int ivc2_p, int vliw_p, int cfg_idx); |
| 1427 | void |
| 1428 | mep_print_insn_set_ivc2_mode (int ivc2_p, int vliw_p, int cfg_idx) |
| 1429 | { |
| 1430 | mep_ivc2_disassemble_p = ivc2_p; |
| 1431 | mep_ivc2_vliw_disassemble_p = vliw_p; |
| 1432 | mep_config_index = cfg_idx; |
| 1433 | } |
| 1434 | |
| 1435 | static int |
| 1436 | mep_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info) |
| 1437 | { |
| 1438 | int status; |
| 1439 | int cop_type; |
| 1440 | int ivc2 = 0; |
| 1441 | static CGEN_ATTR_VALUE_BITSET_TYPE *ivc2_core_isa = NULL; |
| 1442 | |
| 1443 | if (ivc2_core_isa == NULL) |
| 1444 | { |
| 1445 | /* IVC2 has some core-only coprocessor instructions. We |
| 1446 | use COP32 to flag those, and COP64 for the VLIW ones, |
| 1447 | since they have the same names. */ |
| 1448 | ivc2_core_isa = cgen_bitset_create (MAX_ISAS); |
| 1449 | } |
| 1450 | |
| 1451 | /* Extract and adapt to configuration number, if available. */ |
| 1452 | if (info->section && info->section->owner) |
| 1453 | { |
| 1454 | bfd *abfd = info->section->owner; |
| 1455 | mep_config_index = abfd->tdata.elf_obj_data->elf_header->e_flags & EF_MEP_INDEX_MASK; |
| 1456 | /* This instantly redefines MEP_CONFIG, MEP_OMASK, .... MEP_VLIW64 */ |
| 1457 | |
| 1458 | cop_type = abfd->tdata.elf_obj_data->elf_header->e_flags & EF_MEP_COP_MASK; |
| 1459 | if (cop_type == EF_MEP_COP_IVC2) |
| 1460 | ivc2 = 1; |
| 1461 | } |
| 1462 | |
| 1463 | /* Picking the right ISA bitmask for the current context is tricky. */ |
| 1464 | if (info->section) |
| 1465 | { |
| 1466 | if (info->section->flags & SEC_MEP_VLIW) |
| 1467 | { |
| 1468 | #ifdef MEP_IVC2_SUPPORTED |
| 1469 | if (ivc2) |
| 1470 | { |
| 1471 | /* ivc2 has its own way of selecting its functions. */ |
| 1472 | cd->isas = & MEP_CORE_ISA; |
| 1473 | status = mep_examine_ivc2_insns (cd, pc, info); |
| 1474 | } |
| 1475 | else |
| 1476 | #endif |
| 1477 | /* Are we in 32 or 64 bit vliw mode? */ |
| 1478 | if (MEP_VLIW64) |
| 1479 | status = mep_examine_vliw64_insns (cd, pc, info); |
| 1480 | else |
| 1481 | status = mep_examine_vliw32_insns (cd, pc, info); |
| 1482 | /* Both the above branches set their own isa bitmasks. */ |
| 1483 | } |
| 1484 | else |
| 1485 | { |
| 1486 | if (ivc2) |
| 1487 | { |
| 1488 | cgen_bitset_clear (ivc2_core_isa); |
| 1489 | cgen_bitset_union (ivc2_core_isa, &MEP_CORE_ISA, ivc2_core_isa); |
| 1490 | cgen_bitset_union (ivc2_core_isa, &MEP_COP32_ISA, ivc2_core_isa); |
| 1491 | cd->isas = ivc2_core_isa; |
| 1492 | } |
| 1493 | else |
| 1494 | cd->isas = & MEP_CORE_ISA; |
| 1495 | status = default_print_insn (cd, pc, info); |
| 1496 | } |
| 1497 | } |
| 1498 | else /* sid or gdb */ |
| 1499 | { |
| 1500 | #ifdef MEP_IVC2_SUPPORTED |
| 1501 | if (mep_ivc2_disassemble_p) |
| 1502 | { |
| 1503 | if (mep_ivc2_vliw_disassemble_p) |
| 1504 | { |
| 1505 | cd->isas = & MEP_CORE_ISA; |
| 1506 | status = mep_examine_ivc2_insns (cd, pc, info); |
| 1507 | return status; |
| 1508 | } |
| 1509 | else |
| 1510 | { |
| 1511 | if (ivc2) |
| 1512 | cd->isas = ivc2_core_isa; |
| 1513 | } |
| 1514 | } |
| 1515 | #endif |
| 1516 | |
| 1517 | status = default_print_insn (cd, pc, info); |
| 1518 | } |
| 1519 | |
| 1520 | return status; |
| 1521 | } |
| 1522 | |
| 1523 | |
| 1524 | /* -- opc.c */ |
| 1525 | #include "elf/mep.h" |
| 1526 | |
| 1527 | /* A mask for all ISAs executed by the core. */ |
| 1528 | CGEN_ATTR_VALUE_BITSET_TYPE mep_all_core_isas_mask = {0, 0}; |
| 1529 | |
| 1530 | void |
| 1531 | init_mep_all_core_isas_mask (void) |
| 1532 | { |
| 1533 | if (mep_all_core_isas_mask.length != 0) |
| 1534 | return; |
| 1535 | cgen_bitset_init (& mep_all_core_isas_mask, ISA_MAX); |
| 1536 | cgen_bitset_set (& mep_all_core_isas_mask, ISA_MEP); |
| 1537 | /* begin-all-core-isas */ |
| 1538 | cgen_bitset_add (& mep_all_core_isas_mask, ISA_EXT_CORE1); |
| 1539 | /* end-all-core-isas */ |
| 1540 | } |
| 1541 | |
| 1542 | CGEN_ATTR_VALUE_BITSET_TYPE mep_all_cop_isas_mask = {0, 0}; |
| 1543 | |
| 1544 | void |
| 1545 | init_mep_all_cop_isas_mask (void) |
| 1546 | { |
| 1547 | if (mep_all_cop_isas_mask.length != 0) |
| 1548 | return; |
| 1549 | cgen_bitset_init (& mep_all_cop_isas_mask, ISA_MAX); |
| 1550 | /* begin-all-cop-isas */ |
| 1551 | cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_16); |
| 1552 | cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_32); |
| 1553 | cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_48); |
| 1554 | cgen_bitset_add (& mep_all_cop_isas_mask, ISA_EXT_COP1_64); |
| 1555 | /* end-all-cop-isas */ |
| 1556 | } |
| 1557 | |
| 1558 | int |
| 1559 | mep_insn_supported_by_isa (const CGEN_INSN *insn, CGEN_ATTR_VALUE_BITSET_TYPE *isa_mask) |
| 1560 | { |
| 1561 | CGEN_BITSET insn_isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA); |
| 1562 | return cgen_bitset_intersect_p (& insn_isas, isa_mask); |
| 1563 | } |
| 1564 | |
| 1565 | #define OPTION_MASK \ |
| 1566 | ( (1 << CGEN_INSN_OPTIONAL_BIT_INSN) \ |
| 1567 | | (1 << CGEN_INSN_OPTIONAL_MUL_INSN) \ |
| 1568 | | (1 << CGEN_INSN_OPTIONAL_DIV_INSN) \ |
| 1569 | | (1 << CGEN_INSN_OPTIONAL_DEBUG_INSN) \ |
| 1570 | | (1 << CGEN_INSN_OPTIONAL_LDZ_INSN) \ |
| 1571 | | (1 << CGEN_INSN_OPTIONAL_ABS_INSN) \ |
| 1572 | | (1 << CGEN_INSN_OPTIONAL_AVE_INSN) \ |
| 1573 | | (1 << CGEN_INSN_OPTIONAL_MINMAX_INSN) \ |
| 1574 | | (1 << CGEN_INSN_OPTIONAL_CLIP_INSN) \ |
| 1575 | | (1 << CGEN_INSN_OPTIONAL_SAT_INSN) \ |
| 1576 | | (1 << CGEN_INSN_OPTIONAL_UCI_INSN) \ |
| 1577 | | (1 << CGEN_INSN_OPTIONAL_DSP_INSN) \ |
| 1578 | | (1 << CGEN_INSN_OPTIONAL_CP_INSN) \ |
| 1579 | | (1 << CGEN_INSN_OPTIONAL_CP64_INSN) ) |
| 1580 | |
| 1581 | |
| 1582 | mep_config_map_struct mep_config_map[] = |
| 1583 | { |
| 1584 | /* config-map-start */ |
| 1585 | /* Default entry: first module, with all options enabled. */ |
| 1586 | { "", 0, EF_MEP_COP_IVC2 | EF_MEP_CPU_C5,0, 64, { 1, "\x20" }, { 1, "\x10" }, { 1, "\x8" }, { 1, "\x4" }, { 1, "\x3c" }, { 1, "\xc0" }, OPTION_MASK | (1 << CGEN_INSN_OPTIONAL_DSP_INSN) | (1 << CGEN_INSN_OPTIONAL_UCI_INSN) }, |
| 1587 | { "default", CONFIG_DEFAULT, EF_MEP_COP_IVC2 | EF_MEP_CPU_C5, 0, 64, { 1, "\x20" }, { 1, "\x10" }, { 1, "\x8" }, { 1, "\x4" }, { 1, "\x3c" }, { 1, "\xc0" }, |
| 1588 | 0 |
| 1589 | | (1 << CGEN_INSN_OPTIONAL_CP_INSN) |
| 1590 | | (1 << CGEN_INSN_OPTIONAL_CP64_INSN) |
| 1591 | | (1 << CGEN_INSN_OPTIONAL_MUL_INSN) |
| 1592 | | (1 << CGEN_INSN_OPTIONAL_DIV_INSN) |
| 1593 | | (1 << CGEN_INSN_OPTIONAL_BIT_INSN) |
| 1594 | | (1 << CGEN_INSN_OPTIONAL_LDZ_INSN) |
| 1595 | | (1 << CGEN_INSN_OPTIONAL_ABS_INSN) |
| 1596 | | (1 << CGEN_INSN_OPTIONAL_AVE_INSN) |
| 1597 | | (1 << CGEN_INSN_OPTIONAL_MINMAX_INSN) |
| 1598 | | (1 << CGEN_INSN_OPTIONAL_CLIP_INSN) |
| 1599 | | (1 << CGEN_INSN_OPTIONAL_SAT_INSN) }, |
| 1600 | /* config-map-end */ |
| 1601 | { 0, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0 } |
| 1602 | }; |
| 1603 | |
| 1604 | int mep_config_index = 0; |
| 1605 | |
| 1606 | static int |
| 1607 | check_configured_mach (int machs) |
| 1608 | { |
| 1609 | /* All base insns are supported. */ |
| 1610 | int mach = 1 << MACH_BASE; |
| 1611 | switch (MEP_CPU & EF_MEP_CPU_MASK) |
| 1612 | { |
| 1613 | case EF_MEP_CPU_C2: |
| 1614 | case EF_MEP_CPU_C3: |
| 1615 | mach |= (1 << MACH_MEP); |
| 1616 | break; |
| 1617 | case EF_MEP_CPU_H1: |
| 1618 | mach |= (1 << MACH_H1); |
| 1619 | break; |
| 1620 | case EF_MEP_CPU_C5: |
| 1621 | mach |= (1 << MACH_MEP); |
| 1622 | mach |= (1 << MACH_C5); |
| 1623 | break; |
| 1624 | default: |
| 1625 | break; |
| 1626 | } |
| 1627 | return machs & mach; |
| 1628 | } |
| 1629 | |
| 1630 | int |
| 1631 | mep_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn) |
| 1632 | { |
| 1633 | int iconfig = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONFIG); |
| 1634 | int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH); |
| 1635 | CGEN_BITSET isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA); |
| 1636 | int ok1; |
| 1637 | int ok2; |
| 1638 | int ok3; |
| 1639 | |
| 1640 | /* If the insn has an option bit set that we don't want, |
| 1641 | reject it. */ |
| 1642 | if (CGEN_INSN_ATTRS (insn)->bool_ & OPTION_MASK & ~MEP_OMASK) |
| 1643 | return 0; |
| 1644 | |
| 1645 | /* If attributes are absent, assume no restriction. */ |
| 1646 | if (machs == 0) |
| 1647 | machs = ~0; |
| 1648 | |
| 1649 | ok1 = ((machs & cd->machs) && cgen_bitset_intersect_p (& isas, cd->isas)); |
| 1650 | /* If the insn is config-specific, make sure it matches. */ |
| 1651 | ok2 = (iconfig == 0 || iconfig == MEP_CONFIG); |
| 1652 | /* Make sure the insn is supported by the configured mach */ |
| 1653 | ok3 = check_configured_mach (machs); |
| 1654 | |
| 1655 | return (ok1 && ok2 && ok3); |
| 1656 | } |
| 1657 | |
| 1658 | int |
| 1659 | mep_cgen_insn_supported_asm (CGEN_CPU_DESC cd, const CGEN_INSN *insn) |
| 1660 | { |
| 1661 | #ifdef MEP_IVC2_SUPPORTED |
| 1662 | /* If we're assembling VLIW packets, ignore the 12-bit BSR as we |
| 1663 | can't relax that. The 24-bit BSR is matched instead. */ |
| 1664 | if (insn->base->num == MEP_INSN_BSR12 |
| 1665 | && cgen_bitset_contains (cd->isas, ISA_EXT_COP1_64)) |
| 1666 | return 0; |
| 1667 | #endif |
| 1668 | |
| 1669 | return mep_cgen_insn_supported (cd, insn); |
| 1670 | } |