1214571Sdim/* tc-cr16.c -- Assembler code for the CR16 CPU core. 2214571Sdim Copyright 2007 Free Software Foundation, Inc. 3214571Sdim 4214571Sdim Contributed by M R Swami Reddy <MR.Swami.Reddy@nsc.com> 5214571Sdim 6214571Sdim This file is part of GAS, the GNU Assembler. 7214571Sdim 8214571Sdim GAS is free software; you can redistribute it and/or modify 9214571Sdim it under the terms of the GNU General Public License as published by 10214571Sdim the Free Software Foundation; either version 2, or (at your option) 11214571Sdim any later version. 12214571Sdim 13214571Sdim GAS is distributed in the hope that it will be useful, 14214571Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 15214571Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16214571Sdim GNU General Public License for more details. 17214571Sdim 18214571Sdim You should have received a copy of the GNU General Public License 19214571Sdim along with GAS; see the file COPYING. If not, write to the 20214571Sdim Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, 21214571Sdim MA 02110-1301, USA. */ 22214571Sdim 23214571Sdim#include "as.h" 24214571Sdim#include "safe-ctype.h" 25214571Sdim#include "dwarf2dbg.h" 26214571Sdim#include "opcode/cr16.h" 27214571Sdim#include "elf/cr16.h" 28214571Sdim 29214571Sdim 30214571Sdim/* Word is considered here as a 16-bit unsigned short int. */ 31214571Sdim#define WORD_SHIFT 16 32214571Sdim 33214571Sdim/* Register is 2-byte size. */ 34214571Sdim#define REG_SIZE 2 35214571Sdim 36214571Sdim/* Maximum size of a single instruction (in words). */ 37214571Sdim#define INSN_MAX_SIZE 3 38214571Sdim 39214571Sdim/* Maximum bits which may be set in a `mask16' operand. */ 40214571Sdim#define MAX_REGS_IN_MASK16 8 41214571Sdim 42214571Sdim/* Assign a number NUM, shifted by SHIFT bytes, into a location 43214571Sdim pointed by index BYTE of array 'output_opcode'. */ 44214571Sdim#define CR16_PRINT(BYTE, NUM, SHIFT) output_opcode[BYTE] |= (NUM << SHIFT) 45214571Sdim 46214571Sdim/* Operand errors. */ 47214571Sdimtypedef enum 48214571Sdim { 49214571Sdim OP_LEGAL = 0, /* Legal operand. */ 50214571Sdim OP_OUT_OF_RANGE, /* Operand not within permitted range. */ 51214571Sdim OP_NOT_EVEN /* Operand is Odd number, should be even. */ 52214571Sdim } 53214571Sdimop_err; 54214571Sdim 55214571Sdim/* Opcode mnemonics hash table. */ 56214571Sdimstatic struct hash_control *cr16_inst_hash; 57214571Sdim/* CR16 registers hash table. */ 58214571Sdimstatic struct hash_control *reg_hash; 59214571Sdim/* CR16 register pair hash table. */ 60214571Sdimstatic struct hash_control *regp_hash; 61214571Sdim/* CR16 processor registers hash table. */ 62214571Sdimstatic struct hash_control *preg_hash; 63214571Sdim/* CR16 processor registers 32 bit hash table. */ 64214571Sdimstatic struct hash_control *pregp_hash; 65214571Sdim/* Current instruction we're assembling. */ 66214571Sdimconst inst *instruction; 67214571Sdim 68214571Sdim 69214571Sdimstatic int code_label = 0; 70214571Sdim 71214571Sdim/* Global variables. */ 72214571Sdim 73214571Sdim/* Array to hold an instruction encoding. */ 74214571Sdimlong output_opcode[2]; 75214571Sdim 76214571Sdim/* Nonzero means a relocatable symbol. */ 77214571Sdimint relocatable; 78214571Sdim 79214571Sdim/* A copy of the original instruction (used in error messages). */ 80214571Sdimchar ins_parse[MAX_INST_LEN]; 81214571Sdim 82214571Sdim/* The current processed argument number. */ 83214571Sdimint cur_arg_num; 84214571Sdim 85214571Sdim/* Generic assembler global variables which must be defined by all targets. */ 86214571Sdim 87214571Sdim/* Characters which always start a comment. */ 88214571Sdimconst char comment_chars[] = "#"; 89214571Sdim 90214571Sdim/* Characters which start a comment at the beginning of a line. */ 91214571Sdimconst char line_comment_chars[] = "#"; 92214571Sdim 93214571Sdim/* This array holds machine specific line separator characters. */ 94214571Sdimconst char line_separator_chars[] = ";"; 95214571Sdim 96214571Sdim/* Chars that can be used to separate mant from exp in floating point nums. */ 97214571Sdimconst char EXP_CHARS[] = "eE"; 98214571Sdim 99214571Sdim/* Chars that mean this number is a floating point constant as in 0f12.456 */ 100214571Sdimconst char FLT_CHARS[] = "f'"; 101214571Sdim 102214571Sdim/* Target-specific multicharacter options, not const-declared at usage. */ 103214571Sdimconst char *md_shortopts = ""; 104214571Sdimstruct option md_longopts[] = 105214571Sdim{ 106214571Sdim {NULL, no_argument, NULL, 0} 107214571Sdim}; 108214571Sdimsize_t md_longopts_size = sizeof (md_longopts); 109214571Sdim 110214571Sdimstatic void 111214571Sdiml_cons (int nbytes) 112214571Sdim{ 113214571Sdim int c; 114214571Sdim expressionS exp; 115214571Sdim 116214571Sdim#ifdef md_flush_pending_output 117214571Sdim md_flush_pending_output (); 118214571Sdim#endif 119214571Sdim 120214571Sdim if (is_it_end_of_statement ()) 121214571Sdim { 122214571Sdim demand_empty_rest_of_line (); 123214571Sdim return; 124214571Sdim } 125214571Sdim 126214571Sdim#ifdef TC_ADDRESS_BYTES 127214571Sdim if (nbytes == 0) 128214571Sdim nbytes = TC_ADDRESS_BYTES (); 129214571Sdim#endif 130214571Sdim 131214571Sdim#ifdef md_cons_align 132214571Sdim md_cons_align (nbytes); 133214571Sdim#endif 134214571Sdim 135214571Sdim c = 0; 136214571Sdim do 137214571Sdim { 138214571Sdim unsigned int bits_available = BITS_PER_CHAR * nbytes; 139214571Sdim char *hold = input_line_pointer; 140214571Sdim 141214571Sdim expression (&exp); 142214571Sdim 143214571Sdim if (*input_line_pointer == ':') 144214571Sdim { 145214571Sdim /* Bitfields. */ 146214571Sdim long value = 0; 147214571Sdim 148214571Sdim for (;;) 149214571Sdim { 150214571Sdim unsigned long width; 151214571Sdim 152214571Sdim if (*input_line_pointer != ':') 153214571Sdim { 154214571Sdim input_line_pointer = hold; 155214571Sdim break; 156214571Sdim } 157214571Sdim if (exp.X_op == O_absent) 158214571Sdim { 159214571Sdim as_warn (_("using a bit field width of zero")); 160214571Sdim exp.X_add_number = 0; 161214571Sdim exp.X_op = O_constant; 162214571Sdim } 163214571Sdim 164214571Sdim if (exp.X_op != O_constant) 165214571Sdim { 166214571Sdim *input_line_pointer = '\0'; 167214571Sdim as_bad (_("field width \"%s\" too complex for a bitfield"), hold); 168214571Sdim *input_line_pointer = ':'; 169214571Sdim demand_empty_rest_of_line (); 170214571Sdim return; 171214571Sdim } 172214571Sdim 173214571Sdim if ((width = exp.X_add_number) > 174214571Sdim (unsigned int)(BITS_PER_CHAR * nbytes)) 175214571Sdim { 176214571Sdim as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), width, nbytes, (BITS_PER_CHAR * nbytes)); 177214571Sdim width = BITS_PER_CHAR * nbytes; 178214571Sdim } /* Too big. */ 179214571Sdim 180214571Sdim 181214571Sdim if (width > bits_available) 182214571Sdim { 183214571Sdim /* FIXME-SOMEDAY: backing up and reparsing is wasteful. */ 184214571Sdim input_line_pointer = hold; 185214571Sdim exp.X_add_number = value; 186214571Sdim break; 187214571Sdim } 188214571Sdim 189214571Sdim /* Skip ':'. */ 190214571Sdim hold = ++input_line_pointer; 191214571Sdim 192214571Sdim expression (&exp); 193214571Sdim if (exp.X_op != O_constant) 194214571Sdim { 195214571Sdim char cache = *input_line_pointer; 196214571Sdim 197214571Sdim *input_line_pointer = '\0'; 198214571Sdim as_bad (_("field value \"%s\" too complex for a bitfield"), hold); 199214571Sdim *input_line_pointer = cache; 200214571Sdim demand_empty_rest_of_line (); 201214571Sdim return; 202214571Sdim } 203214571Sdim 204214571Sdim value |= ((~(-1 << width) & exp.X_add_number) 205214571Sdim << ((BITS_PER_CHAR * nbytes) - bits_available)); 206214571Sdim 207214571Sdim if ((bits_available -= width) == 0 208214571Sdim || is_it_end_of_statement () 209214571Sdim || *input_line_pointer != ',') 210214571Sdim break; 211214571Sdim 212214571Sdim hold = ++input_line_pointer; 213214571Sdim expression (&exp); 214214571Sdim } 215214571Sdim 216214571Sdim exp.X_add_number = value; 217214571Sdim exp.X_op = O_constant; 218214571Sdim exp.X_unsigned = 1; 219214571Sdim } 220214571Sdim 221214571Sdim if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c')) 222214571Sdim code_label = 1; 223214571Sdim emit_expr (&exp, (unsigned int) nbytes); 224214571Sdim ++c; 225214571Sdim if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c')) 226214571Sdim { 227214571Sdim input_line_pointer +=3; 228214571Sdim break; 229214571Sdim } 230214571Sdim } 231214571Sdim while ((*input_line_pointer++ == ',')); 232214571Sdim 233214571Sdim /* Put terminator back into stream. */ 234214571Sdim input_line_pointer--; 235214571Sdim 236214571Sdim demand_empty_rest_of_line (); 237214571Sdim} 238214571Sdim 239214571Sdim 240214571Sdim/* This table describes all the machine specific pseudo-ops 241214571Sdim the assembler has to support. The fields are: 242214571Sdim *** Pseudo-op name without dot. 243214571Sdim *** Function to call to execute this pseudo-op. 244214571Sdim *** Integer arg to pass to the function. */ 245214571Sdim 246214571Sdimconst pseudo_typeS md_pseudo_table[] = 247214571Sdim{ 248214571Sdim /* In CR16 machine, align is in bytes (not a ptwo boundary). */ 249214571Sdim {"align", s_align_bytes, 0}, 250214571Sdim {"long", l_cons, 4 }, 251214571Sdim {0, 0, 0} 252214571Sdim}; 253214571Sdim 254214571Sdim/* CR16 relaxation table. */ 255214571Sdimconst relax_typeS md_relax_table[] = 256214571Sdim{ 257214571Sdim /* bCC */ 258214571Sdim {0xfa, -0x100, 2, 1}, /* 8 */ 259214571Sdim {0xfffe, -0x10000, 4, 2}, /* 16 */ 260214571Sdim {0xfffffe, -0x1000000, 6, 0}, /* 24 */ 261214571Sdim}; 262214571Sdim 263214571Sdim/* Return the bit size for a given operand. */ 264214571Sdim 265214571Sdimstatic int 266214571Sdimget_opbits (operand_type op) 267214571Sdim{ 268214571Sdim if (op < MAX_OPRD) 269214571Sdim return cr16_optab[op].bit_size; 270214571Sdim 271214571Sdim return 0; 272214571Sdim} 273214571Sdim 274214571Sdim/* Return the argument type of a given operand. */ 275214571Sdim 276214571Sdimstatic argtype 277214571Sdimget_optype (operand_type op) 278214571Sdim{ 279214571Sdim if (op < MAX_OPRD) 280214571Sdim return cr16_optab[op].arg_type; 281214571Sdim else 282214571Sdim return nullargs; 283214571Sdim} 284214571Sdim 285214571Sdim/* Return the flags of a given operand. */ 286214571Sdim 287214571Sdimstatic int 288214571Sdimget_opflags (operand_type op) 289214571Sdim{ 290214571Sdim if (op < MAX_OPRD) 291214571Sdim return cr16_optab[op].flags; 292214571Sdim 293214571Sdim return 0; 294214571Sdim} 295214571Sdim 296214571Sdim/* Get the cc code. */ 297214571Sdim 298214571Sdimstatic int 299214571Sdimget_cc (char *cc_name) 300214571Sdim{ 301214571Sdim unsigned int i; 302214571Sdim 303214571Sdim for (i = 0; i < cr16_num_cc; i++) 304214571Sdim if (strcmp (cc_name, cr16_b_cond_tab[i]) == 0) 305214571Sdim return i; 306214571Sdim 307214571Sdim return -1; 308214571Sdim} 309214571Sdim 310214571Sdim/* Get the core processor register 'reg_name'. */ 311214571Sdim 312214571Sdimstatic reg 313214571Sdimget_register (char *reg_name) 314214571Sdim{ 315214571Sdim const reg_entry *reg; 316214571Sdim 317214571Sdim reg = (const reg_entry *) hash_find (reg_hash, reg_name); 318214571Sdim 319214571Sdim if (reg != NULL) 320214571Sdim return reg->value.reg_val; 321214571Sdim 322214571Sdim return nullregister; 323214571Sdim} 324214571Sdim/* Get the core processor register-pair 'reg_name'. */ 325214571Sdim 326214571Sdimstatic reg 327214571Sdimget_register_pair (char *reg_name) 328214571Sdim{ 329214571Sdim const reg_entry *reg; 330214571Sdim char tmp_rp[16]="\0"; 331214571Sdim 332214571Sdim /* Add '(' and ')' to the reg pair, if its not present. */ 333214571Sdim if (reg_name[0] != '(') 334214571Sdim { 335214571Sdim tmp_rp[0] = '('; 336214571Sdim strcat (tmp_rp, reg_name); 337214571Sdim strcat (tmp_rp,")"); 338214571Sdim reg = (const reg_entry *) hash_find (regp_hash, tmp_rp); 339214571Sdim } 340214571Sdim else 341214571Sdim reg = (const reg_entry *) hash_find (regp_hash, reg_name); 342214571Sdim 343214571Sdim if (reg != NULL) 344214571Sdim return reg->value.reg_val; 345214571Sdim 346214571Sdim return nullregister; 347214571Sdim} 348214571Sdim 349214571Sdim/* Get the index register 'reg_name'. */ 350214571Sdim 351214571Sdimstatic reg 352214571Sdimget_index_register (char *reg_name) 353214571Sdim{ 354214571Sdim const reg_entry *reg; 355214571Sdim 356214571Sdim reg = (const reg_entry *) hash_find (reg_hash, reg_name); 357214571Sdim 358214571Sdim if ((reg != NULL) 359214571Sdim && ((reg->value.reg_val == 12) || (reg->value.reg_val == 13))) 360214571Sdim return reg->value.reg_val; 361214571Sdim 362214571Sdim return nullregister; 363214571Sdim} 364214571Sdim/* Get the core processor index register-pair 'reg_name'. */ 365214571Sdim 366214571Sdimstatic reg 367214571Sdimget_index_register_pair (char *reg_name) 368214571Sdim{ 369214571Sdim const reg_entry *reg; 370214571Sdim 371214571Sdim reg = (const reg_entry *) hash_find (regp_hash, reg_name); 372214571Sdim 373214571Sdim if (reg != NULL) 374214571Sdim { 375214571Sdim if ((reg->value.reg_val != 1) || (reg->value.reg_val != 7) 376214571Sdim || (reg->value.reg_val != 9) || (reg->value.reg_val > 10)) 377214571Sdim return reg->value.reg_val; 378214571Sdim 379214571Sdim as_bad (_("Unknown register pair - index relative mode: `%d'"), reg->value.reg_val); 380214571Sdim } 381214571Sdim 382214571Sdim return nullregister; 383214571Sdim} 384214571Sdim 385214571Sdim/* Get the processor register 'preg_name'. */ 386214571Sdim 387214571Sdimstatic preg 388214571Sdimget_pregister (char *preg_name) 389214571Sdim{ 390214571Sdim const reg_entry *preg; 391214571Sdim 392214571Sdim preg = (const reg_entry *) hash_find (preg_hash, preg_name); 393214571Sdim 394214571Sdim if (preg != NULL) 395214571Sdim return preg->value.preg_val; 396214571Sdim 397214571Sdim return nullpregister; 398214571Sdim} 399214571Sdim 400214571Sdim/* Get the processor register 'preg_name 32 bit'. */ 401214571Sdim 402214571Sdimstatic preg 403214571Sdimget_pregisterp (char *preg_name) 404214571Sdim{ 405214571Sdim const reg_entry *preg; 406214571Sdim 407214571Sdim preg = (const reg_entry *) hash_find (pregp_hash, preg_name); 408214571Sdim 409214571Sdim if (preg != NULL) 410214571Sdim return preg->value.preg_val; 411214571Sdim 412214571Sdim return nullpregister; 413214571Sdim} 414214571Sdim 415214571Sdim 416214571Sdim/* Round up a section size to the appropriate boundary. */ 417214571Sdim 418214571SdimvalueT 419214571Sdimmd_section_align (segT seg, valueT val) 420214571Sdim{ 421214571Sdim /* Round .text section to a multiple of 2. */ 422214571Sdim if (seg == text_section) 423214571Sdim return (val + 1) & ~1; 424214571Sdim return val; 425214571Sdim} 426214571Sdim 427214571Sdim/* Parse an operand that is machine-specific (remove '*'). */ 428214571Sdim 429214571Sdimvoid 430214571Sdimmd_operand (expressionS * exp) 431214571Sdim{ 432214571Sdim char c = *input_line_pointer; 433214571Sdim 434214571Sdim switch (c) 435214571Sdim { 436214571Sdim case '*': 437214571Sdim input_line_pointer++; 438214571Sdim expression (exp); 439214571Sdim break; 440214571Sdim default: 441214571Sdim break; 442214571Sdim } 443214571Sdim} 444214571Sdim 445214571Sdim/* Reset global variables before parsing a new instruction. */ 446214571Sdim 447214571Sdimstatic void 448214571Sdimreset_vars (char *op) 449214571Sdim{ 450214571Sdim cur_arg_num = relocatable = 0; 451214571Sdim memset (& output_opcode, '\0', sizeof (output_opcode)); 452214571Sdim 453214571Sdim /* Save a copy of the original OP (used in error messages). */ 454214571Sdim strncpy (ins_parse, op, sizeof ins_parse - 1); 455214571Sdim ins_parse [sizeof ins_parse - 1] = 0; 456214571Sdim} 457214571Sdim 458214571Sdim/* This macro decides whether a particular reloc is an entry in a 459214571Sdim switch table. It is used when relaxing, because the linker needs 460214571Sdim to know about all such entries so that it can adjust them if 461214571Sdim necessary. */ 462214571Sdim 463214571Sdim#define SWITCH_TABLE(fix) \ 464214571Sdim ( (fix)->fx_addsy != NULL \ 465214571Sdim && (fix)->fx_subsy != NULL \ 466214571Sdim && S_GET_SEGMENT ((fix)->fx_addsy) == \ 467214571Sdim S_GET_SEGMENT ((fix)->fx_subsy) \ 468214571Sdim && S_GET_SEGMENT (fix->fx_addsy) != undefined_section \ 469214571Sdim && ( (fix)->fx_r_type == BFD_RELOC_CR16_NUM8 \ 470214571Sdim || (fix)->fx_r_type == BFD_RELOC_CR16_NUM16 \ 471214571Sdim || (fix)->fx_r_type == BFD_RELOC_CR16_NUM32 \ 472214571Sdim || (fix)->fx_r_type == BFD_RELOC_CR16_NUM32a)) 473214571Sdim 474214571Sdim/* See whether we need to force a relocation into the output file. 475214571Sdim This is used to force out switch and PC relative relocations when 476214571Sdim relaxing. */ 477214571Sdim 478214571Sdimint 479214571Sdimcr16_force_relocation (fixS *fix) 480214571Sdim{ 481214571Sdim /* REVISIT: Check if the "SWITCH_TABLE (fix)" should be added 482214571Sdim if (generic_force_reloc (fix) || SWITCH_TABLE (fix)) */ 483214571Sdim if (generic_force_reloc (fix)) 484214571Sdim return 1; 485214571Sdim 486214571Sdim return 0; 487214571Sdim} 488214571Sdim 489214571Sdim/* Record a fixup for a cons expression. */ 490214571Sdim 491214571Sdimvoid 492214571Sdimcr16_cons_fix_new (fragS *frag, int offset, int len, expressionS *exp) 493214571Sdim{ 494214571Sdim int rtype; 495214571Sdim switch (len) 496214571Sdim { 497214571Sdim default: rtype = BFD_RELOC_NONE; break; 498214571Sdim case 1: rtype = BFD_RELOC_CR16_NUM8 ; break; 499214571Sdim case 2: rtype = BFD_RELOC_CR16_NUM16; break; 500214571Sdim case 4: 501214571Sdim if (code_label) 502214571Sdim { 503214571Sdim rtype = BFD_RELOC_CR16_NUM32a; 504214571Sdim code_label = 0; 505214571Sdim } 506214571Sdim else 507214571Sdim rtype = BFD_RELOC_CR16_NUM32; 508214571Sdim break; 509214571Sdim } 510214571Sdim 511214571Sdim fix_new_exp (frag, offset, len, exp, 0, rtype); 512214571Sdim} 513214571Sdim 514214571Sdim/* Generate a relocation entry for a fixup. */ 515214571Sdim 516214571Sdimarelent * 517214571Sdimtc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP) 518214571Sdim{ 519214571Sdim arelent * reloc; 520214571Sdim 521214571Sdim reloc = xmalloc (sizeof (arelent)); 522214571Sdim reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); 523214571Sdim *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); 524214571Sdim reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; 525214571Sdim reloc->addend = fixP->fx_offset; 526214571Sdim 527214571Sdim if (fixP->fx_subsy != NULL) 528214571Sdim { 529214571Sdim if (SWITCH_TABLE (fixP)) 530214571Sdim { 531214571Sdim /* Keep the current difference in the addend. */ 532214571Sdim reloc->addend = (S_GET_VALUE (fixP->fx_addsy) 533214571Sdim - S_GET_VALUE (fixP->fx_subsy) + fixP->fx_offset); 534214571Sdim 535214571Sdim switch (fixP->fx_r_type) 536214571Sdim { 537214571Sdim case BFD_RELOC_CR16_NUM8: 538214571Sdim fixP->fx_r_type = BFD_RELOC_CR16_NUM8; 539214571Sdim break; 540214571Sdim case BFD_RELOC_CR16_NUM16: 541214571Sdim fixP->fx_r_type = BFD_RELOC_CR16_NUM16; 542214571Sdim break; 543214571Sdim case BFD_RELOC_CR16_NUM32: 544214571Sdim fixP->fx_r_type = BFD_RELOC_CR16_NUM32; 545214571Sdim break; 546214571Sdim case BFD_RELOC_CR16_NUM32a: 547214571Sdim fixP->fx_r_type = BFD_RELOC_CR16_NUM32a; 548214571Sdim break; 549214571Sdim default: 550214571Sdim abort (); 551214571Sdim break; 552214571Sdim } 553214571Sdim } 554214571Sdim else 555214571Sdim { 556214571Sdim /* We only resolve difference expressions in the same section. */ 557214571Sdim as_bad_where (fixP->fx_file, fixP->fx_line, 558214571Sdim _("can't resolve `%s' {%s section} - `%s' {%s section}"), 559214571Sdim fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "0", 560214571Sdim segment_name (fixP->fx_addsy 561214571Sdim ? S_GET_SEGMENT (fixP->fx_addsy) 562214571Sdim : absolute_section), 563214571Sdim S_GET_NAME (fixP->fx_subsy), 564214571Sdim segment_name (S_GET_SEGMENT (fixP->fx_addsy))); 565214571Sdim } 566214571Sdim } 567214571Sdim 568214571Sdim assert ((int) fixP->fx_r_type > 0); 569214571Sdim reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); 570214571Sdim 571214571Sdim if (reloc->howto == NULL) 572214571Sdim { 573214571Sdim as_bad_where (fixP->fx_file, fixP->fx_line, 574214571Sdim _("internal error: reloc %d (`%s') not supported by object file format"), 575214571Sdim fixP->fx_r_type, 576214571Sdim bfd_get_reloc_code_name (fixP->fx_r_type)); 577214571Sdim return NULL; 578214571Sdim } 579214571Sdim assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); 580214571Sdim 581214571Sdim return reloc; 582214571Sdim} 583214571Sdim 584214571Sdim/* Prepare machine-dependent frags for relaxation. */ 585214571Sdim 586214571Sdimint 587214571Sdimmd_estimate_size_before_relax (fragS *fragp, asection *seg) 588214571Sdim{ 589214571Sdim /* If symbol is undefined or located in a different section, 590214571Sdim select the largest supported relocation. */ 591214571Sdim relax_substateT subtype; 592214571Sdim relax_substateT rlx_state[] = {0, 2}; 593214571Sdim 594214571Sdim for (subtype = 0; subtype < ARRAY_SIZE (rlx_state); subtype += 2) 595214571Sdim { 596214571Sdim if (fragp->fr_subtype == rlx_state[subtype] 597214571Sdim && (!S_IS_DEFINED (fragp->fr_symbol) 598214571Sdim || seg != S_GET_SEGMENT (fragp->fr_symbol))) 599214571Sdim { 600214571Sdim fragp->fr_subtype = rlx_state[subtype + 1]; 601214571Sdim break; 602214571Sdim } 603214571Sdim } 604214571Sdim 605214571Sdim if (fragp->fr_subtype >= ARRAY_SIZE (md_relax_table)) 606214571Sdim abort (); 607214571Sdim 608214571Sdim return md_relax_table[fragp->fr_subtype].rlx_length; 609214571Sdim} 610214571Sdim 611214571Sdimvoid 612214571Sdimmd_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, fragS *fragP) 613214571Sdim{ 614214571Sdim /* 'opcode' points to the start of the instruction, whether 615214571Sdim we need to change the instruction's fixed encoding. */ 616214571Sdim bfd_reloc_code_real_type reloc = BFD_RELOC_NONE; 617214571Sdim 618214571Sdim subseg_change (sec, 0); 619214571Sdim 620214571Sdim fix_new (fragP, fragP->fr_fix, 621214571Sdim bfd_get_reloc_size (bfd_reloc_type_lookup (stdoutput, reloc)), 622214571Sdim fragP->fr_symbol, fragP->fr_offset, 1, reloc); 623214571Sdim fragP->fr_var = 0; 624214571Sdim fragP->fr_fix += md_relax_table[fragP->fr_subtype].rlx_length; 625214571Sdim} 626214571Sdim 627214571Sdim/* Process machine-dependent command line options. Called once for 628214571Sdim each option on the command line that the machine-independent part of 629214571Sdim GAS does not understand. */ 630214571Sdim 631214571Sdimint 632214571Sdimmd_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED) 633214571Sdim{ 634214571Sdim return 0; 635214571Sdim} 636214571Sdim 637214571Sdim/* Machine-dependent usage-output. */ 638214571Sdim 639214571Sdimvoid 640214571Sdimmd_show_usage (FILE *stream ATTRIBUTE_UNUSED) 641214571Sdim{ 642214571Sdim return; 643214571Sdim} 644214571Sdim 645214571Sdim/* Turn a string in input_line_pointer into a floating point constant 646214571Sdim of type TYPE, and store the appropriate bytes in *LITP. The number 647214571Sdim of LITTLENUMS emitted is stored in *SIZEP. An error message is 648214571Sdim returned, or NULL on OK. */ 649214571Sdim 650214571Sdimchar * 651214571Sdimmd_atof (int type, char *litP, int *sizeP) 652214571Sdim{ 653214571Sdim int prec; 654214571Sdim int i; 655214571Sdim LITTLENUM_TYPE words[4]; 656214571Sdim char *t; 657214571Sdim 658214571Sdim switch (type) 659214571Sdim { 660214571Sdim case 'f': 661214571Sdim prec = 2; 662214571Sdim break; 663214571Sdim 664214571Sdim case 'd': 665214571Sdim prec = 4; 666214571Sdim break; 667214571Sdim 668214571Sdim default: 669214571Sdim *sizeP = 0; 670214571Sdim return _("bad call to md_atof"); 671214571Sdim } 672214571Sdim 673214571Sdim t = atof_ieee (input_line_pointer, type, words); 674214571Sdim if (t) 675214571Sdim input_line_pointer = t; 676214571Sdim 677214571Sdim *sizeP = prec * 2; 678214571Sdim 679214571Sdim if (! target_big_endian) 680214571Sdim { 681214571Sdim for (i = prec - 1; i >= 0; i--) 682214571Sdim { 683214571Sdim md_number_to_chars (litP, (valueT) words[i], 2); 684214571Sdim litP += 2; 685214571Sdim } 686214571Sdim } 687214571Sdim else 688214571Sdim { 689214571Sdim for (i = 0; i < prec; i++) 690214571Sdim { 691214571Sdim md_number_to_chars (litP, (valueT) words[i], 2); 692214571Sdim litP += 2; 693214571Sdim } 694214571Sdim } 695214571Sdim 696214571Sdim return NULL; 697214571Sdim} 698214571Sdim 699214571Sdim/* Apply a fixS (fixup of an instruction or data that we didn't have 700214571Sdim enough info to complete immediately) to the data in a frag. 701214571Sdim Since linkrelax is nonzero and TC_LINKRELAX_FIXUP is defined to disable 702214571Sdim relaxation of debug sections, this function is called only when 703214571Sdim fixuping relocations of debug sections. */ 704214571Sdim 705214571Sdimvoid 706214571Sdimmd_apply_fix (fixS *fixP, valueT *valP, segT seg) 707214571Sdim{ 708214571Sdim valueT val = * valP; 709214571Sdim char *buf = fixP->fx_frag->fr_literal + fixP->fx_where; 710214571Sdim fixP->fx_offset = 0; 711214571Sdim 712214571Sdim switch (fixP->fx_r_type) 713214571Sdim { 714214571Sdim case BFD_RELOC_CR16_NUM8: 715214571Sdim bfd_put_8 (stdoutput, (unsigned char) val, buf); 716214571Sdim break; 717214571Sdim case BFD_RELOC_CR16_NUM16: 718214571Sdim bfd_put_16 (stdoutput, val, buf); 719214571Sdim break; 720214571Sdim case BFD_RELOC_CR16_NUM32: 721214571Sdim bfd_put_32 (stdoutput, val, buf); 722214571Sdim break; 723214571Sdim case BFD_RELOC_CR16_NUM32a: 724214571Sdim bfd_put_32 (stdoutput, val, buf); 725214571Sdim break; 726214571Sdim default: 727214571Sdim /* We shouldn't ever get here because linkrelax is nonzero. */ 728214571Sdim abort (); 729214571Sdim break; 730214571Sdim } 731214571Sdim 732214571Sdim fixP->fx_done = 0; 733214571Sdim 734214571Sdim if (fixP->fx_addsy == NULL 735214571Sdim && fixP->fx_pcrel == 0) 736214571Sdim fixP->fx_done = 1; 737214571Sdim 738214571Sdim if (fixP->fx_pcrel == 1 739214571Sdim && fixP->fx_addsy != NULL 740214571Sdim && S_GET_SEGMENT (fixP->fx_addsy) == seg) 741214571Sdim fixP->fx_done = 1; 742214571Sdim} 743214571Sdim 744214571Sdim/* The location from which a PC relative jump should be calculated, 745214571Sdim given a PC relative reloc. */ 746214571Sdim 747214571Sdimlong 748214571Sdimmd_pcrel_from (fixS *fixp) 749214571Sdim{ 750214571Sdim return fixp->fx_frag->fr_address + fixp->fx_where; 751214571Sdim} 752214571Sdim 753214571Sdimstatic void 754214571Sdiminitialise_reg_hash_table (struct hash_control ** hash_table, 755214571Sdim const reg_entry * register_table, 756214571Sdim const unsigned int num_entries) 757214571Sdim{ 758214571Sdim const reg_entry * reg; 759214571Sdim const char *hashret; 760214571Sdim 761214571Sdim if ((* hash_table = hash_new ()) == NULL) 762214571Sdim as_fatal (_("Virtual memory exhausted")); 763214571Sdim 764214571Sdim for (reg = register_table; 765214571Sdim reg < (register_table + num_entries); 766214571Sdim reg++) 767214571Sdim { 768214571Sdim hashret = hash_insert (* hash_table, reg->name, (char *) reg); 769214571Sdim if (hashret) 770214571Sdim as_fatal (_("Internal Error: Can't hash %s: %s"), 771214571Sdim reg->name, hashret); 772214571Sdim } 773214571Sdim} 774214571Sdim 775214571Sdim/* This function is called once, at assembler startup time. This should 776214571Sdim set up all the tables, etc that the MD part of the assembler needs. */ 777214571Sdim 778214571Sdimvoid 779214571Sdimmd_begin (void) 780214571Sdim{ 781214571Sdim int i = 0; 782214571Sdim 783214571Sdim /* Set up a hash table for the instructions. */ 784214571Sdim if ((cr16_inst_hash = hash_new ()) == NULL) 785214571Sdim as_fatal (_("Virtual memory exhausted")); 786214571Sdim 787214571Sdim while (cr16_instruction[i].mnemonic != NULL) 788214571Sdim { 789214571Sdim const char *hashret; 790214571Sdim const char *mnemonic = cr16_instruction[i].mnemonic; 791214571Sdim 792214571Sdim hashret = hash_insert (cr16_inst_hash, mnemonic, 793214571Sdim (char *)(cr16_instruction + i)); 794214571Sdim 795214571Sdim if (hashret != NULL && *hashret != '\0') 796214571Sdim as_fatal (_("Can't hash `%s': %s\n"), cr16_instruction[i].mnemonic, 797214571Sdim *hashret == 0 ? _("(unknown reason)") : hashret); 798214571Sdim 799214571Sdim /* Insert unique names into hash table. The CR16 instruction set 800214571Sdim has many identical opcode names that have different opcodes based 801214571Sdim on the operands. This hash table then provides a quick index to 802214571Sdim the first opcode with a particular name in the opcode table. */ 803214571Sdim do 804214571Sdim { 805214571Sdim ++i; 806214571Sdim } 807214571Sdim while (cr16_instruction[i].mnemonic != NULL 808214571Sdim && streq (cr16_instruction[i].mnemonic, mnemonic)); 809214571Sdim } 810214571Sdim 811214571Sdim /* Initialize reg_hash hash table. */ 812214571Sdim initialise_reg_hash_table (& reg_hash, cr16_regtab, NUMREGS); 813214571Sdim /* Initialize regp_hash hash table. */ 814214571Sdim initialise_reg_hash_table (& regp_hash, cr16_regptab, NUMREGPS); 815214571Sdim /* Initialize preg_hash hash table. */ 816214571Sdim initialise_reg_hash_table (& preg_hash, cr16_pregtab, NUMPREGS); 817214571Sdim /* Initialize pregp_hash hash table. */ 818214571Sdim initialise_reg_hash_table (& pregp_hash, cr16_pregptab, NUMPREGPS); 819214571Sdim 820214571Sdim /* Set linkrelax here to avoid fixups in most sections. */ 821214571Sdim linkrelax = 1; 822214571Sdim} 823214571Sdim 824214571Sdim/* Process constants (immediate/absolute) 825214571Sdim and labels (jump targets/Memory locations). */ 826214571Sdim 827214571Sdimstatic void 828214571Sdimprocess_label_constant (char *str, ins * cr16_ins) 829214571Sdim{ 830214571Sdim char *saved_input_line_pointer; 831214571Sdim int symbol_with_at = 0; 832214571Sdim int symbol_with_s = 0; 833214571Sdim int symbol_with_m = 0; 834214571Sdim int symbol_with_l = 0; 835214571Sdim argument *cur_arg = cr16_ins->arg + cur_arg_num; /* Current argument. */ 836214571Sdim 837214571Sdim saved_input_line_pointer = input_line_pointer; 838214571Sdim input_line_pointer = str; 839214571Sdim 840214571Sdim expression (&cr16_ins->exp); 841214571Sdim 842214571Sdim switch (cr16_ins->exp.X_op) 843214571Sdim { 844214571Sdim case O_big: 845214571Sdim case O_absent: 846214571Sdim /* Missing or bad expr becomes absolute 0. */ 847214571Sdim as_bad (_("missing or invalid displacement expression `%s' taken as 0"), 848214571Sdim str); 849214571Sdim cr16_ins->exp.X_op = O_constant; 850214571Sdim cr16_ins->exp.X_add_number = 0; 851214571Sdim cr16_ins->exp.X_add_symbol = NULL; 852214571Sdim cr16_ins->exp.X_op_symbol = NULL; 853214571Sdim /* Fall through. */ 854214571Sdim 855214571Sdim case O_constant: 856214571Sdim cur_arg->X_op = O_constant; 857214571Sdim cur_arg->constant = cr16_ins->exp.X_add_number; 858214571Sdim break; 859214571Sdim 860214571Sdim case O_symbol: 861214571Sdim case O_subtract: 862214571Sdim case O_add: 863214571Sdim cur_arg->X_op = O_symbol; 864214571Sdim cr16_ins->rtype = BFD_RELOC_NONE; 865214571Sdim relocatable = 1; 866214571Sdim 867214571Sdim if (strneq (input_line_pointer, "@c", 2)) 868214571Sdim symbol_with_at = 1; 869214571Sdim 870214571Sdim if (strneq (input_line_pointer, "@l", 2) 871214571Sdim || strneq (input_line_pointer, ":l", 2)) 872214571Sdim symbol_with_l = 1; 873214571Sdim 874214571Sdim if (strneq (input_line_pointer, "@m", 2) 875214571Sdim || strneq (input_line_pointer, ":m", 2)) 876214571Sdim symbol_with_m = 1; 877214571Sdim 878214571Sdim if (strneq (input_line_pointer, "@s", 2) 879214571Sdim || strneq (input_line_pointer, ":s", 2)) 880214571Sdim symbol_with_s = 1; 881214571Sdim 882214571Sdim switch (cur_arg->type) 883214571Sdim { 884214571Sdim case arg_cr: 885214571Sdim if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) 886214571Sdim { 887214571Sdim if (cur_arg->size == 20) 888214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; 889214571Sdim else 890214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a; 891214571Sdim } 892214571Sdim break; 893214571Sdim 894214571Sdim case arg_crp: 895214571Sdim if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) 896214571Sdim switch (instruction->size) 897214571Sdim { 898214571Sdim case 1: 899214571Sdim switch (cur_arg->size) 900214571Sdim { 901214571Sdim case 0: 902214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; 903214571Sdim break; 904214571Sdim case 4: 905214571Sdim if (IS_INSN_MNEMONIC ("loadb") || IS_INSN_MNEMONIC ("storb")) 906214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_REGREL4; 907214571Sdim else 908214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_REGREL4a; 909214571Sdim break; 910214571Sdim default: break; 911214571Sdim } 912214571Sdim break; 913214571Sdim case 2: 914214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_REGREL16; 915214571Sdim break; 916214571Sdim case 3: 917214571Sdim if (cur_arg->size == 20) 918214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; 919214571Sdim else 920214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a; 921214571Sdim break; 922214571Sdim default: 923214571Sdim break; 924214571Sdim } 925214571Sdim break; 926214571Sdim 927214571Sdim case arg_idxr: 928214571Sdim if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) 929214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; 930214571Sdim break; 931214571Sdim 932214571Sdim case arg_idxrp: 933214571Sdim if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) 934214571Sdim switch (instruction->size) 935214571Sdim { 936214571Sdim case 1: cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; break; 937214571Sdim case 2: cr16_ins->rtype = BFD_RELOC_CR16_REGREL14; break; 938214571Sdim case 3: cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; break; 939214571Sdim default: break; 940214571Sdim } 941214571Sdim break; 942214571Sdim 943214571Sdim case arg_c: 944214571Sdim if (IS_INSN_MNEMONIC ("bal")) 945214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_DISP24; 946214571Sdim else if (IS_INSN_TYPE (BRANCH_INS)) 947214571Sdim { 948214571Sdim if (symbol_with_s) 949214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_DISP8; 950214571Sdim else if (symbol_with_m) 951214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_DISP16; 952214571Sdim else 953214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_DISP24; 954214571Sdim } 955214571Sdim else if (IS_INSN_TYPE (STOR_IMM_INS) || IS_INSN_TYPE (LD_STOR_INS) 956214571Sdim || IS_INSN_TYPE (CSTBIT_INS)) 957214571Sdim { 958214571Sdim if (symbol_with_s) 959214571Sdim as_bad (_("operand %d: illegal use expression: `%s`"), cur_arg_num + 1, str); 960214571Sdim if (symbol_with_m) 961214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_ABS20; 962214571Sdim else /* Default to (symbol_with_l) */ 963214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_ABS24; 964214571Sdim } 965214571Sdim else if (IS_INSN_TYPE (BRANCH_NEQ_INS)) 966214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_DISP4; 967214571Sdim break; 968214571Sdim 969214571Sdim case arg_ic: 970214571Sdim if (IS_INSN_TYPE (ARITH_INS)) 971214571Sdim { 972214571Sdim if (symbol_with_s) 973214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_IMM4; 974214571Sdim else if (symbol_with_m) 975214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_IMM20; 976214571Sdim else if (symbol_with_at) 977214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_IMM32a; 978214571Sdim else /* Default to (symbol_with_l) */ 979214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_IMM32; 980214571Sdim } 981214571Sdim else if (IS_INSN_TYPE (ARITH_BYTE_INS)) 982214571Sdim { 983214571Sdim cr16_ins->rtype = BFD_RELOC_CR16_IMM16; 984214571Sdim } 985214571Sdim break; 986214571Sdim default: 987214571Sdim break; 988214571Sdim } 989214571Sdim break; 990214571Sdim 991214571Sdim default: 992214571Sdim cur_arg->X_op = cr16_ins->exp.X_op; 993214571Sdim break; 994214571Sdim } 995214571Sdim 996214571Sdim input_line_pointer = saved_input_line_pointer; 997214571Sdim return; 998214571Sdim} 999214571Sdim 1000214571Sdim/* Retrieve the opcode image of a given register. 1001214571Sdim If the register is illegal for the current instruction, 1002214571Sdim issue an error. */ 1003214571Sdim 1004214571Sdimstatic int 1005214571Sdimgetreg_image (reg r) 1006214571Sdim{ 1007214571Sdim const reg_entry *reg; 1008214571Sdim char *reg_name; 1009214571Sdim int is_procreg = 0; /* Nonzero means argument should be processor reg. */ 1010214571Sdim 1011214571Sdim /* Check whether the register is in registers table. */ 1012214571Sdim if (r < MAX_REG) 1013214571Sdim reg = cr16_regtab + r; 1014214571Sdim else /* Register not found. */ 1015214571Sdim { 1016214571Sdim as_bad (_("Unknown register: `%d'"), r); 1017214571Sdim return 0; 1018214571Sdim } 1019214571Sdim 1020214571Sdim reg_name = reg->name; 1021214571Sdim 1022214571Sdim/* Issue a error message when register is illegal. */ 1023214571Sdim#define IMAGE_ERR \ 1024214571Sdim as_bad (_("Illegal register (`%s') in Instruction: `%s'"), \ 1025214571Sdim reg_name, ins_parse); \ 1026214571Sdim break; 1027214571Sdim 1028214571Sdim switch (reg->type) 1029214571Sdim { 1030214571Sdim case CR16_R_REGTYPE: 1031214571Sdim if (! is_procreg) 1032214571Sdim return reg->image; 1033214571Sdim else 1034214571Sdim IMAGE_ERR; 1035214571Sdim 1036214571Sdim case CR16_P_REGTYPE: 1037214571Sdim return reg->image; 1038214571Sdim break; 1039214571Sdim 1040214571Sdim default: 1041214571Sdim IMAGE_ERR; 1042214571Sdim } 1043214571Sdim 1044214571Sdim return 0; 1045214571Sdim} 1046214571Sdim 1047214571Sdim/* Parsing different types of operands 1048214571Sdim -> constants Immediate/Absolute/Relative numbers 1049214571Sdim -> Labels Relocatable symbols 1050214571Sdim -> (reg pair base) Register pair base 1051214571Sdim -> (rbase) Register base 1052214571Sdim -> disp(rbase) Register relative 1053214571Sdim -> [rinx]disp(reg pair) Register index with reg pair mode 1054214571Sdim -> disp(rbase,ridx,scl) Register index mode. */ 1055214571Sdim 1056214571Sdimstatic void 1057214571Sdimset_operand (char *operand, ins * cr16_ins) 1058214571Sdim{ 1059214571Sdim char *operandS; /* Pointer to start of sub-opearand. */ 1060214571Sdim char *operandE; /* Pointer to end of sub-opearand. */ 1061214571Sdim 1062214571Sdim argument *cur_arg = &cr16_ins->arg[cur_arg_num]; /* Current argument. */ 1063214571Sdim 1064214571Sdim /* Initialize pointers. */ 1065214571Sdim operandS = operandE = operand; 1066214571Sdim 1067214571Sdim switch (cur_arg->type) 1068214571Sdim { 1069214571Sdim case arg_ic: /* Case $0x18. */ 1070214571Sdim operandS++; 1071214571Sdim case arg_c: /* Case 0x18. */ 1072214571Sdim /* Set constant. */ 1073214571Sdim process_label_constant (operandS, cr16_ins); 1074214571Sdim 1075214571Sdim if (cur_arg->type != arg_ic) 1076214571Sdim cur_arg->type = arg_c; 1077214571Sdim break; 1078214571Sdim 1079214571Sdim case arg_icr: /* Case $0x18(r1). */ 1080214571Sdim operandS++; 1081214571Sdim case arg_cr: /* Case 0x18(r1). */ 1082214571Sdim /* Set displacement constant. */ 1083214571Sdim while (*operandE != '(') 1084214571Sdim operandE++; 1085214571Sdim *operandE = '\0'; 1086214571Sdim process_label_constant (operandS, cr16_ins); 1087214571Sdim operandS = operandE; 1088214571Sdim case arg_rbase: /* Case (r1) or (r1,r0). */ 1089214571Sdim operandS++; 1090214571Sdim /* Set register base. */ 1091214571Sdim while (*operandE != ')') 1092214571Sdim operandE++; 1093214571Sdim *operandE = '\0'; 1094214571Sdim if ((cur_arg->r = get_register (operandS)) == nullregister) 1095214571Sdim as_bad (_("Illegal register `%s' in Instruction `%s'"), 1096214571Sdim operandS, ins_parse); 1097214571Sdim 1098214571Sdim /* set the arg->rp, if reg is "r12" or "r13" or "14" or "15" */ 1099214571Sdim if ((cur_arg->type != arg_rbase) 1100214571Sdim && ((getreg_image (cur_arg->r) == 12) 1101214571Sdim || (getreg_image (cur_arg->r) == 13) 1102214571Sdim || (getreg_image (cur_arg->r) == 14) 1103214571Sdim || (getreg_image (cur_arg->r) == 15))) 1104214571Sdim { 1105214571Sdim cur_arg->type = arg_crp; 1106214571Sdim cur_arg->rp = cur_arg->r; 1107214571Sdim } 1108214571Sdim break; 1109214571Sdim 1110214571Sdim case arg_crp: /* Case 0x18(r1,r0). */ 1111214571Sdim /* Set displacement constant. */ 1112214571Sdim while (*operandE != '(') 1113214571Sdim operandE++; 1114214571Sdim *operandE = '\0'; 1115214571Sdim process_label_constant (operandS, cr16_ins); 1116214571Sdim operandS = operandE; 1117214571Sdim operandS++; 1118214571Sdim /* Set register pair base. */ 1119214571Sdim while (*operandE != ')') 1120214571Sdim operandE++; 1121214571Sdim *operandE = '\0'; 1122214571Sdim if ((cur_arg->rp = get_register_pair (operandS)) == nullregister) 1123214571Sdim as_bad (_("Illegal register pair `%s' in Instruction `%s'"), 1124214571Sdim operandS, ins_parse); 1125214571Sdim break; 1126214571Sdim 1127214571Sdim case arg_idxr: 1128214571Sdim /* Set register pair base. */ 1129214571Sdim if ((strchr (operandS,'(') != NULL)) 1130214571Sdim { 1131214571Sdim while ((*operandE != '(') && (! ISSPACE (*operandE))) 1132214571Sdim operandE++; 1133214571Sdim if ((cur_arg->rp = get_index_register_pair (operandE)) == nullregister) 1134214571Sdim as_bad (_("Illegal register pair `%s' in Instruction `%s'"), 1135214571Sdim operandS, ins_parse); 1136214571Sdim *operandE++ = '\0'; 1137214571Sdim cur_arg->type = arg_idxrp; 1138214571Sdim } 1139214571Sdim else 1140214571Sdim cur_arg->rp = -1; 1141214571Sdim 1142214571Sdim operandE = operandS; 1143214571Sdim /* Set displacement constant. */ 1144214571Sdim while (*operandE != ']') 1145214571Sdim operandE++; 1146214571Sdim process_label_constant (++operandE, cr16_ins); 1147214571Sdim *operandE++ = '\0'; 1148214571Sdim operandE = operandS; 1149214571Sdim 1150214571Sdim /* Set index register . */ 1151214571Sdim operandS = strchr (operandE,'['); 1152214571Sdim if (operandS != NULL) 1153214571Sdim { /* Eliminate '[', detach from rest of operand. */ 1154214571Sdim *operandS++ = '\0'; 1155214571Sdim 1156214571Sdim operandE = strchr (operandS, ']'); 1157214571Sdim 1158214571Sdim if (operandE == NULL) 1159214571Sdim as_bad (_("unmatched '['")); 1160214571Sdim else 1161214571Sdim { /* Eliminate ']' and make sure it was the last thing 1162214571Sdim in the string. */ 1163214571Sdim *operandE = '\0'; 1164214571Sdim if (*(operandE + 1) != '\0') 1165214571Sdim as_bad (_("garbage after index spec ignored")); 1166214571Sdim } 1167214571Sdim } 1168214571Sdim 1169214571Sdim if ((cur_arg->i_r = get_index_register (operandS)) == nullregister) 1170214571Sdim as_bad (_("Illegal register `%s' in Instruction `%s'"), 1171214571Sdim operandS, ins_parse); 1172214571Sdim *operandE = '\0'; 1173214571Sdim *operandS = '\0'; 1174214571Sdim break; 1175214571Sdim 1176214571Sdim default: 1177214571Sdim break; 1178214571Sdim } 1179214571Sdim} 1180214571Sdim 1181214571Sdim/* Parse a single operand. 1182214571Sdim operand - Current operand to parse. 1183214571Sdim cr16_ins - Current assembled instruction. */ 1184214571Sdim 1185214571Sdimstatic void 1186214571Sdimparse_operand (char *operand, ins * cr16_ins) 1187214571Sdim{ 1188214571Sdim int ret_val; 1189214571Sdim argument *cur_arg = cr16_ins->arg + cur_arg_num; /* Current argument. */ 1190214571Sdim 1191214571Sdim /* Initialize the type to NULL before parsing. */ 1192214571Sdim cur_arg->type = nullargs; 1193214571Sdim 1194214571Sdim /* Check whether this is a condition code . */ 1195214571Sdim if ((IS_INSN_MNEMONIC ("b")) && ((ret_val = get_cc (operand)) != -1)) 1196214571Sdim { 1197214571Sdim cur_arg->type = arg_cc; 1198214571Sdim cur_arg->cc = ret_val; 1199214571Sdim cur_arg->X_op = O_register; 1200214571Sdim return; 1201214571Sdim } 1202214571Sdim 1203214571Sdim /* Check whether this is a general processor register. */ 1204214571Sdim if ((ret_val = get_register (operand)) != nullregister) 1205214571Sdim { 1206214571Sdim cur_arg->type = arg_r; 1207214571Sdim cur_arg->r = ret_val; 1208214571Sdim cur_arg->X_op = 0; 1209214571Sdim return; 1210214571Sdim } 1211214571Sdim 1212214571Sdim /* Check whether this is a general processor register pair. */ 1213214571Sdim if ((operand[0] == '(') 1214214571Sdim && ((ret_val = get_register_pair (operand)) != nullregister)) 1215214571Sdim { 1216214571Sdim cur_arg->type = arg_rp; 1217214571Sdim cur_arg->rp = ret_val; 1218214571Sdim cur_arg->X_op = O_register; 1219214571Sdim return; 1220214571Sdim } 1221214571Sdim 1222214571Sdim /* Check whether the operand is a processor register. 1223214571Sdim For "lprd" and "sprd" instruction, only 32 bit 1224214571Sdim processor registers used. */ 1225214571Sdim if (!(IS_INSN_MNEMONIC ("lprd") || (IS_INSN_MNEMONIC ("sprd"))) 1226214571Sdim && ((ret_val = get_pregister (operand)) != nullpregister)) 1227214571Sdim { 1228214571Sdim cur_arg->type = arg_pr; 1229214571Sdim cur_arg->pr = ret_val; 1230214571Sdim cur_arg->X_op = O_register; 1231214571Sdim return; 1232214571Sdim } 1233214571Sdim 1234214571Sdim /* Check whether this is a processor register - 32 bit. */ 1235214571Sdim if ((ret_val = get_pregisterp (operand)) != nullpregister) 1236214571Sdim { 1237214571Sdim cur_arg->type = arg_prp; 1238214571Sdim cur_arg->prp = ret_val; 1239214571Sdim cur_arg->X_op = O_register; 1240214571Sdim return; 1241214571Sdim } 1242214571Sdim 1243214571Sdim /* Deal with special characters. */ 1244214571Sdim switch (operand[0]) 1245214571Sdim { 1246214571Sdim case '$': 1247214571Sdim if (strchr (operand, '(') != NULL) 1248214571Sdim cur_arg->type = arg_icr; 1249214571Sdim else 1250214571Sdim cur_arg->type = arg_ic; 1251214571Sdim goto set_params; 1252214571Sdim break; 1253214571Sdim 1254214571Sdim case '(': 1255214571Sdim cur_arg->type = arg_rbase; 1256214571Sdim goto set_params; 1257214571Sdim break; 1258214571Sdim 1259214571Sdim case '[': 1260214571Sdim cur_arg->type = arg_idxr; 1261214571Sdim goto set_params; 1262214571Sdim break; 1263214571Sdim 1264214571Sdim default: 1265214571Sdim break; 1266214571Sdim } 1267214571Sdim 1268214571Sdim if (strchr (operand, '(') != NULL) 1269214571Sdim { 1270214571Sdim if (strchr (operand, ',') != NULL 1271214571Sdim && (strchr (operand, ',') > strchr (operand, '('))) 1272214571Sdim cur_arg->type = arg_crp; 1273214571Sdim else 1274214571Sdim cur_arg->type = arg_cr; 1275214571Sdim } 1276214571Sdim else 1277214571Sdim cur_arg->type = arg_c; 1278214571Sdim 1279214571Sdim/* Parse an operand according to its type. */ 1280214571Sdim set_params: 1281214571Sdim cur_arg->constant = 0; 1282214571Sdim set_operand (operand, cr16_ins); 1283214571Sdim} 1284214571Sdim 1285214571Sdim/* Parse the various operands. Each operand is then analyzed to fillup 1286214571Sdim the fields in the cr16_ins data structure. */ 1287214571Sdim 1288214571Sdimstatic void 1289214571Sdimparse_operands (ins * cr16_ins, char *operands) 1290214571Sdim{ 1291214571Sdim char *operandS; /* Operands string. */ 1292214571Sdim char *operandH, *operandT; /* Single operand head/tail pointers. */ 1293214571Sdim int allocated = 0; /* Indicates a new operands string was allocated.*/ 1294214571Sdim char *operand[MAX_OPERANDS];/* Separating the operands. */ 1295214571Sdim int op_num = 0; /* Current operand number we are parsing. */ 1296214571Sdim int bracket_flag = 0; /* Indicates a bracket '(' was found. */ 1297214571Sdim int sq_bracket_flag = 0; /* Indicates a square bracket '[' was found. */ 1298214571Sdim 1299214571Sdim /* Preprocess the list of registers, if necessary. */ 1300214571Sdim operandS = operandH = operandT = operands; 1301214571Sdim 1302214571Sdim while (*operandT != '\0') 1303214571Sdim { 1304214571Sdim if (*operandT == ',' && bracket_flag != 1 && sq_bracket_flag != 1) 1305214571Sdim { 1306214571Sdim *operandT++ = '\0'; 1307214571Sdim operand[op_num++] = strdup (operandH); 1308214571Sdim operandH = operandT; 1309214571Sdim continue; 1310214571Sdim } 1311214571Sdim 1312214571Sdim if (*operandT == ' ') 1313214571Sdim as_bad (_("Illegal operands (whitespace): `%s'"), ins_parse); 1314214571Sdim 1315214571Sdim if (*operandT == '(') 1316214571Sdim bracket_flag = 1; 1317214571Sdim else if (*operandT == '[') 1318214571Sdim sq_bracket_flag = 1; 1319214571Sdim 1320214571Sdim if (*operandT == ')') 1321214571Sdim { 1322214571Sdim if (bracket_flag) 1323214571Sdim bracket_flag = 0; 1324214571Sdim else 1325214571Sdim as_fatal (_("Missing matching brackets : `%s'"), ins_parse); 1326214571Sdim } 1327214571Sdim else if (*operandT == ']') 1328214571Sdim { 1329214571Sdim if (sq_bracket_flag) 1330214571Sdim sq_bracket_flag = 0; 1331214571Sdim else 1332214571Sdim as_fatal (_("Missing matching brackets : `%s'"), ins_parse); 1333214571Sdim } 1334214571Sdim 1335214571Sdim if (bracket_flag == 1 && *operandT == ')') 1336214571Sdim bracket_flag = 0; 1337214571Sdim else if (sq_bracket_flag == 1 && *operandT == ']') 1338214571Sdim sq_bracket_flag = 0; 1339214571Sdim 1340214571Sdim operandT++; 1341214571Sdim } 1342214571Sdim 1343214571Sdim /* Adding the last operand. */ 1344214571Sdim operand[op_num++] = strdup (operandH); 1345214571Sdim cr16_ins->nargs = op_num; 1346214571Sdim 1347214571Sdim /* Verifying correct syntax of operands (all brackets should be closed). */ 1348214571Sdim if (bracket_flag || sq_bracket_flag) 1349214571Sdim as_fatal (_("Missing matching brackets : `%s'"), ins_parse); 1350214571Sdim 1351214571Sdim /* Now we parse each operand separately. */ 1352214571Sdim for (op_num = 0; op_num < cr16_ins->nargs; op_num++) 1353214571Sdim { 1354214571Sdim cur_arg_num = op_num; 1355214571Sdim parse_operand (operand[op_num], cr16_ins); 1356214571Sdim free (operand[op_num]); 1357214571Sdim } 1358214571Sdim 1359214571Sdim if (allocated) 1360214571Sdim free (operandS); 1361214571Sdim} 1362214571Sdim 1363214571Sdim/* Get the trap index in dispatch table, given its name. 1364214571Sdim This routine is used by assembling the 'excp' instruction. */ 1365214571Sdim 1366214571Sdimstatic int 1367214571Sdimgettrap (char *s) 1368214571Sdim{ 1369214571Sdim const trap_entry *trap; 1370214571Sdim 1371214571Sdim for (trap = cr16_traps; trap < (cr16_traps + NUMTRAPS); trap++) 1372214571Sdim if (strcasecmp (trap->name, s) == 0) 1373214571Sdim return trap->entry; 1374214571Sdim 1375214571Sdim /* To make compatable with CR16 4.1 tools, the below 3-lines of 1376214571Sdim * code added. Refer: Development Tracker item #123 */ 1377214571Sdim for (trap = cr16_traps; trap < (cr16_traps + NUMTRAPS); trap++) 1378214571Sdim if (trap->entry == (unsigned int) atoi (s)) 1379214571Sdim return trap->entry; 1380214571Sdim 1381214571Sdim as_bad (_("Unknown exception: `%s'"), s); 1382214571Sdim return 0; 1383214571Sdim} 1384214571Sdim 1385214571Sdim/* Top level module where instruction parsing starts. 1386214571Sdim cr16_ins - data structure holds some information. 1387214571Sdim operands - holds the operands part of the whole instruction. */ 1388214571Sdim 1389214571Sdimstatic void 1390214571Sdimparse_insn (ins *insn, char *operands) 1391214571Sdim{ 1392214571Sdim int i; 1393214571Sdim 1394214571Sdim /* Handle instructions with no operands. */ 1395214571Sdim for (i = 0; cr16_no_op_insn[i] != NULL; i++) 1396214571Sdim { 1397214571Sdim if (streq (cr16_no_op_insn[i], instruction->mnemonic)) 1398214571Sdim { 1399214571Sdim insn->nargs = 0; 1400214571Sdim return; 1401214571Sdim } 1402214571Sdim } 1403214571Sdim 1404214571Sdim /* Handle 'excp' instructions. */ 1405214571Sdim if (IS_INSN_MNEMONIC ("excp")) 1406214571Sdim { 1407214571Sdim insn->nargs = 1; 1408214571Sdim insn->arg[0].type = arg_ic; 1409214571Sdim insn->arg[0].constant = gettrap (operands); 1410214571Sdim insn->arg[0].X_op = O_constant; 1411214571Sdim return; 1412214571Sdim } 1413214571Sdim 1414214571Sdim if (operands != NULL) 1415214571Sdim parse_operands (insn, operands); 1416214571Sdim} 1417214571Sdim 1418214571Sdim/* bCC instruction requires special handling. */ 1419214571Sdimstatic char * 1420214571Sdimget_b_cc (char * op) 1421214571Sdim{ 1422214571Sdim unsigned int i; 1423214571Sdim char op1[5]; 1424214571Sdim 1425214571Sdim for (i = 1; i < strlen (op); i++) 1426214571Sdim op1[i-1] = op[i]; 1427214571Sdim 1428214571Sdim op1[i-1] = '\0'; 1429214571Sdim 1430214571Sdim for (i = 0; i < cr16_num_cc ; i++) 1431214571Sdim if (streq (op1, cr16_b_cond_tab[i])) 1432214571Sdim return (char *) cr16_b_cond_tab[i]; 1433214571Sdim 1434214571Sdim return NULL; 1435214571Sdim} 1436214571Sdim 1437214571Sdim/* bCC instruction requires special handling. */ 1438214571Sdimstatic int 1439214571Sdimis_bcc_insn (char * op) 1440214571Sdim{ 1441214571Sdim if (!(streq (op, "bal") || streq (op, "beq0b") || streq (op, "bnq0b") 1442214571Sdim || streq (op, "beq0w") || streq (op, "bnq0w"))) 1443214571Sdim if ((op[0] == 'b') && (get_b_cc (op) != NULL)) 1444214571Sdim return 1; 1445214571Sdim return 0; 1446214571Sdim} 1447214571Sdim 1448214571Sdim/* Cinv instruction requires special handling. */ 1449214571Sdim 1450214571Sdimstatic int 1451214571Sdimcheck_cinv_options (char * operand) 1452214571Sdim{ 1453214571Sdim char *p = operand; 1454214571Sdim int i_used = 0, u_used = 0, d_used = 0; 1455214571Sdim 1456214571Sdim while (*++p != ']') 1457214571Sdim { 1458214571Sdim if (*p == ',' || *p == ' ') 1459214571Sdim continue; 1460214571Sdim 1461214571Sdim else if (*p == 'i') 1462214571Sdim i_used = 1; 1463214571Sdim else if (*p == 'u') 1464214571Sdim u_used = 1; 1465214571Sdim else if (*p == 'd') 1466214571Sdim d_used = 1; 1467214571Sdim else 1468214571Sdim as_bad (_("Illegal `cinv' parameter: `%c'"), *p); 1469214571Sdim } 1470214571Sdim 1471214571Sdim return 0; 1472214571Sdim} 1473214571Sdim 1474214571Sdim/* Retrieve the opcode image of a given register pair. 1475214571Sdim If the register is illegal for the current instruction, 1476214571Sdim issue an error. */ 1477214571Sdim 1478214571Sdimstatic int 1479214571Sdimgetregp_image (reg r) 1480214571Sdim{ 1481214571Sdim const reg_entry *reg; 1482214571Sdim char *reg_name; 1483214571Sdim 1484214571Sdim /* Check whether the register is in registers table. */ 1485214571Sdim if (r < MAX_REG) 1486214571Sdim reg = cr16_regptab + r; 1487214571Sdim /* Register not found. */ 1488214571Sdim else 1489214571Sdim { 1490214571Sdim as_bad (_("Unknown register pair: `%d'"), r); 1491214571Sdim return 0; 1492214571Sdim } 1493214571Sdim 1494214571Sdim reg_name = reg->name; 1495214571Sdim 1496214571Sdim/* Issue a error message when register pair is illegal. */ 1497214571Sdim#define RPAIR_IMAGE_ERR \ 1498214571Sdim as_bad (_("Illegal register pair (`%s') in Instruction: `%s'"), \ 1499214571Sdim reg_name, ins_parse); \ 1500214571Sdim break; 1501214571Sdim 1502214571Sdim switch (reg->type) 1503214571Sdim { 1504214571Sdim case CR16_RP_REGTYPE: 1505214571Sdim return reg->image; 1506214571Sdim default: 1507214571Sdim RPAIR_IMAGE_ERR; 1508214571Sdim } 1509214571Sdim 1510214571Sdim return 0; 1511214571Sdim} 1512214571Sdim 1513214571Sdim/* Retrieve the opcode image of a given index register pair. 1514214571Sdim If the register is illegal for the current instruction, 1515214571Sdim issue an error. */ 1516214571Sdim 1517214571Sdimstatic int 1518214571Sdimgetidxregp_image (reg r) 1519214571Sdim{ 1520214571Sdim const reg_entry *reg; 1521214571Sdim char *reg_name; 1522214571Sdim 1523214571Sdim /* Check whether the register is in registers table. */ 1524214571Sdim if (r < MAX_REG) 1525214571Sdim reg = cr16_regptab + r; 1526214571Sdim /* Register not found. */ 1527214571Sdim else 1528214571Sdim { 1529214571Sdim as_bad (_("Unknown register pair: `%d'"), r); 1530214571Sdim return 0; 1531214571Sdim } 1532214571Sdim 1533214571Sdim reg_name = reg->name; 1534214571Sdim 1535214571Sdim/* Issue a error message when register pair is illegal. */ 1536214571Sdim#define IDX_RPAIR_IMAGE_ERR \ 1537214571Sdim as_bad (_("Illegal index register pair (`%s') in Instruction: `%s'"), \ 1538214571Sdim reg_name, ins_parse); \ 1539214571Sdim 1540214571Sdim if (reg->type == CR16_RP_REGTYPE) 1541214571Sdim { 1542214571Sdim switch (reg->image) 1543214571Sdim { 1544214571Sdim case 0: return 0; break; 1545214571Sdim case 2: return 1; break; 1546214571Sdim case 4: return 2; break; 1547214571Sdim case 6: return 3; break; 1548214571Sdim case 8: return 4; break; 1549214571Sdim case 10: return 5; break; 1550214571Sdim case 3: return 6; break; 1551214571Sdim case 5: return 7; break; 1552214571Sdim default: 1553214571Sdim break; 1554214571Sdim } 1555214571Sdim } 1556214571Sdim 1557214571Sdim IDX_RPAIR_IMAGE_ERR; 1558214571Sdim return 0; 1559214571Sdim} 1560214571Sdim 1561214571Sdim/* Retrieve the opcode image of a given processort register. 1562214571Sdim If the register is illegal for the current instruction, 1563214571Sdim issue an error. */ 1564214571Sdimstatic int 1565214571Sdimgetprocreg_image (reg r) 1566214571Sdim{ 1567214571Sdim const reg_entry *reg; 1568214571Sdim char *reg_name; 1569214571Sdim 1570214571Sdim /* Check whether the register is in registers table. */ 1571214571Sdim if (r < MAX_PREG) 1572214571Sdim reg = &cr16_pregtab[r - MAX_REG]; 1573214571Sdim /* Register not found. */ 1574214571Sdim else 1575214571Sdim { 1576214571Sdim as_bad (_("Unknown processor register : `%d'"), r); 1577214571Sdim return 0; 1578214571Sdim } 1579214571Sdim 1580214571Sdim reg_name = reg->name; 1581214571Sdim 1582214571Sdim/* Issue a error message when register pair is illegal. */ 1583214571Sdim#define PROCREG_IMAGE_ERR \ 1584214571Sdim as_bad (_("Illegal processor register (`%s') in Instruction: `%s'"), \ 1585214571Sdim reg_name, ins_parse); \ 1586214571Sdim break; 1587214571Sdim 1588214571Sdim switch (reg->type) 1589214571Sdim { 1590214571Sdim case CR16_P_REGTYPE: 1591214571Sdim return reg->image; 1592214571Sdim default: 1593214571Sdim PROCREG_IMAGE_ERR; 1594214571Sdim } 1595214571Sdim 1596214571Sdim return 0; 1597214571Sdim} 1598214571Sdim 1599214571Sdim/* Retrieve the opcode image of a given processort register. 1600214571Sdim If the register is illegal for the current instruction, 1601214571Sdim issue an error. */ 1602214571Sdimstatic int 1603214571Sdimgetprocregp_image (reg r) 1604214571Sdim{ 1605214571Sdim const reg_entry *reg; 1606214571Sdim char *reg_name; 1607214571Sdim int pregptab_disp = 0; 1608214571Sdim 1609214571Sdim /* Check whether the register is in registers table. */ 1610214571Sdim if (r < MAX_PREG) 1611214571Sdim { 1612214571Sdim r = r - MAX_REG; 1613214571Sdim switch (r) 1614214571Sdim { 1615214571Sdim case 4: pregptab_disp = 1; break; 1616214571Sdim case 6: pregptab_disp = 2; break; 1617214571Sdim case 8: 1618214571Sdim case 9: 1619214571Sdim case 10: 1620214571Sdim pregptab_disp = 3; break; 1621214571Sdim case 12: 1622214571Sdim pregptab_disp = 4; break; 1623214571Sdim case 14: 1624214571Sdim pregptab_disp = 5; break; 1625214571Sdim default: break; 1626214571Sdim } 1627214571Sdim reg = &cr16_pregptab[r - pregptab_disp]; 1628214571Sdim } 1629214571Sdim /* Register not found. */ 1630214571Sdim else 1631214571Sdim { 1632214571Sdim as_bad (_("Unknown processor register (32 bit) : `%d'"), r); 1633214571Sdim return 0; 1634214571Sdim } 1635214571Sdim 1636214571Sdim reg_name = reg->name; 1637214571Sdim 1638214571Sdim/* Issue a error message when register pair is illegal. */ 1639214571Sdim#define PROCREGP_IMAGE_ERR \ 1640214571Sdim as_bad (_("Illegal 32 bit - processor register (`%s') in Instruction: `%s'"),\ 1641214571Sdim reg_name, ins_parse); \ 1642214571Sdim break; 1643214571Sdim 1644214571Sdim switch (reg->type) 1645214571Sdim { 1646214571Sdim case CR16_P_REGTYPE: 1647214571Sdim return reg->image; 1648214571Sdim default: 1649214571Sdim PROCREGP_IMAGE_ERR; 1650214571Sdim } 1651214571Sdim 1652214571Sdim return 0; 1653214571Sdim} 1654214571Sdim 1655214571Sdim/* Routine used to represent integer X using NBITS bits. */ 1656214571Sdim 1657214571Sdimstatic long 1658214571Sdimgetconstant (long x, int nbits) 1659214571Sdim{ 1660214571Sdim /* The following expression avoids overflow if 1661214571Sdim 'nbits' is the number of bits in 'bfd_vma'. */ 1662214571Sdim return (x & ((((1 << (nbits - 1)) - 1) << 1) | 1)); 1663214571Sdim} 1664214571Sdim 1665214571Sdim/* Print a constant value to 'output_opcode': 1666214571Sdim ARG holds the operand's type and value. 1667214571Sdim SHIFT represents the location of the operand to be print into. 1668214571Sdim NBITS determines the size (in bits) of the constant. */ 1669214571Sdim 1670214571Sdimstatic void 1671214571Sdimprint_constant (int nbits, int shift, argument *arg) 1672214571Sdim{ 1673214571Sdim unsigned long mask = 0; 1674214571Sdim 1675214571Sdim long constant = getconstant (arg->constant, nbits); 1676214571Sdim 1677214571Sdim switch (nbits) 1678214571Sdim { 1679214571Sdim case 32: 1680214571Sdim case 28: 1681214571Sdim /* mask the upper part of the constant, that is, the bits 1682214571Sdim going to the lowest byte of output_opcode[0]. 1683214571Sdim The upper part of output_opcode[1] is always filled, 1684214571Sdim therefore it is always masked with 0xFFFF. */ 1685214571Sdim mask = (1 << (nbits - 16)) - 1; 1686214571Sdim /* Divide the constant between two consecutive words : 1687214571Sdim 0 1 2 3 1688214571Sdim +---------+---------+---------+---------+ 1689214571Sdim | | X X X X | x X x X | | 1690214571Sdim +---------+---------+---------+---------+ 1691214571Sdim output_opcode[0] output_opcode[1] */ 1692214571Sdim 1693214571Sdim CR16_PRINT (0, (constant >> WORD_SHIFT) & mask, 0); 1694214571Sdim CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); 1695214571Sdim break; 1696214571Sdim 1697214571Sdim case 21: 1698214571Sdim if ((nbits == 21) && (IS_INSN_TYPE (LD_STOR_INS))) nbits = 20; 1699214571Sdim case 24: 1700214571Sdim case 22: 1701214571Sdim case 20: 1702214571Sdim /* mask the upper part of the constant, that is, the bits 1703214571Sdim going to the lowest byte of output_opcode[0]. 1704214571Sdim The upper part of output_opcode[1] is always filled, 1705214571Sdim therefore it is always masked with 0xFFFF. */ 1706214571Sdim mask = (1 << (nbits - 16)) - 1; 1707214571Sdim /* Divide the constant between two consecutive words : 1708214571Sdim 0 1 2 3 1709214571Sdim +---------+---------+---------+---------+ 1710214571Sdim | | X X X X | - X - X | | 1711214571Sdim +---------+---------+---------+---------+ 1712214571Sdim output_opcode[0] output_opcode[1] */ 1713214571Sdim 1714214571Sdim if ((instruction->size > 2) && (shift == WORD_SHIFT)) 1715214571Sdim { 1716214571Sdim if (arg->type == arg_idxrp) 1717214571Sdim { 1718214571Sdim CR16_PRINT (0, ((constant >> WORD_SHIFT) & mask) << 8, 0); 1719214571Sdim CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); 1720214571Sdim } 1721214571Sdim else 1722214571Sdim { 1723214571Sdim CR16_PRINT (0, (((((constant >> WORD_SHIFT) & mask) << 8) & 0x0f00) | ((((constant >> WORD_SHIFT) & mask) >> 4) & 0xf)),0); 1724214571Sdim CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); 1725214571Sdim } 1726214571Sdim } 1727214571Sdim else 1728214571Sdim CR16_PRINT (0, constant, shift); 1729214571Sdim break; 1730214571Sdim 1731214571Sdim case 14: 1732214571Sdim if (arg->type == arg_idxrp) 1733214571Sdim { 1734214571Sdim if (instruction->size == 2) 1735214571Sdim { 1736214571Sdim CR16_PRINT (0, ((constant)&0xf), shift); // 0-3 bits 1737214571Sdim CR16_PRINT (0, ((constant>>4)&0x3), (shift+20)); // 4-5 bits 1738214571Sdim CR16_PRINT (0, ((constant>>6)&0x3), (shift+14)); // 6-7 bits 1739214571Sdim CR16_PRINT (0, ((constant>>8)&0x3f), (shift+8)); // 8-13 bits 1740214571Sdim } 1741214571Sdim else 1742214571Sdim CR16_PRINT (0, constant, shift); 1743214571Sdim } 1744214571Sdim break; 1745214571Sdim 1746214571Sdim case 16: 1747214571Sdim case 12: 1748214571Sdim /* When instruction size is 3 and 'shift' is 16, a 16-bit constant is 1749214571Sdim always filling the upper part of output_opcode[1]. If we mistakenly 1750214571Sdim write it to output_opcode[0], the constant prefix (that is, 'match') 1751214571Sdim will be overriden. 1752214571Sdim 0 1 2 3 1753214571Sdim +---------+---------+---------+---------+ 1754214571Sdim | 'match' | | X X X X | | 1755214571Sdim +---------+---------+---------+---------+ 1756214571Sdim output_opcode[0] output_opcode[1] */ 1757214571Sdim 1758214571Sdim if ((instruction->size > 2) && (shift == WORD_SHIFT)) 1759214571Sdim CR16_PRINT (1, constant, WORD_SHIFT); 1760214571Sdim else 1761214571Sdim CR16_PRINT (0, constant, shift); 1762214571Sdim break; 1763214571Sdim 1764214571Sdim case 8: 1765214571Sdim CR16_PRINT (0, ((constant/2)&0xf), shift); 1766214571Sdim CR16_PRINT (0, ((constant/2)>>4), (shift+8)); 1767214571Sdim break; 1768214571Sdim 1769214571Sdim default: 1770214571Sdim CR16_PRINT (0, constant, shift); 1771214571Sdim break; 1772214571Sdim } 1773214571Sdim} 1774214571Sdim 1775214571Sdim/* Print an operand to 'output_opcode', which later on will be 1776214571Sdim printed to the object file: 1777214571Sdim ARG holds the operand's type, size and value. 1778214571Sdim SHIFT represents the printing location of operand. 1779214571Sdim NBITS determines the size (in bits) of a constant operand. */ 1780214571Sdim 1781214571Sdimstatic void 1782214571Sdimprint_operand (int nbits, int shift, argument *arg) 1783214571Sdim{ 1784214571Sdim switch (arg->type) 1785214571Sdim { 1786214571Sdim case arg_cc: 1787214571Sdim CR16_PRINT (0, arg->cc, shift); 1788214571Sdim break; 1789214571Sdim 1790214571Sdim case arg_r: 1791214571Sdim CR16_PRINT (0, getreg_image (arg->r), shift); 1792214571Sdim break; 1793214571Sdim 1794214571Sdim case arg_rp: 1795214571Sdim CR16_PRINT (0, getregp_image (arg->rp), shift); 1796214571Sdim break; 1797214571Sdim 1798214571Sdim case arg_pr: 1799214571Sdim CR16_PRINT (0, getprocreg_image (arg->pr), shift); 1800214571Sdim break; 1801214571Sdim 1802214571Sdim case arg_prp: 1803214571Sdim CR16_PRINT (0, getprocregp_image (arg->prp), shift); 1804214571Sdim break; 1805214571Sdim 1806214571Sdim case arg_idxrp: 1807214571Sdim /* 16 12 8 6 0 1808214571Sdim +-----------------------------+ 1809214571Sdim | r_index | disp | rp_base | 1810214571Sdim +-----------------------------+ */ 1811214571Sdim 1812214571Sdim if (instruction->size == 3) 1813214571Sdim { 1814214571Sdim CR16_PRINT (0, getidxregp_image (arg->rp), 0); 1815214571Sdim if (getreg_image (arg->i_r) == 12) 1816214571Sdim CR16_PRINT (0, 0, 3); 1817214571Sdim else 1818214571Sdim CR16_PRINT (0, 1, 3); 1819214571Sdim } 1820214571Sdim else 1821214571Sdim { 1822214571Sdim CR16_PRINT (0, getidxregp_image (arg->rp), 16); 1823214571Sdim if (getreg_image (arg->i_r) == 12) 1824214571Sdim CR16_PRINT (0, 0, 19); 1825214571Sdim else 1826214571Sdim CR16_PRINT (0, 1, 19); 1827214571Sdim } 1828214571Sdim print_constant (nbits, shift, arg); 1829214571Sdim break; 1830214571Sdim 1831214571Sdim case arg_idxr: 1832214571Sdim if (getreg_image (arg->i_r) == 12) 1833214571Sdim if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb") 1834214571Sdim || IS_INSN_MNEMONIC ("tbitb")) 1835214571Sdim CR16_PRINT (0, 0, 23); 1836214571Sdim else CR16_PRINT (0, 0, 24); 1837214571Sdim else 1838214571Sdim if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb") 1839214571Sdim || IS_INSN_MNEMONIC ("tbitb")) 1840214571Sdim CR16_PRINT (0, 1, 23); 1841214571Sdim else CR16_PRINT (0, 1, 24); 1842214571Sdim 1843214571Sdim print_constant (nbits, shift, arg); 1844214571Sdim break; 1845214571Sdim 1846214571Sdim case arg_ic: 1847214571Sdim case arg_c: 1848214571Sdim print_constant (nbits, shift, arg); 1849214571Sdim break; 1850214571Sdim 1851214571Sdim case arg_rbase: 1852214571Sdim CR16_PRINT (0, getreg_image (arg->r), shift); 1853214571Sdim break; 1854214571Sdim 1855214571Sdim case arg_cr: 1856214571Sdim print_constant (nbits, shift , arg); 1857214571Sdim /* Add the register argument to the output_opcode. */ 1858214571Sdim CR16_PRINT (0, getreg_image (arg->r), (shift+16)); 1859214571Sdim break; 1860214571Sdim 1861214571Sdim case arg_crp: 1862214571Sdim print_constant (nbits, shift , arg); 1863214571Sdim if (instruction->size > 1) 1864214571Sdim CR16_PRINT (0, getregp_image (arg->rp), (shift + 16)); 1865214571Sdim else if (IS_INSN_TYPE (LD_STOR_INS) || (IS_INSN_TYPE (CSTBIT_INS))) 1866214571Sdim { 1867214571Sdim if (instruction->size == 2) 1868214571Sdim CR16_PRINT (0, getregp_image (arg->rp), (shift - 8)); 1869214571Sdim else if (instruction->size == 1) 1870214571Sdim CR16_PRINT (0, getregp_image (arg->rp), 16); 1871214571Sdim } 1872214571Sdim else 1873214571Sdim CR16_PRINT (0, getregp_image (arg->rp), shift); 1874214571Sdim break; 1875214571Sdim 1876214571Sdim default: 1877214571Sdim break; 1878214571Sdim } 1879214571Sdim} 1880214571Sdim 1881214571Sdim/* Retrieve the number of operands for the current assembled instruction. */ 1882214571Sdim 1883214571Sdimstatic int 1884214571Sdimget_number_of_operands (void) 1885214571Sdim{ 1886214571Sdim int i; 1887214571Sdim 1888214571Sdim for (i = 0; instruction->operands[i].op_type && i < MAX_OPERANDS; i++) 1889214571Sdim ; 1890214571Sdim return i; 1891214571Sdim} 1892214571Sdim 1893214571Sdim/* Verify that the number NUM can be represented in BITS bits (that is, 1894214571Sdim within its permitted range), based on the instruction's FLAGS. 1895214571Sdim If UPDATE is nonzero, update the value of NUM if necessary. 1896214571Sdim Return OP_LEGAL upon success, actual error type upon failure. */ 1897214571Sdim 1898214571Sdimstatic op_err 1899214571Sdimcheck_range (long *num, int bits, int unsigned flags, int update) 1900214571Sdim{ 1901214571Sdim long min, max; 1902214571Sdim int retval = OP_LEGAL; 1903214571Sdim long value = *num; 1904214571Sdim 1905214571Sdim if (bits == 0 && value > 0) return OP_OUT_OF_RANGE; 1906214571Sdim 1907214571Sdim /* For hosts witah longs bigger than 32-bits make sure that the top 1908214571Sdim bits of a 32-bit negative value read in by the parser are set, 1909214571Sdim so that the correct comparisons are made. */ 1910214571Sdim if (value & 0x80000000) 1911214571Sdim value |= (-1L << 31); 1912214571Sdim 1913214571Sdim 1914214571Sdim /* Verify operand value is even. */ 1915214571Sdim if (flags & OP_EVEN) 1916214571Sdim { 1917214571Sdim if (value % 2) 1918214571Sdim return OP_NOT_EVEN; 1919214571Sdim } 1920214571Sdim 1921214571Sdim if (flags & OP_DEC) 1922214571Sdim { 1923214571Sdim value -= 1; 1924214571Sdim if (update) 1925214571Sdim *num = value; 1926214571Sdim } 1927214571Sdim 1928214571Sdim if (flags & OP_SHIFT) 1929214571Sdim { 1930214571Sdim value >>= 1; 1931214571Sdim if (update) 1932214571Sdim *num = value; 1933214571Sdim } 1934214571Sdim else if (flags & OP_SHIFT_DEC) 1935214571Sdim { 1936214571Sdim value = (value >> 1) - 1; 1937214571Sdim if (update) 1938214571Sdim *num = value; 1939214571Sdim } 1940214571Sdim 1941214571Sdim if (flags & OP_ABS20) 1942214571Sdim { 1943214571Sdim if (value > 0xEFFFF) 1944214571Sdim return OP_OUT_OF_RANGE; 1945214571Sdim } 1946214571Sdim 1947214571Sdim if (flags & OP_ESC) 1948214571Sdim { 1949214571Sdim if (value == 0xB || value == 0x9) 1950214571Sdim return OP_OUT_OF_RANGE; 1951214571Sdim else if (value == -1) 1952214571Sdim { 1953214571Sdim if (update) 1954214571Sdim *num = 9; 1955214571Sdim return retval; 1956214571Sdim } 1957214571Sdim } 1958214571Sdim 1959214571Sdim if (flags & OP_ESC1) 1960214571Sdim { 1961214571Sdim if (value > 13) 1962214571Sdim return OP_OUT_OF_RANGE; 1963214571Sdim } 1964214571Sdim 1965214571Sdim if (flags & OP_SIGNED) 1966214571Sdim { 1967214571Sdim max = (1 << (bits - 1)) - 1; 1968214571Sdim min = - (1 << (bits - 1)); 1969214571Sdim if ((value > max) || (value < min)) 1970214571Sdim retval = OP_OUT_OF_RANGE; 1971214571Sdim } 1972214571Sdim else if (flags & OP_UNSIGNED) 1973214571Sdim { 1974214571Sdim max = ((((1 << (bits - 1)) - 1) << 1) | 1); 1975214571Sdim min = 0; 1976214571Sdim if (((unsigned long) value > (unsigned long) max) 1977214571Sdim || ((unsigned long) value < (unsigned long) min)) 1978214571Sdim retval = OP_OUT_OF_RANGE; 1979214571Sdim } 1980214571Sdim else if (flags & OP_NEG) 1981214571Sdim { 1982214571Sdim max = - 1; 1983214571Sdim min = - ((1 << (bits - 1))-1); 1984214571Sdim if ((value > max) || (value < min)) 1985214571Sdim retval = OP_OUT_OF_RANGE; 1986214571Sdim } 1987214571Sdim return retval; 1988214571Sdim} 1989214571Sdim 1990214571Sdim/* Bunch of error checkings. 1991214571Sdim The checks are made after a matching instruction was found. */ 1992214571Sdim 1993214571Sdimstatic void 1994214571Sdimwarn_if_needed (ins *insn) 1995214571Sdim{ 1996214571Sdim /* If the post-increment address mode is used and the load/store 1997214571Sdim source register is the same as rbase, the result of the 1998214571Sdim instruction is undefined. */ 1999214571Sdim if (IS_INSN_TYPE (LD_STOR_INS_INC)) 2000214571Sdim { 2001214571Sdim /* Enough to verify that one of the arguments is a simple reg. */ 2002214571Sdim if ((insn->arg[0].type == arg_r) || (insn->arg[1].type == arg_r)) 2003214571Sdim if (insn->arg[0].r == insn->arg[1].r) 2004214571Sdim as_bad (_("Same src/dest register is used (`r%d'), result is undefined"), insn->arg[0].r); 2005214571Sdim } 2006214571Sdim 2007214571Sdim if (IS_INSN_MNEMONIC ("pop") 2008214571Sdim || IS_INSN_MNEMONIC ("push") 2009214571Sdim || IS_INSN_MNEMONIC ("popret")) 2010214571Sdim { 2011214571Sdim unsigned int count = insn->arg[0].constant, reg_val; 2012214571Sdim 2013214571Sdim /* Check if count operand caused to save/retrive the RA twice 2014214571Sdim to generate warning message. */ 2015214571Sdim if (insn->nargs > 2) 2016214571Sdim { 2017214571Sdim reg_val = getreg_image (insn->arg[1].r); 2018214571Sdim 2019214571Sdim if ( ((reg_val == 9) && (count > 7)) 2020214571Sdim || ((reg_val == 10) && (count > 6)) 2021214571Sdim || ((reg_val == 11) && (count > 5)) 2022214571Sdim || ((reg_val == 12) && (count > 4)) 2023214571Sdim || ((reg_val == 13) && (count > 2)) 2024214571Sdim || ((reg_val == 14) && (count > 0))) 2025214571Sdim as_warn (_("RA register is saved twice.")); 2026214571Sdim 2027214571Sdim /* Check if the third operand is "RA" or "ra" */ 2028214571Sdim if (!(((insn->arg[2].r) == ra) || ((insn->arg[2].r) == RA))) 2029214571Sdim as_bad (_("`%s' Illegal use of registers."), ins_parse); 2030214571Sdim } 2031214571Sdim 2032214571Sdim if (insn->nargs > 1) 2033214571Sdim { 2034214571Sdim reg_val = getreg_image (insn->arg[1].r); 2035214571Sdim 2036214571Sdim /* If register is a register pair ie r12/r13/r14 in operand1, then 2037214571Sdim the count constant should be validated. */ 2038214571Sdim if (((reg_val == 11) && (count > 7)) 2039214571Sdim || ((reg_val == 12) && (count > 6)) 2040214571Sdim || ((reg_val == 13) && (count > 4)) 2041214571Sdim || ((reg_val == 14) && (count > 2)) 2042214571Sdim || ((reg_val == 15) && (count > 0))) 2043214571Sdim as_bad (_("`%s' Illegal count-register combination."), ins_parse); 2044214571Sdim } 2045214571Sdim else 2046214571Sdim { 2047214571Sdim /* Check if the operand is "RA" or "ra" */ 2048214571Sdim if (!(((insn->arg[0].r) == ra) || ((insn->arg[0].r) == RA))) 2049214571Sdim as_bad (_("`%s' Illegal use of register."), ins_parse); 2050214571Sdim } 2051214571Sdim } 2052214571Sdim 2053214571Sdim /* Some instruction assume the stack pointer as rptr operand. 2054214571Sdim Issue an error when the register to be loaded is also SP. */ 2055214571Sdim if (instruction->flags & NO_SP) 2056214571Sdim { 2057214571Sdim if (getreg_image (insn->arg[1].r) == getreg_image (sp)) 2058214571Sdim as_bad (_("`%s' has undefined result"), ins_parse); 2059214571Sdim } 2060214571Sdim 2061214571Sdim /* If the rptr register is specified as one of the registers to be loaded, 2062214571Sdim the final contents of rptr are undefined. Thus, we issue an error. */ 2063214571Sdim if (instruction->flags & NO_RPTR) 2064214571Sdim { 2065214571Sdim if ((1 << getreg_image (insn->arg[0].r)) & insn->arg[1].constant) 2066214571Sdim as_bad (_("Same src/dest register is used (`r%d'),result is undefined"), 2067214571Sdim getreg_image (insn->arg[0].r)); 2068214571Sdim } 2069214571Sdim} 2070214571Sdim 2071214571Sdim/* In some cases, we need to adjust the instruction pointer although a 2072214571Sdim match was already found. Here, we gather all these cases. 2073214571Sdim Returns 1 if instruction pointer was adjusted, otherwise 0. */ 2074214571Sdim 2075214571Sdimstatic int 2076214571Sdimadjust_if_needed (ins *insn ATTRIBUTE_UNUSED) 2077214571Sdim{ 2078214571Sdim int ret_value = 0; 2079214571Sdim 2080214571Sdim if ((IS_INSN_TYPE (CSTBIT_INS)) || (IS_INSN_TYPE (LD_STOR_INS))) 2081214571Sdim { 2082214571Sdim if ((instruction->operands[0].op_type == abs24) 2083214571Sdim && ((insn->arg[0].constant) > 0xF00000)) 2084214571Sdim { 2085214571Sdim insn->arg[0].constant &= 0xFFFFF; 2086214571Sdim instruction--; 2087214571Sdim ret_value = 1; 2088214571Sdim } 2089214571Sdim } 2090214571Sdim 2091214571Sdim return ret_value; 2092214571Sdim} 2093214571Sdim 2094214571Sdim/* Assemble a single instruction: 2095214571Sdim INSN is already parsed (that is, all operand values and types are set). 2096214571Sdim For instruction to be assembled, we need to find an appropriate template in 2097214571Sdim the instruction table, meeting the following conditions: 2098214571Sdim 1: Has the same number of operands. 2099214571Sdim 2: Has the same operand types. 2100214571Sdim 3: Each operand size is sufficient to represent the instruction's values. 2101214571Sdim Returns 1 upon success, 0 upon failure. */ 2102214571Sdim 2103214571Sdimstatic int 2104214571Sdimassemble_insn (char *mnemonic, ins *insn) 2105214571Sdim{ 2106214571Sdim /* Type of each operand in the current template. */ 2107214571Sdim argtype cur_type[MAX_OPERANDS]; 2108214571Sdim /* Size (in bits) of each operand in the current template. */ 2109214571Sdim unsigned int cur_size[MAX_OPERANDS]; 2110214571Sdim /* Flags of each operand in the current template. */ 2111214571Sdim unsigned int cur_flags[MAX_OPERANDS]; 2112214571Sdim /* Instruction type to match. */ 2113214571Sdim unsigned int ins_type; 2114214571Sdim /* Boolean flag to mark whether a match was found. */ 2115214571Sdim int match = 0; 2116214571Sdim int i; 2117214571Sdim /* Nonzero if an instruction with same number of operands was found. */ 2118214571Sdim int found_same_number_of_operands = 0; 2119214571Sdim /* Nonzero if an instruction with same argument types was found. */ 2120214571Sdim int found_same_argument_types = 0; 2121214571Sdim /* Nonzero if a constant was found within the required range. */ 2122214571Sdim int found_const_within_range = 0; 2123214571Sdim /* Argument number of an operand with invalid type. */ 2124214571Sdim int invalid_optype = -1; 2125214571Sdim /* Argument number of an operand with invalid constant value. */ 2126214571Sdim int invalid_const = -1; 2127214571Sdim /* Operand error (used for issuing various constant error messages). */ 2128214571Sdim op_err op_error, const_err = OP_LEGAL; 2129214571Sdim 2130214571Sdim/* Retrieve data (based on FUNC) for each operand of a given instruction. */ 2131214571Sdim#define GET_CURRENT_DATA(FUNC, ARRAY) \ 2132214571Sdim for (i = 0; i < insn->nargs; i++) \ 2133214571Sdim ARRAY[i] = FUNC (instruction->operands[i].op_type) 2134214571Sdim 2135214571Sdim#define GET_CURRENT_TYPE GET_CURRENT_DATA (get_optype, cur_type) 2136214571Sdim#define GET_CURRENT_SIZE GET_CURRENT_DATA (get_opbits, cur_size) 2137214571Sdim#define GET_CURRENT_FLAGS GET_CURRENT_DATA (get_opflags, cur_flags) 2138214571Sdim 2139214571Sdim /* Instruction has no operands -> only copy the constant opcode. */ 2140214571Sdim if (insn->nargs == 0) 2141214571Sdim { 2142214571Sdim output_opcode[0] = BIN (instruction->match, instruction->match_bits); 2143214571Sdim return 1; 2144214571Sdim } 2145214571Sdim 2146214571Sdim /* In some case, same mnemonic can appear with different instruction types. 2147214571Sdim For example, 'storb' is supported with 3 different types : 2148214571Sdim LD_STOR_INS, LD_STOR_INS_INC, STOR_IMM_INS. 2149214571Sdim We assume that when reaching this point, the instruction type was 2150214571Sdim pre-determined. We need to make sure that the type stays the same 2151214571Sdim during a search for matching instruction. */ 2152214571Sdim ins_type = CR16_INS_TYPE (instruction->flags); 2153214571Sdim 2154214571Sdim while (/* Check that match is still not found. */ 2155214571Sdim match != 1 2156214571Sdim /* Check we didn't get to end of table. */ 2157214571Sdim && instruction->mnemonic != NULL 2158214571Sdim /* Check that the actual mnemonic is still available. */ 2159214571Sdim && IS_INSN_MNEMONIC (mnemonic) 2160214571Sdim /* Check that the instruction type wasn't changed. */ 2161214571Sdim && IS_INSN_TYPE (ins_type)) 2162214571Sdim { 2163214571Sdim /* Check whether number of arguments is legal. */ 2164214571Sdim if (get_number_of_operands () != insn->nargs) 2165214571Sdim goto next_insn; 2166214571Sdim found_same_number_of_operands = 1; 2167214571Sdim 2168214571Sdim /* Initialize arrays with data of each operand in current template. */ 2169214571Sdim GET_CURRENT_TYPE; 2170214571Sdim GET_CURRENT_SIZE; 2171214571Sdim GET_CURRENT_FLAGS; 2172214571Sdim 2173214571Sdim /* Check for type compatibility. */ 2174214571Sdim for (i = 0; i < insn->nargs; i++) 2175214571Sdim { 2176214571Sdim if (cur_type[i] != insn->arg[i].type) 2177214571Sdim { 2178214571Sdim if (invalid_optype == -1) 2179214571Sdim invalid_optype = i + 1; 2180214571Sdim goto next_insn; 2181214571Sdim } 2182214571Sdim } 2183214571Sdim found_same_argument_types = 1; 2184214571Sdim 2185214571Sdim for (i = 0; i < insn->nargs; i++) 2186214571Sdim { 2187214571Sdim /* If 'bal' instruction size is '2' and reg operand is not 'ra' 2188214571Sdim then goto next instruction. */ 2189214571Sdim if (IS_INSN_MNEMONIC ("bal") && (i == 0) 2190214571Sdim && (instruction->size == 2) && (insn->arg[i].rp != 14)) 2191214571Sdim goto next_insn; 2192214571Sdim 2193214571Sdim /* If 'storb' instruction with 'sp' reg and 16-bit disp of 2194214571Sdim * reg-pair, leads to undifined trap, so this should use 2195214571Sdim * 20-bit disp of reg-pair. */ 2196214571Sdim if (IS_INSN_MNEMONIC ("storb") && (instruction->size == 2) 2197214571Sdim && (insn->arg[i].r == 15) && (insn->arg[i + 1].type == arg_crp)) 2198214571Sdim goto next_insn; 2199214571Sdim 2200214571Sdim /* Only check range - don't update the constant's value, since the 2201214571Sdim current instruction may not be the last we try to match. 2202214571Sdim The constant's value will be updated later, right before printing 2203214571Sdim it to the object file. */ 2204214571Sdim if ((insn->arg[i].X_op == O_constant) 2205214571Sdim && (op_error = check_range (&insn->arg[i].constant, cur_size[i], 2206214571Sdim cur_flags[i], 0))) 2207214571Sdim { 2208214571Sdim if (invalid_const == -1) 2209214571Sdim { 2210214571Sdim invalid_const = i + 1; 2211214571Sdim const_err = op_error; 2212214571Sdim } 2213214571Sdim goto next_insn; 2214214571Sdim } 2215214571Sdim /* For symbols, we make sure the relocation size (which was already 2216214571Sdim determined) is sufficient. */ 2217214571Sdim else if ((insn->arg[i].X_op == O_symbol) 2218214571Sdim && ((bfd_reloc_type_lookup (stdoutput, insn->rtype))->bitsize 2219214571Sdim > cur_size[i])) 2220214571Sdim goto next_insn; 2221214571Sdim } 2222214571Sdim found_const_within_range = 1; 2223214571Sdim 2224214571Sdim /* If we got till here -> Full match is found. */ 2225214571Sdim match = 1; 2226214571Sdim break; 2227214571Sdim 2228214571Sdim/* Try again with next instruction. */ 2229214571Sdimnext_insn: 2230214571Sdim instruction++; 2231214571Sdim } 2232214571Sdim 2233214571Sdim if (!match) 2234214571Sdim { 2235214571Sdim /* We haven't found a match - instruction can't be assembled. */ 2236214571Sdim if (!found_same_number_of_operands) 2237214571Sdim as_bad (_("Incorrect number of operands")); 2238214571Sdim else if (!found_same_argument_types) 2239214571Sdim as_bad (_("Illegal type of operand (arg %d)"), invalid_optype); 2240214571Sdim else if (!found_const_within_range) 2241214571Sdim { 2242214571Sdim switch (const_err) 2243214571Sdim { 2244214571Sdim case OP_OUT_OF_RANGE: 2245214571Sdim as_bad (_("Operand out of range (arg %d)"), invalid_const); 2246214571Sdim break; 2247214571Sdim case OP_NOT_EVEN: 2248214571Sdim as_bad (_("Operand has odd displacement (arg %d)"), invalid_const); 2249214571Sdim break; 2250214571Sdim default: 2251214571Sdim as_bad (_("Illegal operand (arg %d)"), invalid_const); 2252214571Sdim break; 2253214571Sdim } 2254214571Sdim } 2255214571Sdim 2256214571Sdim return 0; 2257214571Sdim } 2258214571Sdim else 2259214571Sdim /* Full match - print the encoding to output file. */ 2260214571Sdim { 2261214571Sdim /* Make further checkings (such that couldn't be made earlier). 2262214571Sdim Warn the user if necessary. */ 2263214571Sdim warn_if_needed (insn); 2264214571Sdim 2265214571Sdim /* Check whether we need to adjust the instruction pointer. */ 2266214571Sdim if (adjust_if_needed (insn)) 2267214571Sdim /* If instruction pointer was adjusted, we need to update 2268214571Sdim the size of the current template operands. */ 2269214571Sdim GET_CURRENT_SIZE; 2270214571Sdim 2271214571Sdim for (i = 0; i < insn->nargs; i++) 2272214571Sdim { 2273214571Sdim int j = instruction->flags & REVERSE_MATCH ? 2274214571Sdim i == 0 ? 1 : 2275214571Sdim i == 1 ? 0 : i : 2276214571Sdim i; 2277214571Sdim 2278214571Sdim /* This time, update constant value before printing it. */ 2279214571Sdim if ((insn->arg[j].X_op == O_constant) 2280214571Sdim && (check_range (&insn->arg[j].constant, cur_size[j], 2281214571Sdim cur_flags[j], 1) != OP_LEGAL)) 2282214571Sdim as_fatal (_("Illegal operand (arg %d)"), j+1); 2283214571Sdim } 2284214571Sdim 2285214571Sdim /* First, copy the instruction's opcode. */ 2286214571Sdim output_opcode[0] = BIN (instruction->match, instruction->match_bits); 2287214571Sdim 2288214571Sdim for (i = 0; i < insn->nargs; i++) 2289214571Sdim { 2290214571Sdim /* For BAL (ra),disp17 instuction only. And also set the 2291214571Sdim DISP24a relocation type. */ 2292214571Sdim if (IS_INSN_MNEMONIC ("bal") && (instruction->size == 2) && i == 0) 2293214571Sdim { 2294214571Sdim insn->rtype = BFD_RELOC_CR16_DISP24a; 2295214571Sdim continue; 2296214571Sdim } 2297214571Sdim cur_arg_num = i; 2298214571Sdim print_operand (cur_size[i], instruction->operands[i].shift, 2299214571Sdim &insn->arg[i]); 2300214571Sdim } 2301214571Sdim } 2302214571Sdim 2303214571Sdim return 1; 2304214571Sdim} 2305214571Sdim 2306214571Sdim/* Print the instruction. 2307214571Sdim Handle also cases where the instruction is relaxable/relocatable. */ 2308214571Sdim 2309214571Sdimstatic void 2310214571Sdimprint_insn (ins *insn) 2311214571Sdim{ 2312214571Sdim unsigned int i, j, insn_size; 2313214571Sdim char *this_frag; 2314214571Sdim unsigned short words[4]; 2315214571Sdim int addr_mod; 2316214571Sdim 2317214571Sdim /* Arrange the insn encodings in a WORD size array. */ 2318214571Sdim for (i = 0, j = 0; i < 2; i++) 2319214571Sdim { 2320214571Sdim words[j++] = (output_opcode[i] >> 16) & 0xFFFF; 2321214571Sdim words[j++] = output_opcode[i] & 0xFFFF; 2322214571Sdim } 2323214571Sdim 2324214571Sdim insn_size = instruction->size; 2325214571Sdim this_frag = frag_more (insn_size * 2); 2326214571Sdim 2327214571Sdim /* Handle relocation. */ 2328214571Sdim if ((relocatable) && (insn->rtype != BFD_RELOC_NONE)) 2329214571Sdim { 2330214571Sdim reloc_howto_type *reloc_howto; 2331214571Sdim int size; 2332214571Sdim 2333214571Sdim reloc_howto = bfd_reloc_type_lookup (stdoutput, insn->rtype); 2334214571Sdim 2335214571Sdim if (!reloc_howto) 2336214571Sdim abort (); 2337214571Sdim 2338214571Sdim size = bfd_get_reloc_size (reloc_howto); 2339214571Sdim 2340214571Sdim if (size < 1 || size > 4) 2341214571Sdim abort (); 2342214571Sdim 2343214571Sdim fix_new_exp (frag_now, this_frag - frag_now->fr_literal, 2344214571Sdim size, &insn->exp, reloc_howto->pc_relative, 2345214571Sdim insn->rtype); 2346214571Sdim } 2347214571Sdim 2348214571Sdim /* Verify a 2-byte code alignment. */ 2349214571Sdim addr_mod = frag_now_fix () & 1; 2350214571Sdim if (frag_now->has_code && frag_now->insn_addr != addr_mod) 2351214571Sdim as_bad (_("instruction address is not a multiple of 2")); 2352214571Sdim frag_now->insn_addr = addr_mod; 2353214571Sdim frag_now->has_code = 1; 2354214571Sdim 2355214571Sdim /* Write the instruction encoding to frag. */ 2356214571Sdim for (i = 0; i < insn_size; i++) 2357214571Sdim { 2358214571Sdim md_number_to_chars (this_frag, (valueT) words[i], 2); 2359214571Sdim this_frag += 2; 2360214571Sdim } 2361214571Sdim} 2362214571Sdim 2363214571Sdim/* This is the guts of the machine-dependent assembler. OP points to a 2364214571Sdim machine dependent instruction. This function is supposed to emit 2365214571Sdim the frags/bytes it assembles to. */ 2366214571Sdim 2367214571Sdimvoid 2368214571Sdimmd_assemble (char *op) 2369214571Sdim{ 2370214571Sdim ins cr16_ins; 2371214571Sdim char *param, param1[32]; 2372214571Sdim char c; 2373214571Sdim 2374214571Sdim /* Reset global variables for a new instruction. */ 2375214571Sdim reset_vars (op); 2376214571Sdim 2377214571Sdim /* Strip the mnemonic. */ 2378214571Sdim for (param = op; *param != 0 && !ISSPACE (*param); param++) 2379214571Sdim ; 2380214571Sdim c = *param; 2381214571Sdim *param++ = '\0'; 2382214571Sdim 2383214571Sdim /* bCC instuctions and adjust the mnemonic by adding extra white spaces. */ 2384214571Sdim if (is_bcc_insn (op)) 2385214571Sdim { 2386214571Sdim strcpy (param1, get_b_cc (op)); 2387214571Sdim op = "b"; 2388214571Sdim strcat (param1,","); 2389214571Sdim strcat (param1, param); 2390214571Sdim param = (char *) ¶m1; 2391214571Sdim } 2392214571Sdim 2393214571Sdim /* Checking the cinv options and adjust the mnemonic by removing the 2394214571Sdim extra white spaces. */ 2395214571Sdim if (streq ("cinv", op)) 2396214571Sdim { 2397214571Sdim /* Validate the cinv options. */ 2398214571Sdim check_cinv_options (param); 2399214571Sdim strcat (op, param); 2400214571Sdim } 2401214571Sdim 2402214571Sdim /* MAPPING - SHIFT INSN, if imm4/imm16 positive values 2403214571Sdim lsh[b/w] imm4/imm6, reg ==> ashu[b/w] imm4/imm16, reg 2404214571Sdim as CR16 core doesn't support lsh[b/w] right shift operaions. */ 2405214571Sdim if ((streq ("lshb", op) || streq ("lshw", op) || streq ("lshd", op)) 2406214571Sdim && (param [0] == '$')) 2407214571Sdim { 2408214571Sdim strcpy (param1, param); 2409214571Sdim /* Find the instruction. */ 2410214571Sdim instruction = (const inst *) hash_find (cr16_inst_hash, op); 2411214571Sdim parse_operands (&cr16_ins, param1); 2412214571Sdim if (((&cr16_ins)->arg[0].type == arg_ic) 2413214571Sdim && ((&cr16_ins)->arg[0].constant >= 0)) 2414214571Sdim { 2415214571Sdim if (streq ("lshb", op)) 2416214571Sdim op = "ashub"; 2417214571Sdim else if (streq ("lshd", op)) 2418214571Sdim op = "ashud"; 2419214571Sdim else 2420214571Sdim op = "ashuw"; 2421214571Sdim } 2422214571Sdim } 2423214571Sdim 2424214571Sdim /* Find the instruction. */ 2425214571Sdim instruction = (const inst *) hash_find (cr16_inst_hash, op); 2426214571Sdim if (instruction == NULL) 2427214571Sdim { 2428214571Sdim as_bad (_("Unknown opcode: `%s'"), op); 2429214571Sdim return; 2430214571Sdim } 2431214571Sdim 2432214571Sdim /* Tie dwarf2 debug info to the address at the start of the insn. */ 2433214571Sdim dwarf2_emit_insn (0); 2434214571Sdim 2435214571Sdim /* Parse the instruction's operands. */ 2436214571Sdim parse_insn (&cr16_ins, param); 2437214571Sdim 2438214571Sdim /* Assemble the instruction - return upon failure. */ 2439214571Sdim if (assemble_insn (op, &cr16_ins) == 0) 2440214571Sdim return; 2441214571Sdim 2442214571Sdim /* Print the instruction. */ 2443214571Sdim print_insn (&cr16_ins); 2444214571Sdim} 2445