1 /* tc-lm32.c - Lattice Mico32 assembler. 2 Copyright 2008 Free Software Foundation, Inc. 3 Contributed by Jon Beniston <jon@beniston.com> 4 5 This file is part of GAS, the GNU Assembler. 6 7 GAS is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2, or (at your option) 10 any later version. 11 12 GAS is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License along 18 with GAS; see the file COPYING. If not, write to the Free Software 19 Foundation, 51 Franklin Street - Fifth Floor, Boston, 20 MA 02110-1301, USA. */ 21 22 #include <string.h> 23 #include <stdlib.h> 24 25 #include "as.h" 26 #include "safe-ctype.h" 27 #include "subsegs.h" 28 #include "bfd.h" 29 #include "safe-ctype.h" 30 #include "opcodes/lm32-desc.h" 31 #include "opcodes/lm32-opc.h" 32 #include "cgen.h" 33 #include "elf/lm32.h" 34 35 typedef struct 36 { 37 const CGEN_INSN *insn; 38 const CGEN_INSN *orig_insn; 39 CGEN_FIELDS fields; 40 #if CGEN_INT_INSN_P 41 CGEN_INSN_INT buffer [1]; 42 #define INSN_VALUE(buf) (*(buf)) 43 #else 44 unsigned char buffer[CGEN_MAX_INSN_SIZE]; 45 #define INSN_VALUE(buf) (buf) 46 #endif 47 char *addr; 48 fragS *frag; 49 int num_fixups; 50 fixS *fixups[GAS_CGEN_MAX_FIXUPS]; 51 int indices[MAX_OPERAND_INSTANCES]; 52 } lm32_insn; 53 54 /* Configuration options */ 55 56 #define LM_CFG_MULTIPLIY_ENABLED 0x0001 57 #define LM_CFG_DIVIDE_ENABLED 0x0002 58 #define LM_CFG_BARREL_SHIFT_ENABLED 0x0004 59 #define LM_CFG_SIGN_EXTEND_ENABLED 0x0008 60 #define LM_CFG_USER_ENABLED 0x0010 61 #define LM_CFG_ICACHE_ENABLED 0x0020 62 #define LM_CFG_DCACHE_ENABLED 0x0040 63 #define LM_CFG_BREAK_ENABLED 0x0080 64 65 static unsigned config = 0U; 66 67 /* Target specific assembler tokens / delimiters. */ 68 69 const char comment_chars[] = "#"; 70 const char line_comment_chars[] = "#"; 71 const char line_separator_chars[] = ";"; 72 const char EXP_CHARS[] = "eE"; 73 const char FLT_CHARS[] = "dD"; 74 75 /* Target specific assembly directives. */ 76 77 const pseudo_typeS md_pseudo_table[] = 78 { 79 { "align", s_align_bytes, 0 }, 80 { "byte", cons, 1 }, 81 { "hword", cons, 2 }, 82 { "word", cons, 4 }, 83 { "dword", cons, 8 }, 84 {(char *)0 , (void(*)(int))0, 0} 85 }; 86 87 /* Target specific command line options. */ 88 89 const char * md_shortopts = ""; 90 91 struct option md_longopts[] = 92 { 93 #define OPTION_MULTIPLY_ENABLED (OPTION_MD_BASE + 1) 94 { "mmultiply-enabled", no_argument, NULL, OPTION_MULTIPLY_ENABLED }, 95 #define OPTION_DIVIDE_ENABLED (OPTION_MD_BASE + 2) 96 { "mdivide-enabled", no_argument, NULL, OPTION_DIVIDE_ENABLED }, 97 #define OPTION_BARREL_SHIFT_ENABLED (OPTION_MD_BASE + 3) 98 { "mbarrel-shift-enabled", no_argument, NULL, OPTION_BARREL_SHIFT_ENABLED }, 99 #define OPTION_SIGN_EXTEND_ENABLED (OPTION_MD_BASE + 4) 100 { "msign-extend-enabled", no_argument, NULL, OPTION_SIGN_EXTEND_ENABLED }, 101 #define OPTION_USER_ENABLED (OPTION_MD_BASE + 5) 102 { "muser-enabled", no_argument, NULL, OPTION_USER_ENABLED }, 103 #define OPTION_ICACHE_ENABLED (OPTION_MD_BASE + 6) 104 { "micache-enabled", no_argument, NULL, OPTION_ICACHE_ENABLED }, 105 #define OPTION_DCACHE_ENABLED (OPTION_MD_BASE + 7) 106 { "mdcache-enabled", no_argument, NULL, OPTION_DCACHE_ENABLED }, 107 #define OPTION_BREAK_ENABLED (OPTION_MD_BASE + 8) 108 { "mbreak-enabled", no_argument, NULL, OPTION_BREAK_ENABLED }, 109 #define OPTION_ALL_ENABLED (OPTION_MD_BASE + 9) 110 { "mall-enabled", no_argument, NULL, OPTION_ALL_ENABLED }, 111 }; 112 113 size_t md_longopts_size = sizeof (md_longopts); 114 115 /* Display architecture specific options. */ 116 117 void 118 md_show_usage (FILE * fp) 119 { 120 fprintf (fp, "LM32 specific options:\n" 121 " -mmultiply-enabled enable multiply instructions\n" 122 " -mdivide-enabled enable divide and modulus instructions\n" 123 " -mbarrel-shift-enabled enable multi-bit shift instructions\n" 124 " -msign-extend-enabled enable sign-extension instructions\n" 125 " -muser-enabled enable user-defined instructions\n" 126 " -micache-enabled enable instruction cache instructions\n" 127 " -mdcache-enabled enable data cache instructions\n" 128 " -mbreak-enabled enable the break instruction\n" 129 " -mall-enabled enable all optional instructions\n" 130 ); 131 } 132 133 /* Parse command line options. */ 134 135 int 136 md_parse_option (int c, char * arg ATTRIBUTE_UNUSED) 137 { 138 switch (c) 139 { 140 case OPTION_MULTIPLY_ENABLED: 141 config |= LM_CFG_MULTIPLIY_ENABLED; 142 break; 143 case OPTION_DIVIDE_ENABLED: 144 config |= LM_CFG_DIVIDE_ENABLED; 145 break; 146 case OPTION_BARREL_SHIFT_ENABLED: 147 config |= LM_CFG_BARREL_SHIFT_ENABLED; 148 break; 149 case OPTION_SIGN_EXTEND_ENABLED: 150 config |= LM_CFG_SIGN_EXTEND_ENABLED; 151 break; 152 case OPTION_USER_ENABLED: 153 config |= LM_CFG_USER_ENABLED; 154 break; 155 case OPTION_ICACHE_ENABLED: 156 config |= LM_CFG_ICACHE_ENABLED; 157 break; 158 case OPTION_DCACHE_ENABLED: 159 config |= LM_CFG_DCACHE_ENABLED; 160 break; 161 case OPTION_BREAK_ENABLED: 162 config |= LM_CFG_BREAK_ENABLED; 163 break; 164 case OPTION_ALL_ENABLED: 165 config |= LM_CFG_MULTIPLIY_ENABLED; 166 config |= LM_CFG_DIVIDE_ENABLED; 167 config |= LM_CFG_BARREL_SHIFT_ENABLED; 168 config |= LM_CFG_SIGN_EXTEND_ENABLED; 169 config |= LM_CFG_USER_ENABLED; 170 config |= LM_CFG_ICACHE_ENABLED; 171 config |= LM_CFG_DCACHE_ENABLED; 172 config |= LM_CFG_BREAK_ENABLED; 173 break; 174 default: 175 return 0; 176 } 177 return 1; 178 } 179 180 /* Do any architecture specific initialisation. */ 181 182 void 183 md_begin (void) 184 { 185 /* Initialize the `cgen' interface. */ 186 187 /* Set the machine number and endian. */ 188 gas_cgen_cpu_desc = lm32_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0, 189 CGEN_CPU_OPEN_ENDIAN, 190 CGEN_ENDIAN_BIG, 191 CGEN_CPU_OPEN_END); 192 lm32_cgen_init_asm (gas_cgen_cpu_desc); 193 194 /* This is a callback from cgen to gas to parse operands. */ 195 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand); 196 197 if (! bfd_set_arch_mach (stdoutput, bfd_arch_lm32, bfd_mach_lm32)) 198 as_warn (_("could not set architecture and machine")); 199 } 200 201 /* Turn an integer of n bytes (in val) into a stream of bytes appropriate 202 for use in the a.out file, and stores them in the array pointed to by buf. */ 203 204 void 205 md_number_to_chars (char * buf, valueT val, int n) 206 { 207 if (target_big_endian) 208 number_to_chars_bigendian (buf, val, n); 209 else 210 number_to_chars_littleendian (buf, val, n); 211 } 212 213 /* Turn a string in input_line_pointer into a floating point constant 214 of type TYPE, and store the appropriate bytes in *LITP. The number 215 of LITTLENUMS emitted is stored in *SIZEP. An error message is 216 returned, or NULL on OK. */ 217 218 char * 219 md_atof (int type, char *litP, int *sizeP) 220 { 221 int i; 222 int prec; 223 LITTLENUM_TYPE words[4]; 224 225 char *t; 226 227 switch (type) 228 { 229 case 'f': 230 prec = 2; 231 break; 232 case 'd': 233 prec = 4; 234 break; 235 default: 236 *sizeP = 0; 237 return _("bad call to md_atof"); 238 } 239 240 t = atof_ieee (input_line_pointer, type, words); 241 if (t) 242 input_line_pointer = t; 243 244 *sizeP = prec * sizeof (LITTLENUM_TYPE); 245 246 if (target_big_endian) 247 { 248 for (i = 0; i < prec; i++) 249 { 250 md_number_to_chars (litP, (valueT) words[i], 251 sizeof (LITTLENUM_TYPE)); 252 litP += sizeof (LITTLENUM_TYPE); 253 } 254 } 255 else 256 { 257 for (i = prec - 1; i >= 0; i--) 258 { 259 md_number_to_chars (litP, (valueT) words[i], 260 sizeof (LITTLENUM_TYPE)); 261 litP += sizeof (LITTLENUM_TYPE); 262 } 263 } 264 265 return NULL; 266 } 267 268 /* Called for each undefined symbol. */ 269 270 symbolS * 271 md_undefined_symbol (char * name ATTRIBUTE_UNUSED) 272 { 273 return 0; 274 } 275 276 /* Round up a section size to the appropriate boundary. */ 277 278 valueT 279 md_section_align (asection *seg, valueT addr) 280 { 281 int align = bfd_get_section_alignment (stdoutput, seg); 282 return ((addr + (1 << align) - 1) & (-1 << align)); 283 } 284 285 /* This function assembles the instructions. It emits the frags/bytes to the 286 sections and creates the relocation entries. */ 287 288 void 289 md_assemble (char * str) 290 { 291 lm32_insn insn; 292 char * errmsg; 293 294 /* Initialize GAS's cgen interface for a new instruction. */ 295 gas_cgen_init_parse (); 296 297 insn.insn = lm32_cgen_assemble_insn 298 (gas_cgen_cpu_desc, str, &insn.fields, insn.buffer, &errmsg); 299 300 if (!insn.insn) 301 { 302 as_bad ("%s", errmsg); 303 return; 304 } 305 306 gas_cgen_finish_insn (insn.insn, insn.buffer, 307 CGEN_FIELDS_BITSIZE (&insn.fields), 1, NULL); 308 } 309 310 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP. 311 Returns BFD_RELOC_NONE if no reloc type can be found. 312 *FIXP may be modified if desired. */ 313 314 bfd_reloc_code_real_type 315 md_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED, 316 const CGEN_OPERAND *operand, 317 fixS *fixP ATTRIBUTE_UNUSED) 318 { 319 switch (operand->type) 320 { 321 case LM32_OPERAND_GOT16: 322 return BFD_RELOC_LM32_16_GOT; 323 case LM32_OPERAND_GOTOFFHI16: 324 return BFD_RELOC_LM32_GOTOFF_HI16; 325 case LM32_OPERAND_GOTOFFLO16: 326 return BFD_RELOC_LM32_GOTOFF_LO16; 327 case LM32_OPERAND_GP16: 328 return BFD_RELOC_GPREL16; 329 case LM32_OPERAND_LO16: 330 return BFD_RELOC_LO16; 331 case LM32_OPERAND_HI16: 332 return BFD_RELOC_HI16; 333 case LM32_OPERAND_BRANCH: 334 return BFD_RELOC_LM32_BRANCH; 335 case LM32_OPERAND_CALL: 336 return BFD_RELOC_LM32_CALL; 337 default: 338 break; 339 } 340 return BFD_RELOC_NONE; 341 } 342 343 /* Return the position from which the PC relative adjustment for a PC relative 344 fixup should be made. */ 345 346 long 347 md_pcrel_from (fixS *fixP) 348 { 349 /* Shouldn't get called. */ 350 abort (); 351 /* Return address of current instruction. */ 352 return fixP->fx_where + fixP->fx_frag->fr_address; 353 } 354 355 /* The location from which a PC relative jump should be calculated, 356 given a PC relative reloc. */ 357 358 long 359 md_pcrel_from_section (fixS * fixP, segT sec) 360 { 361 if ((fixP->fx_addsy != (symbolS *) NULL) 362 && (! S_IS_DEFINED (fixP->fx_addsy) 363 || (S_GET_SEGMENT (fixP->fx_addsy) != sec))) 364 { 365 /* The symbol is undefined (or is defined but not in this section). 366 Let the linker figure it out. */ 367 return 0; 368 } 369 370 /*fprintf(stderr, "%s extern %d local %d\n", S_GET_NAME (fixP->fx_addsy), S_IS_EXTERN (fixP->fx_addsy), S_IS_LOCAL (fixP->fx_addsy));*/ 371 /* FIXME: Weak problem? */ 372 if ((fixP->fx_addsy != (symbolS *) NULL) 373 && S_IS_EXTERNAL (fixP->fx_addsy)) 374 { 375 /* If the symbol is external, let the linker handle it. */ 376 return 0; 377 } 378 379 return fixP->fx_where + fixP->fx_frag->fr_address; 380 } 381 382 /* Return true if we can partially resolve a relocation now. */ 383 384 bfd_boolean 385 lm32_fix_adjustable (fixS * fixP) 386 { 387 /* We need the symbol name for the VTABLE entries */ 388 if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT 389 || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) 390 return FALSE; 391 392 return TRUE; 393 } 394 395 /* Relaxation isn't required/supported on this target. */ 396 397 int 398 md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED, 399 asection *seg ATTRIBUTE_UNUSED) 400 { 401 abort (); 402 return 0; 403 } 404 405 void 406 md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, 407 asection *sec ATTRIBUTE_UNUSED, 408 fragS *fragP ATTRIBUTE_UNUSED) 409 { 410 abort (); 411 } 412 413 void 414 md_apply_fix (fixS * fixP, valueT * valP, segT seg) 415 { 416 /* Fix for weak symbols. Why do we have fx_addsy for weak symbols? */ 417 if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy)) 418 *valP = 0; 419 420 gas_cgen_md_apply_fix (fixP, valP, seg); 421 return; 422 } 423