1/* tc-mt.c -- Assembler for the Morpho Technologies mt . 2 Copyright (C) 2005-2017 Free Software Foundation, Inc. 3 4 This file is part of GAS, the GNU Assembler. 5 6 GAS is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 GAS is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GAS; see the file COPYING. If not, write to 18 the Free Software Foundation, 59 Temple Place - Suite 330, 19 Boston, MA 02111-1307, USA. */ 20 21#include "as.h" 22#include "dwarf2dbg.h" 23#include "subsegs.h" 24#include "symcat.h" 25#include "opcodes/mt-desc.h" 26#include "opcodes/mt-opc.h" 27#include "cgen.h" 28#include "elf/common.h" 29#include "elf/mt.h" 30 31/* Structure to hold all of the different components 32 describing an individual instruction. */ 33typedef 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} 51mt_insn; 52 53 54const char comment_chars[] = ";"; 55const char line_comment_chars[] = "#"; 56const char line_separator_chars[] = ""; 57const char EXP_CHARS[] = "eE"; 58const char FLT_CHARS[] = "dD"; 59 60/* The target specific pseudo-ops which we support. */ 61const pseudo_typeS md_pseudo_table[] = 62{ 63 { "word", cons, 4 }, 64 { NULL, NULL, 0 } 65}; 66 67 68 69static int no_scheduling_restrictions = 0; 70 71struct option md_longopts[] = 72{ 73#define OPTION_NO_SCHED_REST (OPTION_MD_BASE) 74 { "nosched", no_argument, NULL, OPTION_NO_SCHED_REST }, 75#define OPTION_MARCH (OPTION_MD_BASE + 1) 76 { "march", required_argument, NULL, OPTION_MARCH}, 77 { NULL, no_argument, NULL, 0 }, 78}; 79size_t md_longopts_size = sizeof (md_longopts); 80 81const char * md_shortopts = ""; 82 83/* Mach selected from command line. */ 84static int mt_mach = bfd_mach_ms1; 85static unsigned mt_mach_bitmask = 1 << MACH_MS1; 86 87/* Flags to set in the elf header */ 88static flagword mt_flags = EF_MT_CPU_MRISC; 89 90/* The architecture to use. */ 91enum mt_architectures 92 { 93 ms1_64_001, 94 ms1_16_002, 95 ms1_16_003, 96 ms2 97 }; 98 99/* MT architecture we are using for this output file. */ 100static enum mt_architectures mt_arch = ms1_16_002; 101 102int 103md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg) 104{ 105 switch (c) 106 { 107 case OPTION_MARCH: 108 if (strcmp (arg, "ms1-64-001") == 0) 109 { 110 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC; 111 mt_mach = bfd_mach_ms1; 112 mt_mach_bitmask = 1 << MACH_MS1; 113 mt_arch = ms1_64_001; 114 } 115 else if (strcmp (arg, "ms1-16-002") == 0) 116 { 117 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC; 118 mt_mach = bfd_mach_ms1; 119 mt_mach_bitmask = 1 << MACH_MS1; 120 mt_arch = ms1_16_002; 121 } 122 else if (strcmp (arg, "ms1-16-003") == 0) 123 { 124 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC2; 125 mt_mach = bfd_mach_mrisc2; 126 mt_mach_bitmask = 1 << MACH_MS1_003; 127 mt_arch = ms1_16_003; 128 } 129 else if (strcmp (arg, "ms2") == 0) 130 { 131 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MS2; 132 mt_mach = bfd_mach_mrisc2; 133 mt_mach_bitmask = 1 << MACH_MS2; 134 mt_arch = ms2; 135 } 136 break; 137 case OPTION_NO_SCHED_REST: 138 no_scheduling_restrictions = 1; 139 break; 140 default: 141 return 0; 142 } 143 144 return 1; 145} 146 147 148void 149md_show_usage (FILE * stream) 150{ 151 fprintf (stream, _("MT specific command line options:\n")); 152 fprintf (stream, _(" -march=ms1-64-001 allow ms1-64-001 instructions\n")); 153 fprintf (stream, _(" -march=ms1-16-002 allow ms1-16-002 instructions (default)\n")); 154 fprintf (stream, _(" -march=ms1-16-003 allow ms1-16-003 instructions\n")); 155 fprintf (stream, _(" -march=ms2 allow ms2 instructions \n")); 156 fprintf (stream, _(" -nosched disable scheduling restrictions\n")); 157} 158 159 160void 161md_begin (void) 162{ 163 /* Initialize the `cgen' interface. */ 164 165 /* Set the machine number and endian. */ 166 gas_cgen_cpu_desc = mt_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, mt_mach_bitmask, 167 CGEN_CPU_OPEN_ENDIAN, 168 CGEN_ENDIAN_BIG, 169 CGEN_CPU_OPEN_END); 170 mt_cgen_init_asm (gas_cgen_cpu_desc); 171 172 /* This is a callback from cgen to gas to parse operands. */ 173 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand); 174 175 /* Set the ELF flags if desired. */ 176 if (mt_flags) 177 bfd_set_private_flags (stdoutput, mt_flags); 178 179 /* Set the machine type. */ 180 bfd_default_set_arch_mach (stdoutput, bfd_arch_mt, mt_mach); 181} 182 183void 184md_assemble (char * str) 185{ 186 static long delayed_load_register = 0; 187 static long prev_delayed_load_register = 0; 188 static int last_insn_had_delay_slot = 0; 189 static int last_insn_in_noncond_delay_slot = 0; 190 static int last_insn_has_load_delay = 0; 191 static int last_insn_was_memory_access = 0; 192 static int last_insn_was_io_insn = 0; 193 static int last_insn_was_arithmetic_or_logic = 0; 194 static int last_insn_was_branch_insn = 0; 195 static int last_insn_was_conditional_branch_insn = 0; 196 197 mt_insn insn; 198 char * errmsg; 199 200 /* Initialize GAS's cgen interface for a new instruction. */ 201 gas_cgen_init_parse (); 202 203 insn.insn = mt_cgen_assemble_insn 204 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg); 205 206 if (!insn.insn) 207 { 208 as_bad ("%s", errmsg); 209 return; 210 } 211 212 /* Doesn't really matter what we pass for RELAX_P here. */ 213 gas_cgen_finish_insn (insn.insn, insn.buffer, 214 CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); 215 216 217 /* Handle Scheduling Restrictions. */ 218 if (!no_scheduling_restrictions) 219 { 220 /* Detect consecutive Memory Accesses. */ 221 if (last_insn_was_memory_access 222 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS) 223 && mt_mach == ms1_64_001) 224 as_warn (_("instruction %s may not follow another memory access instruction."), 225 CGEN_INSN_NAME (insn.insn)); 226 227 /* Detect consecutive I/O Instructions. */ 228 else if (last_insn_was_io_insn 229 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN)) 230 as_warn (_("instruction %s may not follow another I/O instruction."), 231 CGEN_INSN_NAME (insn.insn)); 232 233 /* Detect consecutive branch instructions. */ 234 else if (last_insn_was_branch_insn 235 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)) 236 as_warn (_("%s may not occupy the delay slot of another branch insn."), 237 CGEN_INSN_NAME (insn.insn)); 238 239 /* Detect data dependencies on delayed loads: memory and input insns. */ 240 if (last_insn_has_load_delay && delayed_load_register) 241 { 242 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) 243 && insn.fields.f_sr1 == delayed_load_register) 244 as_warn (_("operand references R%ld of previous load."), 245 insn.fields.f_sr1); 246 247 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) 248 && insn.fields.f_sr2 == delayed_load_register) 249 as_warn (_("operand references R%ld of previous load."), 250 insn.fields.f_sr2); 251 } 252 253 /* Detect JAL/RETI hazard */ 254 if (mt_mach == ms2 255 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_JAL_HAZARD)) 256 { 257 if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) 258 && insn.fields.f_sr1 == delayed_load_register) 259 || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) 260 && insn.fields.f_sr2 == delayed_load_register)) 261 as_warn (_("operand references R%ld of previous instruction."), 262 delayed_load_register); 263 else if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) 264 && insn.fields.f_sr1 == prev_delayed_load_register) 265 || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) 266 && insn.fields.f_sr2 == prev_delayed_load_register)) 267 as_warn (_("operand references R%ld of instruction before previous."), 268 prev_delayed_load_register); 269 } 270 271 /* Detect data dependency between conditional branch instruction 272 and an immediately preceding arithmetic or logical instruction. */ 273 if (last_insn_was_arithmetic_or_logic 274 && !last_insn_in_noncond_delay_slot 275 && (delayed_load_register != 0) 276 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN) 277 && mt_arch == ms1_64_001) 278 { 279 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1) 280 && insn.fields.f_sr1 == delayed_load_register) 281 as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."), 282 insn.fields.f_sr1); 283 284 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2) 285 && insn.fields.f_sr2 == delayed_load_register) 286 as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."), 287 insn.fields.f_sr2); 288 } 289 } 290 291 /* Keep track of details of this insn for processing next insn. */ 292 last_insn_in_noncond_delay_slot = last_insn_was_branch_insn 293 && !last_insn_was_conditional_branch_insn; 294 295 last_insn_had_delay_slot = 296 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT); 297 (void) last_insn_had_delay_slot; 298 299 last_insn_has_load_delay = 300 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY); 301 302 last_insn_was_memory_access = 303 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS); 304 305 last_insn_was_io_insn = 306 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN); 307 308 last_insn_was_arithmetic_or_logic = 309 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_AL_INSN); 310 311 last_insn_was_branch_insn = 312 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN); 313 314 last_insn_was_conditional_branch_insn = 315 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN) 316 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2); 317 318 prev_delayed_load_register = delayed_load_register; 319 320 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDR)) 321 delayed_load_register = insn.fields.f_dr; 322 else if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDRRR)) 323 delayed_load_register = insn.fields.f_drrr; 324 else /* Insns has no destination register. */ 325 delayed_load_register = 0; 326 327 /* Generate dwarf2 line numbers. */ 328 dwarf2_emit_insn (4); 329} 330 331valueT 332md_section_align (segT segment, valueT size) 333{ 334 int align = bfd_get_section_alignment (stdoutput, segment); 335 336 return ((size + (1 << align) - 1) & -(1 << align)); 337} 338 339symbolS * 340md_undefined_symbol (char * name ATTRIBUTE_UNUSED) 341{ 342 return NULL; 343} 344 345int 346md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, 347 segT segment ATTRIBUTE_UNUSED) 348{ 349 as_fatal (_("md_estimate_size_before_relax\n")); 350 return 1; 351} 352 353/* *fragP has been relaxed to its final size, and now needs to have 354 the bytes inside it modified to conform to the new size. 355 356 Called after relaxation is finished. 357 fragP->fr_type == rs_machine_dependent. 358 fragP->fr_subtype is the subtype of what the address relaxed to. */ 359 360void 361md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, 362 segT sec ATTRIBUTE_UNUSED, 363 fragS * fragP ATTRIBUTE_UNUSED) 364{ 365} 366 367 368/* Functions concerning relocs. */ 369 370long 371md_pcrel_from_section (fixS *fixP, segT sec) 372{ 373 if (fixP->fx_addsy != (symbolS *) NULL 374 && (!S_IS_DEFINED (fixP->fx_addsy) 375 || S_GET_SEGMENT (fixP->fx_addsy) != sec)) 376 /* The symbol is undefined (or is defined but not in this section). 377 Let the linker figure it out. */ 378 return 0; 379 380 /* Return the address of the opcode - cgen adjusts for opcode size 381 itself, to be consistent with the disassembler, which must do 382 so. */ 383 return fixP->fx_where + fixP->fx_frag->fr_address; 384} 385 386 387/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP. 388 Returns BFD_RELOC_NONE if no reloc type can be found. 389 *FIXP may be modified if desired. */ 390 391bfd_reloc_code_real_type 392md_cgen_lookup_reloc (const CGEN_INSN * insn ATTRIBUTE_UNUSED, 393 const CGEN_OPERAND * operand, 394 fixS * fixP ATTRIBUTE_UNUSED) 395{ 396 bfd_reloc_code_real_type result; 397 398 result = BFD_RELOC_NONE; 399 400 switch (operand->type) 401 { 402 case MT_OPERAND_IMM16O: 403 result = BFD_RELOC_16_PCREL; 404 fixP->fx_pcrel = 1; 405 /* fixP->fx_no_overflow = 1; */ 406 break; 407 case MT_OPERAND_IMM16: 408 case MT_OPERAND_IMM16Z: 409 /* These may have been processed at parse time. */ 410 if (fixP->fx_cgen.opinfo != 0) 411 result = fixP->fx_cgen.opinfo; 412 fixP->fx_no_overflow = 1; 413 break; 414 case MT_OPERAND_LOOPSIZE: 415 result = BFD_RELOC_MT_PCINSN8; 416 fixP->fx_pcrel = 1; 417 /* Adjust for the delay slot, which is not part of the loop */ 418 fixP->fx_offset -= 8; 419 break; 420 default: 421 result = BFD_RELOC_NONE; 422 break; 423 } 424 425 return result; 426} 427 428/* Write a value out to the object file, using the appropriate endianness. */ 429 430void 431md_number_to_chars (char * buf, valueT val, int n) 432{ 433 number_to_chars_bigendian (buf, val, n); 434} 435 436const char * 437md_atof (int type, char * litP, int * sizeP) 438{ 439 return ieee_md_atof (type, litP, sizeP, FALSE); 440} 441 442/* See whether we need to force a relocation into the output file. */ 443 444int 445mt_force_relocation (fixS * fixp ATTRIBUTE_UNUSED) 446{ 447 return 0; 448} 449 450void 451mt_apply_fix (fixS *fixP, valueT *valueP, segT seg) 452{ 453 if ((fixP->fx_pcrel != 0) && (fixP->fx_r_type == BFD_RELOC_32)) 454 fixP->fx_r_type = BFD_RELOC_32_PCREL; 455 456 gas_cgen_md_apply_fix (fixP, valueP, seg); 457} 458 459bfd_boolean 460mt_fix_adjustable (fixS * fixP) 461{ 462 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) 463 { 464 const CGEN_INSN *insn = NULL; 465 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; 466 const CGEN_OPERAND *operand; 467 468 operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex); 469 md_cgen_lookup_reloc (insn, operand, fixP); 470 } 471 472 if (fixP->fx_addsy == NULL) 473 return TRUE; 474 475 /* Prevent all adjustments to global symbols. */ 476 if (S_IS_EXTERNAL (fixP->fx_addsy)) 477 return FALSE; 478 479 if (S_IS_WEAK (fixP->fx_addsy)) 480 return FALSE; 481 482 return 1; 483} 484