1 /* tc-ip2k.c -- Assembler for the Scenix IP2xxx. 2 Copyright (C) 2000-2016 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 #include "as.h" 22 #include "subsegs.h" 23 #include "symcat.h" 24 #include "opcodes/ip2k-desc.h" 25 #include "opcodes/ip2k-opc.h" 26 #include "cgen.h" 27 #include "elf/common.h" 28 #include "elf/ip2k.h" 29 #include "libbfd.h" 30 31 /* Structure to hold all of the different components describing 32 an individual instruction. */ 33 typedef struct 34 { 35 const CGEN_INSN * insn; 36 const CGEN_INSN * orig_insn; 37 CGEN_FIELDS fields; 38 #if CGEN_INT_INSN_P 39 CGEN_INSN_INT buffer [1]; 40 #define INSN_VALUE(buf) (*(buf)) 41 #else 42 unsigned char buffer [CGEN_MAX_INSN_SIZE]; 43 #define INSN_VALUE(buf) (buf) 44 #endif 45 char * addr; 46 fragS * frag; 47 int num_fixups; 48 fixS * fixups [GAS_CGEN_MAX_FIXUPS]; 49 int indices [MAX_OPERAND_INSTANCES]; 50 } 51 ip2k_insn; 52 53 const char comment_chars[] = ";"; 54 const char line_comment_chars[] = "#"; 55 const char line_separator_chars[] = ""; 56 const char EXP_CHARS[] = "eE"; 57 const char FLT_CHARS[] = "dD"; 58 59 /* Flag to detect when switching to code section where insn alignment is 60 implied. */ 61 static int force_code_align = 0; 62 63 /* Mach selected from command line. */ 64 static int ip2k_mach = 0; 65 static unsigned ip2k_mach_bitmask = 0; 66 67 68 static void 69 ip2k_elf_section_rtn (int i) 70 { 71 obj_elf_section(i); 72 73 if (force_code_align) 74 { 75 do_align (1, NULL, 0, 0); 76 force_code_align = 0; 77 } 78 } 79 80 static void 81 ip2k_elf_section_text (int i) 82 { 83 obj_elf_text(i); 84 85 do_align (1, NULL, 0, 0); 86 force_code_align = 0; 87 } 88 89 /* The target specific pseudo-ops which we support. */ 90 const pseudo_typeS md_pseudo_table[] = 91 { 92 { "text", ip2k_elf_section_text, 0 }, 93 { "sect", ip2k_elf_section_rtn, 0 }, 94 { NULL, NULL, 0 } 95 }; 96 97 98 100 enum options 101 { 102 OPTION_CPU_IP2022 = OPTION_MD_BASE, 103 OPTION_CPU_IP2022EXT 104 }; 105 106 struct option md_longopts[] = 107 { 108 { "mip2022", no_argument, NULL, OPTION_CPU_IP2022 }, 109 { "mip2022ext", no_argument, NULL, OPTION_CPU_IP2022EXT }, 110 { NULL, no_argument, NULL, 0 }, 111 }; 112 size_t md_longopts_size = sizeof (md_longopts); 113 114 const char * md_shortopts = ""; 115 116 int 117 md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg ATTRIBUTE_UNUSED) 118 { 119 switch (c) 120 { 121 case OPTION_CPU_IP2022: 122 ip2k_mach = bfd_mach_ip2022; 123 ip2k_mach_bitmask = 1 << MACH_IP2022; 124 break; 125 126 case OPTION_CPU_IP2022EXT: 127 ip2k_mach = bfd_mach_ip2022ext; 128 ip2k_mach_bitmask = 1 << MACH_IP2022EXT; 129 break; 130 131 default: 132 return 0; 133 } 134 135 return 1; 136 } 137 138 void 139 md_show_usage (FILE * stream) 140 { 141 fprintf (stream, _("IP2K specific command line options:\n")); 142 fprintf (stream, _(" -mip2022 restrict to IP2022 insns \n")); 143 fprintf (stream, _(" -mip2022ext permit extended IP2022 insn\n")); 144 } 145 146 147 void 149 md_begin (void) 150 { 151 /* Initialize the `cgen' interface. */ 152 153 /* Set the machine number and endian. */ 154 gas_cgen_cpu_desc = ip2k_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 155 ip2k_mach_bitmask, 156 CGEN_CPU_OPEN_ENDIAN, 157 CGEN_ENDIAN_BIG, 158 CGEN_CPU_OPEN_END); 159 ip2k_cgen_init_asm (gas_cgen_cpu_desc); 160 161 /* This is a callback from cgen to gas to parse operands. */ 162 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand); 163 164 /* Set the machine type. */ 165 bfd_default_set_arch_mach (stdoutput, bfd_arch_ip2k, ip2k_mach); 166 } 167 168 169 void 170 md_assemble (char * str) 171 { 172 ip2k_insn insn; 173 char * errmsg; 174 175 /* Initialize GAS's cgen interface for a new instruction. */ 176 gas_cgen_init_parse (); 177 178 insn.insn = ip2k_cgen_assemble_insn 179 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg); 180 181 if (!insn.insn) 182 { 183 as_bad ("%s", errmsg); 184 return; 185 } 186 187 /* Check for special relocation required by SKIP instructions. */ 188 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_SKIPA)) 189 /* Unconditional skip has a 1-bit relocation of the current pc, so 190 that we emit either sb pcl.0 or snb pcl.0 depending on whether 191 the PCL (pc + 2) >> 1 is odd or even. */ 192 { 193 enum cgen_parse_operand_result result_type; 194 bfd_vma value; 195 const char *curpc_plus_2 = ".+2"; 196 const char *err; 197 198 err = cgen_parse_address (gas_cgen_cpu_desc, & curpc_plus_2, 199 IP2K_OPERAND_ADDR16CJP, 200 BFD_RELOC_IP2K_PC_SKIP, 201 & result_type, & value); 202 if (err) 203 { 204 as_bad ("%s", err); 205 return; 206 } 207 } 208 209 /* Doesn't really matter what we pass for RELAX_P here. */ 210 gas_cgen_finish_insn (insn.insn, insn.buffer, 211 CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); 212 } 213 214 valueT 215 md_section_align (segT segment, valueT size) 216 { 217 int align = bfd_get_section_alignment (stdoutput, segment); 218 219 return ((size + (1 << align) - 1) & -(1 << align)); 220 } 221 222 223 symbolS * 224 md_undefined_symbol (char * name ATTRIBUTE_UNUSED) 225 { 226 return 0; 227 } 228 229 int 231 md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, 232 segT segment ATTRIBUTE_UNUSED) 233 { 234 as_fatal (_("relaxation not supported\n")); 235 return 1; 236 } 237 238 239 /* *fragP has been relaxed to its final size, and now needs to have 240 the bytes inside it modified to conform to the new size. 241 242 Called after relaxation is finished. 243 fragP->fr_type == rs_machine_dependent. 244 fragP->fr_subtype is the subtype of what the address relaxed to. */ 245 246 void 247 md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, 248 segT sec ATTRIBUTE_UNUSED, 249 fragS * fragP ATTRIBUTE_UNUSED) 250 { 251 } 252 253 254 /* Functions concerning relocs. */ 256 257 long 258 md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED) 259 { 260 abort (); 261 } 262 263 264 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP. 265 Returns BFD_RELOC_NONE if no reloc type can be found. 266 *FIXP may be modified if desired. */ 267 268 bfd_reloc_code_real_type 269 md_cgen_lookup_reloc (const CGEN_INSN * insn ATTRIBUTE_UNUSED, 270 const CGEN_OPERAND * operand, 271 fixS * fixP ATTRIBUTE_UNUSED) 272 { 273 bfd_reloc_code_real_type result; 274 275 result = BFD_RELOC_NONE; 276 277 switch (operand->type) 278 { 279 case IP2K_OPERAND_FR: 280 case IP2K_OPERAND_ADDR16L: 281 case IP2K_OPERAND_ADDR16H: 282 case IP2K_OPERAND_LIT8: 283 /* These may have been processed at parse time. */ 284 if (fixP->fx_cgen.opinfo != 0) 285 result = fixP->fx_cgen.opinfo; 286 fixP->fx_no_overflow = 1; 287 break; 288 289 case IP2K_OPERAND_ADDR16CJP: 290 result = fixP->fx_cgen.opinfo; 291 if (result == 0 || result == BFD_RELOC_NONE) 292 result = BFD_RELOC_IP2K_ADDR16CJP; 293 fixP->fx_no_overflow = 1; 294 break; 295 296 case IP2K_OPERAND_ADDR16P: 297 result = BFD_RELOC_IP2K_PAGE3; 298 fixP->fx_no_overflow = 1; 299 break; 300 301 default: 302 result = BFD_RELOC_NONE; 303 break; 304 } 305 306 return result; 307 } 308 309 310 /* Write a value out to the object file, using the appropriate endianness. */ 311 312 void 313 md_number_to_chars (char * buf, valueT val, int n) 314 { 315 number_to_chars_bigendian (buf, val, n); 316 } 317 318 const char * 319 md_atof (int type, char * litP, int * sizeP) 320 { 321 return ieee_md_atof (type, litP, sizeP, TRUE); 322 } 323 324 325 /* See whether we need to force a relocation into the output file. 326 Force most of them, since the linker's bfd relocation engine 327 understands range limits better than gas' cgen fixup engine. 328 Consider the case of a fixup intermediate value being larger than 329 the instruction it will be eventually encoded within. */ 330 331 int 332 ip2k_force_relocation (fixS * fix) 333 { 334 switch (fix->fx_r_type) 335 { 336 case BFD_RELOC_IP2K_FR9: 337 case BFD_RELOC_IP2K_FR_OFFSET: 338 case BFD_RELOC_IP2K_BANK: 339 case BFD_RELOC_IP2K_ADDR16CJP: 340 case BFD_RELOC_IP2K_PAGE3: 341 case BFD_RELOC_IP2K_LO8DATA: 342 case BFD_RELOC_IP2K_HI8DATA: 343 case BFD_RELOC_IP2K_EX8DATA: 344 case BFD_RELOC_IP2K_LO8INSN: 345 case BFD_RELOC_IP2K_HI8INSN: 346 case BFD_RELOC_IP2K_PC_SKIP: 347 case BFD_RELOC_IP2K_TEXT: 348 return 1; 349 350 case BFD_RELOC_16: 351 if (fix->fx_subsy && S_IS_DEFINED (fix->fx_subsy) 352 && fix->fx_addsy && S_IS_DEFINED (fix->fx_addsy) 353 && (S_GET_SEGMENT (fix->fx_addsy)->flags & SEC_CODE)) 354 { 355 fix->fx_r_type = BFD_RELOC_IP2K_TEXT; 356 return 0; 357 } 358 break; 359 360 default: 361 break; 362 } 363 364 return generic_force_reloc (fix); 365 } 366 367 void 368 ip2k_apply_fix (fixS *fixP, valueT *valueP, segT seg) 369 { 370 if (fixP->fx_r_type == BFD_RELOC_IP2K_TEXT 371 && ! fixP->fx_addsy 372 && ! fixP->fx_subsy) 373 { 374 *valueP = ((int)(* valueP)) / 2; 375 fixP->fx_r_type = BFD_RELOC_16; 376 } 377 else if (fixP->fx_r_type == BFD_RELOC_UNUSED + IP2K_OPERAND_FR) 378 { 379 /* Must be careful when we are fixing up an FR. We could be 380 fixing up an offset to (SP) or (DP) in which case we don't 381 want to step on the top 2 bits of the FR operand. The 382 gas_cgen_md_apply_fix doesn't know any better and overwrites 383 the entire operand. We counter this by adding the bits 384 to the new value. */ 385 char *where = fixP->fx_frag->fr_literal + fixP->fx_where; 386 387 /* Canonical name, since used a lot. */ 388 CGEN_CPU_DESC cd = gas_cgen_cpu_desc; 389 CGEN_INSN_INT insn_value 390 = cgen_get_insn_value (cd, (unsigned char *) where, 391 CGEN_INSN_BITSIZE (fixP->fx_cgen.insn)); 392 /* Preserve (DP) or (SP) specification. */ 393 *valueP += (insn_value & 0x180); 394 } 395 396 gas_cgen_md_apply_fix (fixP, valueP, seg); 397 } 398 399 int 400 ip2k_elf_section_flags (flagword flags, 401 bfd_vma attr ATTRIBUTE_UNUSED, 402 int type ATTRIBUTE_UNUSED) 403 { 404 /* This is used to detect when the section changes to an executable section. 405 This function is called by the elf section processing. When we note an 406 executable section specifier we set an internal flag to denote when 407 word alignment should be forced. */ 408 if (flags & SEC_CODE) 409 force_code_align = 1; 410 411 return flags; 412 } 413 414