FT32: support for FT32B processor - part 1
[binutils-gdb.git] / gas / config / tc-ft32.c
1 /* tc-ft32.c -- Assemble code for ft32
2 Copyright (C) 2008-2017 Free Software Foundation, Inc.
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
27 extern const ft32_opc_info_t ft32_opc_info[128];
28
29 const char comment_chars[] = "#";
30 const char line_separator_chars[] = ";";
31 const char line_comment_chars[] = "#";
32
33 static int pending_reloc;
34 static struct hash_control *opcode_hash_control;
35
36 static valueT md_chars_to_number (char * buf, int n);
37
38 const pseudo_typeS md_pseudo_table[] =
39 {
40 {0, 0, 0}
41 };
42
43 const char FLT_CHARS[] = "rRsSfFdDxXpP";
44 const 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
50 void
51 md_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
65 static char *
66 parse_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
77 static int
78 parse_condition (char **ptr)
79 {
80 char *s = *ptr;
81 static const struct {
82 const char *name;
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
115 static int
116 parse_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
130 static int
131 parse_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
189 void
190 md_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_K15:
352 op_end = parse_exp_save_ilp (op_end, &arg);
353 if (arg.X_add_number & 0x80)
354 arg.X_add_number ^= 0x7f00;
355 fix_new_exp (frag_now,
356 (output - frag_now->fr_literal),
357 2,
358 &arg,
359 0,
360 BFD_RELOC_FT32_15);
361 break;
362 case FT32_FLD_R_D_POST:
363 b |= parse_register_operand (&op_end) << FT32_FLD_R_D_BIT;
364 break;
365 case FT32_FLD_R_1_POST:
366 b |= parse_register_operand (&op_end) << FT32_FLD_R_1_BIT;
367 break;
368 default:
369 as_bad (_("internal error in argument parsing"));
370 break;
371 }
372 f &= ~lobit;
373 if (f)
374 {
375 while (ISSPACE (*op_end))
376 op_end++;
377
378 if (*op_end != ',')
379 {
380 as_bad (_("expected comma separator"));
381 ignore_rest_of_line ();
382 }
383
384 op_end++;
385 while (ISSPACE (*op_end))
386 op_end++;
387 }
388 }
389 }
390 if (*op_end != 0)
391 as_warn (_("extra stuff on line ignored"));
392
393 output[idx++] = 0xff & (b >> 0);
394 output[idx++] = 0xff & (b >> 8);
395 output[idx++] = 0xff & (b >> 16);
396 output[idx++] = 0xff & (b >> 24);
397
398 dwarf2_emit_insn (4);
399
400 while (ISSPACE (*op_end))
401 op_end++;
402
403 if (*op_end != 0)
404 as_warn ("extra stuff on line ignored");
405
406 if (pending_reloc)
407 as_bad ("Something forgot to clean up\n");
408 }
409
410 /* Turn a string in input_line_pointer into a floating point constant
411 of type type, and store the appropriate bytes in *LITP. The number
412 of LITTLENUMS emitted is stored in *SIZEP . An error message is
413 returned, or NULL on OK. */
414
415 const char *
416 md_atof (int type, char *litP, int *sizeP)
417 {
418 int prec;
419 LITTLENUM_TYPE words[4];
420 char *t;
421 int i;
422
423 switch (type)
424 {
425 case 'f':
426 prec = 2;
427 break;
428
429 case 'd':
430 prec = 4;
431 break;
432
433 default:
434 *sizeP = 0;
435 return _("bad call to md_atof");
436 }
437
438 t = atof_ieee (input_line_pointer, type, words);
439 if (t)
440 input_line_pointer = t;
441
442 *sizeP = prec * 2;
443
444 for (i = prec - 1; i >= 0; i--)
445 {
446 md_number_to_chars (litP, (valueT) words[i], 2);
447 litP += 2;
448 }
449
450 return NULL;
451 }
452 \f
453 const char *md_shortopts = "";
454
455 struct option md_longopts[] =
456 {
457 {NULL, no_argument, NULL, 0}
458 };
459 size_t md_longopts_size = sizeof (md_longopts);
460
461 /* We have no target specific options yet, so these next
462 two functions are empty. */
463 int
464 md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
465 {
466 return 0;
467 }
468
469 void
470 md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
471 {
472 }
473
474 /* Convert from target byte order to host byte order. */
475
476 static valueT
477 md_chars_to_number (char * buf, int n)
478 {
479 valueT result = 0;
480 unsigned char * where = (unsigned char *) buf;
481
482 while (n--)
483 {
484 result <<= 8;
485 result |= (where[n] & 255);
486 }
487
488 return result;
489 }
490 /* Apply a fixup to the object file. */
491
492 void
493 md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
494 valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED)
495 {
496 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
497 long val = *valP;
498 long newval;
499
500 switch (fixP->fx_r_type)
501 {
502 case BFD_RELOC_32:
503 buf[3] = val >> 24;
504 buf[2] = val >> 16;
505 buf[1] = val >> 8;
506 buf[0] = val >> 0;
507 break;
508
509 case BFD_RELOC_16:
510 buf[1] = val >> 8;
511 buf[0] = val >> 0;
512 break;
513
514 case BFD_RELOC_8:
515 *buf = val;
516 break;
517
518 case BFD_RELOC_FT32_10:
519 if (!val)
520 break;
521 newval = md_chars_to_number (buf, 2);
522 newval |= (val & ((1 << 10) - 1)) << FT32_FLD_RIMM_BIT;
523 md_number_to_chars (buf, newval, 2);
524 break;
525
526 case BFD_RELOC_FT32_20:
527 if (!val)
528 break;
529 newval = md_chars_to_number (buf, 3);
530 newval |= val & ((1 << 20) - 1);
531 md_number_to_chars (buf, newval, 3);
532 break;
533
534 case BFD_RELOC_FT32_15:
535 if (!val)
536 break;
537 newval = md_chars_to_number (buf, 2);
538 newval |= val & ((1 << 15) - 1);
539 md_number_to_chars (buf, newval, 2);
540 break;
541
542 case BFD_RELOC_FT32_17:
543 if (!val)
544 break;
545 newval = md_chars_to_number (buf, 3);
546 newval |= val & ((1 << 17) - 1);
547 md_number_to_chars (buf, newval, 3);
548 break;
549
550 case BFD_RELOC_FT32_18:
551 if (!val)
552 break;
553 newval = md_chars_to_number (buf, 4);
554 newval |= (val >> 2) & ((1 << 18) - 1);
555 md_number_to_chars (buf, newval, 4);
556 break;
557
558 default:
559 abort ();
560 }
561
562 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
563 fixP->fx_done = 1;
564 // printf("fx_addsy=%p fixP->fx_pcrel=%d fx_done=%d\n", fixP->fx_addsy, fixP->fx_pcrel, fixP->fx_done);
565 }
566
567 void
568 md_number_to_chars (char *ptr, valueT use, int nbytes)
569 {
570 number_to_chars_littleendian (ptr, use, nbytes);
571 }
572
573 /* Generate a machine-dependent relocation. */
574 arelent *
575 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
576 {
577 arelent *relP;
578 bfd_reloc_code_real_type code;
579
580 switch (fixP->fx_r_type)
581 {
582 case BFD_RELOC_32:
583 case BFD_RELOC_16:
584 case BFD_RELOC_8:
585 case BFD_RELOC_FT32_10:
586 case BFD_RELOC_FT32_20:
587 case BFD_RELOC_FT32_15:
588 case BFD_RELOC_FT32_17:
589 case BFD_RELOC_FT32_18:
590 code = fixP->fx_r_type;
591 break;
592 default:
593 as_bad_where (fixP->fx_file, fixP->fx_line,
594 _("Semantics error. This type of operand can not be relocated, it must be an assembly-time constant"));
595 return 0;
596 }
597
598 relP = XNEW (arelent);
599 gas_assert (relP != 0);
600 relP->sym_ptr_ptr = XNEW (asymbol *);
601 *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
602 relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
603
604 relP->addend = fixP->fx_offset;
605
606 relP->howto = bfd_reloc_type_lookup (stdoutput, code);
607 if (! relP->howto)
608 {
609 const char *name;
610
611 name = S_GET_NAME (fixP->fx_addsy);
612 if (name == NULL)
613 name = _("<unknown>");
614 as_fatal (_("Cannot generate relocation type for symbol %s, code %s"),
615 name, bfd_get_reloc_code_name (code));
616 }
617
618 return relP;
619 }