* write.c (fixup_segment): Don't add symbol value to addend if
[external/binutils.git] / gas / config / tc-v850.c
1 /* tc-v850.c -- Assembler code for the NEC V850
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/v850.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 unsigned long v850_insert_operand
58   PARAMS ((unsigned long insn, const struct v850_operand *operand,
59            offsetT val, char *file, unsigned int line));
60 static int reg_name_search PARAMS ((const struct reg_name *, int, const char *));
61 static boolean register_name PARAMS ((expressionS *expressionP));
62 static boolean system_register_name PARAMS ((expressionS *expressionP));
63 static boolean cc_name PARAMS ((expressionS *expressionP));
64 static bfd_reloc_code_real_type v850_reloc_prefix PARAMS ((void));
65
66
67 /* fixups */
68 #define MAX_INSN_FIXUPS (5)
69 struct v850_fixup
70 {
71   expressionS exp;
72   int opindex;
73   bfd_reloc_code_real_type reloc;
74 };
75 struct v850_fixup fixups[MAX_INSN_FIXUPS];
76 static int fc;
77 \f
78 const char *md_shortopts = "";
79 struct option md_longopts[] = {
80   {NULL, no_argument, NULL, 0}
81 };
82 size_t md_longopts_size = sizeof(md_longopts); 
83
84 /* The target specific pseudo-ops which we support.  */
85 const pseudo_typeS md_pseudo_table[] =
86 {
87   { NULL,       NULL,           0 }
88 };
89
90 /* Opcode hash table.  */
91 static struct hash_control *v850_hash;
92
93 /* This table is sorted. Suitable for searching by a binary search. */
94 static const struct reg_name pre_defined_registers[] =
95 {
96   { "ep", 30 },                 /* ep - element ptr */
97   { "gp", 4 },                  /* gp - global ptr */
98   { "lp", 31 },                 /* lp - link ptr */
99   { "r0", 0 },
100   { "r1", 1 },
101   { "r10", 10 },
102   { "r11", 11 },
103   { "r12", 12 },
104   { "r13", 13 },
105   { "r14", 14 },
106   { "r15", 15 },
107   { "r16", 16 },
108   { "r17", 17 },
109   { "r18", 18 },
110   { "r19", 19 },
111   { "r2", 2 },
112   { "r20", 20 },
113   { "r21", 21 },
114   { "r22", 22 },
115   { "r23", 23 },
116   { "r24", 24 },
117   { "r25", 25 },
118   { "r26", 26 },
119   { "r27", 27 },
120   { "r28", 28 },
121   { "r29", 29 },
122   { "r3", 3 },
123   { "r30", 30 },
124   { "r31", 31 },
125   { "r4", 4 },
126   { "r5", 5 },
127   { "r6", 6 },
128   { "r7", 7 },
129   { "r8", 8 },
130   { "r9", 9 },
131   { "sp", 3 },                  /* sp - stack ptr */
132   { "tp", 5 },                  /* tp - text ptr */
133   { "zero", 0 },
134 };
135 #define REG_NAME_CNT    (sizeof(pre_defined_registers) / sizeof(struct reg_name))
136
137
138 static const struct reg_name system_registers[] = 
139 {
140   { "eipc", 0 },
141   { "eipsw", 1 },
142   { "fepc", 2 },
143   { "fepsw", 3 },
144   { "ecr", 4 },
145   { "psw", 5 },
146 };
147 #define SYSREG_NAME_CNT (sizeof(system_registers) / sizeof(struct reg_name))
148
149 static const struct reg_name cc_names[] =
150 {
151   { "c", 0x1 },
152   { "ge", 0xe },
153   { "gt", 0xf },
154   { "h", 0xb },
155   { "l", 0x1 },
156   { "le", 0x7 },
157   { "lt", 0x6 },
158   { "n", 0x4 },
159   { "nc", 0x9 },
160   { "nh", 0x3 },
161   { "nl", 0x9 },
162   { "ns", 0xc },
163   { "nv", 0x8 },
164   { "nz", 0xa },
165   { "p",  0xc },
166   { "s", 0x4 },
167   { "sa", 0xd },
168   { "t", 0x5 },
169   { "v", 0x0 },
170   { "z", 0x2 },
171 };
172 #define CC_NAME_CNT     (sizeof(cc_names) / sizeof(struct reg_name))
173
174 /* reg_name_search does a binary search of the given register table
175    to see if "name" is a valid regiter name.  Returns the register
176    number from the array on success, or -1 on failure. */
177
178 static int
179 reg_name_search (regs, regcount, name)
180      const struct reg_name *regs;
181      int regcount;
182      const char *name;
183 {
184   int middle, low, high;
185   int cmp;
186
187   low = 0;
188   high = regcount - 1;
189
190   do
191     {
192       middle = (low + high) / 2;
193       cmp = strcasecmp (name, regs[middle].name);
194       if (cmp < 0)
195         high = middle - 1;
196       else if (cmp > 0)
197         low = middle + 1;
198       else 
199           return regs[middle].value;
200     }
201   while (low <= high);
202   return -1;
203 }
204
205
206 /* Summary of register_name().
207  *
208  * in: Input_line_pointer points to 1st char of operand.
209  *
210  * out: A expressionS.
211  *      The operand may have been a register: in this case, X_op == O_register,
212  *      X_add_number is set to the register number, and truth is returned.
213  *      Input_line_pointer->(next non-blank) char after operand, or is in
214  *      its original state.
215  */
216 static boolean
217 register_name (expressionP)
218      expressionS *expressionP;
219 {
220   int reg_number;
221   char *name;
222   char *start;
223   char c;
224
225   /* Find the spelling of the operand */
226   start = name = input_line_pointer;
227
228   c = get_symbol_end ();
229   reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name);
230
231   /* look to see if it's in the register table */
232   if (reg_number >= 0) 
233     {
234       expressionP->X_op = O_register;
235       expressionP->X_add_number = reg_number;
236
237       /* make the rest nice */
238       expressionP->X_add_symbol = NULL;
239       expressionP->X_op_symbol = NULL;
240       *input_line_pointer = c;  /* put back the delimiting char */
241       return true;
242     }
243   else
244     {
245       /* reset the line as if we had not done anything */
246       *input_line_pointer = c;   /* put back the delimiting char */
247       input_line_pointer = start; /* reset input_line pointer */
248       return false;
249     }
250 }
251
252 /* Summary of system_register_name().
253  *
254  * in: Input_line_pointer points to 1st char of operand.
255  *
256  * out: A expressionS.
257  *      The operand may have been a register: in this case, X_op == O_register,
258  *      X_add_number is set to the register number, and truth is returned.
259  *      Input_line_pointer->(next non-blank) char after operand, or is in
260  *      its original state.
261  */
262 static boolean
263 system_register_name (expressionP)
264      expressionS *expressionP;
265 {
266   int reg_number;
267   char *name;
268   char *start;
269   char c;
270
271   /* Find the spelling of the operand */
272   start = name = input_line_pointer;
273
274   c = get_symbol_end ();
275   reg_number = reg_name_search (system_registers, SYSREG_NAME_CNT, name);
276
277   /* look to see if it's in the register table */
278   if (reg_number >= 0) 
279     {
280       expressionP->X_op = O_register;
281       expressionP->X_add_number = reg_number;
282
283       /* make the rest nice */
284       expressionP->X_add_symbol = NULL;
285       expressionP->X_op_symbol = NULL;
286       *input_line_pointer = c;  /* put back the delimiting char */
287       return true;
288     }
289   else
290     {
291       /* reset the line as if we had not done anything */
292       *input_line_pointer = c;   /* put back the delimiting char */
293       input_line_pointer = start; /* reset input_line pointer */
294       return false;
295     }
296 }
297
298 /* Summary of cc_name().
299  *
300  * in: Input_line_pointer points to 1st char of operand.
301  *
302  * out: A expressionS.
303  *      The operand may have been a register: in this case, X_op == O_register,
304  *      X_add_number is set to the register number, and truth is returned.
305  *      Input_line_pointer->(next non-blank) char after operand, or is in
306  *      its original state.
307  */
308 static boolean
309 cc_name (expressionP)
310      expressionS *expressionP;
311 {
312   int reg_number;
313   char *name;
314   char *start;
315   char c;
316
317   /* Find the spelling of the operand */
318   start = name = input_line_pointer;
319
320   c = get_symbol_end ();
321   reg_number = reg_name_search (cc_names, CC_NAME_CNT, name);
322
323   /* look to see if it's in the register table */
324   if (reg_number >= 0) 
325     {
326       expressionP->X_op = O_constant;
327       expressionP->X_add_number = reg_number;
328
329       /* make the rest nice */
330       expressionP->X_add_symbol = NULL;
331       expressionP->X_op_symbol = NULL;
332       *input_line_pointer = c;  /* put back the delimiting char */
333       return true;
334     }
335   else
336     {
337       /* reset the line as if we had not done anything */
338       *input_line_pointer = c;   /* put back the delimiting char */
339       input_line_pointer = start; /* reset input_line pointer */
340       return false;
341     }
342 }
343
344 void
345 md_show_usage (stream)
346   FILE *stream;
347 {
348   fprintf(stream, "V850 options:\n\
349 none yet\n");
350
351
352 int
353 md_parse_option (c, arg)
354      int c;
355      char *arg;
356 {
357   return 0;
358 }
359
360 symbolS *
361 md_undefined_symbol (name)
362   char *name;
363 {
364   return 0;
365 }
366
367 char *
368 md_atof (type, litp, sizep)
369   int type;
370   char *litp;
371   int *sizep;
372 {
373   int prec;
374   LITTLENUM_TYPE words[4];
375   char *t;
376   int i;
377
378   switch (type)
379     {
380     case 'f':
381       prec = 2;
382       break;
383
384     case 'd':
385       prec = 4;
386       break;
387
388     default:
389       *sizep = 0;
390       return "bad call to md_atof";
391     }
392   
393   t = atof_ieee (input_line_pointer, type, words);
394   if (t)
395     input_line_pointer = t;
396
397   *sizep = prec * 2;
398
399   for (i = prec - 1; i >= 0; i--)
400     {
401       md_number_to_chars (litp, (valueT) words[i], 2);
402       litp += 2;
403     }
404
405   return NULL;
406 }
407
408
409 void
410 md_convert_frag (abfd, sec, fragP)
411   bfd *abfd;
412   asection *sec;
413   fragS *fragP;
414 {
415   /* printf ("call to md_convert_frag \n"); */
416   abort ();
417 }
418
419 valueT
420 md_section_align (seg, addr)
421      asection *seg;
422      valueT addr;
423 {
424   int align = bfd_get_section_alignment (stdoutput, seg);
425   return ((addr + (1 << align) - 1) & (-1 << align));
426 }
427
428 void
429 md_begin ()
430 {
431   char *prev_name = "";
432   register const struct v850_opcode *op;
433
434   v850_hash = hash_new();
435
436   /* Insert unique names into hash table.  The V850 instruction set
437      has many identical opcode names that have different opcodes based
438      on the operands.  This hash table then provides a quick index to
439      the first opcode with a particular name in the opcode table.  */
440
441   op     = v850_opcodes;
442   while (op->name)
443     {
444       if (strcmp (prev_name, op->name)) 
445         {
446           prev_name = (char *) op->name;
447           hash_insert (v850_hash, op->name, (char *) op);
448         }
449       op++;
450     }
451 }
452
453 static bfd_reloc_code_real_type
454 v850_reloc_prefix()
455 {
456   if (strncmp(input_line_pointer, "hi0(", 4) == 0)
457     {
458       input_line_pointer += 4;
459       return BFD_RELOC_HI16;
460     }
461   if (strncmp(input_line_pointer, "hi(", 3) == 0)
462     {
463       input_line_pointer += 3;
464       return BFD_RELOC_HI16_S;
465     }
466   if (strncmp (input_line_pointer, "lo(", 3) == 0)
467     {
468       input_line_pointer += 3;
469       return BFD_RELOC_LO16;
470     }
471
472   /* FIXME: implement sda, tda, zda here */
473
474   return BFD_RELOC_UNUSED;
475 }
476
477 void
478 md_assemble (str) 
479      char *str;
480 {
481   char *s;
482   struct v850_opcode *opcode;
483   struct v850_opcode *next_opcode;
484   const unsigned char *opindex_ptr;
485   int next_opindex;
486   unsigned long insn, size;
487   char *f;
488   int i;
489   int match;
490   bfd_reloc_code_real_type reloc;
491
492   /* Get the opcode.  */
493   for (s = str; *s != '\0' && ! isspace (*s); s++)
494     ;
495   if (*s != '\0')
496     *s++ = '\0';
497
498   /* find the first opcode with the proper name */
499   opcode = (struct v850_opcode *)hash_find (v850_hash, str);
500   if (opcode == NULL)
501     {
502       as_bad ("Unrecognized opcode: `%s'", str);
503       return;
504     }
505
506   str = s;
507   while (isspace (*str))
508     ++str;
509
510   input_line_pointer = str;
511
512   for(;;)
513     {
514       const char *errmsg = NULL;
515
516       fc = 0;
517       match = 0;
518       next_opindex = 0;
519       insn = opcode->opcode;
520       for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
521         {
522           const struct v850_operand *operand;
523           char *hold;
524           expressionS ex;
525
526           if (next_opindex == 0)
527             {
528               operand = &v850_operands[*opindex_ptr];
529             }
530           else
531             {
532               operand = &v850_operands[next_opindex];
533               next_opindex = 0;
534             }
535
536           errmsg = NULL;
537
538           while (*str == ' ' || *str == ',' || *str == '[' || *str == ']')
539             ++str;
540
541           /* Gather the operand. */
542           hold = input_line_pointer;
543           input_line_pointer = str;
544
545
546           /* lo(), hi(), hi0(), etc... */
547           if ((reloc = v850_reloc_prefix()) != BFD_RELOC_UNUSED)
548             {
549               expression(&ex);
550
551               if (*input_line_pointer++ != ')')
552                 {
553                   errmsg = "syntax error: expected `)'";
554                   goto error;
555                 }
556               
557               if (ex.X_op == O_constant)
558                 {
559                   switch (reloc)
560                     {
561                     case BFD_RELOC_LO16:
562                       ex.X_add_number &= 0xffff;
563                       break;
564
565                     case BFD_RELOC_HI16:
566                       ex.X_add_number = ((ex.X_add_number >> 16) & 0xffff);
567                       break;
568
569                     case BFD_RELOC_HI16_S:
570                       ex.X_add_number = ((ex.X_add_number >> 16) & 0xffff)
571                         + ((ex.X_add_number >> 15) & 1);
572                       break;
573
574                     default:
575                       break;
576                     }
577
578                   insn = v850_insert_operand (insn, operand, ex.X_add_number,
579                                               (char *) NULL, 0);
580                 }
581               else
582                 {
583                   if (fc > MAX_INSN_FIXUPS)
584                     as_fatal ("too many fixups");
585
586                   fixups[fc].exp = ex;
587                   fixups[fc].opindex = *opindex_ptr;
588                   fixups[fc].reloc = reloc;
589                   fc++;
590                 }
591             }
592           else
593             {
594           if ((operand->flags & V850_OPERAND_REG) != 0) 
595             {
596               if (!register_name(&ex))
597                 {
598                   errmsg = "invalid register name";
599                   goto error;
600                 }
601             }
602           else if ((operand->flags & V850_OPERAND_SRG) != 0) 
603             {
604               if (!system_register_name(&ex))
605                 {
606                   errmsg = "invalid system register name";
607                   goto error;
608                 }
609             }
610           else if ((operand->flags & V850_OPERAND_EP) != 0)
611             {
612               char *start = input_line_pointer;
613               char c = get_symbol_end ();
614               if (strcmp (start, "ep") != 0 && strcmp (start, "r30") != 0)
615                 {
616                   /* Put things back the way we found them.  */
617                   *input_line_pointer = c;
618                   input_line_pointer = start;
619                   errmsg = "expected EP register";
620                   goto error;
621                 }
622               *input_line_pointer = c;
623               str = input_line_pointer;
624               input_line_pointer = hold;
625               
626               while (*str == ' ' || *str == ',' || *str == '[' || *str == ']')
627                 ++str;
628               continue;
629             }
630           else if ((operand->flags & V850_OPERAND_CC) != 0) 
631             {
632               if (!cc_name(&ex))
633                 {
634                   errmsg = "invalid condition code name";
635                   goto error;
636                 }
637             }
638           else if (register_name (&ex)
639                    && (operand->flags & V850_OPERAND_REG) == 0)
640             {
641               errmsg = "syntax error: register not expected";
642               goto error;
643             }
644           else if (system_register_name (&ex)
645                    && (operand->flags & V850_OPERAND_SRG) == 0)
646             {
647               errmsg = "syntax error: system register not expected";
648               goto error;
649             }
650           else if (cc_name (&ex)
651                    && (operand->flags & V850_OPERAND_CC) == 0)
652             {
653               errmsg = "syntax error: condition code not expected";
654               goto error;
655             }
656           else
657             {
658               expression(&ex);
659             }
660
661           switch (ex.X_op) 
662             {
663             case O_illegal:
664               errmsg = "illegal operand";
665               goto error;
666             case O_absent:
667               errmsg = "missing operand";
668               goto error;
669             case O_register:
670               if ((operand->flags & (V850_OPERAND_REG | V850_OPERAND_SRG)) == 0)
671                 {
672                   errmsg = "invalid operand";
673                   goto error;
674                 }
675                 
676               insn = v850_insert_operand (insn, operand, ex.X_add_number,
677                                           (char *) NULL, 0);
678               break;
679
680             case O_constant:
681               insn = v850_insert_operand (insn, operand, ex.X_add_number,
682                                           (char *) NULL, 0);
683               break;
684
685             default:
686               /* We need to generate a fixup for this expression.  */
687               if (fc >= MAX_INSN_FIXUPS)
688                 as_fatal ("too many fixups");
689               fixups[fc].exp = ex;
690               fixups[fc].opindex = *opindex_ptr;
691               fixups[fc].reloc = BFD_RELOC_UNUSED;
692               ++fc;
693               break;
694             }
695
696             }
697
698           str = input_line_pointer;
699           input_line_pointer = hold;
700
701           while (*str == ' ' || *str == ',' || *str == '[' || *str == ']')
702             ++str;
703         }
704       match = 1;
705
706     error:
707       if (match == 0)
708         {
709           next_opcode = opcode + 1;
710           if (next_opcode->opcode != 0 && !strcmp(next_opcode->name, opcode->name))
711             {
712               opcode = next_opcode;
713               continue;
714             }
715           
716           as_bad ("%s", errmsg);
717           return;
718         }
719       break;
720     }
721       
722   while (isspace (*str))
723     ++str;
724
725   if (*str != '\0')
726     as_bad ("junk at end of line: `%s'", str);
727
728   input_line_pointer = str;
729
730   /* Write out the instruction.
731
732      Four byte insns have an opcode with the two high bits on.  */ 
733   if ((insn & 0x0600) == 0x0600)
734     size = 4;
735   else
736     size = 2;
737   f = frag_more (size);
738   md_number_to_chars (f, insn, size);
739
740   /* Create any fixups.  At this point we do not use a
741      bfd_reloc_code_real_type, but instead just use the
742      BFD_RELOC_UNUSED plus the operand index.  This lets us easily
743      handle fixups for any operand type, although that is admittedly
744      not a very exciting feature.  We pick a BFD reloc type in
745      md_apply_fix.  */
746   for (i = 0; i < fc; i++)
747     {
748       const struct v850_operand *operand;
749
750       operand = &v850_operands[fixups[i].opindex];
751       if (fixups[i].reloc != BFD_RELOC_UNUSED)
752         {
753           reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
754           int size;
755           int offset;
756           fixS *fixP;
757
758           if (!reloc_howto)
759             abort();
760           
761           size = bfd_get_reloc_size (reloc_howto);
762           offset = 4 - size;
763
764           if (size < 1 || size > 4)
765             abort();
766
767           fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size,
768                               &fixups[i].exp, 
769                               reloc_howto->pc_relative,
770                               fixups[i].reloc);
771         }
772       else
773         {
774           fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
775                        &fixups[i].exp,
776                        1 /* FIXME: V850_OPERAND_RELATIVE ??? */,
777                        ((bfd_reloc_code_real_type)
778                         (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
779         }
780     }
781 }
782
783
784 /* if while processing a fixup, a reloc really needs to be created */
785 /* then it is done here */
786                  
787 arelent *
788 tc_gen_reloc (seg, fixp)
789      asection *seg;
790      fixS *fixp;
791 {
792   arelent *reloc;
793   reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
794   reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
795   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
796   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
797   if (reloc->howto == (reloc_howto_type *) NULL)
798     {
799       as_bad_where (fixp->fx_file, fixp->fx_line,
800                     "reloc %d not supported by object file format", (int)fixp->fx_r_type);
801       return NULL;
802     }
803   reloc->addend = fixp->fx_addnumber;
804   /*  printf("tc_gen_reloc: addr=%x  addend=%x\n", reloc->address, reloc->addend); */
805   return reloc;
806 }
807
808 int
809 md_estimate_size_before_relax (fragp, seg)
810      fragS *fragp;
811      asection *seg;
812 {
813   return 0;
814
815
816 long
817 md_pcrel_from (fixp)
818      fixS *fixp;
819 {
820   /* If the symbol is undefined, or in a section other than our own,
821      then let the linker figure it out.  */
822   if (fixp->fx_addsy != (symbolS *) NULL && ! S_IS_DEFINED (fixp->fx_addsy))
823     {
824       /* The symbol is undefined.  Let the linker figure it out.  */
825       return 0;
826     }
827   return fixp->fx_frag->fr_address + fixp->fx_where;
828 }
829
830 int
831 md_apply_fix3 (fixp, valuep, seg)
832      fixS *fixp;
833      valueT *valuep;
834      segT seg;
835 {
836   valueT value;
837   char *where;
838
839   if (fixp->fx_addsy == (symbolS *) NULL)
840     {
841       value = *valuep;
842       fixp->fx_done = 1;
843     }
844   else if (fixp->fx_pcrel)
845     value = *valuep;
846   else
847     {
848       value = fixp->fx_offset;
849       if (fixp->fx_subsy != (symbolS *) NULL)
850         {
851           if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
852             value -= S_GET_VALUE (fixp->fx_subsy);
853           else
854             {
855               /* We don't actually support subtracting a symbol.  */
856               as_bad_where (fixp->fx_file, fixp->fx_line,
857                             "expression too complex");
858             }
859         }
860     }
861
862   /* printf("md_apply_fix: value=0x%x  type=%d\n",  value, fixp->fx_r_type); */
863
864   if ((int) fixp->fx_r_type >= (int) BFD_RELOC_UNUSED)
865     {
866       int opindex;
867       const struct v850_operand *operand;
868       char *where;
869       unsigned long insn;
870
871       opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
872       operand = &v850_operands[opindex];
873
874       /* Fetch the instruction, insert the fully resolved operand
875          value, and stuff the instruction back again.
876
877          Note the instruction has been stored in little endian
878          format!  */
879       where = fixp->fx_frag->fr_literal + fixp->fx_where;
880
881       insn = bfd_getl32((unsigned char *) where);
882       insn = v850_insert_operand (insn, operand, (offsetT) value,
883                                   fixp->fx_file, fixp->fx_line);
884       bfd_putl32((bfd_vma) insn, (unsigned char *) where);
885
886       if (fixp->fx_done)
887         {
888           /* Nothing else to do here. */
889           return 1;
890         }
891
892       /* Determine a BFD reloc value based on the operand information.  
893          We are only prepared to turn a few of the operands into relocs. */
894
895       if (operand->bits == 22)
896         fixp->fx_r_type = BFD_RELOC_V850_22_PCREL;
897       else if (operand->bits == 9)
898         fixp->fx_r_type = BFD_RELOC_V850_9_PCREL;
899       else
900         {
901           as_bad_where(fixp->fx_file, fixp->fx_line,
902                        "unresolved expression that must be resolved");
903           fixp->fx_done = 1;
904           return 1;
905         }
906     }
907   else if (fixp->fx_done)
908     {
909       /* We still have to insert the value into memory!  */
910       where = fixp->fx_frag->fr_literal + fixp->fx_where;
911       if (fixp->fx_size == 1)
912         *where = value & 0xff;
913       if (fixp->fx_size == 2)
914         bfd_putl16(value & 0xffff, (unsigned char *) where);
915       if (fixp->fx_size == 4)
916         bfd_putl32(value, (unsigned char *) where);
917     }
918
919   fixp->fx_addnumber = value;
920   return 1;
921 }
922
923 \f
924 /* Insert an operand value into an instruction.  */
925
926 static unsigned long
927 v850_insert_operand (insn, operand, val, file, line)
928      unsigned long insn;
929      const struct v850_operand *operand;
930      offsetT val;
931      char *file;
932      unsigned int line;
933 {
934   if (operand->bits != 16)
935     {
936       long min, max;
937       offsetT test;
938
939       if ((operand->flags & V850_OPERAND_SIGNED) != 0)
940         {
941             max = (1 << (operand->bits - 1)) - 1;
942           min = - (1 << (operand->bits - 1));
943         }
944       else
945         {
946           max = (1 << operand->bits) - 1;
947           min = 0;
948         }
949
950       test = val;
951
952
953       if (test < (offsetT) min || test > (offsetT) max)
954         {
955           const char *err =
956             "operand out of range (%s not between %ld and %ld)";
957           char buf[100];
958
959           sprint_value (buf, test);
960           if (file == (char *) NULL)
961             as_warn (err, buf, min, max);
962           else
963             as_warn_where (file, line, err, buf, min, max);
964         }
965     }
966
967   if (operand->insert)
968     {
969       const char *message = NULL;
970       insn = (*operand->insert) (insn, val, &message);
971       if (message != NULL)
972         {
973           if (file == (char *) NULL)
974             as_warn (message);
975           else
976             as_warn_where (file, line, message);
977         }
978     }
979   else
980     insn |= (((long) val & ((1 << operand->bits) - 1)) << operand->shift);
981   return insn;
982 }