xref: /netbsd-src/external/gpl3/binutils/dist/gas/config/tc-dlx.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* tc-dlx.c -- Assemble for the DLX
2    Copyright (C) 2002-2024 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 */
46 static htab_t op_hash = NULL;
47 
48 struct 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 }
61 the_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.  */
65 const 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.  */
74 const 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.  */
78 const char line_separator_chars[] = "@";
79 
80 /* Chars that can be used to separate mant from exp in floating point nums.  */
81 const 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.  */
86 const char FLT_CHARS[] = "rRsSfFdDxXpP";
87 
88 static void
insert_sreg(const char * regname,int regnum)89 insert_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 
108 static void
define_some_regs(void)109 define_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 
152 static int
match_sft_register(char * name)153 match_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 
183 static int
is_ldst_registers(char * name)184 is_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 
200 static void
s_proc(int end_p)201 s_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 
276 void
md_begin(void)277 md_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
301 static char iBuf[81];
302 
303 static char *
dlx_parse_loadop(char * str)304 dlx_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 
421 static char *
dlx_parse_storeop(char * str)422 dlx_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 
538 static char *
fix_ld_st_operand(unsigned long opcode,char * str)539 fix_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 
562 static int
hilo_modifier_ok(char * s)563 hilo_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 
586 static char *
parse_operand(char * s,expressionS * operandp)587 parse_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       resolve_register (operandp);
636     }
637 
638   new_pos = input_line_pointer;
639   input_line_pointer = save;
640   return new_pos;
641 }
642 
643 /* Instruction parsing.  Takes a string containing the opcode.
644    Operands are at input_line_pointer.  Output is in the_insn.
645    Warnings or errors are generated.  */
646 
647 static void
machine_ip(char * str)648 machine_ip (char *str)
649 {
650   char *s;
651   const char *args;
652   struct machine_opcode *insn;
653   unsigned long opcode;
654   expressionS the_operand;
655   expressionS *operand = &the_operand;
656   unsigned int reg, reg_shift = 0;
657 
658   memset (&the_insn, '\0', sizeof (the_insn));
659   the_insn.reloc = NO_RELOC;
660 
661   /* Fixup the opcode string to all lower cases, and also
662      allow numerical digits.  */
663   s = str;
664 
665   if (ISALPHA (*s))
666     for (; ISALNUM (*s); ++s)
667       if (ISUPPER (*s))
668 	*s = TOLOWER (*s);
669 
670   switch (*s)
671     {
672     case '\0':
673       break;
674 
675       /* FIXME-SOMEDAY more whitespace.  */
676     case ' ':
677       *s++ = '\0';
678       break;
679 
680     default:
681       as_bad (_("Unknown opcode: `%s'"), str);
682       return;
683     }
684 
685   /* Hash the opcode, insn will have the string from opcode table.  */
686   if ((insn = (struct machine_opcode *) str_hash_find (op_hash, str)) == NULL)
687     {
688       /* Handle the ret and return macro here.  */
689       if ((strcmp (str, "ret") == 0) || (strcmp (str, "return") == 0))
690 	the_insn.opcode = JROP | 0x03e00000;    /* 0x03e00000 = r31 << 21 */
691       else
692 	as_bad (_("Unknown opcode `%s'."), str);
693 
694       return;
695     }
696 
697   opcode = insn->opcode;
698 
699   /* Set the sip reloc HI16 flag.  */
700   if (!set_dlx_skip_hi16_flag (1))
701     as_bad (_("Can not set dlx_skip_hi16_flag"));
702 
703   /* Fix the operand string if it is one of load store instructions.  */
704   s = fix_ld_st_operand (opcode, s);
705 
706   /* Build the opcode, checking as we go to make sure that the
707      operands match.
708      If an operand matches, we modify the_insn or opcode appropriately,
709      and do a "continue".  If an operand fails to match, we "break".  */
710   if (insn->args[0] != '\0' && insn->args[0] != 'N')
711     {
712       /* Prime the pump.  */
713       if (*s == '\0')
714 	{
715 	  as_bad (_("Missing arguments for opcode <%s>."), str);
716 	  return;
717 	}
718       else
719 	s = parse_operand (s, operand);
720     }
721   else if (insn->args[0] == 'N')
722     {
723       /* Clean up the insn and done!  */
724       the_insn.opcode = opcode;
725       return;
726     }
727 
728   /* Parse through the args (this is from opcode table), *s point to
729      the current character of the instruction stream.  */
730   for (args = insn->args;; ++args)
731     {
732       switch (*args)
733 	{
734 	  /* End of Line.  */
735 	case '\0':
736 	  /* End of args.  */
737 	  if (*s == '\0')
738 	    {
739 	      /* We are truly done.  */
740 	      the_insn.opcode = opcode;
741 	      /* Clean up the HI and LO mark.  */
742 	      the_insn.HI = 0;
743 	      the_insn.LO = 0;
744 	      return;
745 	    }
746 
747 	  the_insn.HI = 0;
748 	  the_insn.LO = 0;
749 	  as_bad (_("Too many operands: %s"), s);
750 	  break;
751 
752 	  /* ',' Args separator */
753 	case ',':
754 	  /* Must match a comma.  */
755 	  if (*s++ == ',')
756 	    {
757 	      /* Parse next operand.  */
758 	      s = parse_operand (s, operand);
759 	      continue;
760 	    }
761 	  break;
762 
763 	  /* It can be a 'a' register or 'i' operand.  */
764 	case 'P':
765 	  /* Macro move operand/reg.  */
766 	  if (operand->X_op == O_register)
767 	    {
768 	      /* It's a register.  */
769 	      reg_shift = 21;
770 	      goto general_reg;
771 	    }
772 	  /* Fall through.  */
773 
774 	  /* The immediate 16 bits literal, bit 0-15.  */
775 	case 'i':
776 	  /* offset, unsigned.  */
777 	case 'I':
778 	  /* offset, signed.  */
779 	  if (operand->X_op == O_constant)
780 	    {
781 	      if (the_insn.HI)
782 		operand->X_add_number >>= 16;
783 
784 	      opcode |= operand->X_add_number & 0xFFFF;
785 
786 	      if (the_insn.HI && the_insn.LO)
787 		as_bad (_("Both the_insn.HI and the_insn.LO are set : %s"), s);
788 	      else
789 		{
790 		  the_insn.HI = 0;
791 		  the_insn.LO = 0;
792 		}
793 	      continue;
794 	    }
795 
796 	  the_insn.reloc        = (the_insn.HI) ? RELOC_DLX_HI16
797 	    : (the_insn.LO ? RELOC_DLX_LO16 : RELOC_DLX_16);
798 	  the_insn.reloc_offset = 2;
799 	  the_insn.size         = 2;
800 	  the_insn.pcrel        = 0;
801 	  the_insn.exp          = * operand;
802 	  the_insn.HI           = 0;
803 	  the_insn.LO           = 0;
804 	  continue;
805 
806 	case 'd':
807 	  /* offset, signed.  */
808 	  if (operand->X_op == O_constant)
809 	    {
810 	      opcode |= operand->X_add_number & 0xFFFF;
811 	      continue;
812 	    }
813 	  the_insn.reloc        = RELOC_DLX_REL16;
814 	  the_insn.reloc_offset = 0;    /* BIG-ENDIAN Byte 3 of insn.  */
815 	  the_insn.size         = 4;
816 	  the_insn.pcrel        = 1;
817 	  the_insn.exp          = *operand;
818 	  continue;
819 
820 	  /* The immediate 26 bits literal, bit 0-25.  */
821 	case 'D':
822 	  /* offset, signed.  */
823 	  if (operand->X_op == O_constant)
824 	    {
825 	      opcode |= operand->X_add_number & 0x3FFFFFF;
826 	      continue;
827 	    }
828 	  the_insn.reloc = RELOC_DLX_REL26;
829 	  the_insn.reloc_offset = 0;    /* BIG-ENDIAN Byte 3 of insn.  */
830 	  the_insn.size  = 4;
831 	  the_insn.pcrel = 1;
832 	  the_insn.exp = *operand;
833 	  continue;
834 
835 	  /* Type 'a' Register.  */
836 	case 'a':
837 	  /* A general register at bits 21-25, rs1.  */
838 	  reg_shift = 21;
839 	  goto general_reg;
840 
841 	  /* Type 'b' Register.  */
842 	case 'b':
843 	  /* A general register at bits 16-20, rs2/rd.  */
844 	  reg_shift = 16;
845 	  goto general_reg;
846 
847 	  /* Type 'c' Register.  */
848 	case 'c':
849 	  /* A general register at bits 11-15, rd.  */
850 	  reg_shift = 11;
851 
852 	general_reg:
853 	  know (operand->X_add_symbol == 0);
854 	  know (operand->X_op_symbol == 0);
855 	  reg = operand->X_add_number;
856 	  if (reg & 0xffffffe0)
857 	    as_fatal (_("failed regnum sanity check."));
858 	  else
859 	    /* Got the register, now figure out where it goes in the opcode.  */
860 	    opcode |= reg << reg_shift;
861 
862 	  switch (*args)
863 	    {
864 	    case 'a':
865 	    case 'b':
866 	    case 'c':
867 	    case 'P':
868 	      continue;
869 	    }
870 	  as_fatal (_("failed general register sanity check."));
871 	  break;
872 
873 	default:
874 	  BAD_CASE (*args);
875 	}
876 
877       /* Types or values of args don't match.  */
878       as_bad (_("Invalid operands"));
879       return;
880     }
881 }
882 
883 /* Assemble a single instruction.  Its label has already been handled
884    by the generic front end.  We just parse opcode and operands, and
885    produce the bytes of data and relocation.  */
886 
887 void
md_assemble(char * str)888 md_assemble (char *str)
889 {
890   char *toP;
891   fixS *fixP;
892   bit_fixS *bitP;
893 
894   know (str);
895   machine_ip (str);
896   toP = frag_more (4);
897   dwarf2_emit_insn (4);
898 
899   /* Put out the opcode.  */
900   md_number_to_chars (toP, the_insn.opcode, 4);
901 
902   /* Put out the symbol-dependent stuff.  */
903   if (the_insn.reloc != NO_RELOC)
904     {
905       fixP = fix_new_exp (frag_now,
906 			  (toP - frag_now->fr_literal + the_insn.reloc_offset),
907 			  the_insn.size, & the_insn.exp, the_insn.pcrel,
908 			  the_insn.reloc);
909 
910       /* Turn off complaints that the addend is
911 	 too large for things like foo+100000@ha.  */
912       switch (the_insn.reloc)
913 	{
914 	case RELOC_DLX_HI16:
915 	case RELOC_DLX_LO16:
916 	  fixP->fx_no_overflow = 1;
917 	  break;
918 	default:
919 	  break;
920 	}
921 
922       switch (fixP->fx_r_type)
923 	{
924 	case RELOC_DLX_REL26:
925 	  bitP = XNEW (bit_fixS);
926 	  bitP->fx_bit_size = 26;
927 	  bitP->fx_bit_offset = 25;
928 	  bitP->fx_bit_base = the_insn.opcode & 0xFC000000;
929 	  bitP->fx_bit_base_adj = 0;
930 	  bitP->fx_bit_max = 0;
931 	  bitP->fx_bit_min = 0;
932 	  bitP->fx_bit_add = 0x03FFFFFF;
933 	  fixP->fx_bit_fixP = bitP;
934 	  break;
935 	case RELOC_DLX_LO16:
936 	case RELOC_DLX_REL16:
937 	  bitP = XNEW (bit_fixS);
938 	  bitP->fx_bit_size = 16;
939 	  bitP->fx_bit_offset = 15;
940 	  bitP->fx_bit_base = the_insn.opcode & 0xFFFF0000;
941 	  bitP->fx_bit_base_adj = 0;
942 	  bitP->fx_bit_max = 0;
943 	  bitP->fx_bit_min = 0;
944 	  bitP->fx_bit_add = 0x0000FFFF;
945 	  fixP->fx_bit_fixP = bitP;
946 	  break;
947 	case RELOC_DLX_HI16:
948 	  bitP = XNEW (bit_fixS);
949 	  bitP->fx_bit_size = 16;
950 	  bitP->fx_bit_offset = 15;
951 	  bitP->fx_bit_base = the_insn.opcode & 0xFFFF0000;
952 	  bitP->fx_bit_base_adj = 0;
953 	  bitP->fx_bit_max = 0;
954 	  bitP->fx_bit_min = 0;
955 	  bitP->fx_bit_add = 0x0000FFFF;
956 	  fixP->fx_bit_fixP = bitP;
957 	  break;
958 	default:
959 	  fixP->fx_bit_fixP = NULL;
960 	  break;
961 	}
962     }
963 }
964 
965 /* This is identical to the md_atof in m68k.c.  I think this is right,
966    but I'm not sure.  Dlx will not use it anyway, so I just leave it
967    here for now.  */
968 
969 const char *
md_atof(int type,char * litP,int * sizeP)970 md_atof (int type, char *litP, int *sizeP)
971 {
972   return ieee_md_atof (type, litP, sizeP, true);
973 }
974 
975 /* Write out big-endian.  */
976 void
md_number_to_chars(char * buf,valueT val,int n)977 md_number_to_chars (char *buf, valueT val, int n)
978 {
979   number_to_chars_bigendian (buf, val, n);
980 }
981 
982 bool
md_dlx_fix_adjustable(fixS * fixP)983 md_dlx_fix_adjustable (fixS *fixP)
984 {
985   /* We need the symbol name for the VTABLE entries.  */
986   return (fixP->fx_r_type != BFD_RELOC_VTABLE_INHERIT
987           && fixP->fx_r_type != BFD_RELOC_VTABLE_ENTRY);
988 }
989 
990 void
md_apply_fix(fixS * fixP,valueT * valP,segT seg ATTRIBUTE_UNUSED)991 md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
992 {
993   long val = *valP;
994   char *place = fixP->fx_where + fixP->fx_frag->fr_literal;
995 
996   switch (fixP->fx_r_type)
997     {
998     case RELOC_DLX_LO16:
999     case RELOC_DLX_REL16:
1000       if (fixP->fx_bit_fixP != NULL)
1001 	{
1002 	  val = (val & 0x0000FFFF) | fixP->fx_bit_fixP->fx_bit_base;
1003 	  free (fixP->fx_bit_fixP);
1004 	  fixP->fx_bit_fixP = NULL;
1005 	}
1006       break;
1007 
1008     case RELOC_DLX_HI16:
1009       if (fixP->fx_bit_fixP != NULL)
1010 	{
1011 	  val = (val >> 16) | fixP->fx_bit_fixP->fx_bit_base;
1012 	  free (fixP->fx_bit_fixP);
1013 	  fixP->fx_bit_fixP = NULL;
1014 	}
1015       break;
1016 
1017     case RELOC_DLX_REL26:
1018       if (fixP->fx_bit_fixP != NULL)
1019 	{
1020 	  val = (val & 0x03FFFFFF) | fixP->fx_bit_fixP->fx_bit_base;
1021 	  free (fixP->fx_bit_fixP);
1022 	  fixP->fx_bit_fixP = NULL;
1023 	}
1024       break;
1025 
1026     case BFD_RELOC_VTABLE_INHERIT:
1027       /* This borrowed from tc-ppc.c on a whim.  */
1028       fixP->fx_done = 0;
1029       if (fixP->fx_addsy
1030 	  && !S_IS_DEFINED (fixP->fx_addsy)
1031 	  && !S_IS_WEAK (fixP->fx_addsy))
1032 	S_SET_WEAK (fixP->fx_addsy);
1033       return;
1034 
1035     case BFD_RELOC_VTABLE_ENTRY:
1036       fixP->fx_done = 0;
1037       return;
1038 
1039     default:
1040       break;
1041     }
1042 
1043   number_to_chars_bigendian (place, val, fixP->fx_size);
1044   if (fixP->fx_addsy == NULL)
1045     fixP->fx_done = 1;
1046   if (fixP->fx_bit_fixP != NULL)
1047     fixP->fx_no_overflow = 1;
1048 }
1049 
1050 const char *md_shortopts = "";
1051 
1052 struct option md_longopts[] =
1053   {
1054     {NULL, no_argument, NULL, 0}
1055   };
1056 
1057 size_t md_longopts_size = sizeof (md_longopts);
1058 
1059 int
md_parse_option(int c ATTRIBUTE_UNUSED,const char * arg ATTRIBUTE_UNUSED)1060 md_parse_option (int c     ATTRIBUTE_UNUSED,
1061 		 const char *arg ATTRIBUTE_UNUSED)
1062 {
1063   return 0;
1064 }
1065 
1066 void
md_show_usage(FILE * stream ATTRIBUTE_UNUSED)1067 md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
1068 {
1069 }
1070 
1071 /* This is called when a line is unrecognized.  */
1072 
1073 int
dlx_unrecognized_line(int c)1074 dlx_unrecognized_line (int c)
1075 {
1076   int lab;
1077   char *s;
1078 
1079   if (c != '$' || ! ISDIGIT ((unsigned char) input_line_pointer[0]))
1080     return 0;
1081 
1082   s = input_line_pointer;
1083 
1084   lab = 0;
1085   while (ISDIGIT ((unsigned char) *s))
1086     {
1087       lab = lab * 10 + *s - '0';
1088       ++s;
1089     }
1090 
1091   if (*s != ':')
1092     /* Not a label definition.  */
1093     return 0;
1094 
1095   if (dollar_label_defined (lab))
1096     {
1097       as_bad (_("label \"$%d\" redefined"), lab);
1098       return 0;
1099     }
1100 
1101   define_dollar_label (lab);
1102   colon (dollar_label_name (lab, 0));
1103   input_line_pointer = s + 1;
1104 
1105   return 1;
1106 }
1107 
1108 /* Default the values of symbols known that should be "predefined".  We
1109    don't bother to predefine them unless you actually use one, since there
1110    are a lot of them.  */
1111 
1112 symbolS *
md_undefined_symbol(char * name ATTRIBUTE_UNUSED)1113 md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
1114 {
1115   return NULL;
1116 }
1117 
1118 /* Parse an operand that is machine-specific, the function was called
1119    in expr.c by operand() function, when everything failed before it
1120    call a quit.  */
1121 
1122 void
md_operand(expressionS * expressionP)1123 md_operand (expressionS* expressionP)
1124 {
1125   /* Check for the #number representation    */
1126   if (input_line_pointer[0] == '#' &&
1127       ISDIGIT ((unsigned char) input_line_pointer[1]))
1128     {
1129       /* We have a numeric number expression.  No biggy.  */
1130       input_line_pointer += 1;	/* Skip # */
1131 
1132       (void) expression (expressionP);
1133 
1134       if (expressionP->X_op != O_constant)
1135 	as_bad (_("Invalid expression after # number\n"));
1136     }
1137 
1138   return;
1139 }
1140 
1141 /* Round up a section size to the appropriate boundary.  */
1142 
1143 valueT
md_section_align(segT segment ATTRIBUTE_UNUSED,valueT size)1144 md_section_align (segT segment ATTRIBUTE_UNUSED,
1145 		  valueT size)
1146 {
1147   /* Byte alignment is fine.  */
1148   return size;
1149 }
1150 
1151 /* Exactly what point is a PC-relative offset relative TO?
1152    On the 29000, they're relative to the address of the instruction,
1153    which we have set up as the address of the fixup too.  */
1154 
1155 long
md_pcrel_from(fixS * fixP)1156 md_pcrel_from (fixS* fixP)
1157 {
1158   return 4 + fixP->fx_where + fixP->fx_frag->fr_address;
1159 }
1160 
1161 /* Translate internal representation of relocation info to BFD target
1162    format.
1163    FIXME: To what extent can we get all relevant targets to use this?
1164    The above FIXME is from a29k, but I think it is also needed here.    */
1165 
1166 arelent *
tc_gen_reloc(asection * section ATTRIBUTE_UNUSED,fixS * fixP)1167 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
1168 	      fixS *fixP)
1169 {
1170   arelent * reloc;
1171 
1172   reloc = XNEW (arelent);
1173   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
1174 
1175   if (reloc->howto == NULL)
1176     {
1177       as_bad_where (fixP->fx_file, fixP->fx_line,
1178 		    _("internal error: can't export reloc type %d (`%s')"),
1179 		    fixP->fx_r_type,
1180 		    bfd_get_reloc_code_name (fixP->fx_r_type));
1181       return NULL;
1182     }
1183 
1184   gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
1185 
1186   reloc->sym_ptr_ptr = XNEW (asymbol *);
1187   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
1188   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
1189 
1190   if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
1191     reloc->address = fixP->fx_offset;
1192   reloc->addend = 0;
1193 
1194   return reloc;
1195 }
1196 
1197 const pseudo_typeS
1198 dlx_pseudo_table[] =
1199 {
1200   /* Some additional ops that are used by gcc-dlx.  */
1201   {"asciiz", stringer, 8 + 1},
1202   {"half", cons, 2},
1203   {"dword", cons, 8},
1204   {"word", cons, 4},
1205   {"proc", s_proc, 0},
1206   {"endproc", s_proc, 1},
1207   {NULL, NULL, 0}
1208 };
1209 
1210 void
dlx_pop_insert(void)1211 dlx_pop_insert (void)
1212 {
1213   pop_insert (dlx_pseudo_table);
1214   return ;
1215 }
1216