1/* tc-dlx.c -- Assemble for the DLX
2   Copyright (C) 2002-2022 Free Software Foundation, Inc.
3
4   This file is part of GAS, the GNU Assembler.
5
6   GAS is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3, or (at your option)
9   any later version.
10
11   GAS is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with GAS; see the file COPYING.  If not, write to the Free
18   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19   02110-1301, USA.  */
20
21/* Initially created by Kuang Hwa Lin, 3/20/2002.  */
22
23#include "as.h"
24#include "safe-ctype.h"
25#include "tc-dlx.h"
26#include "opcode/dlx.h"
27#include "elf/dlx.h"
28#include "bfd/elf32-dlx.h"
29
30/* Make it easier to clone this machine desc into another one.  */
31#define	machine_opcode      dlx_opcode
32#define	machine_opcodes     dlx_opcodes
33#define	machine_ip          dlx_ip
34#define	machine_it          dlx_it
35
36#define NO_RELOC            BFD_RELOC_NONE
37#define RELOC_DLX_REL26     BFD_RELOC_DLX_JMP26
38#define RELOC_DLX_16        BFD_RELOC_16
39#define RELOC_DLX_REL16     BFD_RELOC_16_PCREL_S2
40#define RELOC_DLX_HI16      BFD_RELOC_HI16_S
41#define RELOC_DLX_LO16      BFD_RELOC_LO16
42#define RELOC_DLX_VTINHERIT BFD_RELOC_VTABLE_INHERIT
43#define RELOC_DLX_VTENTRY   BFD_RELOC_VTABLE_ENTRY
44
45/* handle of the OPCODE hash table */
46static htab_t op_hash = NULL;
47
48struct machine_it
49{
50  char *error;
51  unsigned long opcode;
52  struct nlist *nlistp;
53  expressionS exp;
54  int pcrel;
55  int size;
56  int reloc_offset;		/* Offset of reloc within insn.  */
57  bfd_reloc_code_real_type reloc;
58  int HI;
59  int LO;
60}
61the_insn;
62
63/* This array holds the chars that always start a comment.  If the
64   pre-processor is disabled, these aren't very useful.  */
65const char comment_chars[] = ";";
66
67/* This array holds the chars that only start a comment at the beginning of
68   a line.  If the line seems to have the form '# 123 filename'
69   .line and .file directives will appear in the pre-processed output.  */
70/* Note that input_file.c hand checks for '#' at the beginning of the
71   first line of the input file.  This is because the compiler outputs
72   #NO_APP at the beginning of its output.  */
73/* Also note that comments like this one will always work.  */
74const char line_comment_chars[] = "#";
75
76/* We needed an unused char for line separation to work around the
77   lack of macros, using sed and such.  */
78const char line_separator_chars[] = "@";
79
80/* Chars that can be used to separate mant from exp in floating point nums.  */
81const char EXP_CHARS[] = "eE";
82
83/* Chars that mean this number is a floating point constant.
84   As in 0f12.456
85   or    0d1.2345e12.  */
86const char FLT_CHARS[] = "rRsSfFdDxXpP";
87
88static void
89insert_sreg (const char *regname, int regnum)
90{
91  /* Must be large enough to hold the names of the special registers.  */
92  char buf[80];
93  int i;
94
95  symbol_table_insert (symbol_new (regname, reg_section,
96				   &zero_address_frag, regnum));
97  for (i = 0; regname[i]; i++)
98    buf[i] = ISLOWER (regname[i]) ? TOUPPER (regname[i]) : regname[i];
99  buf[i] = '\0';
100
101  symbol_table_insert (symbol_new (buf, reg_section,
102				   &zero_address_frag, regnum));
103}
104
105/* Install symbol definitions for assorted special registers.
106   See MIPS Assembly Language Programmer's Guide page 1-4   */
107
108static void
109define_some_regs (void)
110{
111  /* Software representation.  */
112  insert_sreg ("zero",  0);
113  insert_sreg ("at",    1);
114  insert_sreg ("v0",    2);
115  insert_sreg ("v1",    3);
116  insert_sreg ("a0",    4);
117  insert_sreg ("a1",    5);
118  insert_sreg ("a2",    6);
119  insert_sreg ("a3",    7);
120  insert_sreg ("t0",    8);
121  insert_sreg ("t1",    9);
122  insert_sreg ("t2",    10);
123  insert_sreg ("t3",    11);
124  insert_sreg ("t4",    12);
125  insert_sreg ("t5",    13);
126  insert_sreg ("t6",    14);
127  insert_sreg ("t7",    15);
128  insert_sreg ("s0",    16);
129  insert_sreg ("s1",    17);
130  insert_sreg ("s2",    18);
131  insert_sreg ("s3",    19);
132  insert_sreg ("s4",    20);
133  insert_sreg ("s5",    21);
134  insert_sreg ("s6",    22);
135  insert_sreg ("s7",    23);
136  insert_sreg ("t8",    24);
137  insert_sreg ("t9",    25);
138  insert_sreg ("k0",    26);
139  insert_sreg ("k1",    27);
140  insert_sreg ("gp",    28);
141  insert_sreg ("sp",    29);
142  insert_sreg ("fp",    30);
143  insert_sreg ("ra",    31);
144  /* Special registers.  */
145  insert_sreg ("pc",    0);
146  insert_sreg ("npc",   1);
147  insert_sreg ("iad",   2);
148}
149
150/* Subroutine check the string to match an register.  */
151
152static int
153match_sft_register (char *name)
154{
155#define MAX_REG_NO  35
156/* Currently we have 35 software registers defined -
157   we borrowed from MIPS.   */
158  static const char *soft_reg[] =
159    {
160      "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
161      "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9",
162      "s0", "s1", "s2", "s3", "s4", "s5", "s7", "k0", "k1",
163      "gp", "sp", "fp", "ra", "pc", "npc", "iad",
164      "EndofTab"  /* End of the Table indicator */
165    };
166  char low_name[21], *ptr;
167  int idx;
168
169  for (ptr = name,idx = 0; *ptr != '\0'; ptr++)
170    low_name[idx++] = TOLOWER (*ptr);
171
172  low_name[idx] = '\0';
173  idx = 0;
174
175  while (idx < MAX_REG_NO && strcmp (soft_reg[idx], & low_name [0]))
176    idx += 1;
177
178  return idx < MAX_REG_NO;
179}
180
181/* Subroutine check the string to match an register.  */
182
183static int
184is_ldst_registers (char *name)
185{
186  char *ptr = name;
187
188  /* The first character of the register name got to be either %, $, r of R.  */
189  if ((ptr[0] == '%' || ptr[0] == '$' || ptr[0] == 'r' || ptr[0] == 'R')
190      && ISDIGIT ((unsigned char) ptr[1]))
191    return 1;
192
193  /* Now check the software register representation.  */
194  return match_sft_register (ptr);
195}
196
197/* Subroutine of s_proc so targets can choose a different default prefix.
198   If DEFAULT_PREFIX is NULL, use the target's "leading char".  */
199
200static void
201s_proc (int end_p)
202{
203  /* Record the current function so that we can issue an error message for
204     misplaced .func,.endfunc, and also so that .endfunc needs no
205     arguments.  */
206  static char *current_name;
207  static char *current_label;
208
209  if (end_p)
210    {
211      if (current_name == NULL)
212	{
213	  as_bad (_("missing .proc"));
214	  ignore_rest_of_line ();
215	  return;
216	}
217
218      current_name = current_label = NULL;
219      SKIP_WHITESPACE ();
220      while (!is_end_of_line[(unsigned char) *input_line_pointer])
221        input_line_pointer++;
222    }
223  else
224    {
225      char *name, *label;
226      char delim1, delim2;
227
228      if (current_name != NULL)
229	{
230	  as_bad (_(".endfunc missing for previous .proc"));
231	  ignore_rest_of_line ();
232	  return;
233	}
234
235      delim1 = get_symbol_name (&name);
236      name = xstrdup (name);
237      *input_line_pointer = delim1;
238      SKIP_WHITESPACE_AFTER_NAME ();
239
240      if (*input_line_pointer != ',')
241	{
242	  char leading_char = 0;
243
244	  leading_char = bfd_get_symbol_leading_char (stdoutput);
245	  /* Missing entry point, use function's name with the leading
246	     char prepended.  */
247	  if (leading_char)
248	    {
249	      unsigned len = strlen (name) + 1;
250	      label = XNEWVEC (char, len + 1);
251	      label[0] = leading_char;
252	      memcpy (label + 1, name, len);
253	    }
254	  else
255	    label = name;
256	}
257      else
258	{
259	  ++input_line_pointer;
260	  SKIP_WHITESPACE ();
261	  delim2 = get_symbol_name (&label);
262	  label = xstrdup (label);
263	  (void) restore_line_pointer (delim2);
264	}
265
266      current_name = name;
267      current_label = label;
268    }
269  demand_empty_rest_of_line ();
270}
271
272/* This function is called once, at assembler startup time.  It should
273   set up all the tables, etc., that the MD part of the assembler will
274   need.  */
275
276void
277md_begin (void)
278{
279  unsigned int i;
280
281  /* Create a new hash table.  */
282  op_hash = str_htab_create ();
283
284  /* Hash up all the opcodes for fast use later.  */
285  for (i = 0; i < num_dlx_opcodes; i++)
286    {
287      const char *name = machine_opcodes[i].name;
288      if (str_hash_insert (op_hash, name, &machine_opcodes[i], 0) != NULL)
289	as_fatal (_("duplicate %s"), name);
290    }
291
292  define_some_regs ();
293}
294
295/* This function will check the opcode and return 1 if the opcode is one
296   of the load/store instruction, and it will fix the operand string to
297   the standard form so we can use the standard parse_operand routine.  */
298
299#define READ_OP     0x100
300#define WRITE_OP    0x200
301static char iBuf[81];
302
303static char *
304dlx_parse_loadop (char * str)
305{
306  char *ptr = str;
307  int   idx = 0;
308
309  /* The last pair of ()/[] is the register, all other are the
310     reloc displacement, and if there is a register then it ought
311     to have a pair of ()/[]
312     This is not necessarily true, what if the load instruction come
313     without the register and with %hi/%lo modifier?  */
314  for (idx = 0; idx < 72 && ptr[idx] != '\0'; idx++)
315    ;
316
317  if (idx == 72)
318    {
319    badoperand_load:
320      as_bad (_("Bad operand for a load instruction: <%s>"), str);
321      return NULL;
322    }
323  else
324    {
325      int i, pb = 0;
326      int m2 = 0;
327      char rs1[7], rd[7], endm, match = '0';
328      char imm[72];
329
330      idx -= 1;
331      switch (str[idx])
332	{
333	case ')':
334	  match = '(';
335	  endm  = ')';
336	  break;
337	case ']':
338	  match = '[';
339	  endm  = ']';
340	  break;
341	default:
342	  /* No register indicated, fill in zero.  */
343	  rs1[0] = 'r';
344	  rs1[1] = '0';
345	  rs1[2] = '\0';
346	  match  = 0;
347	  endm = 0;
348	  m2 = 1;
349	}
350
351      if (!m2)
352	{
353	  /* Searching for (/[ which will match the ]/).  */
354	  for (pb = idx - 1; str[pb] != match; pb -= 1)
355	    /* Match can only be either '[' or '(', if it is
356	       '(' then this can be a normal expression, we'll treat
357	       it as an operand.  */
358	    if (str[pb] == endm || pb < (idx - 5))
359	      goto load_no_rs1;
360	  pb += 1;
361
362	  for (i = 0; (pb + i) < idx; i++)
363	    rs1[i] = str[pb+i];
364
365	  rs1[i] = '\0';
366
367	  if (is_ldst_registers (& rs1[0]))
368	    /* Point to the last character of the imm.  */
369	    pb -= 1;
370	  else
371	    {
372	    load_no_rs1:
373	      if (match == '[')
374		goto badoperand_load;
375	      /* No register indicated, fill in zero and restore the imm.  */
376	      rs1[0] = 'r';
377	      rs1[1] = '0';
378	      rs1[2] = '\0';
379	      m2 = 1;
380	    }
381	}
382
383      /* Duplicate the first register.  */
384      for (i = 0; i < 7 && str[i] != ','; i++)
385	rd[i] = ptr[i];
386
387      if (str[i] != ',')
388	goto badoperand_load;
389      else
390	rd[i] = '\0';
391
392      /* Copy the immd.  */
393      if (m2)
394	/* Put the '\0' back in.  */
395	pb = idx + 1;
396
397      for (i++, m2 = 0; i < pb; m2++,i++)
398	imm[m2] = ptr[i];
399
400      imm[m2] = '\0';
401
402      /* Assemble the instruction to gas internal format.  */
403      for (i = 0; rd[i] != '\0'; i++)
404	iBuf[i] = rd[i];
405
406      iBuf[i++] = ',';
407
408      for (pb = 0 ; rs1[pb] != '\0'; i++, pb++)
409	iBuf[i] = rs1[pb];
410
411      iBuf[i++] = ',';
412
413      for (pb = 0; imm[pb] != '\0'; i++, pb++)
414	iBuf[i] = imm[pb];
415
416      iBuf[i] = '\0';
417      return iBuf;
418    }
419}
420
421static char *
422dlx_parse_storeop (char * str)
423{
424  char *ptr = str;
425  int   idx = 0;
426
427  /* Search for the ','.  */
428  for (idx = 0; idx < 72 && ptr[idx] != ','; idx++)
429    ;
430
431  if (idx == 72)
432    {
433    badoperand_store:
434      as_bad (_("Bad operand for a store instruction: <%s>"), str);
435      return NULL;
436    }
437  else
438    {
439      /* idx now points to the ','.  */
440      int i, pb = 0;
441      int comma = idx;
442      int m2 = 0;
443      char rs1[7], rd[7], endm, match = '0';
444      char imm[72];
445
446      /* Now parse the '(' and ')', and make idx point to ')'.  */
447      idx -= 1;
448      switch (str[idx])
449	{
450	case ')':
451	  match = '(';
452	  endm  = ')';
453	  break;
454	case ']':
455	  match = '[';
456	  endm  = ']';
457	  break;
458	default:
459	  /* No register indicated, fill in zero.  */
460	  rs1[0] = 'r';
461	  rs1[1] = '0';
462	  rs1[2] = '\0';
463	  match  = 0;
464	  endm = 0;
465	  m2 = 1;
466	}
467
468      if (!m2)
469	{
470	  /* Searching for (/[ which will match the ]/).  */
471	  for (pb = idx - 1; str[pb] != match; pb -= 1)
472	    if (pb < (idx - 5) || str[pb] == endm)
473	      goto store_no_rs1;
474	  pb += 1;
475
476	  for (i = 0; (pb + i) < idx; i++)
477	    rs1[i] = str[pb + i];
478
479	  rs1[i] = '\0';
480
481	  if (is_ldst_registers (& rs1[0]))
482	    /* Point to the last character of the imm.  */
483	    pb -= 1;
484	  else
485	    {
486	    store_no_rs1:
487	      if (match == '[')
488		goto badoperand_store;
489
490	      /* No register indicated, fill in zero and restore the imm.  */
491	      rs1[0] = 'r';
492	      rs1[1] = '0';
493	      rs1[2] = '\0';
494	      pb = comma;
495	    }
496	}
497      else
498	/* No register was specified.  */
499	pb = comma;
500
501      /* Duplicate the first register.  */
502      for (i = comma + 1; (str[i] == ' ' || str[i] == '\t'); i++)
503	;
504
505      for (m2 = 0; (m2 < 7 && str[i] != '\0'); i++, m2++)
506	{
507	  if (str[i] != ' ' && str[i] != '\t')
508	    rd[m2] = str[i];
509	  else
510	    goto badoperand_store;
511	}
512
513      if (str[i] != '\0')
514	goto badoperand_store;
515      else
516	rd[m2] = '\0';
517
518      /* Copy the immd.  */
519      for (i = 0; i < pb; i++)
520	imm[i] = ptr[i];
521
522      imm[i] = '\0';
523
524      /* Assemble the instruction to gas internal format.  */
525      for (i = 0; rd[i] != '\0'; i++)
526	iBuf[i] = rd[i];
527      iBuf[i++] = ',';
528      for (pb = 0 ; rs1[pb] != '\0'; i++, pb++)
529	iBuf[i] = rs1[pb];
530      iBuf[i++] = ',';
531      for (pb = 0; imm[pb] != '\0'; i++, pb++)
532	iBuf[i] = imm[pb];
533      iBuf[i] = '\0';
534      return iBuf;
535    }
536}
537
538static char *
539fix_ld_st_operand (unsigned long opcode, char* str)
540{
541  /* Check the opcode.  */
542  switch ((int) opcode)
543    {
544    case  LBOP:
545    case  LBUOP:
546    case  LSBUOP:
547    case  LHOP:
548    case  LHUOP:
549    case  LSHUOP:
550    case  LWOP:
551    case  LSWOP:
552      return dlx_parse_loadop (str);
553    case  SBOP:
554    case  SHOP:
555    case  SWOP:
556      return dlx_parse_storeop (str);
557    default:
558      return str;
559    }
560}
561
562static int
563hilo_modifier_ok (char *s)
564{
565  char *ptr = s;
566  int   idx, count = 1;
567
568  if (*ptr != '(')
569    return 1;
570
571  for (idx = 1; ptr[idx] != '\0' && ptr[idx] != '[' && idx < 73; idx += 1)
572    {
573      if (count == 0)
574	return count;
575
576      if (ptr[idx] == '(')
577	count += 1;
578
579      if (ptr[idx] == ')')
580	count -= 1;
581    }
582
583  return (count == 0) ? 1:0;
584}
585
586static char *
587parse_operand (char *s, expressionS *operandp)
588{
589  char *save = input_line_pointer;
590  char *new_pos;
591
592  the_insn.HI = the_insn.LO = 0;
593
594  /* Search for %hi and %lo, make a mark and skip it.  */
595  if (startswith (s, "%hi"))
596    {
597      s += 3;
598      the_insn.HI = 1;
599    }
600  else
601    {
602      if (startswith (s, "%lo"))
603	{
604	  s += 3;
605	  the_insn.LO = 1;
606	}
607      else
608	the_insn.LO = 0;
609    }
610
611  if (the_insn.HI || the_insn.LO)
612    {
613      if (!hilo_modifier_ok (s))
614	as_bad (_("Expression Error for operand modifier %%hi/%%lo\n"));
615    }
616
617  /* Check for the % and $ register representation    */
618  if ((s[0] == '%' || s[0] == '$' || s[0] == 'r' || s[0] == 'R')
619      && ISDIGIT ((unsigned char) s[1]))
620    {
621      /* We have a numeric register expression.  No biggy.  */
622      s += 1;
623      input_line_pointer = s;
624      (void) expression (operandp);
625      if (operandp->X_op != O_constant
626	  || operandp->X_add_number > 31)
627	as_bad (_("Invalid expression after %%%%\n"));
628      operandp->X_op = O_register;
629    }
630  else
631    {
632      /* Normal operand parsing.  */
633      input_line_pointer = s;
634      (void) expression (operandp);
635    }
636
637  new_pos = input_line_pointer;
638  input_line_pointer = save;
639  return new_pos;
640}
641
642/* Instruction parsing.  Takes a string containing the opcode.
643   Operands are at input_line_pointer.  Output is in the_insn.
644   Warnings or errors are generated.  */
645
646static void
647machine_ip (char *str)
648{
649  char *s;
650  const char *args;
651  struct machine_opcode *insn;
652  unsigned long opcode;
653  expressionS the_operand;
654  expressionS *operand = &the_operand;
655  unsigned int reg, reg_shift = 0;
656
657  memset (&the_insn, '\0', sizeof (the_insn));
658  the_insn.reloc = NO_RELOC;
659
660  /* Fixup the opcode string to all lower cases, and also
661     allow numerical digits.  */
662  s = str;
663
664  if (ISALPHA (*s))
665    for (; ISALNUM (*s); ++s)
666      if (ISUPPER (*s))
667	*s = TOLOWER (*s);
668
669  switch (*s)
670    {
671    case '\0':
672      break;
673
674      /* FIXME-SOMEDAY more whitespace.  */
675    case ' ':
676      *s++ = '\0';
677      break;
678
679    default:
680      as_bad (_("Unknown opcode: `%s'"), str);
681      return;
682    }
683
684  /* Hash the opcode, insn will have the string from opcode table.  */
685  if ((insn = (struct machine_opcode *) str_hash_find (op_hash, str)) == NULL)
686    {
687      /* Handle the ret and return macro here.  */
688      if ((strcmp (str, "ret") == 0) || (strcmp (str, "return") == 0))
689	the_insn.opcode = JROP | 0x03e00000;    /* 0x03e00000 = r31 << 21 */
690      else
691	as_bad (_("Unknown opcode `%s'."), str);
692
693      return;
694    }
695
696  opcode = insn->opcode;
697
698  /* Set the sip reloc HI16 flag.  */
699  if (!set_dlx_skip_hi16_flag (1))
700    as_bad (_("Can not set dlx_skip_hi16_flag"));
701
702  /* Fix the operand string if it is one of load store instructions.  */
703  s = fix_ld_st_operand (opcode, s);
704
705  /* Build the opcode, checking as we go to make sure that the
706     operands match.
707     If an operand matches, we modify the_insn or opcode appropriately,
708     and do a "continue".  If an operand fails to match, we "break".  */
709  if (insn->args[0] != '\0' && insn->args[0] != 'N')
710    {
711      /* Prime the pump.  */
712      if (*s == '\0')
713	{
714	  as_bad (_("Missing arguments for opcode <%s>."), str);
715	  return;
716	}
717      else
718	s = parse_operand (s, operand);
719    }
720  else if (insn->args[0] == 'N')
721    {
722      /* Clean up the insn and done!  */
723      the_insn.opcode = opcode;
724      return;
725    }
726
727  /* Parse through the args (this is from opcode table), *s point to
728     the current character of the instruction stream.  */
729  for (args = insn->args;; ++args)
730    {
731      switch (*args)
732	{
733	  /* End of Line.  */
734	case '\0':
735	  /* End of args.  */
736	  if (*s == '\0')
737	    {
738	      /* We are truly done.  */
739	      the_insn.opcode = opcode;
740	      /* Clean up the HI and LO mark.  */
741	      the_insn.HI = 0;
742	      the_insn.LO = 0;
743	      return;
744	    }
745
746	  the_insn.HI = 0;
747	  the_insn.LO = 0;
748	  as_bad (_("Too many operands: %s"), s);
749	  break;
750
751	  /* ',' Args separator */
752	case ',':
753	  /* Must match a comma.  */
754	  if (*s++ == ',')
755	    {
756	      /* Parse next operand.  */
757	      s = parse_operand (s, operand);
758	      continue;
759	    }
760	  break;
761
762	  /* It can be a 'a' register or 'i' operand.  */
763	case 'P':
764	  /* Macro move operand/reg.  */
765	  if (operand->X_op == O_register)
766	    {
767	      /* It's a register.  */
768	      reg_shift = 21;
769	      goto general_reg;
770	    }
771	  /* Fall through.  */
772
773	  /* The immediate 16 bits literal, bit 0-15.  */
774	case 'i':
775	  /* offset, unsigned.  */
776	case 'I':
777	  /* offset, signed.  */
778	  if (operand->X_op == O_constant)
779	    {
780	      if (the_insn.HI)
781		operand->X_add_number >>= 16;
782
783	      opcode |= operand->X_add_number & 0xFFFF;
784
785	      if (the_insn.HI && the_insn.LO)
786		as_bad (_("Both the_insn.HI and the_insn.LO are set : %s"), s);
787	      else
788		{
789		  the_insn.HI = 0;
790		  the_insn.LO = 0;
791		}
792	      continue;
793	    }
794
795	  the_insn.reloc        = (the_insn.HI) ? RELOC_DLX_HI16
796	    : (the_insn.LO ? RELOC_DLX_LO16 : RELOC_DLX_16);
797	  the_insn.reloc_offset = 2;
798	  the_insn.size         = 2;
799	  the_insn.pcrel        = 0;
800	  the_insn.exp          = * operand;
801	  the_insn.HI           = 0;
802	  the_insn.LO           = 0;
803	  continue;
804
805	case 'd':
806	  /* offset, signed.  */
807	  if (operand->X_op == O_constant)
808	    {
809	      opcode |= operand->X_add_number & 0xFFFF;
810	      continue;
811	    }
812	  the_insn.reloc        = RELOC_DLX_REL16;
813	  the_insn.reloc_offset = 0;    /* BIG-ENDIAN Byte 3 of insn.  */
814	  the_insn.size         = 4;
815	  the_insn.pcrel        = 1;
816	  the_insn.exp          = *operand;
817	  continue;
818
819	  /* The immediate 26 bits literal, bit 0-25.  */
820	case 'D':
821	  /* offset, signed.  */
822	  if (operand->X_op == O_constant)
823	    {
824	      opcode |= operand->X_add_number & 0x3FFFFFF;
825	      continue;
826	    }
827	  the_insn.reloc = RELOC_DLX_REL26;
828	  the_insn.reloc_offset = 0;    /* BIG-ENDIAN Byte 3 of insn.  */
829	  the_insn.size  = 4;
830	  the_insn.pcrel = 1;
831	  the_insn.exp = *operand;
832	  continue;
833
834	  /* Type 'a' Register.  */
835	case 'a':
836	  /* A general register at bits 21-25, rs1.  */
837	  reg_shift = 21;
838	  goto general_reg;
839
840	  /* Type 'b' Register.  */
841	case 'b':
842	  /* A general register at bits 16-20, rs2/rd.  */
843	  reg_shift = 16;
844	  goto general_reg;
845
846	  /* Type 'c' Register.  */
847	case 'c':
848	  /* A general register at bits 11-15, rd.  */
849	  reg_shift = 11;
850
851	general_reg:
852	  know (operand->X_add_symbol == 0);
853	  know (operand->X_op_symbol == 0);
854	  reg = operand->X_add_number;
855	  if (reg & 0xffffffe0)
856	    as_fatal (_("failed regnum sanity check."));
857	  else
858	    /* Got the register, now figure out where it goes in the opcode.  */
859	    opcode |= reg << reg_shift;
860
861	  switch (*args)
862	    {
863	    case 'a':
864	    case 'b':
865	    case 'c':
866	    case 'P':
867	      continue;
868	    }
869	  as_fatal (_("failed general register sanity check."));
870	  break;
871
872	default:
873	  BAD_CASE (*args);
874	}
875
876      /* Types or values of args don't match.  */
877      as_bad (_("Invalid operands"));
878      return;
879    }
880}
881
882/* Assemble a single instruction.  Its label has already been handled
883   by the generic front end.  We just parse opcode and operands, and
884   produce the bytes of data and relocation.  */
885
886void
887md_assemble (char *str)
888{
889  char *toP;
890  fixS *fixP;
891  bit_fixS *bitP;
892
893  know (str);
894  machine_ip (str);
895  toP = frag_more (4);
896  dwarf2_emit_insn (4);
897
898  /* Put out the opcode.  */
899  md_number_to_chars (toP, the_insn.opcode, 4);
900
901  /* Put out the symbol-dependent stuff.  */
902  if (the_insn.reloc != NO_RELOC)
903    {
904      fixP = fix_new_exp (frag_now,
905			  (toP - frag_now->fr_literal + the_insn.reloc_offset),
906			  the_insn.size, & the_insn.exp, the_insn.pcrel,
907			  the_insn.reloc);
908
909      /* Turn off complaints that the addend is
910	 too large for things like foo+100000@ha.  */
911      switch (the_insn.reloc)
912	{
913	case RELOC_DLX_HI16:
914	case RELOC_DLX_LO16:
915	  fixP->fx_no_overflow = 1;
916	  break;
917	default:
918	  break;
919	}
920
921      switch (fixP->fx_r_type)
922	{
923	case RELOC_DLX_REL26:
924	  bitP = XNEW (bit_fixS);
925	  bitP->fx_bit_size = 26;
926	  bitP->fx_bit_offset = 25;
927	  bitP->fx_bit_base = the_insn.opcode & 0xFC000000;
928	  bitP->fx_bit_base_adj = 0;
929	  bitP->fx_bit_max = 0;
930	  bitP->fx_bit_min = 0;
931	  bitP->fx_bit_add = 0x03FFFFFF;
932	  fixP->fx_bit_fixP = bitP;
933	  break;
934	case RELOC_DLX_LO16:
935	case RELOC_DLX_REL16:
936	  bitP = XNEW (bit_fixS);
937	  bitP->fx_bit_size = 16;
938	  bitP->fx_bit_offset = 15;
939	  bitP->fx_bit_base = the_insn.opcode & 0xFFFF0000;
940	  bitP->fx_bit_base_adj = 0;
941	  bitP->fx_bit_max = 0;
942	  bitP->fx_bit_min = 0;
943	  bitP->fx_bit_add = 0x0000FFFF;
944	  fixP->fx_bit_fixP = bitP;
945	  break;
946	case RELOC_DLX_HI16:
947	  bitP = XNEW (bit_fixS);
948	  bitP->fx_bit_size = 16;
949	  bitP->fx_bit_offset = 15;
950	  bitP->fx_bit_base = the_insn.opcode & 0xFFFF0000;
951	  bitP->fx_bit_base_adj = 0;
952	  bitP->fx_bit_max = 0;
953	  bitP->fx_bit_min = 0;
954	  bitP->fx_bit_add = 0x0000FFFF;
955	  fixP->fx_bit_fixP = bitP;
956	  break;
957	default:
958	  fixP->fx_bit_fixP = NULL;
959	  break;
960	}
961    }
962}
963
964/* This is identical to the md_atof in m68k.c.  I think this is right,
965   but I'm not sure.  Dlx will not use it anyway, so I just leave it
966   here for now.  */
967
968const char *
969md_atof (int type, char *litP, int *sizeP)
970{
971  return ieee_md_atof (type, litP, sizeP, true);
972}
973
974/* Write out big-endian.  */
975void
976md_number_to_chars (char *buf, valueT val, int n)
977{
978  number_to_chars_bigendian (buf, val, n);
979}
980
981bool
982md_dlx_fix_adjustable (fixS *fixP)
983{
984  /* We need the symbol name for the VTABLE entries.  */
985  return (fixP->fx_r_type != BFD_RELOC_VTABLE_INHERIT
986          && fixP->fx_r_type != BFD_RELOC_VTABLE_ENTRY);
987}
988
989void
990md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
991{
992  long val = *valP;
993  char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
994
995  switch (fixP->fx_r_type)
996    {
997    case RELOC_DLX_LO16:
998    case RELOC_DLX_REL16:
999      if (fixP->fx_bit_fixP != NULL)
1000	{
1001	  val = (val & 0x0000FFFF) | fixP->fx_bit_fixP->fx_bit_base;
1002	  free (fixP->fx_bit_fixP);
1003	  fixP->fx_bit_fixP = NULL;
1004	}
1005      break;
1006
1007    case RELOC_DLX_HI16:
1008      if (fixP->fx_bit_fixP != NULL)
1009	{
1010	  val = (val >> 16) | fixP->fx_bit_fixP->fx_bit_base;
1011	  free (fixP->fx_bit_fixP);
1012	  fixP->fx_bit_fixP = NULL;
1013	}
1014      break;
1015
1016    case RELOC_DLX_REL26:
1017      if (fixP->fx_bit_fixP != NULL)
1018	{
1019	  val = (val & 0x03FFFFFF) | fixP->fx_bit_fixP->fx_bit_base;
1020	  free (fixP->fx_bit_fixP);
1021	  fixP->fx_bit_fixP = NULL;
1022	}
1023      break;
1024
1025    case BFD_RELOC_VTABLE_INHERIT:
1026      /* This borrowed from tc-ppc.c on a whim.  */
1027      fixP->fx_done = 0;
1028      if (fixP->fx_addsy
1029	  && !S_IS_DEFINED (fixP->fx_addsy)
1030	  && !S_IS_WEAK (fixP->fx_addsy))
1031	S_SET_WEAK (fixP->fx_addsy);
1032      return;
1033
1034    case BFD_RELOC_VTABLE_ENTRY:
1035      fixP->fx_done = 0;
1036      return;
1037
1038    default:
1039      break;
1040    }
1041
1042  number_to_chars_bigendian (place, val, fixP->fx_size);
1043  if (fixP->fx_addsy == NULL)
1044    fixP->fx_done = 1;
1045  if (fixP->fx_bit_fixP != NULL)
1046    fixP->fx_no_overflow = 1;
1047}
1048
1049const char *md_shortopts = "";
1050
1051struct option md_longopts[] =
1052  {
1053    {NULL, no_argument, NULL, 0}
1054  };
1055
1056size_t md_longopts_size = sizeof (md_longopts);
1057
1058int
1059md_parse_option (int c     ATTRIBUTE_UNUSED,
1060		 const char *arg ATTRIBUTE_UNUSED)
1061{
1062  return 0;
1063}
1064
1065void
1066md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
1067{
1068}
1069
1070/* This is called when a line is unrecognized.  */
1071
1072int
1073dlx_unrecognized_line (int c)
1074{
1075  int lab;
1076  char *s;
1077
1078  if (c != '$' || ! ISDIGIT ((unsigned char) input_line_pointer[0]))
1079    return 0;
1080
1081  s = input_line_pointer;
1082
1083  lab = 0;
1084  while (ISDIGIT ((unsigned char) *s))
1085    {
1086      lab = lab * 10 + *s - '0';
1087      ++s;
1088    }
1089
1090  if (*s != ':')
1091    /* Not a label definition.  */
1092    return 0;
1093
1094  if (dollar_label_defined (lab))
1095    {
1096      as_bad (_("label \"$%d\" redefined"), lab);
1097      return 0;
1098    }
1099
1100  define_dollar_label (lab);
1101  colon (dollar_label_name (lab, 0));
1102  input_line_pointer = s + 1;
1103
1104  return 1;
1105}
1106
1107/* Default the values of symbols known that should be "predefined".  We
1108   don't bother to predefine them unless you actually use one, since there
1109   are a lot of them.  */
1110
1111symbolS *
1112md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
1113{
1114  return NULL;
1115}
1116
1117/* Parse an operand that is machine-specific, the function was called
1118   in expr.c by operand() function, when everything failed before it
1119   call a quit.  */
1120
1121void
1122md_operand (expressionS* expressionP)
1123{
1124  /* Check for the #number representation    */
1125  if (input_line_pointer[0] == '#' &&
1126      ISDIGIT ((unsigned char) input_line_pointer[1]))
1127    {
1128      /* We have a numeric number expression.  No biggy.  */
1129      input_line_pointer += 1;	/* Skip # */
1130
1131      (void) expression (expressionP);
1132
1133      if (expressionP->X_op != O_constant)
1134	as_bad (_("Invalid expression after # number\n"));
1135    }
1136
1137  return;
1138}
1139
1140/* Round up a section size to the appropriate boundary.  */
1141
1142valueT
1143md_section_align (segT segment ATTRIBUTE_UNUSED,
1144		  valueT size)
1145{
1146  /* Byte alignment is fine.  */
1147  return size;
1148}
1149
1150/* Exactly what point is a PC-relative offset relative TO?
1151   On the 29000, they're relative to the address of the instruction,
1152   which we have set up as the address of the fixup too.  */
1153
1154long
1155md_pcrel_from (fixS* fixP)
1156{
1157  return 4 + fixP->fx_where + fixP->fx_frag->fr_address;
1158}
1159
1160/* Translate internal representation of relocation info to BFD target
1161   format.
1162   FIXME: To what extent can we get all relevant targets to use this?
1163   The above FIXME is from a29k, but I think it is also needed here.    */
1164
1165arelent *
1166tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
1167	      fixS *fixP)
1168{
1169  arelent * reloc;
1170
1171  reloc = XNEW (arelent);
1172  reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
1173
1174  if (reloc->howto == NULL)
1175    {
1176      as_bad_where (fixP->fx_file, fixP->fx_line,
1177		    _("internal error: can't export reloc type %d (`%s')"),
1178		    fixP->fx_r_type,
1179		    bfd_get_reloc_code_name (fixP->fx_r_type));
1180      return NULL;
1181    }
1182
1183  gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
1184
1185  reloc->sym_ptr_ptr = XNEW (asymbol *);
1186  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
1187  reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
1188
1189  if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
1190    reloc->address = fixP->fx_offset;
1191  reloc->addend = 0;
1192
1193  return reloc;
1194}
1195
1196const pseudo_typeS
1197dlx_pseudo_table[] =
1198{
1199  /* Some additional ops that are used by gcc-dlx.  */
1200  {"asciiz", stringer, 8 + 1},
1201  {"half", cons, 2},
1202  {"dword", cons, 8},
1203  {"word", cons, 4},
1204  {"proc", s_proc, 0},
1205  {"endproc", s_proc, 1},
1206  {NULL, NULL, 0}
1207};
1208
1209void
1210dlx_pop_insert (void)
1211{
1212  pop_insert (dlx_pseudo_table);
1213  return ;
1214}
1215