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 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 { 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 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 dwarf2_emit_insn (4); 397 398 while (ISSPACE (*op_end)) 399 op_end++; 400 401 if (*op_end != 0) 402 as_warn ("extra stuff on line ignored"); 403 404 if (pending_reloc) 405 as_bad ("Something forgot to clean up\n"); 406} 407 408/* Turn a string in input_line_pointer into a floating point constant 409 of type type, and store the appropriate bytes in *LITP. The number 410 of LITTLENUMS emitted is stored in *SIZEP . An error message is 411 returned, or NULL on OK. */ 412 413const char * 414md_atof (int type, char *litP, int *sizeP) 415{ 416 int prec; 417 LITTLENUM_TYPE words[4]; 418 char *t; 419 int i; 420 421 switch (type) 422 { 423 case 'f': 424 prec = 2; 425 break; 426 427 case 'd': 428 prec = 4; 429 break; 430 431 default: 432 *sizeP = 0; 433 return _("bad call to md_atof"); 434 } 435 436 t = atof_ieee (input_line_pointer, type, words); 437 if (t) 438 input_line_pointer = t; 439 440 *sizeP = prec * 2; 441 442 for (i = prec - 1; i >= 0; i--) 443 { 444 md_number_to_chars (litP, (valueT) words[i], 2); 445 litP += 2; 446 } 447 448 return NULL; 449} 450 451const char *md_shortopts = ""; 452 453struct option md_longopts[] = 454{ 455 {NULL, no_argument, NULL, 0} 456}; 457size_t md_longopts_size = sizeof (md_longopts); 458 459/* We have no target specific options yet, so these next 460 two functions are empty. */ 461int 462md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED) 463{ 464 return 0; 465} 466 467void 468md_show_usage (FILE *stream ATTRIBUTE_UNUSED) 469{ 470} 471 472/* Convert from target byte order to host byte order. */ 473 474static valueT 475md_chars_to_number (char * buf, int n) 476{ 477 valueT result = 0; 478 unsigned char * where = (unsigned char *) buf; 479 480 while (n--) 481 { 482 result <<= 8; 483 result |= (where[n] & 255); 484 } 485 486 return result; 487} 488/* Apply a fixup to the object file. */ 489 490void 491md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED, 492 valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED) 493{ 494 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; 495 long val = *valP; 496 long newval; 497 498 switch (fixP->fx_r_type) 499 { 500 case BFD_RELOC_32: 501 buf[3] = val >> 24; 502 buf[2] = val >> 16; 503 buf[1] = val >> 8; 504 buf[0] = val >> 0; 505 break; 506 507 case BFD_RELOC_16: 508 buf[1] = val >> 8; 509 buf[0] = val >> 0; 510 break; 511 512 case BFD_RELOC_8: 513 *buf = val; 514 break; 515 516 case BFD_RELOC_FT32_10: 517 if (!val) 518 break; 519 newval = md_chars_to_number (buf, 2); 520 newval |= (val & ((1 << 10) - 1)) << FT32_FLD_RIMM_BIT; 521 md_number_to_chars (buf, newval, 2); 522 break; 523 524 case BFD_RELOC_FT32_20: 525 if (!val) 526 break; 527 newval = md_chars_to_number (buf, 3); 528 newval |= val & ((1 << 20) - 1); 529 md_number_to_chars (buf, newval, 3); 530 break; 531 532 case BFD_RELOC_FT32_17: 533 if (!val) 534 break; 535 newval = md_chars_to_number (buf, 3); 536 newval |= val & ((1 << 17) - 1); 537 md_number_to_chars (buf, newval, 3); 538 break; 539 540 case BFD_RELOC_FT32_18: 541 if (!val) 542 break; 543 newval = md_chars_to_number (buf, 4); 544 newval |= (val >> 2) & ((1 << 18) - 1); 545 md_number_to_chars (buf, newval, 4); 546 break; 547 548 default: 549 abort (); 550 } 551 552 if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) 553 fixP->fx_done = 1; 554 // printf("fx_addsy=%p fixP->fx_pcrel=%d fx_done=%d\n", fixP->fx_addsy, fixP->fx_pcrel, fixP->fx_done); 555} 556 557void 558md_number_to_chars (char *ptr, valueT use, int nbytes) 559{ 560 number_to_chars_littleendian (ptr, use, nbytes); 561} 562 563/* Generate a machine-dependent relocation. */ 564arelent * 565tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP) 566{ 567 arelent *relP; 568 bfd_reloc_code_real_type code; 569 570 switch (fixP->fx_r_type) 571 { 572 case BFD_RELOC_32: 573 case BFD_RELOC_16: 574 case BFD_RELOC_8: 575 case BFD_RELOC_FT32_10: 576 case BFD_RELOC_FT32_20: 577 case BFD_RELOC_FT32_17: 578 case BFD_RELOC_FT32_18: 579 code = fixP->fx_r_type; 580 break; 581 default: 582 as_bad_where (fixP->fx_file, fixP->fx_line, 583 _("Semantics error. This type of operand can not be relocated, it must be an assembly-time constant")); 584 return 0; 585 } 586 587 relP = XNEW (arelent); 588 gas_assert (relP != 0); 589 relP->sym_ptr_ptr = XNEW (asymbol *); 590 *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); 591 relP->address = fixP->fx_frag->fr_address + fixP->fx_where; 592 593 relP->addend = fixP->fx_offset; 594 595 relP->howto = bfd_reloc_type_lookup (stdoutput, code); 596 if (! relP->howto) 597 { 598 const char *name; 599 600 name = S_GET_NAME (fixP->fx_addsy); 601 if (name == NULL) 602 name = _("<unknown>"); 603 as_fatal (_("Cannot generate relocation type for symbol %s, code %s"), 604 name, bfd_get_reloc_code_name (code)); 605 } 606 607 return relP; 608} 609