diff options
author | Nick Clifton <nickc@redhat.com> | 2005-03-24 20:40:28 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2005-03-24 20:40:28 +0000 |
commit | ea1562b345338540cf9a3c8fa28fbcb6da78fd3e (patch) | |
tree | 365f693777e612e6f40b668d1ec2d43f6a0c32ac /gas/config/tc-d10v.c | |
parent | 1acfb01b60e3f3e877aff2c05a29997719807696 (diff) | |
download | gdb-ea1562b345338540cf9a3c8fa28fbcb6da78fd3e.zip gdb-ea1562b345338540cf9a3c8fa28fbcb6da78fd3e.tar.gz gdb-ea1562b345338540cf9a3c8fa28fbcb6da78fd3e.tar.bz2 |
Convert unmaintained files over to ISO-C90 and fix formatting.
Diffstat (limited to 'gas/config/tc-d10v.c')
-rw-r--r-- | gas/config/tc-d10v.c | 1010 |
1 files changed, 474 insertions, 536 deletions
diff --git a/gas/config/tc-d10v.c b/gas/config/tc-d10v.c index a5360a9..eb00fbb 100644 --- a/gas/config/tc-d10v.c +++ b/gas/config/tc-d10v.c @@ -26,12 +26,12 @@ #include "opcode/d10v.h" #include "elf/ppc.h" -const char comment_chars[] = ";"; -const char line_comment_chars[] = "#"; +const char comment_chars[] = ";"; +const char line_comment_chars[] = "#"; const char line_separator_chars[] = ""; -const char *md_shortopts = "O"; -const char EXP_CHARS[] = "eE"; -const char FLT_CHARS[] = "dD"; +const char *md_shortopts = "O"; +const char EXP_CHARS[] = "eE"; +const char FLT_CHARS[] = "dD"; int Optimizing = 0; @@ -42,7 +42,8 @@ int Optimizing = 0; #define AT_WORD_RIGHT_SHIFT 2 /* Fixups. */ -#define MAX_INSN_FIXUPS (5) +#define MAX_INSN_FIXUPS 5 + struct d10v_fixup { expressionS exp; @@ -80,40 +81,19 @@ static bfd_boolean flag_warn_suppress_instructionswap; static bfd_boolean flag_allow_gstabs_packing = 1; /* Local functions. */ -static int reg_name_search PARAMS ((char *name)); -static int register_name PARAMS ((expressionS *expressionP)); -static int check_range PARAMS ((unsigned long num, int bits, int flags)); -static int postfix PARAMS ((char *p)); -static bfd_reloc_code_real_type get_reloc PARAMS ((struct d10v_operand *op)); -static int get_operands PARAMS ((expressionS exp[])); -static struct d10v_opcode *find_opcode PARAMS ((struct d10v_opcode *opcode, expressionS ops[])); -static unsigned long build_insn PARAMS ((struct d10v_opcode *opcode, expressionS *opers, unsigned long insn)); -static void write_long PARAMS ((unsigned long insn, Fixups *fx)); -static void write_1_short PARAMS ((struct d10v_opcode *opcode, unsigned long insn, Fixups *fx)); -static int write_2_short PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1, - struct d10v_opcode *opcode2, unsigned long insn2, packing_type exec_type, Fixups *fx)); -static unsigned long do_assemble PARAMS ((char *str, struct d10v_opcode **opcode)); -static unsigned long d10v_insert_operand PARAMS (( unsigned long insn, int op_type, - offsetT value, int left, fixS *fix)); -static int parallel_ok PARAMS ((struct d10v_opcode *opcode1, unsigned long insn1, - struct d10v_opcode *opcode2, unsigned long insn2, - packing_type exec_type)); - -static void check_resource_conflict PARAMS ((struct d10v_opcode *opcode1, - unsigned long insn1, - struct d10v_opcode *opcode2, - unsigned long insn2)); - -static symbolS * find_symbol_matching_register PARAMS ((expressionS *)); + +enum options +{ + OPTION_NOWARNSWAP = OPTION_MD_BASE, + OPTION_GSTABSPACKING, + OPTION_NOGSTABSPACKING +}; struct option md_longopts[] = { -#define OPTION_NOWARNSWAP (OPTION_MD_BASE) {"nowarnswap", no_argument, NULL, OPTION_NOWARNSWAP}, -#define OPTION_GSTABSPACKING (OPTION_MD_BASE + 1) {"gstabspacking", no_argument, NULL, OPTION_GSTABSPACKING}, {"gstabs-packing", no_argument, NULL, OPTION_GSTABSPACKING}, -#define OPTION_NOGSTABSPACKING (OPTION_MD_BASE + 2) {"nogstabspacking", no_argument, NULL, OPTION_NOGSTABSPACKING}, {"no-gstabs-packing", no_argument, NULL, OPTION_NOGSTABSPACKING}, {NULL, no_argument, NULL, 0} @@ -121,15 +101,6 @@ struct option md_longopts[] = size_t md_longopts_size = sizeof (md_longopts); -static void d10v_dot_word PARAMS ((int)); - -/* The target specific pseudo-ops which we support. */ -const pseudo_typeS md_pseudo_table[] = -{ - { "word", d10v_dot_word, 2 }, - { NULL, NULL, 0 } -}; - /* Opcode hash table. */ static struct hash_control *d10v_hash; @@ -138,8 +109,7 @@ static struct hash_control *d10v_hash; array on success, or -1 on failure. */ static int -reg_name_search (name) - char *name; +reg_name_search (char *name) { int middle, low, high; int cmp; @@ -166,8 +136,7 @@ reg_name_search (name) to see if it is a valid register name. */ static int -register_name (expressionP) - expressionS *expressionP; +register_name (expressionS *expressionP) { int reg_number; char c, *p = input_line_pointer; @@ -197,10 +166,7 @@ register_name (expressionP) } static int -check_range (num, bits, flags) - unsigned long num; - int bits; - int flags; +check_range (unsigned long num, int bits, int flags) { long min, max; int retval = 0; @@ -246,8 +212,7 @@ check_range (num, bits, flags) } void -md_show_usage (stream) - FILE *stream; +md_show_usage (FILE *stream) { fprintf (stream, _("D10V options:\n\ -O Optimize. Will do some operations in parallel.\n\ @@ -258,9 +223,7 @@ md_show_usage (stream) } int -md_parse_option (c, arg) - int c; - char *arg ATTRIBUTE_UNUSED; +md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) { switch (c) { @@ -284,8 +247,7 @@ md_parse_option (c, arg) } symbolS * -md_undefined_symbol (name) - char *name ATTRIBUTE_UNUSED; +md_undefined_symbol (char *name ATTRIBUTE_UNUSED) { return 0; } @@ -296,10 +258,7 @@ md_undefined_symbol (name) returned, or NULL on OK. */ char * -md_atof (type, litP, sizeP) - int type; - char *litP; - int *sizeP; +md_atof (int type, char *litP, int *sizeP) { int prec; LITTLENUM_TYPE words[4]; @@ -334,25 +293,22 @@ md_atof (type, litP, sizeP) } void -md_convert_frag (abfd, sec, fragP) - bfd *abfd ATTRIBUTE_UNUSED; - asection *sec ATTRIBUTE_UNUSED; - fragS *fragP ATTRIBUTE_UNUSED; +md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec ATTRIBUTE_UNUSED, + fragS *fragP ATTRIBUTE_UNUSED) { abort (); } valueT -md_section_align (seg, addr) - asection *seg; - valueT addr; +md_section_align (asection *seg, valueT addr) { int align = bfd_get_section_alignment (stdoutput, seg); return ((addr + (1 << align) - 1) & (-1 << align)); } void -md_begin () +md_begin (void) { char *prev_name = ""; struct d10v_opcode *opcode; @@ -381,8 +337,7 @@ md_begin () from an expression. */ static int -postfix (p) - char *p; +postfix (char *p) { while (*p != '-' && *p != '+') { @@ -394,42 +349,40 @@ postfix (p) if (*p == '-') { *p = ' '; - return (-1); + return -1; } if (*p == '+') { *p = ' '; - return (1); + return 1; } - return (0); + return 0; } static bfd_reloc_code_real_type -get_reloc (op) - struct d10v_operand *op; +get_reloc (struct d10v_operand *op) { int bits = op->bits; if (bits <= 4) - return (0); + return 0; if (op->flags & OPERAND_ADDR) { if (bits == 8) - return (BFD_RELOC_D10V_10_PCREL_R); + return BFD_RELOC_D10V_10_PCREL_R; else - return (BFD_RELOC_D10V_18_PCREL); + return BFD_RELOC_D10V_18_PCREL; } - return (BFD_RELOC_16); + return BFD_RELOC_16; } /* Parse a string of operands. Return an array of expressions. */ static int -get_operands (exp) - expressionS exp[]; +get_operands (expressionS exp[]) { char *p = input_line_pointer; int numops = 0; @@ -561,16 +514,15 @@ get_operands (exp) } exp[numops].X_op = 0; - return (numops); + return numops; } static unsigned long -d10v_insert_operand (insn, op_type, value, left, fix) - unsigned long insn; - int op_type; - offsetT value; - int left; - fixS *fix; +d10v_insert_operand (unsigned long insn, + int op_type, + offsetT value, + int left, + fixS *fix) { int shift, bits; @@ -595,10 +547,9 @@ d10v_insert_operand (insn, op_type, value, left, fix) array of operand expressions. Return the instruction. */ static unsigned long -build_insn (opcode, opers, insn) - struct d10v_opcode *opcode; - expressionS *opers; - unsigned long insn; +build_insn (struct d10v_opcode *opcode, + expressionS *opers, + unsigned long insn) { int i, bits, shift, flags, format; unsigned long number; @@ -689,9 +640,7 @@ build_insn (opcode, opers, insn) /* Write out a long form instruction. */ static void -write_long (insn, fx) - unsigned long insn; - Fixups *fx; +write_long (unsigned long insn, Fixups *fx) { int i, where; char *f = frag_more (4); @@ -724,10 +673,9 @@ write_long (insn, fx) /* Write out a short form instruction by itself. */ static void -write_1_short (opcode, insn, fx) - struct d10v_opcode *opcode; - unsigned long insn; - Fixups *fx; +write_1_short (struct d10v_opcode *opcode, + unsigned long insn, + Fixups *fx) { char *f = frag_more (4); int i, where; @@ -771,171 +719,151 @@ write_1_short (opcode, insn, fx) fx->fc = 0; } -/* Expects two short instructions. - If possible, writes out both as a single packed instruction. - Otherwise, writes out the first one, packed with a NOP. - Returns number of instructions not written out. */ +/* Determine if there are any resource conflicts among two manually + parallelized instructions. Some of this was lifted from parallel_ok. */ -static int -write_2_short (opcode1, insn1, opcode2, insn2, exec_type, fx) - struct d10v_opcode *opcode1, *opcode2; - unsigned long insn1, insn2; - packing_type exec_type; - Fixups *fx; +static void +check_resource_conflict (struct d10v_opcode *op1, + unsigned long insn1, + struct d10v_opcode *op2, + unsigned long insn2) { - unsigned long insn; - char *f; - int i, j, where; + int i, j, flags, mask, shift, regno; + unsigned long ins, mod[2]; + struct d10v_opcode *op; - if ((exec_type != PACK_PARALLEL) - && ((opcode1->exec_type & PARONLY) || (opcode2->exec_type & PARONLY))) - as_fatal (_("Instruction must be executed in parallel")); + if ((op1->exec_type & SEQ) + || ! ((op1->exec_type & PAR) || (op1->exec_type & PARONLY))) + { + as_warn (_("packing conflict: %s must dispatch sequentially"), + op1->name); + return; + } - if ((opcode1->format & LONG_OPCODE) || (opcode2->format & LONG_OPCODE)) - as_fatal (_("Long instructions may not be combined.")); + if ((op2->exec_type & SEQ) + || ! ((op2->exec_type & PAR) || (op2->exec_type & PARONLY))) + { + as_warn (_("packing conflict: %s must dispatch sequentially"), + op2->name); + return; + } - switch (exec_type) + /* See if both instructions write to the same resource. + + The idea here is to create two sets of bitmasks (mod and used) which + indicate which registers are modified or used by each instruction. + The operation can only be done in parallel if neither instruction + modifies the same register. Accesses to control registers and memory + are treated as accesses to a single register. So if both instructions + write memory or if the first instruction writes memory and the second + reads, then they cannot be done in parallel. We treat reads to the PSW + (which includes C, F0, and F1) in isolation. So simultaneously writing + C and F0 in two different sub-instructions is permitted. */ + + /* The bitmasks (mod and used) look like this (bit 31 = MSB). + r0-r15 0-15 + a0-a1 16-17 + cr (not psw) 18 + psw(other) 19 + mem 20 + psw(C flag) 21 + psw(F0 flag) 22 */ + + for (j = 0; j < 2; j++) { - case PACK_UNSPEC: /* Order not specified. */ - if (opcode1->exec_type & ALONE) - { - /* Case of a short branch on a separate GAS line. Pack with NOP. */ - write_1_short (opcode1, insn1, fx->next); - return 1; - } - if (Optimizing - && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type)) + if (j == 0) { - /* Parallel. */ - if (opcode1->unit == IU) - insn = FM00 | (insn2 << 15) | insn1; - else if (opcode2->unit == MU) - insn = FM00 | (insn2 << 15) | insn1; - else - insn = FM00 | (insn1 << 15) | insn2; + op = op1; + ins = insn1; } - else if (opcode1->unit == IU) - /* Reverse sequential with IU opcode1 on right and done first. */ - insn = FM10 | (insn2 << 15) | insn1; else - /* Sequential with non-IU opcode1 on left and done first. */ - insn = FM01 | (insn1 << 15) | insn2; - break; - - case PACK_PARALLEL: - if (opcode1->exec_type & SEQ || opcode2->exec_type & SEQ) - as_fatal - (_("One of these instructions may not be executed in parallel.")); - if (opcode1->unit == IU) { - if (opcode2->unit == IU) - as_fatal (_("Two IU instructions may not be executed in parallel")); - if (!flag_warn_suppress_instructionswap) - as_warn (_("Swapping instruction order")); - insn = FM00 | (insn2 << 15) | insn1; - } - else if (opcode2->unit == MU) - { - if (opcode1->unit == MU) - as_fatal (_("Two MU instructions may not be executed in parallel")); - if (!flag_warn_suppress_instructionswap) - as_warn (_("Swapping instruction order")); - insn = FM00 | (insn2 << 15) | insn1; + op = op2; + ins = insn2; } - else - insn = FM00 | (insn1 << 15) | insn2; - check_resource_conflict (opcode1, insn1, opcode2, insn2); - break; + mod[j] = 0; + if (op->exec_type & BRANCH_LINK) + mod[j] |= 1 << 13; - case PACK_LEFT_RIGHT: - if (opcode1->unit != IU) - insn = FM01 | (insn1 << 15) | insn2; - else if (opcode2->unit == MU || opcode2->unit == EITHER) + for (i = 0; op->operands[i]; i++) { - if (!flag_warn_suppress_instructionswap) - as_warn (_("Swapping instruction order")); - insn = FM10 | (insn2 << 15) | insn1; - } - else - as_fatal (_("IU instruction may not be in the left container")); - if (opcode1->exec_type & ALONE) - as_warn (_("Instruction in R container is squashed by flow control instruction in L container.")); - break; + flags = d10v_operands[op->operands[i]].flags; + shift = d10v_operands[op->operands[i]].shift; + mask = 0x7FFFFFFF >> (31 - d10v_operands[op->operands[i]].bits); + if (flags & OPERAND_REG) + { + regno = (ins >> shift) & mask; + if (flags & (OPERAND_ACC0 | OPERAND_ACC1)) + regno += 16; + else if (flags & OPERAND_CONTROL) /* mvtc or mvfc */ + { + if (regno == 0) + regno = 19; + else + regno = 18; + } + else if (flags & OPERAND_FFLAG) + regno = 22; + else if (flags & OPERAND_CFLAG) + regno = 21; - case PACK_RIGHT_LEFT: - if (opcode2->unit != MU) - insn = FM10 | (insn1 << 15) | insn2; - else if (opcode1->unit == IU || opcode1->unit == EITHER) - { - if (!flag_warn_suppress_instructionswap) - as_warn (_("Swapping instruction order")); - insn = FM01 | (insn2 << 15) | insn1; + if (flags & OPERAND_DEST + /* Auto inc/dec also modifies the register. */ + || (op->operands[i + 1] != 0 + && (d10v_operands[op->operands[i + 1]].flags + & (OPERAND_PLUS | OPERAND_MINUS)) != 0)) + { + mod[j] |= 1 << regno; + if (flags & OPERAND_EVEN) + mod[j] |= 1 << (regno + 1); + } + } + else if (flags & OPERAND_ATMINUS) + { + /* SP implicitly used/modified. */ + mod[j] |= 1 << 15; + } } - else - as_fatal (_("MU instruction may not be in the right container")); - if (opcode2->exec_type & ALONE) - as_warn (_("Instruction in R container is squashed by flow control instruction in L container.")); - break; - default: - as_fatal (_("unknown execution type passed to write_2_short()")); + if (op->exec_type & WMEM) + mod[j] |= 1 << 20; + else if (op->exec_type & WF0) + mod[j] |= 1 << 22; + else if (op->exec_type & WCAR) + mod[j] |= 1 << 21; } - f = frag_more (4); - number_to_chars_bigendian (f, insn, 4); - - /* Process fixup chains. fx refers to insn2 when j == 0, and to - insn1 when j == 1. Yes, it's reversed. */ - - for (j = 0; j < 2; j++) + if ((mod[0] & mod[1]) == 0) + return; + else { - for (i = 0; i < fx->fc; i++) - { - if (fx->fix[i].reloc) - { - where = f - frag_now->fr_literal; - if (fx->fix[i].size == 2) - where += 2; - - if (fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R - /* A BFD_RELOC_D10V_10_PCREL_R relocation applied to - the instruction in the L container has to be - adjusted to BDF_RELOC_D10V_10_PCREL_L. When - j==0, we're processing insn2's operands, so we - want to mark the operand if insn2 is *not* in the - R container. When j==1, we're processing insn1's - operands, so we want to mark the operand if insn2 - *is* in the R container. Note that, if two - instructions are identical, we're never going to - swap them, so the test is safe. */ - && j == ((insn & 0x7fff) == insn2)) - fx->fix[i].operand |= 1024; - - if (fx->fix[i].reloc == BFD_RELOC_D10V_18) - fx->fix[i].operand |= 4096; + unsigned long x; + x = mod[0] & mod[1]; - fix_new_exp (frag_now, - where, - fx->fix[i].size, - &(fx->fix[i].exp), - fx->fix[i].pcrel, - fx->fix[i].operand|2048); - } - } - fx->fc = 0; - fx = fx->next; + for (j = 0; j <= 15; j++) + if (x & (1 << j)) + as_warn (_("resource conflict (R%d)"), j); + for (j = 16; j <= 17; j++) + if (x & (1 << j)) + as_warn (_("resource conflict (A%d)"), j - 16); + if (x & (1 << 19)) + as_warn (_("resource conflict (PSW)")); + if (x & (1 << 21)) + as_warn (_("resource conflict (C flag)")); + if (x & (1 << 22)) + as_warn (_("resource conflict (F flag)")); } - return (0); } /* Check 2 instructions and determine if they can be safely executed in parallel. Return 1 if they can be. */ static int -parallel_ok (op1, insn1, op2, insn2, exec_type) - struct d10v_opcode *op1, *op2; - unsigned long insn1, insn2; - packing_type exec_type; +parallel_ok (struct d10v_opcode *op1, + unsigned long insn1, + struct d10v_opcode *op2, + unsigned long insn2, + packing_type exec_type) { int i, j, flags, mask, shift, regno; unsigned long ins, mod[2], used[2]; @@ -1054,310 +982,179 @@ parallel_ok (op1, insn1, op2, insn2, exec_type) return 0; } -/* Determine if there are any resource conflicts among two manually - parallelized instructions. Some of this was lifted from parallel_ok. */ +/* Expects two short instructions. + If possible, writes out both as a single packed instruction. + Otherwise, writes out the first one, packed with a NOP. + Returns number of instructions not written out. */ -static void -check_resource_conflict (op1, insn1, op2, insn2) - struct d10v_opcode *op1, *op2; - unsigned long insn1, insn2; +static int +write_2_short (struct d10v_opcode *opcode1, + unsigned long insn1, + struct d10v_opcode *opcode2, + unsigned long insn2, + packing_type exec_type, + Fixups *fx) { - int i, j, flags, mask, shift, regno; - unsigned long ins, mod[2]; - struct d10v_opcode *op; - - if ((op1->exec_type & SEQ) - || ! ((op1->exec_type & PAR) || (op1->exec_type & PARONLY))) - { - as_warn (_("packing conflict: %s must dispatch sequentially"), - op1->name); - return; - } - - if ((op2->exec_type & SEQ) - || ! ((op2->exec_type & PAR) || (op2->exec_type & PARONLY))) - { - as_warn (_("packing conflict: %s must dispatch sequentially"), - op2->name); - return; - } - - /* See if both instructions write to the same resource. + unsigned long insn; + char *f; + int i, j, where; - The idea here is to create two sets of bitmasks (mod and used) which - indicate which registers are modified or used by each instruction. - The operation can only be done in parallel if neither instruction - modifies the same register. Accesses to control registers and memory - are treated as accesses to a single register. So if both instructions - write memory or if the first instruction writes memory and the second - reads, then they cannot be done in parallel. We treat reads to the PSW - (which includes C, F0, and F1) in isolation. So simultaneously writing - C and F0 in two different sub-instructions is permitted. */ + if ((exec_type != PACK_PARALLEL) + && ((opcode1->exec_type & PARONLY) || (opcode2->exec_type & PARONLY))) + as_fatal (_("Instruction must be executed in parallel")); - /* The bitmasks (mod and used) look like this (bit 31 = MSB). - r0-r15 0-15 - a0-a1 16-17 - cr (not psw) 18 - psw(other) 19 - mem 20 - psw(C flag) 21 - psw(F0 flag) 22 */ + if ((opcode1->format & LONG_OPCODE) || (opcode2->format & LONG_OPCODE)) + as_fatal (_("Long instructions may not be combined.")); - for (j = 0; j < 2; j++) + switch (exec_type) { - if (j == 0) + case PACK_UNSPEC: /* Order not specified. */ + if (opcode1->exec_type & ALONE) { - op = op1; - ins = insn1; + /* Case of a short branch on a separate GAS line. Pack with NOP. */ + write_1_short (opcode1, insn1, fx->next); + return 1; } - else + if (Optimizing + && parallel_ok (opcode1, insn1, opcode2, insn2, exec_type)) { - op = op2; - ins = insn2; + /* Parallel. */ + if (opcode1->unit == IU) + insn = FM00 | (insn2 << 15) | insn1; + else if (opcode2->unit == MU) + insn = FM00 | (insn2 << 15) | insn1; + else + insn = FM00 | (insn1 << 15) | insn2; } - mod[j] = 0; - if (op->exec_type & BRANCH_LINK) - mod[j] |= 1 << 13; + else if (opcode1->unit == IU) + /* Reverse sequential with IU opcode1 on right and done first. */ + insn = FM10 | (insn2 << 15) | insn1; + else + /* Sequential with non-IU opcode1 on left and done first. */ + insn = FM01 | (insn1 << 15) | insn2; + break; - for (i = 0; op->operands[i]; i++) + case PACK_PARALLEL: + if (opcode1->exec_type & SEQ || opcode2->exec_type & SEQ) + as_fatal + (_("One of these instructions may not be executed in parallel.")); + if (opcode1->unit == IU) { - flags = d10v_operands[op->operands[i]].flags; - shift = d10v_operands[op->operands[i]].shift; - mask = 0x7FFFFFFF >> (31 - d10v_operands[op->operands[i]].bits); - if (flags & OPERAND_REG) - { - regno = (ins >> shift) & mask; - if (flags & (OPERAND_ACC0 | OPERAND_ACC1)) - regno += 16; - else if (flags & OPERAND_CONTROL) /* mvtc or mvfc */ - { - if (regno == 0) - regno = 19; - else - regno = 18; - } - else if (flags & OPERAND_FFLAG) - regno = 22; - else if (flags & OPERAND_CFLAG) - regno = 21; - - if (flags & OPERAND_DEST - /* Auto inc/dec also modifies the register. */ - || (op->operands[i + 1] != 0 - && (d10v_operands[op->operands[i + 1]].flags - & (OPERAND_PLUS | OPERAND_MINUS)) != 0)) - { - mod[j] |= 1 << regno; - if (flags & OPERAND_EVEN) - mod[j] |= 1 << (regno + 1); - } - } - else if (flags & OPERAND_ATMINUS) - { - /* SP implicitly used/modified. */ - mod[j] |= 1 << 15; - } + if (opcode2->unit == IU) + as_fatal (_("Two IU instructions may not be executed in parallel")); + if (!flag_warn_suppress_instructionswap) + as_warn (_("Swapping instruction order")); + insn = FM00 | (insn2 << 15) | insn1; } - - if (op->exec_type & WMEM) - mod[j] |= 1 << 20; - else if (op->exec_type & WF0) - mod[j] |= 1 << 22; - else if (op->exec_type & WCAR) - mod[j] |= 1 << 21; - } - - if ((mod[0] & mod[1]) == 0) - return; - else - { - unsigned long x; - x = mod[0] & mod[1]; - - for (j = 0; j <= 15; j++) - if (x & (1 << j)) - as_warn (_("resource conflict (R%d)"), j); - for (j = 16; j <= 17; j++) - if (x & (1 << j)) - as_warn (_("resource conflict (A%d)"), j - 16); - if (x & (1 << 19)) - as_warn (_("resource conflict (PSW)")); - if (x & (1 << 21)) - as_warn (_("resource conflict (C flag)")); - if (x & (1 << 22)) - as_warn (_("resource conflict (F flag)")); - } -} - -/* This is the main entry point for the machine-dependent assembler. - str points to a machine-dependent instruction. This function is - supposed to emit the frags/bytes it assembles to. For the D10V, it - mostly handles the special VLIW parsing and packing and leaves the - difficult stuff to do_assemble(). */ - -static unsigned long prev_insn; -static struct d10v_opcode *prev_opcode = 0; -static subsegT prev_subseg; -static segT prev_seg = 0;; - -void -md_assemble (str) - char *str; -{ - /* etype is saved extype. For multi-line instructions. */ - - packing_type extype = PACK_UNSPEC; /* Parallel, etc. */ - - struct d10v_opcode *opcode; - unsigned long insn; - char *str2; - - if (etype == PACK_UNSPEC) - { - /* Look for the special multiple instruction separators. */ - str2 = strstr (str, "||"); - if (str2) - extype = PACK_PARALLEL; - else + else if (opcode2->unit == MU) { - str2 = strstr (str, "->"); - if (str2) - extype = PACK_LEFT_RIGHT; - else - { - str2 = strstr (str, "<-"); - if (str2) - extype = PACK_RIGHT_LEFT; - } + if (opcode1->unit == MU) + as_fatal (_("Two MU instructions may not be executed in parallel")); + if (!flag_warn_suppress_instructionswap) + as_warn (_("Swapping instruction order")); + insn = FM00 | (insn2 << 15) | insn1; } + else + insn = FM00 | (insn1 << 15) | insn2; + check_resource_conflict (opcode1, insn1, opcode2, insn2); + break; - /* str2 points to the separator, if there is one. */ - if (str2) + case PACK_LEFT_RIGHT: + if (opcode1->unit != IU) + insn = FM01 | (insn1 << 15) | insn2; + else if (opcode2->unit == MU || opcode2->unit == EITHER) { - *str2 = 0; - - /* If two instructions are present and we already have one saved, - then first write out the saved one. */ - d10v_cleanup (); - - /* Assemble first instruction and save it. */ - prev_insn = do_assemble (str, &prev_opcode); - prev_seg = now_seg; - prev_subseg = now_subseg; - if (prev_insn == (unsigned long) -1) - as_fatal (_("can't find opcode ")); - fixups = fixups->next; - str = str2 + 2; + if (!flag_warn_suppress_instructionswap) + as_warn (_("Swapping instruction order")); + insn = FM10 | (insn2 << 15) | insn1; } - } + else + as_fatal (_("IU instruction may not be in the left container")); + if (opcode1->exec_type & ALONE) + as_warn (_("Instruction in R container is squashed by flow control instruction in L container.")); + break; - insn = do_assemble (str, &opcode); - if (insn == (unsigned long) -1) - { - if (extype != PACK_UNSPEC) + case PACK_RIGHT_LEFT: + if (opcode2->unit != MU) + insn = FM10 | (insn1 << 15) | insn2; + else if (opcode1->unit == IU || opcode1->unit == EITHER) { - etype = extype; - return; + if (!flag_warn_suppress_instructionswap) + as_warn (_("Swapping instruction order")); + insn = FM01 | (insn2 << 15) | insn1; } - as_fatal (_("can't find opcode ")); - } + else + as_fatal (_("MU instruction may not be in the right container")); + if (opcode2->exec_type & ALONE) + as_warn (_("Instruction in R container is squashed by flow control instruction in L container.")); + break; - if (etype != PACK_UNSPEC) - { - extype = etype; - etype = PACK_UNSPEC; + default: + as_fatal (_("unknown execution type passed to write_2_short()")); } - /* If this is a long instruction, write it and any previous short - instruction. */ - if (opcode->format & LONG_OPCODE) - { - if (extype != PACK_UNSPEC) - as_fatal (_("Unable to mix instructions as specified")); - d10v_cleanup (); - write_long (insn, fixups); - prev_opcode = NULL; - return; - } + f = frag_more (4); + number_to_chars_bigendian (f, insn, 4); - if (prev_opcode - && prev_seg - && ((prev_seg != now_seg) || (prev_subseg != now_subseg))) - d10v_cleanup (); + /* Process fixup chains. fx refers to insn2 when j == 0, and to + insn1 when j == 1. Yes, it's reversed. */ - if (prev_opcode - && (0 == write_2_short (prev_opcode, prev_insn, opcode, insn, extype, - fixups))) - { - /* No instructions saved. */ - prev_opcode = NULL; - } - else + for (j = 0; j < 2; j++) { - if (extype != PACK_UNSPEC) - as_fatal (_("Unable to mix instructions as specified")); - /* Save last instruction so it may be packed on next pass. */ - prev_opcode = opcode; - prev_insn = insn; - prev_seg = now_seg; - prev_subseg = now_subseg; - fixups = fixups->next; - } -} - -/* Assemble a single instruction. - Return an opcode, or -1 (an invalid opcode) on error. */ + for (i = 0; i < fx->fc; i++) + { + if (fx->fix[i].reloc) + { + where = f - frag_now->fr_literal; + if (fx->fix[i].size == 2) + where += 2; -static unsigned long -do_assemble (str, opcode) - char *str; - struct d10v_opcode **opcode; -{ - unsigned char *op_start, *op_end; - char *save; - char name[20]; - int nlen = 0; - expressionS myops[6]; - unsigned long insn; + if (fx->fix[i].reloc == BFD_RELOC_D10V_10_PCREL_R + /* A BFD_RELOC_D10V_10_PCREL_R relocation applied to + the instruction in the L container has to be + adjusted to BDF_RELOC_D10V_10_PCREL_L. When + j==0, we're processing insn2's operands, so we + want to mark the operand if insn2 is *not* in the + R container. When j==1, we're processing insn1's + operands, so we want to mark the operand if insn2 + *is* in the R container. Note that, if two + instructions are identical, we're never going to + swap them, so the test is safe. */ + && j == ((insn & 0x7fff) == insn2)) + fx->fix[i].operand |= 1024; - /* Drop leading whitespace. */ - while (*str == ' ') - str++; + if (fx->fix[i].reloc == BFD_RELOC_D10V_18) + fx->fix[i].operand |= 4096; - /* Find the opcode end. */ - for (op_start = op_end = (unsigned char *) str; - *op_end && nlen < 20 && !is_end_of_line[*op_end] && *op_end != ' '; - op_end++) - { - name[nlen] = TOLOWER (op_start[nlen]); - nlen++; + fix_new_exp (frag_now, + where, + fx->fix[i].size, + &(fx->fix[i].exp), + fx->fix[i].pcrel, + fx->fix[i].operand|2048); + } + } + fx->fc = 0; + fx = fx->next; } - name[nlen] = 0; - - if (nlen == 0) - return -1; - - /* Find the first opcode with the proper name. */ - *opcode = (struct d10v_opcode *) hash_find (d10v_hash, name); - if (*opcode == NULL) - as_fatal (_("unknown opcode: %s"), name); + return 0; +} - save = input_line_pointer; - input_line_pointer = (char *) op_end; - *opcode = find_opcode (*opcode, myops); - if (*opcode == 0) - return -1; - input_line_pointer = save; +/* This is the main entry point for the machine-dependent assembler. + str points to a machine-dependent instruction. This function is + supposed to emit the frags/bytes it assembles to. For the D10V, it + mostly handles the special VLIW parsing and packing and leaves the + difficult stuff to do_assemble(). */ - insn = build_insn ((*opcode), myops, 0); - return (insn); -} +static unsigned long prev_insn; +static struct d10v_opcode *prev_opcode = 0; +static subsegT prev_subseg; +static segT prev_seg = 0;; /* Find the symbol which has the same name as the register in exp. */ static symbolS * -find_symbol_matching_register (exp) - expressionS *exp; +find_symbol_matching_register (expressionS *exp) { int i; @@ -1381,9 +1178,7 @@ find_symbol_matching_register (exp) the operands to choose the correct opcode. */ static struct d10v_opcode * -find_opcode (opcode, myops) - struct d10v_opcode *opcode; - expressionS myops[]; +find_opcode (struct d10v_opcode *opcode, expressionS myops[]) { int i, match; struct d10v_opcode *next_opcode; @@ -1503,10 +1298,8 @@ find_opcode (opcode, myops) opcode = next_opcode; } else - { - /* Not a constant, so use a long instruction. */ - opcode += 2; - } + /* Not a constant, so use a long instruction. */ + opcode += 2; } match = 0; @@ -1599,7 +1392,7 @@ find_opcode (opcode, myops) if (!match) { as_bad (_("bad opcode or operands")); - return (0); + return 0; } /* Check that all registers that are required to be even are. @@ -1637,17 +1430,61 @@ find_opcode (opcode, myops) return opcode; } +/* Assemble a single instruction. + Return an opcode, or -1 (an invalid opcode) on error. */ + +static unsigned long +do_assemble (char *str, struct d10v_opcode **opcode) +{ + unsigned char *op_start, *op_end; + char *save; + char name[20]; + int nlen = 0; + expressionS myops[6]; + unsigned long insn; + + /* Drop leading whitespace. */ + while (*str == ' ') + str++; + + /* Find the opcode end. */ + for (op_start = op_end = (unsigned char *) str; + *op_end && nlen < 20 && !is_end_of_line[*op_end] && *op_end != ' '; + op_end++) + { + name[nlen] = TOLOWER (op_start[nlen]); + nlen++; + } + name[nlen] = 0; + + if (nlen == 0) + return -1; + + /* Find the first opcode with the proper name. */ + *opcode = (struct d10v_opcode *) hash_find (d10v_hash, name); + if (*opcode == NULL) + as_fatal (_("unknown opcode: %s"), name); + + save = input_line_pointer; + input_line_pointer = (char *) op_end; + *opcode = find_opcode (*opcode, myops); + if (*opcode == 0) + return -1; + input_line_pointer = save; + + insn = build_insn ((*opcode), myops, 0); + return insn; +} + /* If while processing a fixup, a reloc really needs to be created. Then it is done here. */ arelent * -tc_gen_reloc (seg, fixp) - asection *seg ATTRIBUTE_UNUSED; - fixS *fixp; +tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp) { arelent *reloc; - reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + reloc = xmalloc (sizeof (arelent)); + reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); @@ -1668,18 +1505,15 @@ tc_gen_reloc (seg, fixp) } int -md_estimate_size_before_relax (fragp, seg) - fragS *fragp ATTRIBUTE_UNUSED; - asection *seg ATTRIBUTE_UNUSED; +md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED, + asection *seg ATTRIBUTE_UNUSED) { abort (); return 0; } long -md_pcrel_from_section (fixp, sec) - fixS *fixp; - segT sec; +md_pcrel_from_section (fixS *fixp, segT sec) { if (fixp->fx_addsy != (symbolS *) NULL && (!S_IS_DEFINED (fixp->fx_addsy) @@ -1689,10 +1523,7 @@ md_pcrel_from_section (fixp, sec) } void -md_apply_fix3 (fixP, valP, seg) - fixS *fixP; - valueT *valP; - segT seg ATTRIBUTE_UNUSED; +md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) { char *where; unsigned long insn; @@ -1804,7 +1635,7 @@ md_apply_fix3 (fixP, valP, seg) NOTE: invoked by various macros such as md_cleanup: see. */ int -d10v_cleanup () +d10v_cleanup (void) { segT seg; subsegT subseg; @@ -1836,8 +1667,7 @@ d10v_cleanup () Clobbers input_line_pointer, checks end-of-line. */ static void -d10v_dot_word (dummy) - int dummy ATTRIBUTE_UNUSED; +d10v_dot_word (int dummy ATTRIBUTE_UNUSED) { expressionS exp; char *p; @@ -1880,8 +1710,7 @@ d10v_dot_word (dummy) From expr.c. */ void -md_operand (expressionP) - expressionS *expressionP; +md_operand (expressionS *expressionP) { if (*input_line_pointer == '#' && ! do_not_ignore_hash) { @@ -1891,8 +1720,7 @@ md_operand (expressionP) } bfd_boolean -d10v_fix_adjustable (fixP) - fixS *fixP; +d10v_fix_adjustable (fixS *fixP) { /* We need the symbol name for the VTABLE entries. */ if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT @@ -1901,3 +1729,113 @@ d10v_fix_adjustable (fixP) return 1; } + +/* The target specific pseudo-ops which we support. */ +const pseudo_typeS md_pseudo_table[] = +{ + { "word", d10v_dot_word, 2 }, + { NULL, NULL, 0 } +}; + +void +md_assemble (char *str) +{ + /* etype is saved extype. For multi-line instructions. */ + packing_type extype = PACK_UNSPEC; /* Parallel, etc. */ + struct d10v_opcode *opcode; + unsigned long insn; + char *str2; + + if (etype == PACK_UNSPEC) + { + /* Look for the special multiple instruction separators. */ + str2 = strstr (str, "||"); + if (str2) + extype = PACK_PARALLEL; + else + { + str2 = strstr (str, "->"); + if (str2) + extype = PACK_LEFT_RIGHT; + else + { + str2 = strstr (str, "<-"); + if (str2) + extype = PACK_RIGHT_LEFT; + } + } + + /* str2 points to the separator, if there is one. */ + if (str2) + { + *str2 = 0; + + /* If two instructions are present and we already have one saved, + then first write out the saved one. */ + d10v_cleanup (); + + /* Assemble first instruction and save it. */ + prev_insn = do_assemble (str, &prev_opcode); + prev_seg = now_seg; + prev_subseg = now_subseg; + if (prev_insn == (unsigned long) -1) + as_fatal (_("can't find opcode ")); + fixups = fixups->next; + str = str2 + 2; + } + } + + insn = do_assemble (str, &opcode); + if (insn == (unsigned long) -1) + { + if (extype != PACK_UNSPEC) + { + etype = extype; + return; + } + as_fatal (_("can't find opcode ")); + } + + if (etype != PACK_UNSPEC) + { + extype = etype; + etype = PACK_UNSPEC; + } + + /* If this is a long instruction, write it and any previous short + instruction. */ + if (opcode->format & LONG_OPCODE) + { + if (extype != PACK_UNSPEC) + as_fatal (_("Unable to mix instructions as specified")); + d10v_cleanup (); + write_long (insn, fixups); + prev_opcode = NULL; + return; + } + + if (prev_opcode + && prev_seg + && ((prev_seg != now_seg) || (prev_subseg != now_subseg))) + d10v_cleanup (); + + if (prev_opcode + && (0 == write_2_short (prev_opcode, prev_insn, opcode, insn, extype, + fixups))) + { + /* No instructions saved. */ + prev_opcode = NULL; + } + else + { + if (extype != PACK_UNSPEC) + as_fatal (_("Unable to mix instructions as specified")); + /* Save last instruction so it may be packed on next pass. */ + prev_opcode = opcode; + prev_insn = insn; + prev_seg = now_seg; + prev_subseg = now_subseg; + fixups = fixups->next; + } +} + |