xref: /openbsd-src/gnu/usr.bin/binutils/gas/config/tc-xstormy16.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
1d2201f2fSdrahn /* tc-xstormy16.c -- Assembler for the Sanyo XSTORMY16.
2d2201f2fSdrahn    Copyright 2000, 2001, 2002, 2003 Free Software Foundation.
3d2201f2fSdrahn 
4d2201f2fSdrahn    This file is part of GAS, the GNU Assembler.
5d2201f2fSdrahn 
6d2201f2fSdrahn    GAS is free software; you can redistribute it and/or modify
7d2201f2fSdrahn    it under the terms of the GNU General Public License as published by
8d2201f2fSdrahn    the Free Software Foundation; either version 2, or (at your option)
9d2201f2fSdrahn    any later version.
10d2201f2fSdrahn 
11d2201f2fSdrahn    GAS is distributed in the hope that it will be useful,
12d2201f2fSdrahn    but WITHOUT ANY WARRANTY; without even the implied warranty of
13d2201f2fSdrahn    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14d2201f2fSdrahn    GNU General Public License for more details.
15d2201f2fSdrahn 
16d2201f2fSdrahn    You should have received a copy of the GNU General Public License
17d2201f2fSdrahn    along with GAS; see the file COPYING.  If not, write to
18d2201f2fSdrahn    the Free Software Foundation, 59 Temple Place - Suite 330,
19d2201f2fSdrahn    Boston, MA 02111-1307, USA.  */
20d2201f2fSdrahn 
21d2201f2fSdrahn #include <stdio.h>
22d2201f2fSdrahn #include "as.h"
23d2201f2fSdrahn #include "subsegs.h"
24d2201f2fSdrahn #include "symcat.h"
25d2201f2fSdrahn #include "opcodes/xstormy16-desc.h"
26d2201f2fSdrahn #include "opcodes/xstormy16-opc.h"
27d2201f2fSdrahn #include "cgen.h"
28d2201f2fSdrahn 
29d2201f2fSdrahn /* Structure to hold all of the different components describing
30d2201f2fSdrahn    an individual instruction.  */
31d2201f2fSdrahn typedef struct
32d2201f2fSdrahn {
33d2201f2fSdrahn   const CGEN_INSN *	insn;
34d2201f2fSdrahn   const CGEN_INSN *	orig_insn;
35d2201f2fSdrahn   CGEN_FIELDS		fields;
36d2201f2fSdrahn #if CGEN_INT_INSN_P
37d2201f2fSdrahn   CGEN_INSN_INT         buffer [1];
38d2201f2fSdrahn #define INSN_VALUE(buf) (*(buf))
39d2201f2fSdrahn #else
40d2201f2fSdrahn   unsigned char         buffer [CGEN_MAX_INSN_SIZE];
41d2201f2fSdrahn #define INSN_VALUE(buf) (buf)
42d2201f2fSdrahn #endif
43d2201f2fSdrahn   char *		addr;
44d2201f2fSdrahn   fragS *		frag;
45d2201f2fSdrahn   int                   num_fixups;
46d2201f2fSdrahn   fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
47d2201f2fSdrahn   int                   indices [MAX_OPERAND_INSTANCES];
48d2201f2fSdrahn }
49d2201f2fSdrahn xstormy16_insn;
50d2201f2fSdrahn 
51d2201f2fSdrahn const char comment_chars[]        = ";";
52d2201f2fSdrahn const char line_comment_chars[]   = "#";
53d2201f2fSdrahn const char line_separator_chars[] = "|";
54d2201f2fSdrahn const char EXP_CHARS[]            = "eE";
55d2201f2fSdrahn const char FLT_CHARS[]            = "dD";
56d2201f2fSdrahn 
57d2201f2fSdrahn #define O_fptr_symbol	(O_max + 1)
58d2201f2fSdrahn 
59d2201f2fSdrahn #define XSTORMY16_SHORTOPTS ""
60d2201f2fSdrahn const char * md_shortopts = XSTORMY16_SHORTOPTS;
61d2201f2fSdrahn 
62d2201f2fSdrahn struct option md_longopts[] =
63d2201f2fSdrahn {
64d2201f2fSdrahn   {NULL, no_argument, NULL, 0}
65d2201f2fSdrahn };
66d2201f2fSdrahn size_t md_longopts_size = sizeof (md_longopts);
67d2201f2fSdrahn 
68d2201f2fSdrahn int
md_parse_option(c,arg)69d2201f2fSdrahn md_parse_option (c, arg)
70d2201f2fSdrahn      int    c ATTRIBUTE_UNUSED;
71d2201f2fSdrahn      char * arg ATTRIBUTE_UNUSED;
72d2201f2fSdrahn {
73d2201f2fSdrahn   return 0;
74d2201f2fSdrahn }
75d2201f2fSdrahn 
76d2201f2fSdrahn void
md_show_usage(stream)77d2201f2fSdrahn md_show_usage (stream)
78d2201f2fSdrahn   FILE * stream;
79d2201f2fSdrahn {
80d2201f2fSdrahn   fprintf (stream, _(" XSTORMY16 specific command line options:\n"));
81d2201f2fSdrahn }
82d2201f2fSdrahn 
83d2201f2fSdrahn /* The target specific pseudo-ops which we support.  */
84d2201f2fSdrahn const pseudo_typeS md_pseudo_table[] =
85d2201f2fSdrahn {
86d2201f2fSdrahn   { "word",	cons,		4 },
87d2201f2fSdrahn   { NULL, 	NULL, 		0 }
88d2201f2fSdrahn };
89d2201f2fSdrahn 
90d2201f2fSdrahn 
91d2201f2fSdrahn void
md_begin()92d2201f2fSdrahn md_begin ()
93d2201f2fSdrahn {
94d2201f2fSdrahn   /* Initialize the `cgen' interface.  */
95d2201f2fSdrahn 
96d2201f2fSdrahn   /* Set the machine number and endian.  */
97d2201f2fSdrahn   gas_cgen_cpu_desc = xstormy16_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
98d2201f2fSdrahn 					  CGEN_CPU_OPEN_ENDIAN,
99d2201f2fSdrahn 					  CGEN_ENDIAN_LITTLE,
100d2201f2fSdrahn 					  CGEN_CPU_OPEN_END);
101d2201f2fSdrahn   xstormy16_cgen_init_asm (gas_cgen_cpu_desc);
102d2201f2fSdrahn 
103d2201f2fSdrahn   /* This is a callback from cgen to gas to parse operands.  */
104d2201f2fSdrahn   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
105d2201f2fSdrahn }
106d2201f2fSdrahn 
107*cf2f2c56Smiod static bfd_boolean skipping_fptr = FALSE;
108*cf2f2c56Smiod 
109d2201f2fSdrahn void
md_assemble(str)110d2201f2fSdrahn md_assemble (str)
111d2201f2fSdrahn      char * str;
112d2201f2fSdrahn {
113d2201f2fSdrahn   xstormy16_insn insn;
114d2201f2fSdrahn   char *    errmsg;
115d2201f2fSdrahn 
116*cf2f2c56Smiod   /* Make sure that if we had an erroneous input line which triggered
117*cf2f2c56Smiod      the skipping_fptr boolean that it does not affect following lines.  */
118*cf2f2c56Smiod   skipping_fptr = FALSE;
119*cf2f2c56Smiod 
120d2201f2fSdrahn   /* Initialize GAS's cgen interface for a new instruction.  */
121d2201f2fSdrahn   gas_cgen_init_parse ();
122d2201f2fSdrahn 
123d2201f2fSdrahn   insn.insn = xstormy16_cgen_assemble_insn
124d2201f2fSdrahn     (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
125d2201f2fSdrahn 
126d2201f2fSdrahn   if (!insn.insn)
127d2201f2fSdrahn     {
128d2201f2fSdrahn       as_bad (errmsg);
129d2201f2fSdrahn       return;
130d2201f2fSdrahn     }
131d2201f2fSdrahn 
132d2201f2fSdrahn   /* Doesn't really matter what we pass for RELAX_P here.  */
133d2201f2fSdrahn   gas_cgen_finish_insn (insn.insn, insn.buffer,
134d2201f2fSdrahn 			CGEN_FIELDS_BITSIZE (& insn.fields), 0, NULL);
135d2201f2fSdrahn }
136d2201f2fSdrahn 
137d2201f2fSdrahn void
md_operand(e)138d2201f2fSdrahn md_operand (e)
139d2201f2fSdrahn      expressionS * e;
140d2201f2fSdrahn {
141d2201f2fSdrahn   if (*input_line_pointer != '@')
142d2201f2fSdrahn     return;
143d2201f2fSdrahn 
144d2201f2fSdrahn   if (strncmp (input_line_pointer + 1, "fptr", 4) == 0)
145d2201f2fSdrahn     {
146d2201f2fSdrahn       input_line_pointer += 5;
147d2201f2fSdrahn       SKIP_WHITESPACE ();
148d2201f2fSdrahn       if (*input_line_pointer != '(')
149d2201f2fSdrahn 	{
150d2201f2fSdrahn 	  as_bad ("Expected '('");
151d2201f2fSdrahn 	  goto err;
152d2201f2fSdrahn 	}
153d2201f2fSdrahn       input_line_pointer++;
154d2201f2fSdrahn 
155d2201f2fSdrahn       expression (e);
156d2201f2fSdrahn 
157d2201f2fSdrahn       if (*input_line_pointer != ')')
158d2201f2fSdrahn 	{
159d2201f2fSdrahn 	  as_bad ("Missing ')'");
160d2201f2fSdrahn 	  goto err;
161d2201f2fSdrahn 	}
162d2201f2fSdrahn       input_line_pointer++;
163*cf2f2c56Smiod       SKIP_WHITESPACE ();
164d2201f2fSdrahn 
165d2201f2fSdrahn       if (e->X_op != O_symbol)
166d2201f2fSdrahn 	as_bad ("Not a symbolic expression");
167*cf2f2c56Smiod       else if (* input_line_pointer == '-')
168*cf2f2c56Smiod 	/* We are computing the difference of two function pointers
169*cf2f2c56Smiod 	   like this:
170*cf2f2c56Smiod 
171*cf2f2c56Smiod 	    .hword  @fptr (foo) - @fptr (bar)
172*cf2f2c56Smiod 
173*cf2f2c56Smiod 	  In this situation we do not want to generate O_fptr_symbol
174*cf2f2c56Smiod 	  operands because the result is an absolute value, not a
175*cf2f2c56Smiod 	  function pointer.
176*cf2f2c56Smiod 
177*cf2f2c56Smiod 	  We need to make the check here, rather than when the fixup
178*cf2f2c56Smiod 	  is generated as the function names (foo & bar in the above
179*cf2f2c56Smiod 	  example) might be local symbols and we want the expression
180*cf2f2c56Smiod 	  to be evaluated now.  This kind of thing can happen when
181*cf2f2c56Smiod 	  gcc is generating computed gotos.  */
182*cf2f2c56Smiod 	skipping_fptr = TRUE;
183*cf2f2c56Smiod       else if (skipping_fptr)
184*cf2f2c56Smiod 	skipping_fptr = FALSE;
185d2201f2fSdrahn       else
186d2201f2fSdrahn         e->X_op = O_fptr_symbol;
187d2201f2fSdrahn     }
188d2201f2fSdrahn 
189d2201f2fSdrahn   return;
190d2201f2fSdrahn  err:
191d2201f2fSdrahn   ignore_rest_of_line ();
192d2201f2fSdrahn }
193d2201f2fSdrahn 
194d2201f2fSdrahn /* Called while parsing data to create a fixup.
195d2201f2fSdrahn    Create BFD_RELOC_XSTORMY16_FPTR16 relocations.  */
196d2201f2fSdrahn 
197d2201f2fSdrahn void
xstormy16_cons_fix_new(f,where,nbytes,exp)198d2201f2fSdrahn xstormy16_cons_fix_new (f, where, nbytes, exp)
199d2201f2fSdrahn      fragS *f;
200d2201f2fSdrahn      int where;
201d2201f2fSdrahn      int nbytes;
202d2201f2fSdrahn      expressionS *exp;
203d2201f2fSdrahn {
204d2201f2fSdrahn   bfd_reloc_code_real_type code;
205d2201f2fSdrahn   fixS *fix;
206d2201f2fSdrahn 
207d2201f2fSdrahn   if (exp->X_op == O_fptr_symbol)
208d2201f2fSdrahn     {
209d2201f2fSdrahn       if (nbytes != 2)
210d2201f2fSdrahn 	{
211d2201f2fSdrahn 	  as_bad ("unsupported fptr fixup size %d", nbytes);
212d2201f2fSdrahn 	  return;
213d2201f2fSdrahn 	}
214d2201f2fSdrahn       exp->X_op = O_symbol;
215d2201f2fSdrahn       code = BFD_RELOC_XSTORMY16_FPTR16;
216d2201f2fSdrahn     }
217d2201f2fSdrahn   else if (nbytes == 1)
218d2201f2fSdrahn     code = BFD_RELOC_8;
219d2201f2fSdrahn   else if (nbytes == 2)
220d2201f2fSdrahn     code = BFD_RELOC_16;
221d2201f2fSdrahn   else if (nbytes == 4)
222d2201f2fSdrahn     code = BFD_RELOC_32;
223d2201f2fSdrahn   else
224d2201f2fSdrahn     {
225d2201f2fSdrahn       as_bad ("unsupported fixup size %d", nbytes);
226d2201f2fSdrahn       return;
227d2201f2fSdrahn     }
228d2201f2fSdrahn 
229d2201f2fSdrahn   fix = fix_new_exp (f, where, nbytes, exp, 0, code);
230d2201f2fSdrahn }
231d2201f2fSdrahn 
232d2201f2fSdrahn /* Called while parsing an instruction to create a fixup.
233d2201f2fSdrahn    Create BFD_RELOC_XSTORMY16_FPTR16 relocations.  */
234d2201f2fSdrahn 
235d2201f2fSdrahn fixS *
xstormy16_cgen_record_fixup_exp(frag,where,insn,length,operand,opinfo,exp)236d2201f2fSdrahn xstormy16_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp)
237d2201f2fSdrahn      fragS *              frag;
238d2201f2fSdrahn      int                  where;
239d2201f2fSdrahn      const CGEN_INSN *    insn;
240d2201f2fSdrahn      int                  length;
241d2201f2fSdrahn      const CGEN_OPERAND * operand;
242d2201f2fSdrahn      int                  opinfo;
243d2201f2fSdrahn      expressionS *        exp;
244d2201f2fSdrahn {
245d2201f2fSdrahn   fixS *fixP;
246d2201f2fSdrahn   operatorT op = exp->X_op;
247d2201f2fSdrahn 
248d2201f2fSdrahn   if (op == O_fptr_symbol)
249d2201f2fSdrahn     exp->X_op = O_symbol;
250d2201f2fSdrahn 
251d2201f2fSdrahn   fixP = gas_cgen_record_fixup_exp (frag, where, insn, length,
252d2201f2fSdrahn 				    operand, opinfo, exp);
253d2201f2fSdrahn 
254d2201f2fSdrahn   if (op == O_fptr_symbol)
255d2201f2fSdrahn     {
256d2201f2fSdrahn       if (operand->type != XSTORMY16_OPERAND_IMM16)
257d2201f2fSdrahn 	as_bad ("unsupported fptr fixup");
258d2201f2fSdrahn       else
259d2201f2fSdrahn 	{
260d2201f2fSdrahn 	  fixP->fx_r_type = BFD_RELOC_XSTORMY16_FPTR16;
261d2201f2fSdrahn 	  fixP->fx_where += 2;
262d2201f2fSdrahn 	}
263d2201f2fSdrahn     }
264d2201f2fSdrahn 
265d2201f2fSdrahn   return fixP;
266d2201f2fSdrahn }
267d2201f2fSdrahn 
268d2201f2fSdrahn valueT
md_section_align(segment,size)269d2201f2fSdrahn md_section_align (segment, size)
270d2201f2fSdrahn      segT   segment;
271d2201f2fSdrahn      valueT size;
272d2201f2fSdrahn {
273d2201f2fSdrahn   int align = bfd_get_section_alignment (stdoutput, segment);
274d2201f2fSdrahn   return ((size + (1 << align) - 1) & (-1 << align));
275d2201f2fSdrahn }
276d2201f2fSdrahn 
277d2201f2fSdrahn symbolS *
md_undefined_symbol(name)278d2201f2fSdrahn md_undefined_symbol (name)
279d2201f2fSdrahn   char * name ATTRIBUTE_UNUSED;
280d2201f2fSdrahn {
281d2201f2fSdrahn   return 0;
282d2201f2fSdrahn }
283d2201f2fSdrahn 
284d2201f2fSdrahn /* Return an initial guess of the length by which a fragment must grow to
285d2201f2fSdrahn    hold a branch to reach its destination.
286d2201f2fSdrahn    Also updates fr_type/fr_subtype as necessary.
287d2201f2fSdrahn 
288d2201f2fSdrahn    Called just before doing relaxation.
289d2201f2fSdrahn    Any symbol that is now undefined will not become defined.
290d2201f2fSdrahn    The guess for fr_var is ACTUALLY the growth beyond fr_fix.
291d2201f2fSdrahn    Whatever we do to grow fr_fix or fr_var contributes to our returned value.
292d2201f2fSdrahn    Although it may not be explicit in the frag, pretend fr_var starts with a
293d2201f2fSdrahn    0 value.  */
294d2201f2fSdrahn 
295d2201f2fSdrahn int
md_estimate_size_before_relax(fragP,segment)296d2201f2fSdrahn md_estimate_size_before_relax (fragP, segment)
297d2201f2fSdrahn      fragS * fragP ATTRIBUTE_UNUSED;
298d2201f2fSdrahn      segT    segment ATTRIBUTE_UNUSED;
299d2201f2fSdrahn {
300d2201f2fSdrahn   /* No assembler relaxation is defined (or necessary) for this port.  */
301d2201f2fSdrahn   abort ();
302d2201f2fSdrahn }
303d2201f2fSdrahn 
304d2201f2fSdrahn /* *fragP has been relaxed to its final size, and now needs to have
305d2201f2fSdrahn    the bytes inside it modified to conform to the new size.
306d2201f2fSdrahn 
307d2201f2fSdrahn    Called after relaxation is finished.
308d2201f2fSdrahn    fragP->fr_type == rs_machine_dependent.
309d2201f2fSdrahn    fragP->fr_subtype is the subtype of what the address relaxed to.  */
310d2201f2fSdrahn 
311d2201f2fSdrahn void
md_convert_frag(abfd,sec,fragP)312d2201f2fSdrahn md_convert_frag (abfd, sec, fragP)
313d2201f2fSdrahn   bfd *   abfd ATTRIBUTE_UNUSED;
314d2201f2fSdrahn   segT    sec ATTRIBUTE_UNUSED;
315d2201f2fSdrahn   fragS * fragP ATTRIBUTE_UNUSED;
316d2201f2fSdrahn {
317d2201f2fSdrahn   /* No assembler relaxation is defined (or necessary) for this port.  */
318d2201f2fSdrahn   abort ();
319d2201f2fSdrahn }
320d2201f2fSdrahn 
321d2201f2fSdrahn /* Functions concerning relocs.  */
322d2201f2fSdrahn 
323d2201f2fSdrahn /* The location from which a PC relative jump should be calculated,
324d2201f2fSdrahn    given a PC relative reloc.  */
325d2201f2fSdrahn 
326d2201f2fSdrahn long
md_pcrel_from_section(fixP,sec)327d2201f2fSdrahn md_pcrel_from_section (fixP, sec)
328d2201f2fSdrahn      fixS * fixP;
329d2201f2fSdrahn      segT   sec;
330d2201f2fSdrahn {
331d2201f2fSdrahn   if (fixP->fx_addsy != (symbolS *) NULL
332d2201f2fSdrahn       && (! S_IS_DEFINED (fixP->fx_addsy)
333*cf2f2c56Smiod 	  || S_GET_SEGMENT (fixP->fx_addsy) != sec)
334*cf2f2c56Smiod           || xstormy16_force_relocation (fixP))
335*cf2f2c56Smiod     /* The symbol is undefined,
336*cf2f2c56Smiod        or it is defined but not in this section,
337*cf2f2c56Smiod        or the relocation will be relative to this symbol not the section symbol.
338d2201f2fSdrahn        Let the linker figure it out.  */
339d2201f2fSdrahn     return 0;
340d2201f2fSdrahn 
341d2201f2fSdrahn   return fixP->fx_frag->fr_address + fixP->fx_where;
342d2201f2fSdrahn }
343d2201f2fSdrahn 
344d2201f2fSdrahn /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
345d2201f2fSdrahn    Returns BFD_RELOC_NONE if no reloc type can be found.
346d2201f2fSdrahn    *FIXP may be modified if desired.  */
347d2201f2fSdrahn 
348d2201f2fSdrahn bfd_reloc_code_real_type
md_cgen_lookup_reloc(insn,operand,fixP)349d2201f2fSdrahn md_cgen_lookup_reloc (insn, operand, fixP)
350d2201f2fSdrahn      const CGEN_INSN *    insn ATTRIBUTE_UNUSED;
351d2201f2fSdrahn      const CGEN_OPERAND * operand;
352d2201f2fSdrahn      fixS *               fixP;
353d2201f2fSdrahn {
354d2201f2fSdrahn   switch (operand->type)
355d2201f2fSdrahn     {
356d2201f2fSdrahn     case XSTORMY16_OPERAND_IMM2:
357d2201f2fSdrahn     case XSTORMY16_OPERAND_IMM3:
358d2201f2fSdrahn     case XSTORMY16_OPERAND_IMM3B:
359d2201f2fSdrahn     case XSTORMY16_OPERAND_IMM4:
360d2201f2fSdrahn     case XSTORMY16_OPERAND_HMEM8:
361d2201f2fSdrahn       return BFD_RELOC_NONE;
362d2201f2fSdrahn 
363d2201f2fSdrahn     case XSTORMY16_OPERAND_IMM12:
364d2201f2fSdrahn       fixP->fx_where += 2;
365d2201f2fSdrahn       return BFD_RELOC_XSTORMY16_12;
366d2201f2fSdrahn 
367d2201f2fSdrahn     case XSTORMY16_OPERAND_IMM8:
368d2201f2fSdrahn     case XSTORMY16_OPERAND_LMEM8:
369d2201f2fSdrahn       return fixP->fx_pcrel ? BFD_RELOC_8_PCREL : BFD_RELOC_8;
370d2201f2fSdrahn 
371d2201f2fSdrahn     case XSTORMY16_OPERAND_IMM16:
372d2201f2fSdrahn       /* This might have been processed at parse time.  */
373d2201f2fSdrahn       fixP->fx_where += 2;
374d2201f2fSdrahn       if (fixP->fx_cgen.opinfo && fixP->fx_cgen.opinfo != BFD_RELOC_NONE)
375d2201f2fSdrahn 	return fixP->fx_cgen.opinfo;
376d2201f2fSdrahn       return fixP->fx_pcrel ? BFD_RELOC_16_PCREL : BFD_RELOC_16;
377d2201f2fSdrahn 
378d2201f2fSdrahn     case XSTORMY16_OPERAND_ABS24:
379d2201f2fSdrahn       return BFD_RELOC_XSTORMY16_24;
380d2201f2fSdrahn 
381d2201f2fSdrahn     case XSTORMY16_OPERAND_REL8_4:
382d2201f2fSdrahn       fixP->fx_addnumber -= 2;
383d2201f2fSdrahn     case XSTORMY16_OPERAND_REL8_2:
384d2201f2fSdrahn       fixP->fx_addnumber -= 2;
385d2201f2fSdrahn       fixP->fx_pcrel = 1;
386d2201f2fSdrahn       return BFD_RELOC_8_PCREL;
387d2201f2fSdrahn 
388d2201f2fSdrahn     case XSTORMY16_OPERAND_REL12:
389d2201f2fSdrahn       fixP->fx_where += 2;
390d2201f2fSdrahn       /* Fall through...  */
391d2201f2fSdrahn     case XSTORMY16_OPERAND_REL12A:
392d2201f2fSdrahn       fixP->fx_addnumber -= 2;
393d2201f2fSdrahn       fixP->fx_pcrel = 1;
394d2201f2fSdrahn       return BFD_RELOC_XSTORMY16_REL_12;
395d2201f2fSdrahn 
396d2201f2fSdrahn     default : /* avoid -Wall warning */
397d2201f2fSdrahn       abort ();
398d2201f2fSdrahn     }
399d2201f2fSdrahn }
400d2201f2fSdrahn 
401d2201f2fSdrahn /* See whether we need to force a relocation into the output file.
402d2201f2fSdrahn    This is used to force out switch and PC relative relocations when
403d2201f2fSdrahn    relaxing.  */
404d2201f2fSdrahn 
405d2201f2fSdrahn int
xstormy16_force_relocation(fix)406d2201f2fSdrahn xstormy16_force_relocation (fix)
407d2201f2fSdrahn      fixS * fix;
408d2201f2fSdrahn {
409d2201f2fSdrahn   if (fix->fx_r_type == BFD_RELOC_XSTORMY16_FPTR16)
410d2201f2fSdrahn     return 1;
411d2201f2fSdrahn 
412d2201f2fSdrahn   return generic_force_reloc (fix);
413d2201f2fSdrahn }
414d2201f2fSdrahn 
415d2201f2fSdrahn /* Return true if a relocation against a symbol may be replaced with
416d2201f2fSdrahn    a relocation against section+offset.  */
417d2201f2fSdrahn 
418d2201f2fSdrahn bfd_boolean
xstormy16_fix_adjustable(fixP)419d2201f2fSdrahn xstormy16_fix_adjustable (fixP)
420d2201f2fSdrahn    fixS * fixP;
421d2201f2fSdrahn {
422d2201f2fSdrahn   /* We need the symbol name for the VTABLE entries.  */
423d2201f2fSdrahn   if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
424d2201f2fSdrahn       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
425d2201f2fSdrahn     return 0;
426d2201f2fSdrahn 
427d2201f2fSdrahn   if (fixP->fx_r_type == BFD_RELOC_XSTORMY16_FPTR16)
428d2201f2fSdrahn     return 0;
429d2201f2fSdrahn 
430d2201f2fSdrahn   return 1;
431d2201f2fSdrahn }
432d2201f2fSdrahn 
433d2201f2fSdrahn /* This is a copy of gas_cgen_md_apply_fix3, with some enhancements to
434d2201f2fSdrahn    do various things that would not be valid for all ports.  */
435d2201f2fSdrahn 
436d2201f2fSdrahn void
xstormy16_md_apply_fix3(fixP,valueP,seg)437d2201f2fSdrahn xstormy16_md_apply_fix3 (fixP, valueP, seg)
438d2201f2fSdrahn      fixS *   fixP;
439d2201f2fSdrahn      valueT * valueP;
440d2201f2fSdrahn      segT     seg ATTRIBUTE_UNUSED;
441d2201f2fSdrahn {
442d2201f2fSdrahn   char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
443d2201f2fSdrahn   valueT value = *valueP;
444d2201f2fSdrahn   /* Canonical name, since used a lot.  */
445d2201f2fSdrahn   CGEN_CPU_DESC cd = gas_cgen_cpu_desc;
446d2201f2fSdrahn 
447d2201f2fSdrahn   /* md_cgen_lookup_reloc() will adjust this to compensate for where
448d2201f2fSdrahn      in the opcode the relocation happens, for pcrel relocations.  We
449d2201f2fSdrahn      have no other way of keeping track of what this offset needs to
450d2201f2fSdrahn      be.  */
451d2201f2fSdrahn   fixP->fx_addnumber = 0;
452d2201f2fSdrahn 
453d2201f2fSdrahn   /* This port has pc-relative relocs and DIFF_EXPR_OK defined, so
454d2201f2fSdrahn      it must deal with turning a BFD_RELOC_{8,16,32,64} into a
455d2201f2fSdrahn      BFD_RELOC_*_PCREL for the case of
456d2201f2fSdrahn 
457d2201f2fSdrahn 	.word something-.
458d2201f2fSdrahn   */
459d2201f2fSdrahn   if (fixP->fx_pcrel)
460d2201f2fSdrahn     switch (fixP->fx_r_type)
461d2201f2fSdrahn       {
462d2201f2fSdrahn       case BFD_RELOC_8:
463d2201f2fSdrahn 	fixP->fx_r_type = BFD_RELOC_8_PCREL;
464d2201f2fSdrahn 	break;
465d2201f2fSdrahn       case BFD_RELOC_16:
466d2201f2fSdrahn 	fixP->fx_r_type = BFD_RELOC_16_PCREL;
467d2201f2fSdrahn 	break;
468d2201f2fSdrahn       case BFD_RELOC_32:
469d2201f2fSdrahn 	fixP->fx_r_type = BFD_RELOC_32_PCREL;
470d2201f2fSdrahn 	break;
471d2201f2fSdrahn       case BFD_RELOC_64:
472d2201f2fSdrahn 	fixP->fx_r_type = BFD_RELOC_64_PCREL;
473d2201f2fSdrahn 	break;
474d2201f2fSdrahn       default:
475d2201f2fSdrahn 	break;
476d2201f2fSdrahn       }
477d2201f2fSdrahn 
478d2201f2fSdrahn   if (fixP->fx_addsy == (symbolS *) NULL)
479d2201f2fSdrahn     fixP->fx_done = 1;
480d2201f2fSdrahn 
481d2201f2fSdrahn   /* We don't actually support subtracting a symbol.  */
482d2201f2fSdrahn   if (fixP->fx_subsy != (symbolS *) NULL)
483d2201f2fSdrahn     as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
484d2201f2fSdrahn 
485d2201f2fSdrahn   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
486d2201f2fSdrahn     {
487d2201f2fSdrahn       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
488d2201f2fSdrahn       const CGEN_OPERAND *operand = cgen_operand_lookup_by_num (cd, opindex);
489d2201f2fSdrahn       const char *errmsg;
490d2201f2fSdrahn       bfd_reloc_code_real_type reloc_type;
491d2201f2fSdrahn       CGEN_FIELDS *fields = alloca (CGEN_CPU_SIZEOF_FIELDS (cd));
492d2201f2fSdrahn       const CGEN_INSN *insn = fixP->fx_cgen.insn;
493d2201f2fSdrahn 
494d2201f2fSdrahn       /* If the reloc has been fully resolved finish the operand here.  */
495d2201f2fSdrahn       /* FIXME: This duplicates the capabilities of code in BFD.  */
496d2201f2fSdrahn       if (fixP->fx_done)
497d2201f2fSdrahn 	{
498d2201f2fSdrahn 	  CGEN_CPU_SET_FIELDS_BITSIZE (cd) (fields, CGEN_INSN_BITSIZE (insn));
499d2201f2fSdrahn 	  CGEN_CPU_SET_VMA_OPERAND (cd) (cd, opindex, fields, (bfd_vma) value);
500d2201f2fSdrahn 
501d2201f2fSdrahn #if CGEN_INT_INSN_P
502d2201f2fSdrahn 	  {
503d2201f2fSdrahn 	    CGEN_INSN_INT insn_value =
504d2201f2fSdrahn 	      cgen_get_insn_value (cd, where, CGEN_INSN_BITSIZE (insn));
505d2201f2fSdrahn 
506d2201f2fSdrahn 	    /* ??? 0 is passed for `pc'.  */
507d2201f2fSdrahn 	    errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields,
508d2201f2fSdrahn 						   &insn_value, (bfd_vma) 0);
509d2201f2fSdrahn 	    cgen_put_insn_value (cd, where, CGEN_INSN_BITSIZE (insn),
510d2201f2fSdrahn 				 insn_value);
511d2201f2fSdrahn 	  }
512d2201f2fSdrahn #else
513d2201f2fSdrahn 	  /* ??? 0 is passed for `pc'.  */
514d2201f2fSdrahn 	  errmsg = CGEN_CPU_INSERT_OPERAND (cd) (cd, opindex, fields, where,
515d2201f2fSdrahn 						 (bfd_vma) 0);
516d2201f2fSdrahn #endif
517d2201f2fSdrahn 	  if (errmsg)
518d2201f2fSdrahn 	    as_bad_where (fixP->fx_file, fixP->fx_line, "%s", errmsg);
519d2201f2fSdrahn 	}
520d2201f2fSdrahn 
521d2201f2fSdrahn       if (fixP->fx_done)
522d2201f2fSdrahn 	return;
523d2201f2fSdrahn 
524d2201f2fSdrahn       /* The operand isn't fully resolved.  Determine a BFD reloc value
525d2201f2fSdrahn 	 based on the operand information and leave it to
526d2201f2fSdrahn 	 bfd_install_relocation.  Note that this doesn't work when
527d2201f2fSdrahn 	 !partial_inplace.  */
528d2201f2fSdrahn 
529d2201f2fSdrahn       reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
530d2201f2fSdrahn       if (reloc_type != BFD_RELOC_NONE)
531d2201f2fSdrahn 	{
532d2201f2fSdrahn 	  fixP->fx_r_type = reloc_type;
533d2201f2fSdrahn 	}
534d2201f2fSdrahn       else
535d2201f2fSdrahn 	{
536d2201f2fSdrahn 	  as_bad_where (fixP->fx_file, fixP->fx_line,
537d2201f2fSdrahn 			_("unresolved expression that must be resolved"));
538d2201f2fSdrahn 	  fixP->fx_done = 1;
539d2201f2fSdrahn 	  return;
540d2201f2fSdrahn 	}
541d2201f2fSdrahn     }
542d2201f2fSdrahn   else if (fixP->fx_done)
543d2201f2fSdrahn     {
544d2201f2fSdrahn       /* We're finished with this fixup.  Install it because
545d2201f2fSdrahn 	 bfd_install_relocation won't be called to do it.  */
546d2201f2fSdrahn       switch (fixP->fx_r_type)
547d2201f2fSdrahn 	{
548d2201f2fSdrahn 	case BFD_RELOC_8:
549d2201f2fSdrahn 	  md_number_to_chars (where, value, 1);
550d2201f2fSdrahn 	  break;
551d2201f2fSdrahn 	case BFD_RELOC_16:
552d2201f2fSdrahn 	  md_number_to_chars (where, value, 2);
553d2201f2fSdrahn 	  break;
554d2201f2fSdrahn 	case BFD_RELOC_32:
555d2201f2fSdrahn 	  md_number_to_chars (where, value, 4);
556d2201f2fSdrahn 	  break;
557d2201f2fSdrahn 	case BFD_RELOC_64:
558d2201f2fSdrahn 	  md_number_to_chars (where, value, 8);
559d2201f2fSdrahn 	  break;
560d2201f2fSdrahn 	default:
561d2201f2fSdrahn 	  as_bad_where (fixP->fx_file, fixP->fx_line,
562d2201f2fSdrahn 			_("internal error: can't install fix for reloc type %d (`%s')"),
563d2201f2fSdrahn 			fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type));
564d2201f2fSdrahn 	  break;
565d2201f2fSdrahn 	}
566d2201f2fSdrahn     }
567d2201f2fSdrahn   else
568d2201f2fSdrahn     {
569d2201f2fSdrahn       /* bfd_install_relocation will be called to finish things up.  */
570d2201f2fSdrahn     }
571d2201f2fSdrahn 
572d2201f2fSdrahn   /* This is a RELA port.  Thus, it does not need to store a
573d2201f2fSdrahn      value if it is going to make a reloc.  What's more, when
574d2201f2fSdrahn      assembling a line like
575d2201f2fSdrahn 
576d2201f2fSdrahn      .byte global-0x7f00
577d2201f2fSdrahn 
578d2201f2fSdrahn      we'll get a spurious error message if we try to stuff 0x7f00 into
579d2201f2fSdrahn      the byte.  */
580d2201f2fSdrahn   if (! fixP->fx_done)
581d2201f2fSdrahn     *valueP = 0;
582d2201f2fSdrahn 
583d2201f2fSdrahn   /* Tuck `value' away for use by tc_gen_reloc.
584d2201f2fSdrahn      See the comment describing fx_addnumber in write.h.
585d2201f2fSdrahn      This field is misnamed (or misused :-).  */
586d2201f2fSdrahn   fixP->fx_addnumber += value;
587d2201f2fSdrahn }
588d2201f2fSdrahn 
589d2201f2fSdrahn 
590d2201f2fSdrahn /* Write a value out to the object file, using the appropriate endianness.  */
591d2201f2fSdrahn 
592d2201f2fSdrahn void
md_number_to_chars(buf,val,n)593d2201f2fSdrahn md_number_to_chars (buf, val, n)
594d2201f2fSdrahn      char * buf;
595d2201f2fSdrahn      valueT val;
596d2201f2fSdrahn      int    n;
597d2201f2fSdrahn {
598d2201f2fSdrahn   number_to_chars_littleendian (buf, val, n);
599d2201f2fSdrahn }
600d2201f2fSdrahn 
601d2201f2fSdrahn /* Turn a string in input_line_pointer into a floating point constant of type
602d2201f2fSdrahn    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
603d2201f2fSdrahn    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
604d2201f2fSdrahn */
605d2201f2fSdrahn 
606d2201f2fSdrahn /* Equal to MAX_PRECISION in atof-ieee.c */
607d2201f2fSdrahn #define MAX_LITTLENUMS 6
608d2201f2fSdrahn 
609d2201f2fSdrahn char *
md_atof(type,litP,sizeP)610d2201f2fSdrahn md_atof (type, litP, sizeP)
611d2201f2fSdrahn      char   type;
612d2201f2fSdrahn      char * litP;
613d2201f2fSdrahn      int *  sizeP;
614d2201f2fSdrahn {
615d2201f2fSdrahn   int              prec;
616d2201f2fSdrahn   LITTLENUM_TYPE   words [MAX_LITTLENUMS];
617d2201f2fSdrahn   LITTLENUM_TYPE   *wordP;
618d2201f2fSdrahn   char *           t;
619d2201f2fSdrahn 
620d2201f2fSdrahn   switch (type)
621d2201f2fSdrahn     {
622d2201f2fSdrahn     case 'f':
623d2201f2fSdrahn     case 'F':
624d2201f2fSdrahn       prec = 2;
625d2201f2fSdrahn       break;
626d2201f2fSdrahn 
627d2201f2fSdrahn     case 'd':
628d2201f2fSdrahn     case 'D':
629d2201f2fSdrahn       prec = 4;
630d2201f2fSdrahn       break;
631d2201f2fSdrahn 
632d2201f2fSdrahn    /* FIXME: Some targets allow other format chars for bigger sizes here.  */
633d2201f2fSdrahn 
634d2201f2fSdrahn     default:
635d2201f2fSdrahn       * sizeP = 0;
636d2201f2fSdrahn       return _("Bad call to md_atof()");
637d2201f2fSdrahn     }
638d2201f2fSdrahn 
639d2201f2fSdrahn   t = atof_ieee (input_line_pointer, type, words);
640d2201f2fSdrahn   if (t)
641d2201f2fSdrahn     input_line_pointer = t;
642d2201f2fSdrahn   * sizeP = prec * sizeof (LITTLENUM_TYPE);
643d2201f2fSdrahn 
644d2201f2fSdrahn   *sizeP = prec * sizeof (LITTLENUM_TYPE);
645d2201f2fSdrahn   /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
646d2201f2fSdrahn      the littleendianness of the processor.  */
647d2201f2fSdrahn   for (wordP = words + prec - 1; prec--;)
648d2201f2fSdrahn     {
649d2201f2fSdrahn       md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE));
650d2201f2fSdrahn       litP += sizeof (LITTLENUM_TYPE);
651d2201f2fSdrahn     }
652d2201f2fSdrahn 
653d2201f2fSdrahn   return 0;
654d2201f2fSdrahn }
655