]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gas/config/tc-ft32.c
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / gas / config / tc-ft32.c
CommitLineData
3f8107ab 1/* tc-ft32.c -- Assemble code for ft32
6f2750fe 2 Copyright (C) 2008-2016 Free Software Foundation, Inc.
3f8107ab
AM
3
4 This file is part of GAS, the GNU Assembler.
5
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING. If not, write to
18 the Free Software Foundation, 51 Franklin Street - Fifth Floor,
19 Boston, MA 02110-1301, USA. */
20
21/* Contributed by Anthony Green <green@spindazzle.org>. */
22
23#include "as.h"
24#include "safe-ctype.h"
25#include "opcode/ft32.h"
26
27extern const ft32_opc_info_t ft32_opc_info[128];
28
29const char comment_chars[] = "#";
30const char line_separator_chars[] = ";";
31const char line_comment_chars[] = "#";
32
33static int pending_reloc;
34static struct hash_control *opcode_hash_control;
35
36static valueT md_chars_to_number (char * buf, int n);
37
38const pseudo_typeS md_pseudo_table[] =
39{
40 {0, 0, 0}
41};
42
43const char FLT_CHARS[] = "rRsSfFdDxXpP";
44const char EXP_CHARS[] = "eE";
45
46/* This function is called once, at assembler startup time. It sets
47 up the hash table with all the opcodes in it, and also initializes
48 some aliases for compatibility with other assemblers. */
49
50void
51md_begin (void)
52{
53 const ft32_opc_info_t *opcode;
54 opcode_hash_control = hash_new ();
55
56 /* Insert names into hash table. */
57 for (opcode = ft32_opc_info; opcode->name; opcode++)
58 hash_insert (opcode_hash_control, opcode->name, (char *) opcode);
59
60 bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
61}
62
63/* Parse an expression and then restore the input line pointer. */
64
65static char *
66parse_exp_save_ilp (char *s, expressionS *op)
67{
68 char *save = input_line_pointer;
69
70 input_line_pointer = s;
71 expression (op);
72 s = input_line_pointer;
73 input_line_pointer = save;
74 return s;
75}
76
77static int
78parse_condition (char **ptr)
79{
80 char *s = *ptr;
81 static const struct {
e0471c16 82 const char *name;
3f8107ab
AM
83 int bits;
84 } ccs[] = {
85 { "gt," , (2 << FT32_FLD_CR_BIT) | (5 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
86 { "gte," , (2 << FT32_FLD_CR_BIT) | (4 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
87 { "lt," , (2 << FT32_FLD_CR_BIT) | (4 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
88 { "lte," , (2 << FT32_FLD_CR_BIT) | (5 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
89 { "a," , (2 << FT32_FLD_CR_BIT) | (6 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
90 { "ae," , (2 << FT32_FLD_CR_BIT) | (1 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
91 { "be," , (2 << FT32_FLD_CR_BIT) | (6 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
92 { "b," , (2 << FT32_FLD_CR_BIT) | (1 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
93 { "nz," , (2 << FT32_FLD_CR_BIT) | (0 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
94 { "z," , (2 << FT32_FLD_CR_BIT) | (0 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
95 { "nc," , (2 << FT32_FLD_CR_BIT) | (1 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
96 { "c," , (2 << FT32_FLD_CR_BIT) | (1 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
97 { "no," , (2 << FT32_FLD_CR_BIT) | (2 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
98 { "o," , (2 << FT32_FLD_CR_BIT) | (2 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
99 { "ns," , (2 << FT32_FLD_CR_BIT) | (3 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
100 { "s," , (2 << FT32_FLD_CR_BIT) | (3 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
101 { NULL, 0}
102 }, *pc;
103
104 for (pc = ccs; pc->name; pc++)
105 {
106 if (memcmp(pc->name, s, strlen(pc->name)) == 0)
107 {
108 *ptr += strlen(pc->name) - 1;
109 return pc->bits;
110 }
111 }
112 return -1;
113}
114
115static int
116parse_decimal (char **ptr)
117{
118 int r = 0;
119 char *s = *ptr;
120
121 while (('0' <= *s) && (*s <= '9'))
122 {
123 r *= 10;
124 r += (*s++ - '0');
125 }
126 *ptr = s;
127 return r;
128}
129
130static int
131parse_register_operand (char **ptr)
132{
133 int reg;
134 char *s = *ptr;
135
136 if (*s != '$')
137 {
138 as_bad (_("expecting register"));
139 ignore_rest_of_line ();
140 return -1;
141 }
142 if ((s[1] == 's') && (s[2] == 'p'))
143 {
144 reg = 31;
145 }
146 else if ((s[1] == 'c') && (s[2] == 'c'))
147 {
148 reg = 30;
149 }
150 else if ((s[1] == 'f') && (s[2] == 'p'))
151 {
152 reg = 29;
153 }
154 else if (s[1] == 'r')
155 {
156 reg = s[2] - '0';
157 if ((reg < 0) || (reg > 9))
158 {
159 as_bad (_("illegal register number"));
160 ignore_rest_of_line ();
161 return -1;
162 }
163 if ((reg == 1) || (reg == 2) || (reg == 3))
164 {
165 int r2 = s[3] - '0';
166 if ((r2 >= 0) && (r2 <= 9))
167 {
168 reg = (reg * 10) + r2;
169 *ptr += 1;
170 }
171 }
172 }
173 else
174 {
175 as_bad (_("illegal register number"));
176 ignore_rest_of_line ();
177 return -1;
178 }
179
180 *ptr += 3;
181
182 return reg;
183}
184
185/* This is the guts of the machine-dependent assembler. STR points to
186 a machine dependent instruction. This function is supposed to emit
187 the frags/bytes it assembles to. */
188
189void
190md_assemble (char *str)
191{
192 char *op_start;
193 char *op_end;
194
195 ft32_opc_info_t *opcode;
196 char *output;
197 int idx = 0;
198 char pend;
199
200 int nlen = 0;
201
202 unsigned int b;
203 int f;
204
205 expressionS arg;
206
207 /* Drop leading whitespace. */
208 while (*str == ' ')
209 str++;
210
211 /* Find the op code end. */
212 op_start = str;
213 for (op_end = str;
214 *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ' && *op_end != '.';
215 op_end++)
216 nlen++;
217
218 pend = *op_end;
219 *op_end = 0;
220
221 if (nlen == 0)
222 as_bad (_("can't find opcode "));
223
224 opcode = (ft32_opc_info_t *) hash_find (opcode_hash_control, op_start);
225 *op_end = pend;
226
227 if (opcode == NULL)
228 {
229 as_bad (_("unknown opcode %s"), op_start);
230 return;
231 }
232
233 b = opcode->bits;
234 f = opcode->fields;
235
236 if (opcode->dw)
237 {
238 int dw;
239 if (*op_end == '.')
240 {
241 switch (op_end[1])
242 {
243 case 'b':
244 dw = 0;
245 break;
246 case 's':
247 dw = 1;
248 break;
249 case 'l':
250 dw = 2;
251 break;
252 default:
253 as_bad (_("unknown width specifier '.%c'"), op_end[1]);
254 return;
255 }
256 op_end += 2;
257 }
258 else
259 {
260 dw = 2; /* default is ".l" */
261 }
262 b |= dw << FT32_FLD_DW_BIT;
263 }
264
265 while (ISSPACE (*op_end))
266 op_end++;
267
268 output = frag_more (4);
269
270 while (f)
271 {
272 int lobit = f & -f;
273 if (f & lobit)
274 {
275 switch (lobit)
276 {
277 case FT32_FLD_CBCRCV:
278 b |= parse_condition( &op_end);
279 break;
280 case FT32_FLD_CB:
281 b |= parse_decimal (&op_end) << FT32_FLD_CB_BIT;
282 break;
283 case FT32_FLD_R_D:
284 b |= parse_register_operand (&op_end) << FT32_FLD_R_D_BIT;
285 break;
286 case FT32_FLD_CR:
287 b |= (parse_register_operand (&op_end) - 28) << FT32_FLD_CR_BIT;
288 break;
289 case FT32_FLD_CV:
290 b |= parse_decimal (&op_end) << FT32_FLD_CV_BIT;
291 break;
292 case FT32_FLD_R_1:
293 b |= parse_register_operand (&op_end) << FT32_FLD_R_1_BIT;
294 break;
295 case FT32_FLD_RIMM:
296 if (*op_end == '$')
297 {
298 b |= parse_register_operand (&op_end) << FT32_FLD_RIMM_BIT;
299 }
300 else
301 {
302 b |= 0x400 << FT32_FLD_RIMM_BIT;
303 op_end = parse_exp_save_ilp (op_end, &arg);
304 fix_new_exp (frag_now,
305 (output - frag_now->fr_literal),
306 2,
307 &arg,
308 0,
309 BFD_RELOC_FT32_10);
310 }
311 break;
312 case FT32_FLD_R_2:
313 b |= parse_register_operand (&op_end) << FT32_FLD_R_2_BIT;
314 break;
315 case FT32_FLD_K20:
316 op_end = parse_exp_save_ilp (op_end, &arg);
317 fix_new_exp (frag_now,
318 (output - frag_now->fr_literal),
319 3,
320 &arg,
321 0,
322 BFD_RELOC_FT32_20);
323 break;
324 case FT32_FLD_PA:
325 op_end = parse_exp_save_ilp (op_end, &arg);
326 fix_new_exp (frag_now,
327 (output - frag_now->fr_literal),
328 3,
329 &arg,
330 0,
331 BFD_RELOC_FT32_18);
332 break;
333 case FT32_FLD_AA:
334 op_end = parse_exp_save_ilp (op_end, &arg);
335 fix_new_exp (frag_now,
336 (output - frag_now->fr_literal),
337 3,
338 &arg,
339 0,
340 BFD_RELOC_FT32_17);
341 break;
342 case FT32_FLD_K16:
343 op_end = parse_exp_save_ilp (op_end, &arg);
344 fix_new_exp (frag_now,
345 (output - frag_now->fr_literal),
346 2,
347 &arg,
348 0,
349 BFD_RELOC_16);
350 break;
351 case FT32_FLD_K8:
352 op_end = parse_exp_save_ilp (op_end, &arg);
353 fix_new_exp (frag_now,
354 (output - frag_now->fr_literal),
355 1,
356 &arg,
357 0,
358 BFD_RELOC_8);
359 break;
360 case FT32_FLD_R_D_POST:
361 b |= parse_register_operand (&op_end) << FT32_FLD_R_D_BIT;
362 break;
363 case FT32_FLD_R_1_POST:
364 b |= parse_register_operand (&op_end) << FT32_FLD_R_1_BIT;
365 break;
366 default:
367 as_bad (_("internal error in argument parsing"));
368 break;
369 }
370 f &= ~lobit;
371 if (f)
372 {
373 while (ISSPACE (*op_end))
374 op_end++;
375
376 if (*op_end != ',')
377 {
378 as_bad (_("expected comma separator"));
379 ignore_rest_of_line ();
380 }
381
382 op_end++;
383 while (ISSPACE (*op_end))
384 op_end++;
385 }
386 }
387 }
388 if (*op_end != 0)
389 as_warn (_("extra stuff on line ignored"));
390
391 output[idx++] = 0xff & (b >> 0);
392 output[idx++] = 0xff & (b >> 8);
393 output[idx++] = 0xff & (b >> 16);
394 output[idx++] = 0xff & (b >> 24);
395
396 while (ISSPACE (*op_end))
397 op_end++;
398
399 if (*op_end != 0)
400 as_warn ("extra stuff on line ignored");
401
402 if (pending_reloc)
403 as_bad ("Something forgot to clean up\n");
404}
405
406/* Turn a string in input_line_pointer into a floating point constant
407 of type type, and store the appropriate bytes in *LITP. The number
408 of LITTLENUMS emitted is stored in *SIZEP . An error message is
409 returned, or NULL on OK. */
410
411char *
412md_atof (int type, char *litP, int *sizeP)
413{
414 int prec;
415 LITTLENUM_TYPE words[4];
416 char *t;
417 int i;
418
419 switch (type)
420 {
421 case 'f':
422 prec = 2;
423 break;
424
425 case 'd':
426 prec = 4;
427 break;
428
429 default:
430 *sizeP = 0;
431 return _("bad call to md_atof");
432 }
433
434 t = atof_ieee (input_line_pointer, type, words);
435 if (t)
436 input_line_pointer = t;
437
438 *sizeP = prec * 2;
439
440 for (i = prec - 1; i >= 0; i--)
441 {
442 md_number_to_chars (litP, (valueT) words[i], 2);
443 litP += 2;
444 }
445
446 return NULL;
447}
448\f
449const char *md_shortopts = "";
450
451struct option md_longopts[] =
452{
453 {NULL, no_argument, NULL, 0}
454};
455size_t md_longopts_size = sizeof (md_longopts);
456
457/* We have no target specific options yet, so these next
458 two functions are empty. */
459int
17b9d67d 460md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
3f8107ab
AM
461{
462 return 0;
463}
464
465void
466md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
467{
468}
469
470/* Convert from target byte order to host byte order. */
471
472static valueT
473md_chars_to_number (char * buf, int n)
474{
475 valueT result = 0;
476 unsigned char * where = (unsigned char *) buf;
477
478 while (n--)
479 {
480 result <<= 8;
481 result |= (where[n] & 255);
482 }
483
484 return result;
485}
486/* Apply a fixup to the object file. */
487
488void
489md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
490 valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED)
491{
492 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
493 long val = *valP;
494 long newval;
495
496 switch (fixP->fx_r_type)
497 {
498 case BFD_RELOC_32:
499 buf[3] = val >> 24;
500 buf[2] = val >> 16;
501 buf[1] = val >> 8;
502 buf[0] = val >> 0;
503 break;
504
505 case BFD_RELOC_16:
506 buf[1] = val >> 8;
507 buf[0] = val >> 0;
508 break;
509
510 case BFD_RELOC_8:
511 *buf = val;
512 break;
513
514 case BFD_RELOC_FT32_10:
515 if (!val)
516 break;
517 newval = md_chars_to_number (buf, 2);
518 newval |= (val & ((1 << 10) - 1)) << FT32_FLD_RIMM_BIT;
519 md_number_to_chars (buf, newval, 2);
520 break;
521
522 case BFD_RELOC_FT32_20:
523 if (!val)
524 break;
525 newval = md_chars_to_number (buf, 3);
526 newval |= val & ((1 << 20) - 1);
527 md_number_to_chars (buf, newval, 3);
528 break;
529
530 case BFD_RELOC_FT32_17:
531 if (!val)
532 break;
533 newval = md_chars_to_number (buf, 3);
534 newval |= val & ((1 << 17) - 1);
535 md_number_to_chars (buf, newval, 3);
536 break;
537
538 case BFD_RELOC_FT32_18:
539 if (!val)
540 break;
541 newval = md_chars_to_number (buf, 4);
542 newval |= (val >> 2) & ((1 << 18) - 1);
543 md_number_to_chars (buf, newval, 4);
544 break;
545
546 default:
547 abort ();
548 }
549
550 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
551 fixP->fx_done = 1;
552 // printf("fx_addsy=%p fixP->fx_pcrel=%d fx_done=%d\n", fixP->fx_addsy, fixP->fx_pcrel, fixP->fx_done);
553}
554
555void
556md_number_to_chars (char *ptr, valueT use, int nbytes)
557{
558 number_to_chars_littleendian (ptr, use, nbytes);
559}
560
561/* Generate a machine-dependent relocation. */
562arelent *
563tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
564{
565 arelent *relP;
566 bfd_reloc_code_real_type code;
567
568 switch (fixP->fx_r_type)
569 {
570 case BFD_RELOC_32:
571 case BFD_RELOC_16:
572 case BFD_RELOC_8:
573 case BFD_RELOC_FT32_10:
574 case BFD_RELOC_FT32_20:
575 case BFD_RELOC_FT32_17:
576 case BFD_RELOC_FT32_18:
577 code = fixP->fx_r_type;
578 break;
579 default:
580 as_bad_where (fixP->fx_file, fixP->fx_line,
581 _("Semantics error. This type of operand can not be relocated, it must be an assembly-time constant"));
582 return 0;
583 }
584
585 relP = xmalloc (sizeof (arelent));
586 gas_assert (relP != 0);
587 relP->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
588 *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
589 relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
590
591 relP->addend = fixP->fx_offset;
592
593 relP->howto = bfd_reloc_type_lookup (stdoutput, code);
594 if (! relP->howto)
595 {
596 const char *name;
597
598 name = S_GET_NAME (fixP->fx_addsy);
599 if (name == NULL)
600 name = _("<unknown>");
601 as_fatal (_("Cannot generate relocation type for symbol %s, code %s"),
602 name, bfd_get_reloc_code_name (code));
603 }
604
605 return relP;
606}