Back to index

cell-binutils  2.17cvs20070401
tc-dlx.c
Go to the documentation of this file.
00001 /* tc-ldx.c -- Assemble for the DLX
00002    Copyright 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
00003 
00004    This file is part of GAS, the GNU Assembler.
00005 
00006    GAS is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2, or (at your option)
00009    any later version.
00010 
00011    GAS is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with GAS; see the file COPYING.  If not, write to the Free
00018    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
00019    02110-1301, USA.  */
00020 
00021 /* Initially created by Kuang Hwa Lin, 3/20/2002.  */
00022 
00023 #include "safe-ctype.h"
00024 #include "as.h"
00025 #include "tc-dlx.h"
00026 #include "opcode/dlx.h"
00027 
00028 /* Make it easier to clone this machine desc into another one.  */
00029 #define       machine_opcode      dlx_opcode
00030 #define       machine_opcodes     dlx_opcodes
00031 #define       machine_ip          dlx_ip
00032 #define       machine_it          dlx_it
00033 
00034 #define NO_RELOC            BFD_RELOC_NONE
00035 #define RELOC_DLX_REL26     BFD_RELOC_DLX_JMP26
00036 #define RELOC_DLX_16        BFD_RELOC_16
00037 #define RELOC_DLX_REL16     BFD_RELOC_16_PCREL_S2
00038 #define RELOC_DLX_HI16      BFD_RELOC_HI16_S
00039 #define RELOC_DLX_LO16      BFD_RELOC_LO16
00040 #define RELOC_DLX_VTINHERIT BFD_RELOC_VTABLE_INHERIT
00041 #define RELOC_DLX_VTENTRY   BFD_RELOC_VTABLE_ENTRY
00042 
00043 /* handle of the OPCODE hash table */
00044 static struct hash_control *op_hash = NULL;
00045 
00046 struct machine_it
00047 {
00048   char *error;
00049   unsigned long opcode;
00050   struct nlist *nlistp;
00051   expressionS exp;
00052   int pcrel;
00053   int size;
00054   int reloc_offset;         /* Offset of reloc within insn.  */
00055   int reloc;
00056   int HI;
00057   int LO;
00058 }
00059 the_insn;
00060 
00061 /* This array holds the chars that always start a comment.  If the
00062    pre-processor is disabled, these aren't very useful.  */
00063 const char comment_chars[] = ";";
00064 
00065 /* This array holds the chars that only start a comment at the beginning of
00066    a line.  If the line seems to have the form '# 123 filename'
00067    .line and .file directives will appear in the pre-processed output.  */
00068 /* Note that input_file.c hand checks for '#' at the beginning of the
00069    first line of the input file.  This is because the compiler outputs
00070    #NO_APP at the beginning of its output.  */
00071 /* Also note that comments like this one will always work.  */
00072 const char line_comment_chars[] = "#";
00073 
00074 /* We needed an unused char for line separation to work around the
00075    lack of macros, using sed and such.  */
00076 const char line_separator_chars[] = "@";
00077 
00078 /* Chars that can be used to separate mant from exp in floating point nums.  */
00079 const char EXP_CHARS[] = "eE";
00080 
00081 /* Chars that mean this number is a floating point constant.
00082    As in 0f12.456
00083    or    0d1.2345e12.  */
00084 const char FLT_CHARS[] = "rRsSfFdDxXpP";
00085 
00086 static void
00087 insert_sreg (char *regname, int regnum)
00088 {
00089   /* Must be large enough to hold the names of the special registers.  */
00090   char buf[80];
00091   int i;
00092 
00093   symbol_table_insert (symbol_new (regname, reg_section, (valueT) regnum,
00094                                &zero_address_frag));
00095   for (i = 0; regname[i]; i++)
00096     buf[i] = ISLOWER (regname[i]) ? TOUPPER (regname[i]) : regname[i];
00097   buf[i] = '\0';
00098 
00099   symbol_table_insert (symbol_new (buf, reg_section, (valueT) regnum,
00100                                &zero_address_frag));
00101 }
00102 
00103 /* Install symbol definitions for assorted special registers.
00104    See MIPS Assembly Language Programmer's Guide page 1-4   */
00105 
00106 static void
00107 define_some_regs (void)
00108 {
00109   /* Software representation.  */
00110   insert_sreg ("zero",  0);
00111   insert_sreg ("at",    1);
00112   insert_sreg ("v0",    2);
00113   insert_sreg ("v1",    3);
00114   insert_sreg ("a0",    4);
00115   insert_sreg ("a1",    5);
00116   insert_sreg ("a2",    6);
00117   insert_sreg ("a3",    7);
00118   insert_sreg ("t0",    8);
00119   insert_sreg ("t1",    9);
00120   insert_sreg ("t2",    10);
00121   insert_sreg ("t3",    11);
00122   insert_sreg ("t4",    12);
00123   insert_sreg ("t5",    13);
00124   insert_sreg ("t6",    14);
00125   insert_sreg ("t7",    15);
00126   insert_sreg ("s0",    16);
00127   insert_sreg ("s1",    17);
00128   insert_sreg ("s2",    18);
00129   insert_sreg ("s3",    19);
00130   insert_sreg ("s4",    20);
00131   insert_sreg ("s5",    21);
00132   insert_sreg ("s6",    22);
00133   insert_sreg ("s7",    23);
00134   insert_sreg ("t8",    24);
00135   insert_sreg ("t9",    25);
00136   insert_sreg ("k0",    26);
00137   insert_sreg ("k1",    27);
00138   insert_sreg ("gp",    28);
00139   insert_sreg ("sp",    29);
00140   insert_sreg ("fp",    30);
00141   insert_sreg ("ra",    31);
00142   /* Special registers.  */
00143   insert_sreg ("pc",    0);
00144   insert_sreg ("npc",   1);
00145   insert_sreg ("iad",   2);
00146 }
00147 
00148 /* Subroutine check the string to match an register.  */
00149 
00150 static int
00151 match_sft_register (char *name)
00152 {
00153 #define MAX_REG_NO  35
00154 /* Currently we have 35 software registers defined -
00155    we borrowed from MIPS.   */
00156   static char *soft_reg[] =
00157     {
00158       "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
00159       "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9",
00160       "s0", "s1", "s2", "s3", "s4", "s5", "s7", "k0", "k1",
00161       "gp", "sp", "fp", "ra", "pc", "npc", "iad",
00162       "EndofTab"  /* End of the Table indicator */
00163     };
00164   char low_name[21], *ptr;
00165   int idx;
00166 
00167   for (ptr = name,idx = 0; *ptr != '\0'; ptr++)
00168     low_name[idx++] = TOLOWER (*ptr);
00169 
00170   low_name[idx] = '\0';
00171   idx = 0;
00172 
00173   while (idx < MAX_REG_NO && strcmp (soft_reg[idx], & low_name [0]))
00174     idx += 1;
00175 
00176   return idx < MAX_REG_NO;
00177 }
00178 
00179 /* Subroutine check the string to match an register.  */
00180 
00181 static int
00182 is_ldst_registers (char *name)
00183 {
00184   char *ptr = name;
00185 
00186   /* The first character of the register name got to be either %, $, r of R.  */
00187   if ((ptr[0] == '%' || ptr[0] == '$' || ptr[0] == 'r' || ptr[0] == 'R')
00188       && ISDIGIT ((unsigned char) ptr[1]))
00189     return 1;
00190 
00191   /* Now check the software register representation.  */
00192   return match_sft_register (ptr);
00193 }
00194 
00195 /* Subroutine of s_proc so targets can choose a different default prefix.
00196    If DEFAULT_PREFIX is NULL, use the target's "leading char".  */
00197 
00198 static void
00199 s_proc (int end_p)
00200 {
00201   /* Record the current function so that we can issue an error message for
00202      misplaced .func,.endfunc, and also so that .endfunc needs no
00203      arguments.  */
00204   static char *current_name;
00205   static char *current_label;
00206 
00207   if (end_p)
00208     {
00209       if (current_name == NULL)
00210        {
00211          as_bad (_("missing .proc"));
00212          ignore_rest_of_line ();
00213          return;
00214        }
00215 
00216       current_name = current_label = NULL;
00217       SKIP_WHITESPACE ();
00218       while (!is_end_of_line[(unsigned char) *input_line_pointer])
00219         input_line_pointer++;
00220     }
00221   else
00222     {
00223       char *name, *label;
00224       char delim1, delim2;
00225 
00226       if (current_name != NULL)
00227        {
00228          as_bad (_(".endfunc missing for previous .proc"));
00229          ignore_rest_of_line ();
00230          return;
00231        }
00232 
00233       name = input_line_pointer;
00234       delim1 = get_symbol_end ();
00235       name = xstrdup (name);
00236       *input_line_pointer = delim1;
00237       SKIP_WHITESPACE ();
00238 
00239       if (*input_line_pointer != ',')
00240        {
00241          char leading_char = 0;
00242 
00243          leading_char = bfd_get_symbol_leading_char (stdoutput);
00244          /* Missing entry point, use function's name with the leading
00245             char prepended.  */
00246          if (leading_char)
00247            asprintf (&label, "%c%s", leading_char, name);
00248          else
00249            label = name;
00250        }
00251       else
00252        {
00253          ++input_line_pointer;
00254          SKIP_WHITESPACE ();
00255          label = input_line_pointer;
00256          delim2 = get_symbol_end ();
00257          label = xstrdup (label);
00258          *input_line_pointer = delim2;
00259        }
00260 
00261       current_name = name;
00262       current_label = label;
00263     }
00264   demand_empty_rest_of_line ();
00265 }
00266 
00267 /* This function is called once, at assembler startup time.  It should
00268    set up all the tables, etc., that the MD part of the assembler will
00269    need.  */
00270 
00271 void
00272 md_begin (void)
00273 {
00274   const char *retval = NULL;
00275   int lose = 0;
00276   unsigned int i;
00277 
00278   /* Create a new hash table.  */
00279   op_hash = hash_new ();
00280 
00281   /* Hash up all the opcodes for fast use later.  */
00282   for (i = 0; i < num_dlx_opcodes; i++)
00283     {
00284       const char *name = machine_opcodes[i].name;
00285 
00286       retval = hash_insert (op_hash, name, (void *) &machine_opcodes[i]);
00287 
00288       if (retval != NULL)
00289        {
00290          fprintf (stderr, "internal error: can't hash `%s': %s\n",
00291                  machine_opcodes[i].name, retval);
00292          lose = 1;
00293        }
00294     }
00295 
00296   if (lose)
00297     as_fatal (_("Broken assembler.  No assembly attempted."));
00298 
00299   define_some_regs ();
00300 }
00301 
00302 /* This function will check the opcode and return 1 if the opcode is one
00303    of the load/store instruction, and it will fix the operand string to
00304    the standard form so we can use the standard parse_operand routine.  */
00305 
00306 #define READ_OP     0x100
00307 #define WRITE_OP    0x200
00308 static char iBuf[81];
00309 
00310 static char *
00311 dlx_parse_loadop (char * str)
00312 {
00313   char *ptr = str;
00314   int   idx = 0;
00315 
00316   /* The last pair of ()/[] is the register, all other are the
00317      reloc displacement, and if there is a register then it ought
00318      to have a pair of ()/[]
00319      This is not necessarily true, what if the load instruction come
00320      without the register and with %hi/%lo modifier?  */
00321   for (idx = 0; idx < 72 && ptr[idx] != '\0'; idx++)
00322     ;
00323 
00324   if (idx == 72)
00325     {
00326     badoperand_load:
00327       as_bad (_("Bad operand for a load instruction: <%s>"), str);
00328       return NULL;
00329     }
00330   else
00331     {
00332       int i, pb = 0;
00333       int m2 = 0;
00334       char rs1[7], rd[7], endm, match = '0';
00335       char imm[72];
00336 
00337       idx -= 1;
00338       switch (str[idx])
00339        {
00340        case ')':
00341          match = '(';
00342          endm  = ')';
00343          break;
00344        case ']':
00345          match = '[';
00346          endm  = ']';
00347          break;
00348        default:
00349          /* No register indicated, fill in zero.  */
00350          rs1[0] = 'r';
00351          rs1[1] = '0';
00352          rs1[2] = '\0';
00353          match  = 0;
00354          endm = 0;
00355          m2 = 1;
00356        }
00357 
00358       if (!m2)
00359        {
00360          /* Searching for (/[ which will match the ]/).  */
00361          for (pb = idx - 1; str[pb] != match; pb -= 1)
00362            /* Match can only be either '[' or '(', if it is
00363               '(' then this can be a normal expression, we'll treat
00364               it as an operand.  */
00365            if (str[pb] == endm || pb < (idx - 5))
00366              goto load_no_rs1;
00367          pb += 1;
00368 
00369          for (i = 0; (pb + i) < idx; i++)
00370            rs1[i] = str[pb+i];
00371 
00372          rs1[i] = '\0';
00373 
00374          if (is_ldst_registers (& rs1[0]))
00375            /* Point to the last character of the imm.  */
00376            pb -= 1;
00377          else
00378            {
00379            load_no_rs1:
00380              if (match == '[')
00381               goto badoperand_load;
00382              /* No register indicated, fill in zero and restore the imm.  */
00383              rs1[0] = 'r';
00384              rs1[1] = '0';
00385              rs1[2] = '\0';
00386              m2 = 1;
00387            }
00388        }
00389 
00390       /* Duplicate the first register.  */
00391       for (i = 0; i < 7 && str[i] != ','; i++)
00392        rd[i] = ptr[i];
00393 
00394       if (str[i] != ',')
00395        goto badoperand_load;
00396       else
00397        rd[i] = '\0';
00398 
00399       /* Copy the immd.  */
00400       if (m2)
00401        /* Put the '\0' back in.  */
00402        pb = idx + 1;
00403 
00404       for (i++, m2 = 0; i < pb; m2++,i++)
00405        imm[m2] = ptr[i];
00406 
00407       imm[m2] = '\0';
00408 
00409       /* Assemble the instruction to gas internal format.  */
00410       for (i = 0; rd[i] != '\0'; i++)
00411        iBuf[i] = rd[i];
00412 
00413       iBuf[i++] = ',';
00414 
00415       for (pb = 0 ; rs1[pb] != '\0'; i++, pb++)
00416        iBuf[i] = rs1[pb];
00417 
00418       iBuf[i++] = ',';
00419 
00420       for (pb = 0; imm[pb] != '\0'; i++, pb++)
00421        iBuf[i] = imm[pb];
00422 
00423       iBuf[i] = '\0';
00424       return iBuf;
00425     }
00426 }
00427 
00428 static char *
00429 dlx_parse_storeop (char * str)
00430 {
00431   char *ptr = str;
00432   int   idx = 0;
00433 
00434   /* Search for the ','.  */
00435   for (idx = 0; idx < 72 && ptr[idx] != ','; idx++)
00436     ;
00437 
00438   if (idx == 72)
00439     {
00440     badoperand_store:
00441       as_bad (_("Bad operand for a store instruction: <%s>"), str);
00442       return NULL;
00443     }
00444   else
00445     {
00446       /* idx now points to the ','.  */
00447       int i, pb = 0;
00448       int comma = idx;
00449       int m2 = 0;
00450       char rs1[7], rd[7], endm, match = '0';
00451       char imm[72];
00452 
00453       /* Now parse the '(' and ')', and make idx point to ')'.  */
00454       idx -= 1;
00455       switch (str[idx])
00456        {
00457        case ')':
00458          match = '(';
00459          endm  = ')';
00460          break;
00461        case ']':
00462          match = '[';
00463          endm  = ']';
00464          break;
00465        default:
00466          /* No register indicated, fill in zero.  */
00467          rs1[0] = 'r';
00468          rs1[1] = '0';
00469          rs1[2] = '\0';
00470          match  = 0;
00471          endm = 0;
00472          m2 = 1;
00473        }
00474 
00475       if (!m2)
00476        {
00477          /* Searching for (/[ which will match the ]/).  */
00478          for (pb = idx - 1; str[pb] != match; pb -= 1)
00479            if (pb < (idx - 5) || str[pb] == endm)
00480              goto store_no_rs1;
00481          pb += 1;
00482 
00483          for (i = 0; (pb + i) < idx; i++)
00484            rs1[i] = str[pb + i];
00485 
00486          rs1[i] = '\0';
00487 
00488          if (is_ldst_registers (& rs1[0]))
00489            /* Point to the last character of the imm.  */
00490            pb -= 1;
00491          else
00492            {
00493            store_no_rs1:
00494              if (match == '[')
00495               goto badoperand_store;
00496 
00497              /* No register indicated, fill in zero and restore the imm.  */
00498              rs1[0] = 'r';
00499              rs1[1] = '0';
00500              rs1[2] = '\0';
00501              pb = comma;
00502            }
00503        }
00504       else
00505        /* No register was specified.  */
00506        pb = comma;
00507 
00508       /* Duplicate the first register.  */
00509       for (i = comma + 1; (str[i] == ' ' || str[i] == '\t'); i++)
00510        ;
00511 
00512       for (m2 = 0; (m2 < 7 && str[i] != '\0'); i++, m2++)
00513        {
00514          if (str[i] != ' ' && str[i] != '\t')
00515            rd[m2] = str[i];
00516          else
00517            goto badoperand_store;
00518        }
00519 
00520       if (str[i] != '\0')
00521        goto badoperand_store;
00522       else
00523        rd[m2] = '\0';
00524 
00525       /* Copy the immd.  */
00526       for (i = 0; i < pb; i++)
00527        imm[i] = ptr[i];
00528 
00529       imm[i] = '\0';
00530 
00531       /* Assemble the instruction to gas internal format.  */
00532       for (i = 0; rd[i] != '\0'; i++)
00533        iBuf[i] = rd[i];
00534       iBuf[i++] = ',';
00535       for (pb = 0 ; rs1[pb] != '\0'; i++, pb++)
00536        iBuf[i] = rs1[pb];
00537       iBuf[i++] = ',';
00538       for (pb = 0; imm[pb] != '\0'; i++, pb++)
00539        iBuf[i] = imm[pb];
00540       iBuf[i] = '\0';
00541       return iBuf;
00542     }
00543 }
00544 
00545 static char *
00546 fix_ld_st_operand (unsigned long opcode, char* str)
00547 {
00548   /* Check the opcode.  */
00549   switch ((int) opcode)
00550     {
00551     case  LBOP:
00552     case  LBUOP:
00553     case  LSBUOP:
00554     case  LHOP:
00555     case  LHUOP:
00556     case  LSHUOP:
00557     case  LWOP:
00558     case  LSWOP:
00559       return dlx_parse_loadop (str);
00560     case  SBOP:
00561     case  SHOP:
00562     case  SWOP:
00563       return dlx_parse_storeop (str);
00564     default:
00565       return str;
00566     }
00567 }
00568 
00569 static int
00570 hilo_modifier_ok (char *s)
00571 {
00572   char *ptr = s;
00573   int   idx, count = 1;
00574 
00575   if (*ptr != '(')
00576     return 1;
00577 
00578   for (idx = 1; ptr[idx] != '\0' && ptr[idx] != '[' && idx < 73; idx += 1)
00579     {
00580       if (count == 0)
00581        return count;
00582 
00583       if (ptr[idx] == '(')
00584        count += 1;
00585 
00586       if (ptr[idx] == ')')
00587        count -= 1;
00588     }
00589 
00590   return (count == 0) ? 1:0;
00591 }
00592 
00593 static char *
00594 parse_operand (char *s, expressionS *operandp)
00595 {
00596   char *save = input_line_pointer;
00597   char *new;
00598 
00599   the_insn.HI = the_insn.LO = 0;
00600 
00601   /* Search for %hi and %lo, make a mark and skip it.  */
00602   if (strncmp (s, "%hi", 3) == 0)
00603     {
00604       s += 3;
00605       the_insn.HI = 1;
00606     }
00607   else
00608     {
00609       if (strncmp (s, "%lo", 3) == 0)
00610        {
00611          s += 3;
00612          the_insn.LO = 1;
00613        }
00614       else
00615        the_insn.LO = 0;
00616     }
00617 
00618   if (the_insn.HI || the_insn.LO)
00619     {
00620       if (!hilo_modifier_ok (s))
00621        as_bad (_("Expression Error for operand modifier %%hi/%%lo\n"));
00622     }
00623 
00624   /* Check for the % and $ register representation    */
00625   if ((s[0] == '%' || s[0] == '$' || s[0] == 'r' || s[0] == 'R')
00626       && ISDIGIT ((unsigned char) s[1]))
00627     {
00628       /* We have a numeric register expression.  No biggy.  */
00629       s += 1;
00630       input_line_pointer = s;
00631       (void) expression (operandp);
00632       if (operandp->X_op != O_constant
00633          || operandp->X_add_number > 31)
00634        as_bad (_("Invalid expression after %%%%\n"));
00635       operandp->X_op = O_register;
00636     }
00637   else
00638     {
00639       /* Normal operand parsing.  */
00640       input_line_pointer = s;
00641       (void) expression (operandp);
00642     }
00643 
00644   new = input_line_pointer;
00645   input_line_pointer = save;
00646   return new;
00647 }
00648 
00649 /* Instruction parsing.  Takes a string containing the opcode.
00650    Operands are at input_line_pointer.  Output is in the_insn.
00651    Warnings or errors are generated.  */
00652 
00653 static void
00654 machine_ip (char *str)
00655 {
00656   char *s;
00657   const char *args;
00658   struct machine_opcode *insn;
00659   char *argsStart;
00660   unsigned long opcode;
00661   expressionS the_operand;
00662   expressionS *operand = &the_operand;
00663   unsigned int reg, reg_shift = 0;
00664 
00665   /* Fixup the opcode string to all lower cases, and also
00666      allow numerical digits.  */
00667   s = str;
00668 
00669   if (ISALPHA (*s))
00670     for (; ISALNUM (*s); ++s)
00671       if (ISUPPER (*s))
00672        *s = TOLOWER (*s);
00673 
00674   switch (*s)
00675     {
00676     case '\0':
00677       break;
00678 
00679       /* FIXME-SOMEDAY more whitespace.  */
00680     case ' ':
00681       *s++ = '\0';
00682       break;
00683 
00684     default:
00685       as_bad (_("Unknown opcode: `%s'"), str);
00686       return;
00687     }
00688 
00689   /* Hash the opcode, insn will have the string from opcode table.
00690      also initialized the_insn struct.  */
00691   if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL)
00692     {
00693       /* Handle the ret and return macro here.  */
00694       if ((strcmp (str, "ret") == 0) || (strcmp (str, "return") == 0))
00695        {
00696          memset (&the_insn, '\0', sizeof (the_insn));
00697          the_insn.reloc = NO_RELOC;
00698          the_insn.pcrel = 0;
00699          the_insn.opcode =
00700            (unsigned long)(JROP | 0x03e00000);    /* 0x03e00000 = r31 << 21 */
00701        }
00702       else
00703        as_bad (_("Unknown opcode `%s'."), str);
00704 
00705       return;
00706     }
00707 
00708   argsStart = s;
00709   opcode = insn->opcode;
00710   memset (&the_insn, '\0', sizeof (the_insn));
00711   the_insn.reloc = NO_RELOC;
00712   the_insn.pcrel = 0;
00713 
00714   /* Set the sip reloc HI16 flag.  */
00715   if (!set_dlx_skip_hi16_flag (1))
00716     as_bad (_("Can not set dlx_skip_hi16_flag"));
00717 
00718   /* Fix the operand string if it is one of load store instructions.  */
00719   s = fix_ld_st_operand (opcode, s);
00720 
00721   /* Build the opcode, checking as we go to make sure that the
00722      operands match.
00723      If an operand matches, we modify the_insn or opcode appropriately,
00724      and do a "continue".  If an operand fails to match, we "break".  */
00725   if (insn->args[0] != '\0' && insn->args[0] != 'N')
00726     {
00727       /* Prime the pump.  */
00728       if (*s == '\0')
00729        {
00730          as_bad (_("Missing arguments for opcode <%s>."), str);
00731          return;
00732        }
00733       else
00734        s = parse_operand (s, operand);
00735     }
00736   else if (insn->args[0] == 'N')
00737     {
00738       /* Clean up the insn and done!  */
00739       the_insn.opcode = opcode;
00740       return;
00741     }
00742 
00743   /* Parse through the args (this is from opcode table), *s point to
00744      the current character of the instruction stream.  */
00745   for (args = insn->args;; ++args)
00746     {
00747       switch (*args)
00748        {
00749          /* End of Line.  */
00750        case '\0':
00751          /* End of args.  */
00752          if (*s == '\0')
00753            {
00754              /* We are truly done.  */
00755              the_insn.opcode = opcode;
00756              /* Clean up the HI and LO mark.  */
00757              the_insn.HI = 0;
00758              the_insn.LO = 0;
00759              return;
00760            }
00761 
00762          the_insn.HI = 0;
00763          the_insn.LO = 0;
00764          as_bad (_("Too many operands: %s"), s);
00765          break;
00766 
00767          /* ',' Args separator */
00768        case ',':
00769          /* Must match a comma.  */
00770          if (*s++ == ',')
00771            {
00772              /* Parse next operand.  */
00773              s = parse_operand (s, operand);
00774              continue;
00775            }
00776          break;
00777 
00778          /* It can be a 'a' register or 'i' operand.  */
00779        case 'P':
00780          /* Macro move operand/reg.  */
00781          if (operand->X_op == O_register)
00782            {
00783              /* Its a register.  */
00784              reg_shift = 21;
00785              goto general_reg;
00786            }
00787 
00788          /* The immediate 16 bits literal, bit 0-15.  */
00789        case 'i':
00790          /* offset, unsigned.  */
00791        case 'I':
00792          /* offset, signed.  */
00793          if (operand->X_op == O_constant)
00794            {
00795              if (the_insn.HI)
00796               operand->X_add_number >>= 16;
00797 
00798              opcode |= operand->X_add_number & 0xFFFF;
00799 
00800              if (the_insn.HI && the_insn.LO)
00801               as_bad (_("Both the_insn.HI and the_insn.LO are set : %s"), s);
00802              else
00803               {
00804                 the_insn.HI = 0;
00805                 the_insn.LO = 0;
00806               }
00807              continue;
00808            }
00809 
00810          the_insn.reloc        = (the_insn.HI) ? RELOC_DLX_HI16 
00811            : (the_insn.LO ? RELOC_DLX_LO16 : RELOC_DLX_16);
00812          the_insn.reloc_offset = 2;
00813          the_insn.size         = 2;
00814          the_insn.pcrel        = 0;
00815          the_insn.exp          = * operand;
00816          the_insn.HI           = 0;
00817          the_insn.LO           = 0;
00818          continue;
00819 
00820        case 'd':
00821          /* offset, signed.  */
00822          if (operand->X_op == O_constant)
00823            {
00824              opcode |= operand->X_add_number & 0xFFFF;
00825              continue;
00826            }
00827          the_insn.reloc        = RELOC_DLX_REL16;
00828          the_insn.reloc_offset = 0;    /* BIG-ENDIAN Byte 3 of insn.  */
00829          the_insn.size         = 4;
00830          the_insn.pcrel        = 1;
00831          the_insn.exp          = *operand;
00832          continue;
00833 
00834          /* The immediate 26 bits literal, bit 0-25.  */
00835        case 'D':
00836          /* offset, signed.  */
00837          if (operand->X_op == O_constant)
00838            {
00839              opcode |= operand->X_add_number & 0x3FFFFFF;
00840              continue;
00841            }
00842          the_insn.reloc = RELOC_DLX_REL26;
00843          the_insn.reloc_offset = 0;    /* BIG-ENDIAN Byte 3 of insn.  */
00844          the_insn.size  = 4;
00845          the_insn.pcrel = 1;
00846          the_insn.exp = *operand;
00847          continue;
00848 
00849          /* Type 'a' Register.  */
00850        case 'a':
00851          /* A general register at bits 21-25, rs1.  */
00852          reg_shift = 21;
00853          goto general_reg;
00854 
00855          /* Type 'b' Register.  */
00856        case 'b':
00857          /* A general register at bits 16-20, rs2/rd.  */
00858          reg_shift = 16;
00859          goto general_reg;
00860 
00861          /* Type 'c' Register.  */
00862        case 'c':
00863          /* A general register at bits 11-15, rd.  */
00864          reg_shift = 11;
00865 
00866        general_reg:
00867          know (operand->X_add_symbol == 0);
00868          know (operand->X_op_symbol == 0);
00869          reg = operand->X_add_number;
00870          if (reg & 0xffffffe0)
00871            as_fatal (_("failed regnum sanity check."));
00872          else
00873            /* Got the register, now figure out where it goes in the opcode.  */
00874            opcode |= reg << reg_shift;
00875 
00876          switch (*args)
00877            {
00878            case 'a':
00879            case 'b':
00880            case 'c':
00881            case 'P':
00882              continue;
00883            }
00884          as_fatal (_("failed general register sanity check."));
00885          break;
00886 
00887        default:
00888          BAD_CASE (*args);
00889        }
00890 
00891       /* Types or values of args don't match.  */
00892       as_bad ("Invalid operands");
00893       return;
00894     }
00895 }
00896 
00897 /* Assemble a single instruction.  Its label has already been handled
00898    by the generic front end.  We just parse opcode and operands, and
00899    produce the bytes of data and relocation.  */
00900 
00901 void
00902 md_assemble (char *str)
00903 {
00904   char *toP;
00905   fixS *fixP;
00906   bit_fixS *bitP;
00907 
00908   know (str);
00909   machine_ip (str);
00910   toP = frag_more (4);
00911   /* Put out the opcode.  */
00912   md_number_to_chars (toP, the_insn.opcode, 4);
00913 
00914   /* Put out the symbol-dependent stuff.  */
00915   if (the_insn.reloc != NO_RELOC)
00916     {
00917       fixP = fix_new_exp (frag_now,
00918                        (toP - frag_now->fr_literal + the_insn.reloc_offset),
00919                        the_insn.size, & the_insn.exp, the_insn.pcrel,
00920                        the_insn.reloc);
00921 
00922       /* Turn off complaints that the addend is
00923         too large for things like foo+100000@ha.  */
00924       switch (the_insn.reloc)
00925        {
00926        case RELOC_DLX_HI16:
00927        case RELOC_DLX_LO16:
00928          fixP->fx_no_overflow = 1;
00929          break;
00930        default:
00931          break;
00932        }
00933 
00934       switch (fixP->fx_r_type)
00935        {
00936        case RELOC_DLX_REL26:
00937          bitP = malloc (sizeof (bit_fixS));
00938          bitP->fx_bit_size = 26;
00939          bitP->fx_bit_offset = 25;
00940          bitP->fx_bit_base = the_insn.opcode & 0xFC000000;
00941          bitP->fx_bit_base_adj = 0;
00942          bitP->fx_bit_max = 0;
00943          bitP->fx_bit_min = 0;
00944          bitP->fx_bit_add = 0x03FFFFFF;
00945          fixP->fx_bit_fixP = bitP;
00946          break;
00947        case RELOC_DLX_LO16:
00948        case RELOC_DLX_REL16:
00949          bitP = malloc (sizeof (bit_fixS));
00950          bitP->fx_bit_size = 16;
00951          bitP->fx_bit_offset = 15;
00952          bitP->fx_bit_base = the_insn.opcode & 0xFFFF0000;
00953          bitP->fx_bit_base_adj = 0;
00954          bitP->fx_bit_max = 0;
00955          bitP->fx_bit_min = 0;
00956          bitP->fx_bit_add = 0x0000FFFF;
00957          fixP->fx_bit_fixP = bitP;
00958          break;
00959        case RELOC_DLX_HI16:
00960          bitP = malloc (sizeof (bit_fixS));
00961          bitP->fx_bit_size = 16;
00962          bitP->fx_bit_offset = 15;
00963          bitP->fx_bit_base = the_insn.opcode & 0xFFFF0000;
00964          bitP->fx_bit_base_adj = 0;
00965          bitP->fx_bit_max = 0;
00966          bitP->fx_bit_min = 0;
00967          bitP->fx_bit_add = 0x0000FFFF;
00968          fixP->fx_bit_fixP = bitP;
00969          break;
00970        default:
00971          fixP->fx_bit_fixP = NULL;
00972          break;
00973        }
00974     }
00975 }
00976 
00977 /* This is identical to the md_atof in m68k.c.  I think this is right,
00978    but I'm not sure.
00979 
00980    Turn a string in input_line_pointer into a floating point constant
00981    of type TYPE, and store the appropriate bytes in *LITP.  The number
00982    of LITTLENUMS emitted is stored in *SIZEP.  An error message is
00983    returned, or NULL on OK.  */
00984 /* Dlx will not use it anyway, so I just leave it here for now.  */
00985 
00986 /* Equal to MAX_PRECISION in atof-ieee.c.  */
00987 #define MAX_LITTLENUMS 6
00988 
00989 char *
00990 md_atof (int type, char *litP, int *sizeP)
00991 {
00992   int prec;
00993   LITTLENUM_TYPE words[MAX_LITTLENUMS];
00994   LITTLENUM_TYPE *wordP;
00995   char *t;
00996 
00997   switch (type)
00998     {
00999     case 'f':
01000     case 'F':
01001     case 's':
01002     case 'S':
01003       prec = 2;
01004       break;
01005 
01006     case 'd':
01007     case 'D':
01008     case 'r':
01009     case 'R':
01010       prec = 4;
01011       break;
01012 
01013     case 'x':
01014     case 'X':
01015       prec = 6;
01016       break;
01017 
01018     case 'p':
01019     case 'P':
01020       prec = 6;
01021       break;
01022 
01023     default:
01024       *sizeP = 0;
01025       return "Bad call to MD_ATOF()";
01026     }
01027 
01028   t = atof_ieee (input_line_pointer, type, words);
01029   if (t)
01030     input_line_pointer = t;
01031 
01032   *sizeP = prec * sizeof (LITTLENUM_TYPE);
01033 
01034   for (wordP = words; prec--;)
01035     {
01036       md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
01037       litP += sizeof (LITTLENUM_TYPE);
01038     }
01039 
01040   return 0;
01041 }
01042 
01043 /* Write out big-endian.  */
01044 void
01045 md_number_to_chars (char *buf, valueT val, int n)
01046 {
01047   number_to_chars_bigendian (buf, val, n);
01048 }
01049 
01050 bfd_boolean
01051 md_dlx_fix_adjustable (fixS *fixP)
01052 {
01053   /* We need the symbol name for the VTABLE entries.  */
01054   return (fixP->fx_r_type != BFD_RELOC_VTABLE_INHERIT
01055           && fixP->fx_r_type != BFD_RELOC_VTABLE_ENTRY);
01056 }
01057 
01058 void
01059 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
01060 {
01061   long val = *valP;
01062   char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
01063 
01064   switch (fixP->fx_r_type)
01065     {
01066     case RELOC_DLX_LO16:
01067     case RELOC_DLX_REL16:
01068       if (fixP->fx_bit_fixP != NULL)
01069        {
01070          val = (val & 0x0000FFFF) | fixP->fx_bit_fixP->fx_bit_base;
01071          free (fixP->fx_bit_fixP);
01072          fixP->fx_bit_fixP = NULL;
01073        }
01074 #ifdef DEBUG
01075       else
01076        know ((fixP->fx_bit_fixP != NULL));
01077 #endif
01078       break;
01079 
01080     case RELOC_DLX_HI16:
01081       if (fixP->fx_bit_fixP != NULL)
01082        {
01083          val = (val >> 16) | fixP->fx_bit_fixP->fx_bit_base;
01084          free (fixP->fx_bit_fixP);
01085          fixP->fx_bit_fixP = NULL;
01086        }
01087 #ifdef DEBUG
01088       else
01089        know ((fixP->fx_bit_fixP != NULL));
01090 #endif
01091       break;
01092 
01093     case RELOC_DLX_REL26:
01094       if (fixP->fx_bit_fixP != NULL)
01095        {
01096          val = (val & 0x03FFFFFF) | fixP->fx_bit_fixP->fx_bit_base;
01097          free (fixP->fx_bit_fixP);
01098          fixP->fx_bit_fixP = NULL;
01099        }
01100 #ifdef DEBUG
01101       else
01102        know ((fixP->fx_bit_fixP != NULL));
01103 #endif
01104       break;
01105 
01106     case BFD_RELOC_VTABLE_INHERIT:
01107       /* This borrowed from tc-ppc.c on a whim.  */
01108       fixP->fx_done = 0;
01109       if (fixP->fx_addsy
01110          && !S_IS_DEFINED (fixP->fx_addsy)
01111          && !S_IS_WEAK (fixP->fx_addsy))
01112        S_SET_WEAK (fixP->fx_addsy);
01113       return;
01114 
01115     case BFD_RELOC_VTABLE_ENTRY:
01116       fixP->fx_done = 0;
01117       return;
01118 
01119     default:
01120       break;
01121     }
01122 
01123   number_to_chars_bigendian (place, val, fixP->fx_size);
01124   if (fixP->fx_addsy == NULL)
01125     fixP->fx_done = 1;
01126 }
01127 
01128 const char *md_shortopts = "";
01129 
01130 struct option md_longopts[] =
01131   {
01132     {NULL, no_argument, NULL, 0}
01133   };
01134 
01135 size_t md_longopts_size = sizeof (md_longopts);
01136 
01137 int
01138 md_parse_option (int c     ATTRIBUTE_UNUSED,
01139                char *arg ATTRIBUTE_UNUSED)
01140 {
01141   return 0;
01142 }
01143 
01144 void
01145 md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
01146 {
01147 }
01148 
01149 /* This is called when a line is unrecognized.  */
01150 
01151 int
01152 dlx_unrecognized_line (int c)
01153 {
01154   int lab;
01155   char *s;
01156 
01157   if (c != '$' || ! ISDIGIT ((unsigned char) input_line_pointer[0]))
01158     return 0;
01159 
01160   s = input_line_pointer;
01161 
01162   lab = 0;
01163   while (ISDIGIT ((unsigned char) *s))
01164     {
01165       lab = lab * 10 + *s - '0';
01166       ++s;
01167     }
01168 
01169   if (*s != ':')
01170     /* Not a label definition.  */
01171     return 0;
01172 
01173   if (dollar_label_defined (lab))
01174     {
01175       as_bad (_("label \"$%d\" redefined"), lab);
01176       return 0;
01177     }
01178 
01179   define_dollar_label (lab);
01180   colon (dollar_label_name (lab, 0));
01181   input_line_pointer = s + 1;
01182 
01183   return 1;
01184 }
01185 
01186 /* Default the values of symbols known that should be "predefined".  We
01187    don't bother to predefine them unless you actually use one, since there
01188    are a lot of them.  */
01189 
01190 symbolS *
01191 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
01192 {
01193   return NULL;
01194 }
01195 
01196 /* Parse an operand that is machine-specific, the function was called
01197    in expr.c by operand() function, when everything failed before it
01198    call a quit.  */
01199 
01200 void
01201 md_operand (expressionS* expressionP)
01202 {
01203   /* Check for the #number representation    */
01204   if (input_line_pointer[0] == '#' &&
01205       ISDIGIT ((unsigned char) input_line_pointer[1]))
01206     {
01207       /* We have a numeric number expression.  No biggy.  */
01208       input_line_pointer += 1;     /* Skip # */
01209 
01210       (void) expression (expressionP);
01211 
01212       if (expressionP->X_op != O_constant)
01213        as_bad (_("Invalid expression after # number\n"));
01214     }
01215 
01216   return;
01217 }
01218 
01219 /* Round up a section size to the appropriate boundary.  */
01220 
01221 valueT
01222 md_section_align (segT segment ATTRIBUTE_UNUSED,
01223                 valueT size)
01224 {
01225   /* Byte alignment is fine.  */
01226   return size;
01227 }
01228 
01229 /* Exactly what point is a PC-relative offset relative TO?
01230    On the 29000, they're relative to the address of the instruction,
01231    which we have set up as the address of the fixup too.  */
01232 
01233 long
01234 md_pcrel_from (fixS* fixP)
01235 {
01236   return 4 + fixP->fx_where + fixP->fx_frag->fr_address;
01237 }
01238 
01239 /* Translate internal representation of relocation info to BFD target
01240    format.
01241    FIXME: To what extent can we get all relevant targets to use this?
01242    The above FIXME is from a29k, but I think it is also needed here.    */
01243 
01244 arelent *
01245 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
01246              fixS *fixP)
01247 {
01248   arelent * reloc;
01249 
01250   reloc = xmalloc (sizeof (arelent));
01251   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
01252 
01253   if (reloc->howto == NULL)
01254     {
01255       as_bad_where (fixP->fx_file, fixP->fx_line,
01256                   "internal error: can't export reloc type %d (`%s')",
01257                   fixP->fx_r_type,
01258                   bfd_get_reloc_code_name (fixP->fx_r_type));
01259       return NULL;
01260     }
01261 
01262   assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
01263 
01264   reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
01265   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
01266   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
01267 
01268   if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
01269     reloc->address = fixP->fx_offset;
01270   reloc->addend = 0;
01271 
01272   return reloc;
01273 }
01274 
01275 const pseudo_typeS
01276 dlx_pseudo_table[] =
01277 {
01278   /* Some additional ops that are used by gcc-dlx.  */
01279   {"asciiz", stringer, 1},
01280   {"half", cons, 2},
01281   {"dword", cons, 8},
01282   {"word", cons, 4},
01283   {"proc", s_proc, 0},
01284   {"endproc", s_proc, 1},
01285   {NULL, NULL, 0}
01286 };
01287 
01288 void
01289 dlx_pop_insert (void)
01290 {
01291   pop_insert (dlx_pseudo_table);
01292   return ;
01293 }
01294