]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gas/config/tc-mn10200.c
* config/tc-mn10200.c: Flesh out assembler support for MN10200.
[thirdparty/binutils-gdb.git] / gas / config / tc-mn10200.c
1 /* tc-mn10200.c -- Assembler code for the Matsushita 10200
2
3 Copyright (C) 1996 Free Software Foundation.
4
5 This file is part of GAS, the GNU Assembler.
6
7 GAS is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GAS is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GAS; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include <stdio.h>
23 #include <ctype.h>
24 #include "as.h"
25 #include "subsegs.h"
26 #include "opcode/mn10200.h"
27 \f
28 /* Structure to hold information about predefined registers. */
29 struct reg_name
30 {
31 const char *name;
32 int value;
33 };
34
35 /* Generic assembler global variables which must be defined by all targets. */
36
37 /* Characters which always start a comment. */
38 const char comment_chars[] = "#";
39
40 /* Characters which start a comment at the beginning of a line. */
41 const char line_comment_chars[] = ";#";
42
43 /* Characters which may be used to separate multiple commands on a
44 single line. */
45 const char line_separator_chars[] = ";";
46
47 /* Characters which are used to indicate an exponent in a floating
48 point number. */
49 const char EXP_CHARS[] = "eE";
50
51 /* Characters which mean that a number is a floating point constant,
52 as in 0d1.0. */
53 const char FLT_CHARS[] = "dD";
54 \f
55
56 /* local functions */
57 static void mn10200_insert_operand PARAMS ((unsigned long *, unsigned long *,
58 const struct mn10200_operand *,
59 offsetT, char *, unsigned,
60 unsigned));
61 static unsigned long check_operand PARAMS ((unsigned long,
62 const struct mn10200_operand *,
63 offsetT));
64 static int reg_name_search PARAMS ((const struct reg_name *, int, const char *));
65 static boolean data_register_name PARAMS ((expressionS *expressionP));
66 static boolean address_register_name PARAMS ((expressionS *expressionP));
67 static boolean other_register_name PARAMS ((expressionS *expressionP));
68
69
70 /* fixups */
71 #define MAX_INSN_FIXUPS (5)
72 struct mn10200_fixup
73 {
74 expressionS exp;
75 int opindex;
76 bfd_reloc_code_real_type reloc;
77 };
78 struct mn10200_fixup fixups[MAX_INSN_FIXUPS];
79 static int fc;
80 \f
81 const char *md_shortopts = "";
82 struct option md_longopts[] = {
83 {NULL, no_argument, NULL, 0}
84 };
85 size_t md_longopts_size = sizeof(md_longopts);
86
87 /* The target specific pseudo-ops which we support. */
88 const pseudo_typeS md_pseudo_table[] =
89 {
90 { NULL, NULL, 0 }
91 };
92
93 /* Opcode hash table. */
94 static struct hash_control *mn10200_hash;
95
96 /* This table is sorted. Suitable for searching by a binary search. */
97 static const struct reg_name data_registers[] =
98 {
99 { "d0", 0 },
100 { "d1", 1 },
101 { "d2", 2 },
102 { "d3", 3 },
103 };
104 #define DATA_REG_NAME_CNT (sizeof(data_registers) / sizeof(struct reg_name))
105
106 static const struct reg_name address_registers[] =
107 {
108 { "a0", 0 },
109 { "a1", 1 },
110 { "a2", 2 },
111 { "a3", 3 },
112 };
113 #define ADDRESS_REG_NAME_CNT (sizeof(address_registers) / sizeof(struct reg_name))
114
115 static const struct reg_name other_registers[] =
116 {
117 { "mdr", 0 },
118 { "psw", 0 },
119 };
120 #define OTHER_REG_NAME_CNT (sizeof(other_registers) / sizeof(struct reg_name))
121
122 /* reg_name_search does a binary search of the given register table
123 to see if "name" is a valid regiter name. Returns the register
124 number from the array on success, or -1 on failure. */
125
126 static int
127 reg_name_search (regs, regcount, name)
128 const struct reg_name *regs;
129 int regcount;
130 const char *name;
131 {
132 int middle, low, high;
133 int cmp;
134
135 low = 0;
136 high = regcount - 1;
137
138 do
139 {
140 middle = (low + high) / 2;
141 cmp = strcasecmp (name, regs[middle].name);
142 if (cmp < 0)
143 high = middle - 1;
144 else if (cmp > 0)
145 low = middle + 1;
146 else
147 return regs[middle].value;
148 }
149 while (low <= high);
150 return -1;
151 }
152
153
154 /* Summary of register_name().
155 *
156 * in: Input_line_pointer points to 1st char of operand.
157 *
158 * out: A expressionS.
159 * The operand may have been a register: in this case, X_op == O_register,
160 * X_add_number is set to the register number, and truth is returned.
161 * Input_line_pointer->(next non-blank) char after operand, or is in
162 * its original state.
163 */
164 static boolean
165 data_register_name (expressionP)
166 expressionS *expressionP;
167 {
168 int reg_number;
169 char *name;
170 char *start;
171 char c;
172
173 /* Find the spelling of the operand */
174 start = name = input_line_pointer;
175
176 c = get_symbol_end ();
177 reg_number = reg_name_search (data_registers, DATA_REG_NAME_CNT, name);
178
179 /* look to see if it's in the register table */
180 if (reg_number >= 0)
181 {
182 expressionP->X_op = O_register;
183 expressionP->X_add_number = reg_number;
184
185 /* make the rest nice */
186 expressionP->X_add_symbol = NULL;
187 expressionP->X_op_symbol = NULL;
188 *input_line_pointer = c; /* put back the delimiting char */
189 return true;
190 }
191 else
192 {
193 /* reset the line as if we had not done anything */
194 *input_line_pointer = c; /* put back the delimiting char */
195 input_line_pointer = start; /* reset input_line pointer */
196 return false;
197 }
198 }
199
200 /* Summary of register_name().
201 *
202 * in: Input_line_pointer points to 1st char of operand.
203 *
204 * out: A expressionS.
205 * The operand may have been a register: in this case, X_op == O_register,
206 * X_add_number is set to the register number, and truth is returned.
207 * Input_line_pointer->(next non-blank) char after operand, or is in
208 * its original state.
209 */
210 static boolean
211 address_register_name (expressionP)
212 expressionS *expressionP;
213 {
214 int reg_number;
215 char *name;
216 char *start;
217 char c;
218
219 /* Find the spelling of the operand */
220 start = name = input_line_pointer;
221
222 c = get_symbol_end ();
223 reg_number = reg_name_search (address_registers, ADDRESS_REG_NAME_CNT, name);
224
225 /* look to see if it's in the register table */
226 if (reg_number >= 0)
227 {
228 expressionP->X_op = O_register;
229 expressionP->X_add_number = reg_number;
230
231 /* make the rest nice */
232 expressionP->X_add_symbol = NULL;
233 expressionP->X_op_symbol = NULL;
234 *input_line_pointer = c; /* put back the delimiting char */
235 return true;
236 }
237 else
238 {
239 /* reset the line as if we had not done anything */
240 *input_line_pointer = c; /* put back the delimiting char */
241 input_line_pointer = start; /* reset input_line pointer */
242 return false;
243 }
244 }
245
246 /* Summary of register_name().
247 *
248 * in: Input_line_pointer points to 1st char of operand.
249 *
250 * out: A expressionS.
251 * The operand may have been a register: in this case, X_op == O_register,
252 * X_add_number is set to the register number, and truth is returned.
253 * Input_line_pointer->(next non-blank) char after operand, or is in
254 * its original state.
255 */
256 static boolean
257 other_register_name (expressionP)
258 expressionS *expressionP;
259 {
260 int reg_number;
261 char *name;
262 char *start;
263 char c;
264
265 /* Find the spelling of the operand */
266 start = name = input_line_pointer;
267
268 c = get_symbol_end ();
269 reg_number = reg_name_search (other_registers, OTHER_REG_NAME_CNT, name);
270
271 /* look to see if it's in the register table */
272 if (reg_number >= 0)
273 {
274 expressionP->X_op = O_register;
275 expressionP->X_add_number = reg_number;
276
277 /* make the rest nice */
278 expressionP->X_add_symbol = NULL;
279 expressionP->X_op_symbol = NULL;
280 *input_line_pointer = c; /* put back the delimiting char */
281 return true;
282 }
283 else
284 {
285 /* reset the line as if we had not done anything */
286 *input_line_pointer = c; /* put back the delimiting char */
287 input_line_pointer = start; /* reset input_line pointer */
288 return false;
289 }
290 }
291
292 void
293 md_show_usage (stream)
294 FILE *stream;
295 {
296 fprintf(stream, "MN10200 options:\n\
297 none yet\n");
298 }
299
300 int
301 md_parse_option (c, arg)
302 int c;
303 char *arg;
304 {
305 return 0;
306 }
307
308 symbolS *
309 md_undefined_symbol (name)
310 char *name;
311 {
312 return 0;
313 }
314
315 char *
316 md_atof (type, litp, sizep)
317 int type;
318 char *litp;
319 int *sizep;
320 {
321 int prec;
322 LITTLENUM_TYPE words[4];
323 char *t;
324 int i;
325
326 switch (type)
327 {
328 case 'f':
329 prec = 2;
330 break;
331
332 case 'd':
333 prec = 4;
334 break;
335
336 default:
337 *sizep = 0;
338 return "bad call to md_atof";
339 }
340
341 t = atof_ieee (input_line_pointer, type, words);
342 if (t)
343 input_line_pointer = t;
344
345 *sizep = prec * 2;
346
347 for (i = prec - 1; i >= 0; i--)
348 {
349 md_number_to_chars (litp, (valueT) words[i], 2);
350 litp += 2;
351 }
352
353 return NULL;
354 }
355
356
357 void
358 md_convert_frag (abfd, sec, fragP)
359 bfd *abfd;
360 asection *sec;
361 fragS *fragP;
362 {
363 /* printf ("call to md_convert_frag \n"); */
364 abort ();
365 }
366
367 valueT
368 md_section_align (seg, addr)
369 asection *seg;
370 valueT addr;
371 {
372 int align = bfd_get_section_alignment (stdoutput, seg);
373 return ((addr + (1 << align) - 1) & (-1 << align));
374 }
375
376 void
377 md_begin ()
378 {
379 char *prev_name = "";
380 register const struct mn10200_opcode *op;
381
382 mn10200_hash = hash_new();
383
384 /* Insert unique names into hash table. The MN10200 instruction set
385 has many identical opcode names that have different opcodes based
386 on the operands. This hash table then provides a quick index to
387 the first opcode with a particular name in the opcode table. */
388
389 op = mn10200_opcodes;
390 while (op->name)
391 {
392 if (strcmp (prev_name, op->name))
393 {
394 prev_name = (char *) op->name;
395 hash_insert (mn10200_hash, op->name, (char *) op);
396 }
397 op++;
398 }
399
400 /* This is both a simplification (we don't have to write md_apply_fix)
401 and support for future optimizations (branch shortening and similar
402 stuff in the linker. */
403 linkrelax = 1;
404 }
405
406 void
407 md_assemble (str)
408 char *str;
409 {
410 char *s;
411 struct mn10200_opcode *opcode;
412 struct mn10200_opcode *next_opcode;
413 const unsigned char *opindex_ptr;
414 int next_opindex;
415 unsigned long insn, extension, size = 0;
416 char *f;
417 int i;
418 int match;
419
420 /* Get the opcode. */
421 for (s = str; *s != '\0' && ! isspace (*s); s++)
422 ;
423 if (*s != '\0')
424 *s++ = '\0';
425
426 /* find the first opcode with the proper name */
427 opcode = (struct mn10200_opcode *)hash_find (mn10200_hash, str);
428 if (opcode == NULL)
429 {
430 as_bad ("Unrecognized opcode: `%s'", str);
431 return;
432 }
433
434 str = s;
435 while (isspace (*str))
436 ++str;
437
438 input_line_pointer = str;
439
440 for(;;)
441 {
442 const char *errmsg = NULL;
443 int op_idx;
444 char *hold;
445 int extra_shift = 0;
446
447 fc = 0;
448 match = 0;
449 next_opindex = 0;
450 insn = opcode->opcode;
451 extension = 0;
452 for (op_idx = 1, opindex_ptr = opcode->operands;
453 *opindex_ptr != 0;
454 opindex_ptr++, op_idx++)
455 {
456 const struct mn10200_operand *operand;
457 expressionS ex;
458
459 if (next_opindex == 0)
460 {
461 operand = &mn10200_operands[*opindex_ptr];
462 }
463 else
464 {
465 operand = &mn10200_operands[next_opindex];
466 next_opindex = 0;
467 }
468
469 errmsg = NULL;
470
471 while (*str == ' ' || *str == ',')
472 ++str;
473
474 /* Gather the operand. */
475 hold = input_line_pointer;
476 input_line_pointer = str;
477
478 if (operand->flags & MN10200_OPERAND_PAREN)
479 {
480 if (*input_line_pointer != ')' && *input_line_pointer != '(')
481 {
482 input_line_pointer = hold;
483 str = hold;
484 goto error;
485 }
486 input_line_pointer++;
487 goto keep_going;
488 }
489 /* See if we can match the operands. */
490 else if (operand->flags & MN10200_OPERAND_DREG)
491 {
492 if (!data_register_name (&ex))
493 {
494 input_line_pointer = hold;
495 str = hold;
496 goto error;
497 }
498 }
499 else if (operand->flags & MN10200_OPERAND_AREG)
500 {
501 if (!address_register_name (&ex))
502 {
503 input_line_pointer = hold;
504 str = hold;
505 goto error;
506 }
507 }
508 else if (operand->flags & MN10200_OPERAND_PSW)
509 {
510 char *start = input_line_pointer;
511 char c = get_symbol_end ();
512
513 if (strcmp (start, "psw") != 0)
514 {
515 *input_line_pointer = c;
516 input_line_pointer = hold;
517 str = hold;
518 goto error;
519 }
520 *input_line_pointer = c;
521 goto keep_going;
522 }
523 else if (operand->flags & MN10200_OPERAND_MDR)
524 {
525 char *start = input_line_pointer;
526 char c = get_symbol_end ();
527
528 if (strcmp (start, "mdr") != 0)
529 {
530 *input_line_pointer = c;
531 input_line_pointer = hold;
532 str = hold;
533 goto error;
534 }
535 *input_line_pointer = c;
536 goto keep_going;
537 }
538 else if (data_register_name (&ex))
539 {
540 input_line_pointer = hold;
541 str = hold;
542 goto error;
543 }
544 else if (address_register_name (&ex))
545 {
546 input_line_pointer = hold;
547 str = hold;
548 goto error;
549 }
550 else if (other_register_name (&ex))
551 {
552 input_line_pointer = hold;
553 str = hold;
554 goto error;
555 }
556 else if (*str == ')' || *str == '(')
557 {
558 input_line_pointer = hold;
559 str = hold;
560 goto error;
561 }
562 else
563 {
564 expression (&ex);
565 }
566
567 switch (ex.X_op)
568 {
569 case O_illegal:
570 errmsg = "illegal operand";
571 goto error;
572 case O_absent:
573 errmsg = "missing operand";
574 goto error;
575 case O_register:
576 if ((operand->flags
577 & (MN10200_OPERAND_DREG | MN10200_OPERAND_AREG)) == 0)
578 {
579 input_line_pointer = hold;
580 str = hold;
581 goto error;
582 }
583
584 if (opcode->format == FMT_2 || opcode->format == FMT_5)
585 extra_shift = 8;
586 else if (opcode->format == FMT_3 || opcode->format == FMT_6
587 || opcode->format == FMT_7)
588 extra_shift = 16;
589 else
590 extra_shift = 0;
591
592 mn10200_insert_operand (&insn, &extension, operand,
593 ex.X_add_number, (char *) NULL,
594 0, extra_shift);
595
596 break;
597
598 case O_constant:
599 /* If this operand can be promoted, and it doesn't
600 fit into the allocated bitfield for this insn,
601 then promote it (ie this opcode does not match). */
602 if (operand->flags & MN10200_OPERAND_PROMOTE
603 && ! check_operand (insn, operand, ex.X_add_number))
604 {
605 input_line_pointer = hold;
606 str = hold;
607 goto error;
608 }
609
610 mn10200_insert_operand (&insn, &extension, operand,
611 ex.X_add_number, (char *) NULL,
612 0, 0);
613 break;
614
615 default:
616 /* If this operand can be promoted, then this opcode didn't
617 match since we can't know if it needed promotion! */
618 if (operand->flags & MN10200_OPERAND_PROMOTE)
619 {
620 input_line_pointer = hold;
621 str = hold;
622 goto error;
623 }
624
625 /* We need to generate a fixup for this expression. */
626 if (fc >= MAX_INSN_FIXUPS)
627 as_fatal ("too many fixups");
628 fixups[fc].exp = ex;
629 fixups[fc].opindex = *opindex_ptr;
630 fixups[fc].reloc = BFD_RELOC_UNUSED;
631 ++fc;
632 break;
633 }
634
635 keep_going:
636 str = input_line_pointer;
637 input_line_pointer = hold;
638
639 while (*str == ' ' || *str == ',')
640 ++str;
641
642 }
643
644 /* Make sure we used all the operands! */
645 if (*str != ',')
646 match = 1;
647
648 error:
649 if (match == 0)
650 {
651 next_opcode = opcode + 1;
652 if (next_opcode->opcode != 0 && !strcmp(next_opcode->name, opcode->name))
653 {
654 opcode = next_opcode;
655 continue;
656 }
657
658 as_bad ("%s", errmsg);
659 return;
660 }
661 break;
662 }
663
664 while (isspace (*str))
665 ++str;
666
667 if (*str != '\0')
668 as_bad ("junk at end of line: `%s'", str);
669
670 input_line_pointer = str;
671
672 if (opcode->format == FMT_1)
673 size = 1;
674 else if (opcode->format == FMT_2 || opcode->format == FMT_4)
675 size = 2;
676 else if (opcode->format == FMT_3 || opcode->format == FMT_5)
677 size = 3;
678 else if (opcode->format == FMT_6)
679 size = 4;
680 else if (opcode->format == FMT_7)
681 size = 5;
682 else
683 abort ();
684
685 /* Write out the instruction. */
686
687 f = frag_more (size);
688
689 /* Oh, what a mess. The instruction is in big endian format, but
690 16 and 24bit immediates are little endian! */
691 if (opcode->format == FMT_3)
692 {
693 number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1);
694 number_to_chars_littleendian (f + 1, insn & 0xffff, 2);
695 }
696 else if (opcode->format == FMT_6)
697 {
698 number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
699 number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
700 }
701 else if (opcode->format == FMT_7)
702 {
703 number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
704 number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
705 number_to_chars_littleendian (f + 4, extension & 0xff, 1);
706 }
707 else
708 {
709 number_to_chars_bigendian (f, insn, size > 4 ? 4 : size);
710 }
711
712 #if 0
713 /* Create any fixups. */
714 for (i = 0; i < fc; i++)
715 {
716 const struct mn10200_operand *operand;
717
718 operand = &mn10200_operands[fixups[i].opindex];
719 if (fixups[i].reloc != BFD_RELOC_UNUSED)
720 {
721 reloc_howto_type *reloc_howto;
722 int size;
723 int offset;
724 fixS *fixP;
725
726 reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
727
728 if (!reloc_howto)
729 abort();
730
731 size = bfd_get_reloc_size (reloc_howto);
732
733 if (size < 1 || size > 4)
734 abort();
735
736 offset = 4 - size;
737 fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size,
738 &fixups[i].exp,
739 reloc_howto->pc_relative,
740 fixups[i].reloc);
741 }
742 else
743 {
744 int reloc, pcrel, reloc_size, offset;
745
746 reloc = BFD_RELOC_NONE;
747 /* How big is the reloc? Remember SPLIT relocs are
748 implicitly 32bits. */
749 reloc_size = operand->bits;
750
751 /* Is the reloc pc-relative? */
752 pcrel = (operand->flags & MN10200_OPERAND_PCREL) != 0;
753
754 /* Gross. This disgusting hack is to make sure we
755 get the right offset for the 16/32 bit reloc in
756 "call" instructions. Basically they're a pain
757 because the reloc isn't at the end of the instruction. */
758 if ((size == 5 || size == 7)
759 && (((insn >> 24) & 0xff) == 0xcd
760 || ((insn >> 24) & 0xff) == 0xdd))
761 size -= 2;
762
763 /* Similarly for certain bit instructions which don't
764 hav their 32bit reloc at the tail of the instruction. */
765 if (size == 7
766 && (((insn >> 16) & 0xffff) == 0xfe00
767 || ((insn >> 16) & 0xffff) == 0xfe01
768 || ((insn >> 16) & 0xffff) == 0xfe02))
769 size -= 1;
770
771 offset = size - reloc_size / 8;
772
773 /* Choose a proper BFD relocation type. */
774 if (pcrel)
775 {
776 if (size == 6)
777 reloc = BFD_RELOC_MN10200_32_PCREL;
778 else if (size == 4)
779 reloc = BFD_RELOC_MN10200_16_PCREL;
780 else if (reloc_size == 32)
781 reloc = BFD_RELOC_32_PCREL;
782 else if (reloc_size == 16)
783 reloc = BFD_RELOC_16_PCREL;
784 else if (reloc_size == 8)
785 reloc = BFD_RELOC_8_PCREL;
786 else
787 abort ();
788 }
789 else
790 {
791 if (reloc_size == 32)
792 reloc = BFD_RELOC_MN10200_32B;
793 else if (reloc_size == 16)
794 reloc = BFD_RELOC_MN10200_16B;
795 else if (reloc_size == 8)
796 reloc = BFD_RELOC_8;
797 else
798 abort ();
799 }
800
801 /* Convert the size of the reloc into what fix_new_exp wants. */
802 reloc_size = reloc_size / 8;
803 if (reloc_size == 8)
804 reloc_size = 0;
805 else if (reloc_size == 16)
806 reloc_size = 1;
807 else if (reloc_size == 32)
808 reloc_size = 2;
809
810 fix_new_exp (frag_now, f - frag_now->fr_literal + offset, reloc_size,
811 &fixups[i].exp, pcrel,
812 ((bfd_reloc_code_real_type) reloc));
813 }
814 }
815 #endif
816 }
817
818
819 /* if while processing a fixup, a reloc really needs to be created */
820 /* then it is done here */
821
822 arelent *
823 tc_gen_reloc (seg, fixp)
824 asection *seg;
825 fixS *fixp;
826 {
827 arelent *reloc;
828 reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
829 reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
830 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
831 reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
832 if (reloc->howto == (reloc_howto_type *) NULL)
833 {
834 as_bad_where (fixp->fx_file, fixp->fx_line,
835 "reloc %d not supported by object file format", (int)fixp->fx_r_type);
836 return NULL;
837 }
838 reloc->addend = fixp->fx_offset;
839 /* printf("tc_gen_reloc: addr=%x addend=%x\n", reloc->address, reloc->addend); */
840 return reloc;
841 }
842
843 int
844 md_estimate_size_before_relax (fragp, seg)
845 fragS *fragp;
846 asection *seg;
847 {
848 return 0;
849 }
850
851 long
852 md_pcrel_from (fixp)
853 fixS *fixp;
854 {
855 return fixp->fx_frag->fr_address;
856 #if 0
857 if (fixp->fx_addsy != (symbolS *) NULL && ! S_IS_DEFINED (fixp->fx_addsy))
858 {
859 /* The symbol is undefined. Let the linker figure it out. */
860 return 0;
861 }
862 return fixp->fx_frag->fr_address + fixp->fx_where;
863 #endif
864 }
865
866 int
867 md_apply_fix3 (fixp, valuep, seg)
868 fixS *fixp;
869 valueT *valuep;
870 segT seg;
871 {
872 /* We shouldn't ever get here because linkrelax is nonzero. */
873 abort ();
874 fixp->fx_done = 1;
875 return 0;
876 }
877
878 /* Insert an operand value into an instruction. */
879
880 static void
881 mn10200_insert_operand (insnp, extensionp, operand, val, file, line, shift)
882 unsigned long *insnp;
883 unsigned long *extensionp;
884 const struct mn10200_operand *operand;
885 offsetT val;
886 char *file;
887 unsigned int line;
888 unsigned int shift;
889 {
890 /* No need to check 32bit operands for a bit. */
891 if (operand->bits != 32)
892 {
893 long min, max;
894 offsetT test;
895
896 if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
897 {
898 max = (1 << (operand->bits - 1)) - 1;
899 min = - (1 << (operand->bits - 1));
900 }
901 else
902 {
903 max = (1 << operand->bits) - 1;
904 min = 0;
905 }
906
907 test = val;
908
909
910 if (test < (offsetT) min || test > (offsetT) max)
911 {
912 const char *err =
913 "operand out of range (%s not between %ld and %ld)";
914 char buf[100];
915
916 sprint_value (buf, test);
917 if (file == (char *) NULL)
918 as_warn (err, buf, min, max);
919 else
920 as_warn_where (file, line, err, buf, min, max);
921 }
922 }
923
924 if ((operand->flags & MN10200_OPERAND_EXTENDED) == 0)
925 {
926 *insnp |= (((long) val & ((1 << operand->bits) - 1))
927 << (operand->shift + shift));
928
929 if ((operand->flags & MN10200_OPERAND_REPEATED) != 0)
930 *insnp |= (((long) val & ((1 << operand->bits) - 1))
931 << (operand->shift + shift + 2));
932 }
933 else
934 {
935 *extensionp |= (val >> 16) & 0xff;
936 *insnp |= val & 0xffff;
937 }
938 }
939
940 static unsigned long
941 check_operand (insn, operand, val)
942 unsigned long insn;
943 const struct mn10200_operand *operand;
944 offsetT val;
945 {
946 /* No need to check 32bit operands for a bit. */
947 if (operand->bits != 32)
948 {
949 long min, max;
950 offsetT test;
951
952 if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
953 {
954 max = (1 << (operand->bits - 1)) - 1;
955 min = - (1 << (operand->bits - 1));
956 }
957 else
958 {
959 max = (1 << operand->bits) - 1;
960 min = 0;
961 }
962
963 test = val;
964
965
966 if (test < (offsetT) min || test > (offsetT) max)
967 return 0;
968 else
969 return 1;
970 }
971 return 1;
972 }