Annotation of src/external/gpl3/binutils.old/dist/opcodes/or1k-asm.c, Revision 1.7
1.6 christos 1: /* DO NOT EDIT! -*- buffer-read-only: t -*- vi:set ro: */
1.1 christos 2: /* Assembler interface for targets using CGEN. -*- C -*-
3: CGEN: Cpu tools GENerator
4:
5: THIS FILE IS MACHINE GENERATED WITH CGEN.
6: - the resultant file is machine generated, cgen-asm.in isn't
7:
1.7 ! christos 8: Copyright (C) 1996-2020 Free Software Foundation, Inc.
1.1 christos 9:
10: This file is part of libopcodes.
11:
12: This library is free software; you can redistribute it and/or modify
13: it under the terms of the GNU General Public License as published by
14: the Free Software Foundation; either version 3, or (at your option)
15: any later version.
16:
17: It is distributed in the hope that it will be useful, but WITHOUT
18: ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
20: License for more details.
21:
22: You should have received a copy of the GNU General Public License
23: along with this program; if not, write to the Free Software Foundation, Inc.,
24: 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
25:
26:
27: /* ??? Eventually more and more of this stuff can go to cpu-independent files.
28: Keep that in mind. */
29:
30: #include "sysdep.h"
31: #include <stdio.h>
32: #include "ansidecl.h"
33: #include "bfd.h"
34: #include "symcat.h"
35: #include "or1k-desc.h"
36: #include "or1k-opc.h"
37: #include "opintl.h"
38: #include "xregex.h"
39: #include "libiberty.h"
40: #include "safe-ctype.h"
41:
42: #undef min
43: #define min(a,b) ((a) < (b) ? (a) : (b))
44: #undef max
45: #define max(a,b) ((a) > (b) ? (a) : (b))
46:
47: static const char * parse_insn_normal
48: (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
49:
50: /* -- assembler routines inserted here. */
51:
52: /* -- asm.c */
53:
54: static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
1.7 ! christos 55: static const char * INVALID_STORE_RELOC = N_("relocation invalid for store");
! 56: static const char * INVALID_RELOC_TYPE = N_("internal relocation type invalid");
1.1 christos 57:
58: #define CGEN_VERBOSE_ASSEMBLER_ERRORS
59:
60: static const char *
61: parse_disp26 (CGEN_CPU_DESC cd,
62: const char ** strp,
63: int opindex,
1.7 ! christos 64: int opinfo ATTRIBUTE_UNUSED,
1.1 christos 65: enum cgen_parse_operand_result * resultp,
66: bfd_vma * valuep)
67: {
1.7 ! christos 68: const char *str = *strp;
1.1 christos 69: const char *errmsg = NULL;
1.7 ! christos 70: bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_REL_26;
1.1 christos 71:
1.7 ! christos 72: if (strncasecmp (str, "plta(", 5) == 0)
! 73: {
! 74: *strp = str + 5;
! 75: reloc = BFD_RELOC_OR1K_PLTA26;
! 76: }
! 77: else if (strncasecmp (str, "plt(", 4) == 0)
1.1 christos 78: {
1.7 ! christos 79: *strp = str + 4;
! 80: reloc = BFD_RELOC_OR1K_PLT26;
1.1 christos 81: }
82:
1.7 ! christos 83: errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
1.1 christos 84:
1.7 ! christos 85: if (reloc != BFD_RELOC_OR1K_REL_26)
1.1 christos 86: {
87: if (**strp != ')')
88: errmsg = MISSING_CLOSING_PARENTHESIS;
1.7 ! christos 89: else
! 90: ++*strp;
1.1 christos 91: }
92:
1.7 ! christos 93: return errmsg;
! 94: }
1.1 christos 95:
1.7 ! christos 96: static const char *
! 97: parse_disp21 (CGEN_CPU_DESC cd,
! 98: const char ** strp,
! 99: int opindex,
! 100: int opinfo ATTRIBUTE_UNUSED,
! 101: enum cgen_parse_operand_result * resultp,
! 102: bfd_vma * valuep)
! 103: {
! 104: const char *str = *strp;
! 105: const char *errmsg = NULL;
! 106: bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_PCREL_PG21;
1.1 christos 107:
1.7 ! christos 108: if (strncasecmp (str, "got(", 4) == 0)
! 109: {
! 110: *strp = str + 4;
! 111: reloc = BFD_RELOC_OR1K_GOT_PG21;
1.1 christos 112: }
1.7 ! christos 113: else if (strncasecmp (str, "tlsgd(", 6) == 0)
1.1 christos 114: {
1.7 ! christos 115: *strp = str + 6;
! 116: reloc = BFD_RELOC_OR1K_TLS_GD_PG21;
1.1 christos 117: }
1.7 ! christos 118: else if (strncasecmp (str, "tlsldm(", 7) == 0)
1.1 christos 119: {
1.7 ! christos 120: *strp = str + 7;
! 121: reloc = BFD_RELOC_OR1K_TLS_LDM_PG21;
1.1 christos 122: }
1.7 ! christos 123: else if (strncasecmp (str, "gottp(", 6) == 0)
1.1 christos 124: {
1.7 ! christos 125: *strp = str + 6;
! 126: reloc = BFD_RELOC_OR1K_TLS_IE_PG21;
1.1 christos 127: }
128:
1.7 ! christos 129: errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
1.1 christos 130:
1.7 ! christos 131: if (reloc != BFD_RELOC_OR1K_PCREL_PG21)
! 132: {
1.1 christos 133: if (**strp != ')')
1.7 ! christos 134: errmsg = MISSING_CLOSING_PARENTHESIS;
! 135: else
! 136: ++*strp;
1.1 christos 137: }
138:
1.7 ! christos 139: return errmsg;
! 140: }
! 141:
! 142: enum or1k_rclass
! 143: {
! 144: RCLASS_DIRECT = 0,
! 145: RCLASS_GOT = 1,
! 146: RCLASS_GOTPC = 2,
! 147: RCLASS_GOTOFF = 3,
! 148: RCLASS_TLSGD = 4,
! 149: RCLASS_TLSLDM = 5,
! 150: RCLASS_DTPOFF = 6,
! 151: RCLASS_GOTTPOFF = 7,
! 152: RCLASS_TPOFF = 8,
! 153: };
1.1 christos 154:
1.7 ! christos 155: enum or1k_rtype
! 156: {
! 157: RTYPE_LO = 0,
! 158: RTYPE_SLO = 1,
! 159: RTYPE_PO = 2,
! 160: RTYPE_SPO = 3,
! 161: RTYPE_HI = 4,
! 162: RTYPE_AHI = 5,
! 163: };
1.1 christos 164:
1.7 ! christos 165: #define RCLASS_SHIFT 3
! 166: #define RTYPE_MASK 7
1.1 christos 167:
1.7 ! christos 168: static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
! 169: { BFD_RELOC_LO16,
! 170: BFD_RELOC_OR1K_SLO16,
! 171: BFD_RELOC_OR1K_LO13,
! 172: BFD_RELOC_OR1K_SLO13,
! 173: BFD_RELOC_HI16,
! 174: BFD_RELOC_HI16_S, },
! 175: { BFD_RELOC_OR1K_GOT16,
! 176: BFD_RELOC_UNUSED,
! 177: BFD_RELOC_OR1K_GOT_LO13,
! 178: BFD_RELOC_UNUSED,
! 179: BFD_RELOC_UNUSED,
! 180: BFD_RELOC_UNUSED },
! 181: { BFD_RELOC_OR1K_GOTPC_LO16,
! 182: BFD_RELOC_UNUSED,
! 183: BFD_RELOC_UNUSED,
! 184: BFD_RELOC_UNUSED,
! 185: BFD_RELOC_OR1K_GOTPC_HI16,
! 186: BFD_RELOC_UNUSED },
! 187: { BFD_RELOC_LO16_GOTOFF,
! 188: BFD_RELOC_OR1K_GOTOFF_SLO16,
! 189: BFD_RELOC_UNUSED,
! 190: BFD_RELOC_UNUSED,
! 191: BFD_RELOC_HI16_GOTOFF,
! 192: BFD_RELOC_HI16_S_GOTOFF },
! 193: { BFD_RELOC_OR1K_TLS_GD_LO16,
! 194: BFD_RELOC_UNUSED,
! 195: BFD_RELOC_OR1K_TLS_GD_LO13,
! 196: BFD_RELOC_UNUSED,
! 197: BFD_RELOC_OR1K_TLS_GD_HI16,
! 198: BFD_RELOC_UNUSED },
! 199: { BFD_RELOC_OR1K_TLS_LDM_LO16,
! 200: BFD_RELOC_UNUSED,
! 201: BFD_RELOC_OR1K_TLS_LDM_LO13,
! 202: BFD_RELOC_UNUSED,
! 203: BFD_RELOC_OR1K_TLS_LDM_HI16,
! 204: BFD_RELOC_UNUSED },
! 205: { BFD_RELOC_OR1K_TLS_LDO_LO16,
! 206: BFD_RELOC_UNUSED,
! 207: BFD_RELOC_UNUSED,
! 208: BFD_RELOC_UNUSED,
! 209: BFD_RELOC_OR1K_TLS_LDO_HI16,
! 210: BFD_RELOC_UNUSED },
! 211: { BFD_RELOC_OR1K_TLS_IE_LO16,
! 212: BFD_RELOC_UNUSED,
! 213: BFD_RELOC_OR1K_TLS_IE_LO13,
! 214: BFD_RELOC_UNUSED,
! 215: BFD_RELOC_OR1K_TLS_IE_HI16,
! 216: BFD_RELOC_OR1K_TLS_IE_AHI16 },
! 217: { BFD_RELOC_OR1K_TLS_LE_LO16,
! 218: BFD_RELOC_OR1K_TLS_LE_SLO16,
! 219: BFD_RELOC_UNUSED,
! 220: BFD_RELOC_UNUSED,
! 221: BFD_RELOC_OR1K_TLS_LE_HI16,
! 222: BFD_RELOC_OR1K_TLS_LE_AHI16 },
! 223: };
1.1 christos 224:
1.7 ! christos 225: static int
! 226: parse_reloc (const char **strp)
! 227: {
! 228: const char *str = *strp;
! 229: enum or1k_rclass cls = RCLASS_DIRECT;
! 230: enum or1k_rtype typ;
1.1 christos 231:
1.7 ! christos 232: if (strncasecmp (str, "got(", 4) == 0)
! 233: {
! 234: *strp = str + 4;
! 235: return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_LO;
! 236: }
! 237: if (strncasecmp (str, "gotpo(", 6) == 0)
! 238: {
! 239: *strp = str + 6;
! 240: return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_PO;
! 241: }
! 242: if (strncasecmp (str, "gottppo(", 8) == 0)
! 243: {
! 244: *strp = str + 8;
! 245: return (RCLASS_GOTTPOFF << RCLASS_SHIFT) | RTYPE_PO;
! 246: }
1.1 christos 247:
1.7 ! christos 248: if (strncasecmp (str, "gotpc", 5) == 0)
! 249: {
! 250: str += 5;
! 251: cls = RCLASS_GOTPC;
! 252: }
! 253: else if (strncasecmp (str, "gotoff", 6) == 0)
! 254: {
! 255: str += 6;
! 256: cls = RCLASS_GOTOFF;
! 257: }
! 258: else if (strncasecmp (str, "tlsgd", 5) == 0)
! 259: {
! 260: str += 5;
! 261: cls = RCLASS_TLSGD;
! 262: }
! 263: else if (strncasecmp (str, "tlsldm", 6) == 0)
! 264: {
! 265: str += 6;
! 266: cls = RCLASS_TLSLDM;
! 267: }
! 268: else if (strncasecmp (str, "dtpoff", 6) == 0)
! 269: {
! 270: str += 6;
! 271: cls = RCLASS_DTPOFF;
! 272: }
! 273: else if (strncasecmp (str, "gottpoff", 8) == 0)
! 274: {
! 275: str += 8;
! 276: cls = RCLASS_GOTTPOFF;
! 277: }
! 278: else if (strncasecmp (str, "tpoff", 5) == 0)
! 279: {
! 280: str += 5;
! 281: cls = RCLASS_TPOFF;
! 282: }
1.1 christos 283:
1.7 ! christos 284: if (strncasecmp (str, "hi(", 3) == 0)
! 285: {
! 286: str += 3;
! 287: typ = RTYPE_HI;
! 288: }
! 289: else if (strncasecmp (str, "lo(", 3) == 0)
! 290: {
! 291: str += 3;
! 292: typ = RTYPE_LO;
! 293: }
! 294: else if (strncasecmp (str, "ha(", 3) == 0)
! 295: {
! 296: str += 3;
! 297: typ = RTYPE_AHI;
! 298: }
! 299: else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF)
! 300: {
! 301: str += 3;
! 302: typ = RTYPE_PO;
! 303: }
! 304: else
! 305: return -1;
1.1 christos 306:
1.7 ! christos 307: *strp = str;
! 308: return (cls << RCLASS_SHIFT) | typ;
! 309: }
1.1 christos 310:
1.7 ! christos 311: static const char *
! 312: parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
! 313: long *valuep, int splitp)
! 314: {
! 315: const char *errmsg;
! 316: enum cgen_parse_operand_result result_type;
! 317: bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
! 318: enum or1k_rtype reloc_type;
! 319: int reloc_code;
! 320: bfd_vma ret;
1.1 christos 321:
1.7 ! christos 322: if (**strp == '#')
! 323: ++*strp;
1.1 christos 324:
1.7 ! christos 325: reloc_code = parse_reloc (strp);
! 326: reloc_type = reloc_code & RTYPE_MASK;
! 327: if (reloc_code >= 0)
! 328: {
! 329: enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT;
! 330: if (splitp)
! 331: {
! 332: if ((reloc_type == RTYPE_LO || reloc_type == RTYPE_PO)
! 333: && reloc_class != RCLASS_GOT)
! 334: /* If split we or up the type to RTYPE_SLO or RTYPE_SPO. */
! 335: reloc_type |= 1;
! 336: else
! 337: return INVALID_STORE_RELOC;
! 338: }
! 339: reloc = or1k_imm16_relocs[reloc_class][reloc_type];
1.1 christos 340: }
1.7 ! christos 341:
! 342: if (reloc != BFD_RELOC_UNUSED)
1.1 christos 343: {
344: bfd_vma value;
345:
1.7 ! christos 346: errmsg = cgen_parse_address (cd, strp, opindex, reloc,
1.1 christos 347: &result_type, &value);
348: if (**strp != ')')
1.7 ! christos 349: errmsg = MISSING_CLOSING_PARENTHESIS;
1.1 christos 350: ++*strp;
351:
1.7 ! christos 352: ret = value;
1.1 christos 353:
1.7 ! christos 354: if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
! 355: switch (reloc_type)
! 356: {
! 357: case RTYPE_AHI:
! 358: ret += 0x8000;
! 359: /* FALLTHRU */
! 360: case RTYPE_HI:
! 361: ret >>= 16;
! 362: /* FALLTHRU */
! 363: case RTYPE_LO:
! 364: case RTYPE_SLO:
! 365: ret &= 0xffff;
! 366: ret = (ret ^ 0x8000) - 0x8000;
! 367: break;
! 368: case RTYPE_PO:
! 369: case RTYPE_SPO:
! 370: ret &= 0x1fff;
! 371: break;
! 372: default:
! 373: errmsg = INVALID_RELOC_TYPE;
! 374: }
1.1 christos 375: }
376: else
377: {
378: long value;
379: errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
380: ret = value;
381: }
382:
383: if (errmsg == NULL)
384: *valuep = ret;
385:
386: return errmsg;
387: }
388:
389: static const char *
1.7 ! christos 390: parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
! 391: {
! 392: return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
! 393: }
! 394:
! 395: static const char *
! 396: parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
! 397: long *valuep)
1.1 christos 398: {
1.7 ! christos 399: return parse_imm16(cd, strp, opindex, (long *) valuep, 1);
! 400: }
! 401:
! 402: static const char *
! 403: parse_uimm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
! 404: unsigned long *valuep)
! 405: {
! 406: const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 0);
! 407: if (errmsg == NULL)
! 408: *valuep &= 0xffff;
! 409: return errmsg;
! 410: }
1.1 christos 411:
1.7 ! christos 412: static const char *
! 413: parse_uimm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
! 414: unsigned long *valuep)
! 415: {
! 416: const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 1);
1.1 christos 417: if (errmsg == NULL)
418: *valuep &= 0xffff;
419: return errmsg;
420: }
421:
1.7 ! christos 422: /* Parse register pairs with syntax rA,rB to a flag + rA value. */
! 423:
! 424: static const char *
! 425: parse_regpair (CGEN_CPU_DESC cd, const char **strp,
! 426: int opindex ATTRIBUTE_UNUSED, unsigned long *valuep)
! 427: {
! 428: long reg1_index;
! 429: long reg2_index;
! 430: const char *errmsg;
! 431:
! 432: /* The first part should just be a register. */
! 433: errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
! 434: ®1_index);
! 435:
! 436: /* If that worked skip the comma separator. */
! 437: if (errmsg == NULL)
! 438: {
! 439: if (**strp == ',')
! 440: ++*strp;
! 441: else
! 442: errmsg = "Unexpected character, expected ','";
! 443: }
! 444:
! 445: /* If that worked the next part is just another register. */
! 446: if (errmsg == NULL)
! 447: errmsg = cgen_parse_keyword (cd, strp, &or1k_cgen_opval_h_gpr,
! 448: ®2_index);
! 449:
! 450: /* Validate the register pair is valid and create the output value. */
! 451: if (errmsg == NULL)
! 452: {
! 453: int regoffset = reg2_index - reg1_index;
! 454:
! 455: if (regoffset == 1 || regoffset == 2)
! 456: {
! 457: unsigned short offsetmask;
! 458: unsigned short value;
! 459:
! 460: offsetmask = ((regoffset == 2 ? 1 : 0) << 5);
! 461: value = offsetmask | reg1_index;
! 462:
! 463: *valuep = value;
! 464: }
! 465: else
! 466: errmsg = "Invalid register pair, offset not 1 or 2.";
! 467: }
! 468:
! 469: return errmsg;
! 470: }
! 471:
1.1 christos 472: /* -- */
473:
474: const char * or1k_cgen_parse_operand
475: (CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *);
476:
477: /* Main entry point for operand parsing.
478:
479: This function is basically just a big switch statement. Earlier versions
480: used tables to look up the function to use, but
481: - if the table contains both assembler and disassembler functions then
482: the disassembler contains much of the assembler and vice-versa,
483: - there's a lot of inlining possibilities as things grow,
484: - using a switch statement avoids the function call overhead.
485:
486: This function could be moved into `parse_insn_normal', but keeping it
487: separate makes clear the interface between `parse_insn_normal' and each of
488: the handlers. */
489:
490: const char *
491: or1k_cgen_parse_operand (CGEN_CPU_DESC cd,
492: int opindex,
493: const char ** strp,
494: CGEN_FIELDS * fields)
495: {
496: const char * errmsg = NULL;
497: /* Used by scalar operands that still need to be parsed. */
498: long junk ATTRIBUTE_UNUSED;
499:
500: switch (opindex)
501: {
1.7 ! christos 502: case OR1K_OPERAND_DISP21 :
! 503: {
! 504: bfd_vma value = 0;
! 505: errmsg = parse_disp21 (cd, strp, OR1K_OPERAND_DISP21, 0, NULL, & value);
! 506: fields->f_disp21 = value;
! 507: }
! 508: break;
1.1 christos 509: case OR1K_OPERAND_DISP26 :
510: {
511: bfd_vma value = 0;
512: errmsg = parse_disp26 (cd, strp, OR1K_OPERAND_DISP26, 0, NULL, & value);
513: fields->f_disp26 = value;
514: }
515: break;
516: case OR1K_OPERAND_RA :
517: errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_gpr, & fields->f_r2);
518: break;
1.7 ! christos 519: case OR1K_OPERAND_RAD32F :
! 520: errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RAD32F, (unsigned long *) (& fields->f_rad32));
! 521: break;
1.1 christos 522: case OR1K_OPERAND_RADF :
1.7 ! christos 523: errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fdr, & fields->f_r2);
! 524: break;
! 525: case OR1K_OPERAND_RADI :
! 526: errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RADI, (unsigned long *) (& fields->f_rad32));
1.1 christos 527: break;
528: case OR1K_OPERAND_RASF :
529: errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fsr, & fields->f_r2);
530: break;
531: case OR1K_OPERAND_RB :
532: errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_gpr, & fields->f_r3);
533: break;
1.7 ! christos 534: case OR1K_OPERAND_RBD32F :
! 535: errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RBD32F, (unsigned long *) (& fields->f_rbd32));
! 536: break;
1.1 christos 537: case OR1K_OPERAND_RBDF :
1.7 ! christos 538: errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fdr, & fields->f_r3);
! 539: break;
! 540: case OR1K_OPERAND_RBDI :
! 541: errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RBDI, (unsigned long *) (& fields->f_rbd32));
1.1 christos 542: break;
543: case OR1K_OPERAND_RBSF :
544: errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fsr, & fields->f_r3);
545: break;
546: case OR1K_OPERAND_RD :
547: errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_gpr, & fields->f_r1);
548: break;
1.7 ! christos 549: case OR1K_OPERAND_RDD32F :
! 550: errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RDD32F, (unsigned long *) (& fields->f_rdd32));
! 551: break;
1.1 christos 552: case OR1K_OPERAND_RDDF :
553: errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fdr, & fields->f_r1);
554: break;
1.7 ! christos 555: case OR1K_OPERAND_RDDI :
! 556: errmsg = parse_regpair (cd, strp, OR1K_OPERAND_RDDI, (unsigned long *) (& fields->f_rdd32));
! 557: break;
1.1 christos 558: case OR1K_OPERAND_RDSF :
559: errmsg = cgen_parse_keyword (cd, strp, & or1k_cgen_opval_h_fsr, & fields->f_r1);
560: break;
561: case OR1K_OPERAND_SIMM16 :
562: errmsg = parse_simm16 (cd, strp, OR1K_OPERAND_SIMM16, (long *) (& fields->f_simm16));
563: break;
564: case OR1K_OPERAND_SIMM16_SPLIT :
1.7 ! christos 565: errmsg = parse_simm16_split (cd, strp, OR1K_OPERAND_SIMM16_SPLIT, (long *) (& fields->f_simm16_split));
1.1 christos 566: break;
567: case OR1K_OPERAND_UIMM16 :
568: errmsg = parse_uimm16 (cd, strp, OR1K_OPERAND_UIMM16, (unsigned long *) (& fields->f_uimm16));
569: break;
570: case OR1K_OPERAND_UIMM16_SPLIT :
1.7 ! christos 571: errmsg = parse_uimm16_split (cd, strp, OR1K_OPERAND_UIMM16_SPLIT, (unsigned long *) (& fields->f_uimm16_split));
1.1 christos 572: break;
573: case OR1K_OPERAND_UIMM6 :
574: errmsg = cgen_parse_unsigned_integer (cd, strp, OR1K_OPERAND_UIMM6, (unsigned long *) (& fields->f_uimm6));
575: break;
576:
577: default :
578: /* xgettext:c-format */
1.6 christos 579: opcodes_error_handler
580: (_("internal error: unrecognized field %d while parsing"),
581: opindex);
1.1 christos 582: abort ();
583: }
584:
585: return errmsg;
586: }
587:
1.3 christos 588: cgen_parse_fn * const or1k_cgen_parse_handlers[] =
1.1 christos 589: {
590: parse_insn_normal,
591: };
592:
593: void
594: or1k_cgen_init_asm (CGEN_CPU_DESC cd)
595: {
596: or1k_cgen_init_opcode_table (cd);
597: or1k_cgen_init_ibld_table (cd);
598: cd->parse_handlers = & or1k_cgen_parse_handlers[0];
599: cd->parse_operand = or1k_cgen_parse_operand;
600: #ifdef CGEN_ASM_INIT_HOOK
601: CGEN_ASM_INIT_HOOK
602: #endif
603: }
604:
605:
606:
607: /* Regex construction routine.
608:
609: This translates an opcode syntax string into a regex string,
610: by replacing any non-character syntax element (such as an
611: opcode) with the pattern '.*'
612:
613: It then compiles the regex and stores it in the opcode, for
614: later use by or1k_cgen_assemble_insn
615:
616: Returns NULL for success, an error message for failure. */
617:
1.3 christos 618: char *
1.1 christos 619: or1k_cgen_build_insn_regex (CGEN_INSN *insn)
1.3 christos 620: {
1.1 christos 621: CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
622: const char *mnem = CGEN_INSN_MNEMONIC (insn);
623: char rxbuf[CGEN_MAX_RX_ELEMENTS];
624: char *rx = rxbuf;
625: const CGEN_SYNTAX_CHAR_TYPE *syn;
626: int reg_err;
627:
628: syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
629:
630: /* Mnemonics come first in the syntax string. */
631: if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
632: return _("missing mnemonic in syntax string");
633: ++syn;
634:
635: /* Generate a case sensitive regular expression that emulates case
636: insensitive matching in the "C" locale. We cannot generate a case
637: insensitive regular expression because in Turkish locales, 'i' and 'I'
638: are not equal modulo case conversion. */
639:
640: /* Copy the literal mnemonic out of the insn. */
641: for (; *mnem; mnem++)
642: {
643: char c = *mnem;
644:
645: if (ISALPHA (c))
646: {
647: *rx++ = '[';
648: *rx++ = TOLOWER (c);
649: *rx++ = TOUPPER (c);
650: *rx++ = ']';
651: }
652: else
653: *rx++ = c;
654: }
655:
656: /* Copy any remaining literals from the syntax string into the rx. */
657: for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
658: {
1.3 christos 659: if (CGEN_SYNTAX_CHAR_P (* syn))
1.1 christos 660: {
661: char c = CGEN_SYNTAX_CHAR (* syn);
662:
1.3 christos 663: switch (c)
1.1 christos 664: {
665: /* Escape any regex metacharacters in the syntax. */
1.3 christos 666: case '.': case '[': case '\\':
667: case '*': case '^': case '$':
1.1 christos 668:
669: #ifdef CGEN_ESCAPE_EXTENDED_REGEX
1.3 christos 670: case '?': case '{': case '}':
1.1 christos 671: case '(': case ')': case '*':
672: case '|': case '+': case ']':
673: #endif
674: *rx++ = '\\';
675: *rx++ = c;
676: break;
677:
678: default:
679: if (ISALPHA (c))
680: {
681: *rx++ = '[';
682: *rx++ = TOLOWER (c);
683: *rx++ = TOUPPER (c);
684: *rx++ = ']';
685: }
686: else
687: *rx++ = c;
688: break;
689: }
690: }
691: else
692: {
693: /* Replace non-syntax fields with globs. */
694: *rx++ = '.';
695: *rx++ = '*';
696: }
697: }
698:
699: /* Trailing whitespace ok. */
1.3 christos 700: * rx++ = '[';
701: * rx++ = ' ';
702: * rx++ = '\t';
703: * rx++ = ']';
704: * rx++ = '*';
1.1 christos 705:
706: /* But anchor it after that. */
1.3 christos 707: * rx++ = '$';
1.1 christos 708: * rx = '\0';
709:
710: CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
711: reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
712:
1.3 christos 713: if (reg_err == 0)
1.1 christos 714: return NULL;
715: else
716: {
717: static char msg[80];
718:
719: regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
720: regfree ((regex_t *) CGEN_INSN_RX (insn));
721: free (CGEN_INSN_RX (insn));
722: (CGEN_INSN_RX (insn)) = NULL;
723: return msg;
724: }
725: }
726:
727:
728: /* Default insn parser.
729:
730: The syntax string is scanned and operands are parsed and stored in FIELDS.
731: Relocs are queued as we go via other callbacks.
732:
733: ??? Note that this is currently an all-or-nothing parser. If we fail to
734: parse the instruction, we return 0 and the caller will start over from
735: the beginning. Backtracking will be necessary in parsing subexpressions,
736: but that can be handled there. Not handling backtracking here may get
737: expensive in the case of the m68k. Deal with later.
738:
739: Returns NULL for success, an error message for failure. */
740:
741: static const char *
742: parse_insn_normal (CGEN_CPU_DESC cd,
743: const CGEN_INSN *insn,
744: const char **strp,
745: CGEN_FIELDS *fields)
746: {
747: /* ??? Runtime added insns not handled yet. */
748: const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
749: const char *str = *strp;
750: const char *errmsg;
751: const char *p;
752: const CGEN_SYNTAX_CHAR_TYPE * syn;
753: #ifdef CGEN_MNEMONIC_OPERANDS
754: /* FIXME: wip */
755: int past_opcode_p;
756: #endif
757:
758: /* For now we assume the mnemonic is first (there are no leading operands).
759: We can parse it without needing to set up operand parsing.
760: GAS's input scrubber will ensure mnemonics are lowercase, but we may
761: not be called from GAS. */
762: p = CGEN_INSN_MNEMONIC (insn);
763: while (*p && TOLOWER (*p) == TOLOWER (*str))
764: ++p, ++str;
765:
766: if (* p)
767: return _("unrecognized instruction");
768:
769: #ifndef CGEN_MNEMONIC_OPERANDS
770: if (* str && ! ISSPACE (* str))
771: return _("unrecognized instruction");
772: #endif
773:
774: CGEN_INIT_PARSE (cd);
775: cgen_init_parse_operand (cd);
776: #ifdef CGEN_MNEMONIC_OPERANDS
777: past_opcode_p = 0;
778: #endif
779:
780: /* We don't check for (*str != '\0') here because we want to parse
781: any trailing fake arguments in the syntax string. */
782: syn = CGEN_SYNTAX_STRING (syntax);
783:
784: /* Mnemonics come first for now, ensure valid string. */
785: if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
786: abort ();
787:
788: ++syn;
789:
790: while (* syn != 0)
791: {
792: /* Non operand chars must match exactly. */
793: if (CGEN_SYNTAX_CHAR_P (* syn))
794: {
795: /* FIXME: While we allow for non-GAS callers above, we assume the
796: first char after the mnemonic part is a space. */
797: /* FIXME: We also take inappropriate advantage of the fact that
798: GAS's input scrubber will remove extraneous blanks. */
799: if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
800: {
801: #ifdef CGEN_MNEMONIC_OPERANDS
802: if (CGEN_SYNTAX_CHAR(* syn) == ' ')
803: past_opcode_p = 1;
804: #endif
805: ++ syn;
806: ++ str;
807: }
808: else if (*str)
809: {
810: /* Syntax char didn't match. Can't be this insn. */
811: static char msg [80];
812:
813: /* xgettext:c-format */
814: sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
815: CGEN_SYNTAX_CHAR(*syn), *str);
816: return msg;
817: }
818: else
819: {
820: /* Ran out of input. */
821: static char msg [80];
822:
823: /* xgettext:c-format */
824: sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
825: CGEN_SYNTAX_CHAR(*syn));
826: return msg;
827: }
828: continue;
829: }
830:
831: #ifdef CGEN_MNEMONIC_OPERANDS
832: (void) past_opcode_p;
833: #endif
834: /* We have an operand of some sort. */
835: errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), &str, fields);
836: if (errmsg)
837: return errmsg;
838:
839: /* Done with this operand, continue with next one. */
840: ++ syn;
841: }
842:
843: /* If we're at the end of the syntax string, we're done. */
844: if (* syn == 0)
845: {
846: /* FIXME: For the moment we assume a valid `str' can only contain
847: blanks now. IE: We needn't try again with a longer version of
848: the insn and it is assumed that longer versions of insns appear
849: before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */
850: while (ISSPACE (* str))
851: ++ str;
852:
853: if (* str != '\0')
854: return _("junk at end of line"); /* FIXME: would like to include `str' */
855:
856: return NULL;
857: }
858:
859: /* We couldn't parse it. */
860: return _("unrecognized instruction");
861: }
862:
863: /* Main entry point.
864: This routine is called for each instruction to be assembled.
865: STR points to the insn to be assembled.
866: We assume all necessary tables have been initialized.
867: The assembled instruction, less any fixups, is stored in BUF.
868: Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
869: still needs to be converted to target byte order, otherwise BUF is an array
870: of bytes in target byte order.
871: The result is a pointer to the insn's entry in the opcode table,
872: or NULL if an error occured (an error message will have already been
873: printed).
874:
875: Note that when processing (non-alias) macro-insns,
876: this function recurses.
877:
878: ??? It's possible to make this cpu-independent.
879: One would have to deal with a few minor things.
880: At this point in time doing so would be more of a curiosity than useful
881: [for example this file isn't _that_ big], but keeping the possibility in
882: mind helps keep the design clean. */
883:
884: const CGEN_INSN *
885: or1k_cgen_assemble_insn (CGEN_CPU_DESC cd,
886: const char *str,
887: CGEN_FIELDS *fields,
888: CGEN_INSN_BYTES_PTR buf,
889: char **errmsg)
890: {
891: const char *start;
892: CGEN_INSN_LIST *ilist;
893: const char *parse_errmsg = NULL;
894: const char *insert_errmsg = NULL;
895: int recognized_mnemonic = 0;
896:
897: /* Skip leading white space. */
898: while (ISSPACE (* str))
899: ++ str;
900:
901: /* The instructions are stored in hashed lists.
902: Get the first in the list. */
903: ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
904:
905: /* Keep looking until we find a match. */
906: start = str;
907: for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
908: {
909: const CGEN_INSN *insn = ilist->insn;
910: recognized_mnemonic = 1;
911:
1.3 christos 912: #ifdef CGEN_VALIDATE_INSN_SUPPORTED
1.1 christos 913: /* Not usually needed as unsupported opcodes
914: shouldn't be in the hash lists. */
915: /* Is this insn supported by the selected cpu? */
916: if (! or1k_cgen_insn_supported (cd, insn))
917: continue;
918: #endif
919: /* If the RELAXED attribute is set, this is an insn that shouldn't be
920: chosen immediately. Instead, it is used during assembler/linker
921: relaxation if possible. */
922: if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
923: continue;
924:
925: str = start;
926:
927: /* Skip this insn if str doesn't look right lexically. */
928: if (CGEN_INSN_RX (insn) != NULL &&
929: regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
930: continue;
931:
932: /* Allow parse/insert handlers to obtain length of insn. */
933: CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
934:
935: parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
936: if (parse_errmsg != NULL)
937: continue;
938:
939: /* ??? 0 is passed for `pc'. */
940: insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
941: (bfd_vma) 0);
942: if (insert_errmsg != NULL)
943: continue;
944:
945: /* It is up to the caller to actually output the insn and any
946: queued relocs. */
947: return insn;
948: }
949:
950: {
951: static char errbuf[150];
952: const char *tmp_errmsg;
953: #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
954: #define be_verbose 1
955: #else
956: #define be_verbose 0
957: #endif
958:
959: if (be_verbose)
960: {
961: /* If requesting verbose error messages, use insert_errmsg.
962: Failing that, use parse_errmsg. */
963: tmp_errmsg = (insert_errmsg ? insert_errmsg :
964: parse_errmsg ? parse_errmsg :
965: recognized_mnemonic ?
966: _("unrecognized form of instruction") :
967: _("unrecognized instruction"));
968:
969: if (strlen (start) > 50)
970: /* xgettext:c-format */
971: sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
1.3 christos 972: else
1.1 christos 973: /* xgettext:c-format */
974: sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
975: }
976: else
977: {
978: if (strlen (start) > 50)
979: /* xgettext:c-format */
980: sprintf (errbuf, _("bad instruction `%.50s...'"), start);
1.3 christos 981: else
1.1 christos 982: /* xgettext:c-format */
983: sprintf (errbuf, _("bad instruction `%.50s'"), start);
984: }
1.3 christos 985:
1.1 christos 986: *errmsg = errbuf;
987: return NULL;
988: }
989: }
CVSweb <webmaster@jp.NetBSD.org>