source: trunk/binutils/gas/config/tc-openrisc.c@ 2562

Last change on this file since 2562 was 607, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 11.7 KB
Line 
1/* tc-openrisc.c -- Assembler for the OpenRISC family.
2 Copyright 2001, 2002, 2003 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, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, 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
62#define OPENRISC_SHORTOPTS "m:"
63const char * md_shortopts = OPENRISC_SHORTOPTS;
64
65struct option md_longopts[] =
66{
67 {NULL, no_argument, NULL, 0}
68};
69size_t md_longopts_size = sizeof (md_longopts);
70
71unsigned long openrisc_machine = 0; /* default */
72
73int
74md_parse_option (c, arg)
75 int c ATTRIBUTE_UNUSED;
76 char * arg ATTRIBUTE_UNUSED;
77{
78 return 0;
79}
80
81void
82md_show_usage (stream)
83 FILE * stream ATTRIBUTE_UNUSED;
84{
85}
86
87static void ignore_pseudo PARAMS ((int));
88
89static void
90ignore_pseudo (val)
91 int val ATTRIBUTE_UNUSED;
92{
93 discard_rest_of_line ();
94}
95
96const char openrisc_comment_chars [] = ";#";
97
98/* The target specific pseudo-ops which we support. */
99const pseudo_typeS md_pseudo_table[] =
100{
101 { "word", cons, 4 },
102 { "proc", ignore_pseudo, 0 },
103 { "endproc", ignore_pseudo, 0 },
104 { NULL, NULL, 0 }
105};
106
107
108
109
110void
111md_begin ()
112{
113 /* Initialize the `cgen' interface. */
114
115 /* Set the machine number and endian. */
116 gas_cgen_cpu_desc = openrisc_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0,
117 CGEN_CPU_OPEN_ENDIAN,
118 CGEN_ENDIAN_BIG,
119 CGEN_CPU_OPEN_END);
120 openrisc_cgen_init_asm (gas_cgen_cpu_desc);
121
122 /* This is a callback from cgen to gas to parse operands. */
123 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
124}
125
126void
127md_assemble (str)
128 char * str;
129{
130 static int last_insn_had_delay_slot = 0;
131 openrisc_insn insn;
132 char * errmsg;
133
134 /* Initialize GAS's cgen interface for a new instruction. */
135 gas_cgen_init_parse ();
136
137 insn.insn = openrisc_cgen_assemble_insn
138 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
139
140 if (!insn.insn)
141 {
142 as_bad (errmsg);
143 return;
144 }
145
146 /* Doesn't really matter what we pass for RELAX_P here. */
147 gas_cgen_finish_insn (insn.insn, insn.buffer,
148 CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
149
150#if 0 /* Currently disabled */
151 /* Warn about invalid insns in delay slots. */
152 if (last_insn_had_delay_slot
153 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_NOT_IN_DELAY_SLOT))
154 as_warn (_("Instruction %s not allowed in a delay slot."),
155 CGEN_INSN_NAME (insn.insn));
156#endif
157
158 last_insn_had_delay_slot
159 = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
160}
161
162
163/* The syntax in the manual says constants begin with '#'.
164 We just ignore it. */
165
166void
167md_operand (expressionP)
168 expressionS * expressionP;
169{
170 if (* input_line_pointer == '#')
171 {
172 input_line_pointer ++;
173 expression (expressionP);
174 }
175}
176
177valueT
178md_section_align (segment, size)
179 segT segment;
180 valueT size;
181{
182 int align = bfd_get_section_alignment (stdoutput, segment);
183 return ((size + (1 << align) - 1) & (-1 << align));
184}
185
186symbolS *
187md_undefined_symbol (name)
188 char * name ATTRIBUTE_UNUSED;
189{
190 return 0;
191}
192
193
194
195/* Interface to relax_segment. */
196
197/* FIXME: Look through this. */
198
199const relax_typeS md_relax_table[] =
200{
201/* The fields are:
202 1) most positive reach of this state,
203 2) most negative reach of this state,
204 3) how many bytes this mode will add to the size of the current frag
205 4) which index into the table to try if we can't fit into this one. */
206
207 /* The first entry must be unused because an `rlx_more' value of zero ends
208 each list. */
209 {1, 1, 0, 0},
210
211 /* The displacement used by GAS is from the end of the 2 byte insn,
212 so we subtract 2 from the following. */
213 /* 16 bit insn, 8 bit disp -> 10 bit range.
214 This doesn't handle a branch in the right slot at the border:
215 the "& -4" isn't taken into account. It's not important enough to
216 complicate things over it, so we subtract an extra 2 (or + 2 in -ve
217 case). */
218 {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
219 /* 32 bit insn, 24 bit disp -> 26 bit range. */
220 {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
221 /* Same thing, but with leading nop for alignment. */
222 {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
223};
224
225long
226openrisc_relax_frag (segment, fragP, stretch)
227 segT segment;
228 fragS * fragP;
229 long stretch;
230{
231 /* Address of branch insn. */
232 long address = fragP->fr_address + fragP->fr_fix - 2;
233 long growth = 0;
234
235 /* Keep 32 bit insns aligned on 32 bit boundaries. */
236 if (fragP->fr_subtype == 2)
237 {
238 if ((address & 3) != 0)
239 {
240 fragP->fr_subtype = 3;
241 growth = 2;
242 }
243 }
244 else if (fragP->fr_subtype == 3)
245 {
246 if ((address & 3) == 0)
247 {
248 fragP->fr_subtype = 2;
249 growth = -2;
250 }
251 }
252 else
253 {
254 growth = relax_frag (segment, fragP, stretch);
255
256 /* Long jump on odd halfword boundary? */
257 if (fragP->fr_subtype == 2 && (address & 3) != 0)
258 {
259 fragP->fr_subtype = 3;
260 growth += 2;
261 }
262 }
263
264 return growth;
265}
266
267
268/* Return an initial guess of the length by which a fragment must grow to
269 hold a branch to reach its destination.
270 Also updates fr_type/fr_subtype as necessary.
271
272 Called just before doing relaxation.
273 Any symbol that is now undefined will not become defined.
274 The guess for fr_var is ACTUALLY the growth beyond fr_fix.
275 Whatever we do to grow fr_fix or fr_var contributes to our returned value.
276 Although it may not be explicit in the frag, pretend fr_var starts with a
277 0 value. */
278
279int
280md_estimate_size_before_relax (fragP, segment)
281 fragS * fragP;
282 segT segment;
283{
284 /* The only thing we have to handle here are symbols outside of the
285 current segment. They may be undefined or in a different segment in
286 which case linker scripts may place them anywhere.
287 However, we can't finish the fragment here and emit the reloc as insn
288 alignment requirements may move the insn about. */
289
290 if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
291 {
292 /* The symbol is undefined in this segment.
293 Change the relaxation subtype to the max allowable and leave
294 all further handling to md_convert_frag. */
295 fragP->fr_subtype = 2;
296
297 {
298 const CGEN_INSN * insn;
299 int i;
300
301 /* Update the recorded insn.
302 Fortunately we don't have to look very far.
303 FIXME: Change this to record in the instruction the next higher
304 relaxable insn to use. */
305 for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
306 {
307 if ((strcmp (CGEN_INSN_MNEMONIC (insn),
308 CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
309 == 0)
310 && CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAX))
311 break;
312 }
313 if (i == 4)
314 abort ();
315
316 fragP->fr_cgen.insn = insn;
317 return 2;
318 }
319 }
320
321 return md_relax_table[fragP->fr_subtype].rlx_length;
322}
323
324/* *fragP has been relaxed to its final size, and now needs to have
325 the bytes inside it modified to conform to the new size.
326
327 Called after relaxation is finished.
328 fragP->fr_type == rs_machine_dependent.
329 fragP->fr_subtype is the subtype of what the address relaxed to. */
330
331void
332md_convert_frag (abfd, sec, fragP)
333 bfd * abfd ATTRIBUTE_UNUSED;
334 segT sec ATTRIBUTE_UNUSED;
335 fragS * fragP ATTRIBUTE_UNUSED;
336{
337 /* FIXME */
338}
339
340
341
342/* Functions concerning relocs. */
343
344/* The location from which a PC relative jump should be calculated,
345 given a PC relative reloc. */
346
347long
348md_pcrel_from_section (fixP, sec)
349 fixS * fixP;
350 segT sec;
351{
352 if (fixP->fx_addsy != (symbolS *) NULL
353 && (! S_IS_DEFINED (fixP->fx_addsy)
354 || S_GET_SEGMENT (fixP->fx_addsy) != sec))
355 {
356 /* The symbol is undefined (or is defined but not in this section).
357 Let the linker figure it out. */
358 return 0;
359 }
360
361 return (fixP->fx_frag->fr_address + fixP->fx_where) & ~1;
362}
363
364
365/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
366 Returns BFD_RELOC_NONE if no reloc type can be found.
367 *FIXP may be modified if desired. */
368
369bfd_reloc_code_real_type
370md_cgen_lookup_reloc (insn, operand, fixP)
371 const CGEN_INSN * insn ATTRIBUTE_UNUSED;
372 const CGEN_OPERAND * operand;
373 fixS * fixP;
374{
375 bfd_reloc_code_real_type type;
376
377 switch (operand->type)
378 {
379 case OPENRISC_OPERAND_ABS_26:
380 fixP->fx_pcrel = 0;
381 type = BFD_RELOC_OPENRISC_ABS_26;
382 goto emit;
383 case OPENRISC_OPERAND_DISP_26:
384 fixP->fx_pcrel = 1;
385 type = BFD_RELOC_OPENRISC_REL_26;
386 goto emit;
387
388 case OPENRISC_OPERAND_HI16:
389 type = BFD_RELOC_HI16;
390 goto emit;
391
392 case OPENRISC_OPERAND_LO16:
393 type = BFD_RELOC_LO16;
394 goto emit;
395
396 emit:
397 return type;
398
399 default : /* avoid -Wall warning */
400 break;
401 }
402
403 return BFD_RELOC_NONE;
404}
405
406
407/* Write a value out to the object file, using the appropriate endianness. */
408
409void
410md_number_to_chars (buf, val, n)
411 char * buf;
412 valueT val;
413 int n;
414{
415 number_to_chars_bigendian (buf, val, n);
416}
417
418/* Turn a string in input_line_pointer into a floating point constant of type
419 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
420 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
421*/
422
423/* Equal to MAX_PRECISION in atof-ieee.c */
424#define MAX_LITTLENUMS 6
425
426char *
427md_atof (type, litP, sizeP)
428 char type;
429 char * litP;
430 int * sizeP;
431{
432 int i;
433 int prec;
434 LITTLENUM_TYPE words [MAX_LITTLENUMS];
435 char * t;
436
437 switch (type)
438 {
439 case 'f':
440 case 'F':
441 case 's':
442 case 'S':
443 prec = 2;
444 break;
445
446 case 'd':
447 case 'D':
448 case 'r':
449 case 'R':
450 prec = 4;
451 break;
452
453 /* FIXME: Some targets allow other format chars for bigger sizes here. */
454
455 default:
456 * sizeP = 0;
457 return _("Bad call to md_atof()");
458 }
459
460 t = atof_ieee (input_line_pointer, type, words);
461 if (t)
462 input_line_pointer = t;
463 * sizeP = prec * sizeof (LITTLENUM_TYPE);
464
465 for (i = 0; i < prec; i++)
466 {
467 md_number_to_chars (litP, (valueT) words[i],
468 sizeof (LITTLENUM_TYPE));
469 litP += sizeof (LITTLENUM_TYPE);
470 }
471
472 return 0;
473}
474
475bfd_boolean
476openrisc_fix_adjustable (fixP)
477 fixS * fixP;
478{
479 /* We need the symbol name for the VTABLE entries */
480 if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
481 || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
482 return 0;
483
484 return 1;
485}
486
487
488
Note: See TracBrowser for help on using the repository browser.