* config/tc-v850.c (v850_reloc_prefix): Recognize zdaoff, tdaoff
[platform/upstream/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   if (strncmp (input_line_pointer, "sdaoff(", 7) == 0)
473     {
474       input_line_pointer += 7;
475       return BFD_RELOC_V850_SDA_OFFSET;
476     }
477
478   if (strncmp (input_line_pointer, "zdaoff(", 7) == 0)
479     {
480       input_line_pointer += 7;
481       return BFD_RELOC_V850_ZDA_OFFSET;
482     }
483
484   if (strncmp (input_line_pointer, "tdaoff(", 7) == 0)
485     {
486       input_line_pointer += 7;
487       return BFD_RELOC_V850_TDA_OFFSET;
488     }
489
490   /* FIXME: implement sda, tda, zda here */
491
492   return BFD_RELOC_UNUSED;
493 }
494
495 void
496 md_assemble (str) 
497      char *str;
498 {
499   char *s;
500   struct v850_opcode *opcode;
501   struct v850_opcode *next_opcode;
502   const unsigned char *opindex_ptr;
503   int next_opindex;
504   unsigned long insn, size;
505   char *f;
506   int i;
507   int match;
508   bfd_reloc_code_real_type reloc;
509
510   /* Get the opcode.  */
511   for (s = str; *s != '\0' && ! isspace (*s); s++)
512     ;
513   if (*s != '\0')
514     *s++ = '\0';
515
516   /* find the first opcode with the proper name */
517   opcode = (struct v850_opcode *)hash_find (v850_hash, str);
518   if (opcode == NULL)
519     {
520       as_bad ("Unrecognized opcode: `%s'", str);
521       return;
522     }
523
524   str = s;
525   while (isspace (*str))
526     ++str;
527
528   input_line_pointer = str;
529
530   for(;;)
531     {
532       const char *errmsg = NULL;
533
534       fc = 0;
535       match = 0;
536       next_opindex = 0;
537       insn = opcode->opcode;
538       for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
539         {
540           const struct v850_operand *operand;
541           char *hold;
542           expressionS ex;
543
544           if (next_opindex == 0)
545             {
546               operand = &v850_operands[*opindex_ptr];
547             }
548           else
549             {
550               operand = &v850_operands[next_opindex];
551               next_opindex = 0;
552             }
553
554           errmsg = NULL;
555
556           while (*str == ' ' || *str == ',' || *str == '[' || *str == ']')
557             ++str;
558
559           /* Gather the operand. */
560           hold = input_line_pointer;
561           input_line_pointer = str;
562
563
564           /* lo(), hi(), hi0(), etc... */
565           if ((reloc = v850_reloc_prefix()) != BFD_RELOC_UNUSED)
566             {
567               expression(&ex);
568
569               if (*input_line_pointer++ != ')')
570                 {
571                   errmsg = "syntax error: expected `)'";
572                   goto error;
573                 }
574               
575               if (ex.X_op == O_constant)
576                 {
577                   switch (reloc)
578                     {
579                     case BFD_RELOC_LO16:
580                       ex.X_add_number &= 0xffff;
581                       break;
582
583                     case BFD_RELOC_HI16:
584                       ex.X_add_number = ((ex.X_add_number >> 16) & 0xffff);
585                       break;
586
587                     case BFD_RELOC_HI16_S:
588                       ex.X_add_number = ((ex.X_add_number >> 16) & 0xffff)
589                         + ((ex.X_add_number >> 15) & 1);
590                       break;
591
592                     default:
593                       break;
594                     }
595
596                   insn = v850_insert_operand (insn, operand, ex.X_add_number,
597                                               (char *) NULL, 0);
598                 }
599               else
600                 {
601                   if (fc > MAX_INSN_FIXUPS)
602                     as_fatal ("too many fixups");
603
604                   fixups[fc].exp = ex;
605                   fixups[fc].opindex = *opindex_ptr;
606                   fixups[fc].reloc = reloc;
607                   fc++;
608                 }
609             }
610           else
611             {
612           if ((operand->flags & V850_OPERAND_REG) != 0) 
613             {
614               if (!register_name(&ex))
615                 {
616                   errmsg = "invalid register name";
617                   goto error;
618                 }
619             }
620           else if ((operand->flags & V850_OPERAND_SRG) != 0) 
621             {
622               if (!system_register_name(&ex))
623                 {
624                   errmsg = "invalid system register name";
625                   goto error;
626                 }
627             }
628           else if ((operand->flags & V850_OPERAND_EP) != 0)
629             {
630               char *start = input_line_pointer;
631               char c = get_symbol_end ();
632               if (strcmp (start, "ep") != 0 && strcmp (start, "r30") != 0)
633                 {
634                   /* Put things back the way we found them.  */
635                   *input_line_pointer = c;
636                   input_line_pointer = start;
637                   errmsg = "expected EP register";
638                   goto error;
639                 }
640               *input_line_pointer = c;
641               str = input_line_pointer;
642               input_line_pointer = hold;
643               
644               while (*str == ' ' || *str == ',' || *str == '[' || *str == ']')
645                 ++str;
646               continue;
647             }
648           else if ((operand->flags & V850_OPERAND_CC) != 0) 
649             {
650               if (!cc_name(&ex))
651                 {
652                   errmsg = "invalid condition code name";
653                   goto error;
654                 }
655             }
656           else if (register_name (&ex)
657                    && (operand->flags & V850_OPERAND_REG) == 0)
658             {
659               errmsg = "syntax error: register not expected";
660               goto error;
661             }
662           else if (system_register_name (&ex)
663                    && (operand->flags & V850_OPERAND_SRG) == 0)
664             {
665               errmsg = "syntax error: system register not expected";
666               goto error;
667             }
668           else if (cc_name (&ex)
669                    && (operand->flags & V850_OPERAND_CC) == 0)
670             {
671               errmsg = "syntax error: condition code not expected";
672               goto error;
673             }
674           else
675             {
676               expression(&ex);
677             }
678
679           switch (ex.X_op) 
680             {
681             case O_illegal:
682               errmsg = "illegal operand";
683               goto error;
684             case O_absent:
685               errmsg = "missing operand";
686               goto error;
687             case O_register:
688               if ((operand->flags & (V850_OPERAND_REG | V850_OPERAND_SRG)) == 0)
689                 {
690                   errmsg = "invalid operand";
691                   goto error;
692                 }
693                 
694               insn = v850_insert_operand (insn, operand, ex.X_add_number,
695                                           (char *) NULL, 0);
696               break;
697
698             case O_constant:
699               insn = v850_insert_operand (insn, operand, ex.X_add_number,
700                                           (char *) NULL, 0);
701               break;
702
703             default:
704               /* We need to generate a fixup for this expression.  */
705               if (fc >= MAX_INSN_FIXUPS)
706                 as_fatal ("too many fixups");
707               fixups[fc].exp = ex;
708               fixups[fc].opindex = *opindex_ptr;
709               fixups[fc].reloc = BFD_RELOC_UNUSED;
710               ++fc;
711               break;
712             }
713
714             }
715
716           str = input_line_pointer;
717           input_line_pointer = hold;
718
719           while (*str == ' ' || *str == ',' || *str == '[' || *str == ']')
720             ++str;
721         }
722       match = 1;
723
724     error:
725       if (match == 0)
726         {
727           next_opcode = opcode + 1;
728           if (next_opcode->opcode != 0 && !strcmp(next_opcode->name, opcode->name))
729             {
730               opcode = next_opcode;
731               continue;
732             }
733           
734           as_bad ("%s", errmsg);
735           return;
736         }
737       break;
738     }
739       
740   while (isspace (*str))
741     ++str;
742
743   if (*str != '\0')
744     as_bad ("junk at end of line: `%s'", str);
745
746   input_line_pointer = str;
747
748   /* Write out the instruction.
749
750      Four byte insns have an opcode with the two high bits on.  */ 
751   if ((insn & 0x0600) == 0x0600)
752     size = 4;
753   else
754     size = 2;
755   f = frag_more (size);
756   md_number_to_chars (f, insn, size);
757
758   /* Create any fixups.  At this point we do not use a
759      bfd_reloc_code_real_type, but instead just use the
760      BFD_RELOC_UNUSED plus the operand index.  This lets us easily
761      handle fixups for any operand type, although that is admittedly
762      not a very exciting feature.  We pick a BFD reloc type in
763      md_apply_fix.  */
764   for (i = 0; i < fc; i++)
765     {
766       const struct v850_operand *operand;
767
768       operand = &v850_operands[fixups[i].opindex];
769       if (fixups[i].reloc != BFD_RELOC_UNUSED)
770         {
771           reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
772           int size;
773           int offset;
774           fixS *fixP;
775
776           if (!reloc_howto)
777             abort();
778           
779           size = bfd_get_reloc_size (reloc_howto);
780           offset = 4 - size;
781
782           if (size < 1 || size > 4)
783             abort();
784
785           fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size,
786                               &fixups[i].exp, 
787                               reloc_howto->pc_relative,
788                               fixups[i].reloc);
789         }
790       else
791         {
792           fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
793                        &fixups[i].exp,
794                        1 /* FIXME: V850_OPERAND_RELATIVE ??? */,
795                        ((bfd_reloc_code_real_type)
796                         (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
797         }
798     }
799 }
800
801
802 /* if while processing a fixup, a reloc really needs to be created */
803 /* then it is done here */
804                  
805 arelent *
806 tc_gen_reloc (seg, fixp)
807      asection *seg;
808      fixS *fixp;
809 {
810   arelent *reloc;
811   reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
812   reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
813   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
814   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
815   if (reloc->howto == (reloc_howto_type *) NULL)
816     {
817       as_bad_where (fixp->fx_file, fixp->fx_line,
818                     "reloc %d not supported by object file format", (int)fixp->fx_r_type);
819       return NULL;
820     }
821   reloc->addend = fixp->fx_addnumber;
822   /*  printf("tc_gen_reloc: addr=%x  addend=%x\n", reloc->address, reloc->addend); */
823   return reloc;
824 }
825
826 int
827 md_estimate_size_before_relax (fragp, seg)
828      fragS *fragp;
829      asection *seg;
830 {
831   return 0;
832
833
834 long
835 md_pcrel_from (fixp)
836      fixS *fixp;
837 {
838   /* If the symbol is undefined, or in a section other than our own,
839      then let the linker figure it out.  */
840   if (fixp->fx_addsy != (symbolS *) NULL && ! S_IS_DEFINED (fixp->fx_addsy))
841     {
842       /* The symbol is undefined.  Let the linker figure it out.  */
843       return 0;
844     }
845   return fixp->fx_frag->fr_address + fixp->fx_where;
846 }
847
848 int
849 md_apply_fix3 (fixp, valuep, seg)
850      fixS *fixp;
851      valueT *valuep;
852      segT seg;
853 {
854   valueT value;
855   char *where;
856
857   if (fixp->fx_addsy == (symbolS *) NULL)
858     {
859       value = *valuep;
860       fixp->fx_done = 1;
861     }
862   else if (fixp->fx_pcrel)
863     value = *valuep;
864   else
865     {
866       value = fixp->fx_offset;
867       if (fixp->fx_subsy != (symbolS *) NULL)
868         {
869           if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
870             value -= S_GET_VALUE (fixp->fx_subsy);
871           else
872             {
873               /* We don't actually support subtracting a symbol.  */
874               as_bad_where (fixp->fx_file, fixp->fx_line,
875                             "expression too complex");
876             }
877         }
878     }
879
880   /* printf("md_apply_fix: value=0x%x  type=%d\n",  value, fixp->fx_r_type); */
881
882   if ((int) fixp->fx_r_type >= (int) BFD_RELOC_UNUSED)
883     {
884       int opindex;
885       const struct v850_operand *operand;
886       char *where;
887       unsigned long insn;
888
889       opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED;
890       operand = &v850_operands[opindex];
891
892       /* Fetch the instruction, insert the fully resolved operand
893          value, and stuff the instruction back again.
894
895          Note the instruction has been stored in little endian
896          format!  */
897       where = fixp->fx_frag->fr_literal + fixp->fx_where;
898
899       insn = bfd_getl32((unsigned char *) where);
900       insn = v850_insert_operand (insn, operand, (offsetT) value,
901                                   fixp->fx_file, fixp->fx_line);
902       bfd_putl32((bfd_vma) insn, (unsigned char *) where);
903
904       if (fixp->fx_done)
905         {
906           /* Nothing else to do here. */
907           return 1;
908         }
909
910       /* Determine a BFD reloc value based on the operand information.  
911          We are only prepared to turn a few of the operands into relocs. */
912
913       if (operand->bits == 22)
914         fixp->fx_r_type = BFD_RELOC_V850_22_PCREL;
915       else if (operand->bits == 9)
916         fixp->fx_r_type = BFD_RELOC_V850_9_PCREL;
917       else
918         {
919           as_bad_where(fixp->fx_file, fixp->fx_line,
920                        "unresolved expression that must be resolved");
921           fixp->fx_done = 1;
922           return 1;
923         }
924     }
925   else if (fixp->fx_done)
926     {
927       /* We still have to insert the value into memory!  */
928       where = fixp->fx_frag->fr_literal + fixp->fx_where;
929       if (fixp->fx_size == 1)
930         *where = value & 0xff;
931       if (fixp->fx_size == 2)
932         bfd_putl16(value & 0xffff, (unsigned char *) where);
933       if (fixp->fx_size == 4)
934         bfd_putl32(value, (unsigned char *) where);
935     }
936
937   fixp->fx_addnumber = value;
938   return 1;
939 }
940
941 \f
942 /* Insert an operand value into an instruction.  */
943
944 static unsigned long
945 v850_insert_operand (insn, operand, val, file, line)
946      unsigned long insn;
947      const struct v850_operand *operand;
948      offsetT val;
949      char *file;
950      unsigned int line;
951 {
952   if (operand->bits != 16)
953     {
954       long min, max;
955       offsetT test;
956
957       if ((operand->flags & V850_OPERAND_SIGNED) != 0)
958         {
959             max = (1 << (operand->bits - 1)) - 1;
960           min = - (1 << (operand->bits - 1));
961         }
962       else
963         {
964           max = (1 << operand->bits) - 1;
965           min = 0;
966         }
967
968       test = val;
969
970
971       if (test < (offsetT) min || test > (offsetT) max)
972         {
973           const char *err =
974             "operand out of range (%s not between %ld and %ld)";
975           char buf[100];
976
977           sprint_value (buf, test);
978           if (file == (char *) NULL)
979             as_warn (err, buf, min, max);
980           else
981             as_warn_where (file, line, err, buf, min, max);
982         }
983     }
984
985   if (operand->insert)
986     {
987       const char *message = NULL;
988       insn = (*operand->insert) (insn, val, &message);
989       if (message != NULL)
990         {
991           if (file == (char *) NULL)
992             as_warn (message);
993           else
994             as_warn_where (file, line, message);
995         }
996     }
997   else
998     insn |= (((long) val & ((1 << operand->bits) - 1)) << operand->shift);
999   return insn;
1000 }