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