1/* tc-openrisc.c -- Assembler for the OpenRISC family.
2   Copyright 2001, 2002, 2003, 2005 Free Software Foundation.
3   Contributed by Johan Rydberg, jrydberg@opencores.org
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, 51 Franklin Street - Fifth Floor,
20   Boston, MA 02110-1301, USA.  */
21
22#include <stdio.h>
23#include "as.h"
24#include "subsegs.h"
25#include "symcat.h"
26#include "opcodes/openrisc-desc.h"
27#include "opcodes/openrisc-opc.h"
28#include "cgen.h"
29
30/* Structure to hold all of the different components describing
31   an individual instruction.  */
32typedef struct openrisc_insn openrisc_insn;
33
34struct openrisc_insn
35{
36  const CGEN_INSN *	insn;
37  const CGEN_INSN *	orig_insn;
38  CGEN_FIELDS		fields;
39#if CGEN_INT_INSN_P
40  CGEN_INSN_INT         buffer [1];
41#define INSN_VALUE(buf) (*(buf))
42#else
43  unsigned char         buffer [CGEN_MAX_INSN_SIZE];
44#define INSN_VALUE(buf) (buf)
45#endif
46  char *		addr;
47  fragS *		frag;
48  int                   num_fixups;
49  fixS *                fixups [GAS_CGEN_MAX_FIXUPS];
50  int                   indices [MAX_OPERAND_INSTANCES];
51};
52
53
54const char comment_chars[]        = "#";
55const char line_comment_chars[]   = "#";
56const char line_separator_chars[] = ";";
57const char EXP_CHARS[]            = "eE";
58const char FLT_CHARS[]            = "dD";
59
60
61#define OPENRISC_SHORTOPTS "m:"
62const char * md_shortopts = OPENRISC_SHORTOPTS;
63
64struct option md_longopts[] =
65{
66  {NULL, no_argument, NULL, 0}
67};
68size_t md_longopts_size = sizeof (md_longopts);
69
70unsigned long openrisc_machine = 0; /* default */
71
72int
73md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
74{
75  return 0;
76}
77
78void
79md_show_usage (FILE * stream ATTRIBUTE_UNUSED)
80{
81}
82
83static void
84ignore_pseudo (int val ATTRIBUTE_UNUSED)
85{
86  discard_rest_of_line ();
87}
88
89const char openrisc_comment_chars [] = ";#";
90
91/* The target specific pseudo-ops which we support.  */
92const pseudo_typeS md_pseudo_table[] =
93{
94  { "word",     cons,           4 },
95  { "proc",     ignore_pseudo,  0 },
96  { "endproc",  ignore_pseudo,  0 },
97  { NULL, 	NULL, 		0 }
98};
99
100
101
102void
103md_begin (void)
104{
105  /* Initialize the `cgen' interface.  */
106
107  /* Set the machine number and endian.  */
108  gas_cgen_cpu_desc = openrisc_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
109                                              CGEN_CPU_OPEN_ENDIAN,
110                                              CGEN_ENDIAN_BIG,
111                                              CGEN_CPU_OPEN_END);
112  openrisc_cgen_init_asm (gas_cgen_cpu_desc);
113
114  /* This is a callback from cgen to gas to parse operands.  */
115  cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
116}
117
118void
119md_assemble (char * str)
120{
121  static int last_insn_had_delay_slot = 0;
122  openrisc_insn insn;
123  char *    errmsg;
124
125  /* Initialize GAS's cgen interface for a new instruction.  */
126  gas_cgen_init_parse ();
127
128  insn.insn = openrisc_cgen_assemble_insn
129    (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
130
131  if (!insn.insn)
132    {
133      as_bad (errmsg);
134      return;
135    }
136
137  /* Doesn't really matter what we pass for RELAX_P here.  */
138  gas_cgen_finish_insn (insn.insn, insn.buffer,
139			CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
140
141  last_insn_had_delay_slot
142    = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
143}
144
145
146/* The syntax in the manual says constants begin with '#'.
147   We just ignore it.  */
148
149void
150md_operand (expressionS * expressionP)
151{
152  if (* input_line_pointer == '#')
153    {
154      input_line_pointer ++;
155      expression (expressionP);
156    }
157}
158
159valueT
160md_section_align (segT segment, valueT size)
161{
162  int align = bfd_get_section_alignment (stdoutput, segment);
163  return ((size + (1 << align) - 1) & (-1 << align));
164}
165
166symbolS *
167md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
168{
169  return 0;
170}
171
172
173/* Interface to relax_segment.  */
174
175/* FIXME: Look through this.  */
176
177const relax_typeS md_relax_table[] =
178{
179/* The fields are:
180   1) most positive reach of this state,
181   2) most negative reach of this state,
182   3) how many bytes this mode will add to the size of the current frag
183   4) which index into the table to try if we can't fit into this one.  */
184
185  /* The first entry must be unused because an `rlx_more' value of zero ends
186     each list.  */
187  {1, 1, 0, 0},
188
189  /* The displacement used by GAS is from the end of the 2 byte insn,
190     so we subtract 2 from the following.  */
191  /* 16 bit insn, 8 bit disp -> 10 bit range.
192     This doesn't handle a branch in the right slot at the border:
193     the "& -4" isn't taken into account.  It's not important enough to
194     complicate things over it, so we subtract an extra 2 (or + 2 in -ve
195     case).  */
196  {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
197  /* 32 bit insn, 24 bit disp -> 26 bit range.  */
198  {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
199  /* Same thing, but with leading nop for alignment.  */
200  {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
201};
202
203/* Return an initial guess of the length by which a fragment must grow to
204   hold a branch to reach its destination.
205   Also updates fr_type/fr_subtype as necessary.
206
207   Called just before doing relaxation.
208   Any symbol that is now undefined will not become defined.
209   The guess for fr_var is ACTUALLY the growth beyond fr_fix.
210   Whatever we do to grow fr_fix or fr_var contributes to our returned value.
211   Although it may not be explicit in the frag, pretend fr_var starts with a
212   0 value.  */
213
214int
215md_estimate_size_before_relax (fragS * fragP, segT segment)
216{
217  /* The only thing we have to handle here are symbols outside of the
218     current segment.  They may be undefined or in a different segment in
219     which case linker scripts may place them anywhere.
220     However, we can't finish the fragment here and emit the reloc as insn
221     alignment requirements may move the insn about.  */
222
223  if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
224    {
225      /* The symbol is undefined in this segment.
226	 Change the relaxation subtype to the max allowable and leave
227	 all further handling to md_convert_frag.  */
228      fragP->fr_subtype = 2;
229
230      {
231	const CGEN_INSN * insn;
232	int               i;
233
234	/* Update the recorded insn.
235	   Fortunately we don't have to look very far.
236	   FIXME: Change this to record in the instruction the next higher
237	   relaxable insn to use.  */
238	for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
239	  {
240	    if ((strcmp (CGEN_INSN_MNEMONIC (insn),
241			 CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
242		 == 0)
243		&& CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED))
244	      break;
245	  }
246	if (i == 4)
247	  abort ();
248
249	fragP->fr_cgen.insn = insn;
250	return 2;
251      }
252    }
253
254  return md_relax_table[fragP->fr_subtype].rlx_length;
255}
256
257/* *fragP has been relaxed to its final size, and now needs to have
258   the bytes inside it modified to conform to the new size.
259
260   Called after relaxation is finished.
261   fragP->fr_type == rs_machine_dependent.
262   fragP->fr_subtype is the subtype of what the address relaxed to.  */
263
264void
265md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
266		 segT    sec  ATTRIBUTE_UNUSED,
267		 fragS * fragP ATTRIBUTE_UNUSED)
268{
269  /* FIXME */
270}
271
272
273/* Functions concerning relocs.  */
274
275/* The location from which a PC relative jump should be calculated,
276   given a PC relative reloc.  */
277
278long
279md_pcrel_from_section (fixS * fixP, segT sec)
280{
281  if (fixP->fx_addsy != (symbolS *) NULL
282      && (! S_IS_DEFINED (fixP->fx_addsy)
283	  || S_GET_SEGMENT (fixP->fx_addsy) != sec))
284    /* The symbol is undefined (or is defined but not in this section).
285       Let the linker figure it out.  */
286    return 0;
287
288  return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
289}
290
291
292/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
293   Returns BFD_RELOC_NONE if no reloc type can be found.
294   *FIXP may be modified if desired.  */
295
296bfd_reloc_code_real_type
297md_cgen_lookup_reloc (const CGEN_INSN *    insn ATTRIBUTE_UNUSED,
298		      const CGEN_OPERAND * operand,
299		      fixS *               fixP)
300{
301  bfd_reloc_code_real_type type;
302
303  switch (operand->type)
304    {
305    case OPENRISC_OPERAND_ABS_26:
306      fixP->fx_pcrel = 0;
307      type = BFD_RELOC_OPENRISC_ABS_26;
308      goto emit;
309    case OPENRISC_OPERAND_DISP_26:
310      fixP->fx_pcrel = 1;
311      type = BFD_RELOC_OPENRISC_REL_26;
312      goto emit;
313
314    case OPENRISC_OPERAND_HI16:
315      type = BFD_RELOC_HI16;
316      goto emit;
317
318    case OPENRISC_OPERAND_LO16:
319      type = BFD_RELOC_LO16;
320      goto emit;
321
322    emit:
323      return type;
324
325    default : /* avoid -Wall warning */
326      break;
327    }
328
329  return BFD_RELOC_NONE;
330}
331
332/* Write a value out to the object file, using the appropriate endianness.  */
333
334void
335md_number_to_chars (char * buf, valueT val, int n)
336{
337  number_to_chars_bigendian (buf, val, n);
338}
339
340/* Turn a string in input_line_pointer into a floating point constant of type
341   type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
342   emitted is stored in *sizeP .  An error message is returned, or NULL on OK.
343*/
344
345/* Equal to MAX_PRECISION in atof-ieee.c */
346#define MAX_LITTLENUMS 6
347
348char *
349md_atof (int type, char * litP, int *  sizeP)
350{
351  int              i;
352  int              prec;
353  LITTLENUM_TYPE   words [MAX_LITTLENUMS];
354  char *           t;
355
356  switch (type)
357    {
358    case 'f':
359    case 'F':
360    case 's':
361    case 'S':
362      prec = 2;
363      break;
364
365    case 'd':
366    case 'D':
367    case 'r':
368    case 'R':
369      prec = 4;
370      break;
371
372   /* FIXME: Some targets allow other format chars for bigger sizes here.  */
373
374    default:
375      * sizeP = 0;
376      return _("Bad call to md_atof()");
377    }
378
379  t = atof_ieee (input_line_pointer, type, words);
380  if (t)
381    input_line_pointer = t;
382  * sizeP = prec * sizeof (LITTLENUM_TYPE);
383
384  for (i = 0; i < prec; i++)
385    {
386      md_number_to_chars (litP, (valueT) words[i],
387			  sizeof (LITTLENUM_TYPE));
388      litP += sizeof (LITTLENUM_TYPE);
389    }
390
391  return 0;
392}
393
394bfd_boolean
395openrisc_fix_adjustable (fixS * fixP)
396{
397  /* We need the symbol name for the VTABLE entries.  */
398  if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
399      || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
400    return 0;
401
402  return 1;
403}
404