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