1214571Sdim/* tc-mep.c -- Assembler for the Toshiba Media Processor. 2214571Sdim Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation. 3214571Sdim 4214571Sdim This file is part of GAS, the GNU Assembler. 5214571Sdim 6214571Sdim GAS is free software; you can redistribute it and/or modify 7214571Sdim it under the terms of the GNU General Public License as published by 8214571Sdim the Free Software Foundation; either version 2, or (at your option) 9214571Sdim any later version. 10214571Sdim 11214571Sdim GAS is distributed in the hope that it will be useful, 12214571Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 13214571Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14214571Sdim GNU General Public License for more details. 15214571Sdim 16214571Sdim You should have received a copy of the GNU General Public License 17214571Sdim along with GAS; see the file COPYING. If not, write to 18214571Sdim the Free Software Foundation, 51 Franklin Street, Fifth Floor, 19214571Sdim Boston, MA 02110-1301, USA. */ 20214571Sdim 21214571Sdim#include <stdio.h> 22214571Sdim#include "as.h" 23214571Sdim#include "dwarf2dbg.h" 24214571Sdim#include "subsegs.h" 25214571Sdim#include "symcat.h" 26214571Sdim#include "opcodes/mep-desc.h" 27214571Sdim#include "opcodes/mep-opc.h" 28214571Sdim#include "cgen.h" 29214571Sdim#include "elf/common.h" 30214571Sdim#include "elf/mep.h" 31214571Sdim#include "libbfd.h" 32214571Sdim#include "xregex.h" 33214571Sdim 34214571Sdim/* Structure to hold all of the different components describing 35214571Sdim an individual instruction. */ 36214571Sdimtypedef struct 37214571Sdim{ 38214571Sdim const CGEN_INSN * insn; 39214571Sdim const CGEN_INSN * orig_insn; 40214571Sdim CGEN_FIELDS fields; 41214571Sdim#if CGEN_INT_INSN_P 42214571Sdim CGEN_INSN_INT buffer [1]; 43214571Sdim#define INSN_VALUE(buf) (*(buf)) 44214571Sdim#else 45214571Sdim unsigned char buffer [CGEN_MAX_INSN_SIZE]; 46214571Sdim#define INSN_VALUE(buf) (buf) 47214571Sdim#endif 48214571Sdim char * addr; 49214571Sdim fragS * frag; 50214571Sdim int num_fixups; 51214571Sdim fixS * fixups [GAS_CGEN_MAX_FIXUPS]; 52214571Sdim int indices [MAX_OPERAND_INSTANCES]; 53214571Sdim} mep_insn; 54214571Sdim 55214571Sdimstatic int mode = CORE; /* Start in core mode. */ 56214571Sdimstatic int pluspresent = 0; 57214571Sdimstatic int allow_disabled_registers = 0; 58214571Sdimstatic int library_flag = 0; 59214571Sdim 60214571Sdim/* We're going to need to store all of the instructions along with 61214571Sdim their fixups so that we can parallelization grouping rules. */ 62214571Sdim 63214571Sdimstatic mep_insn saved_insns[MAX_SAVED_FIXUP_CHAINS]; 64214571Sdimstatic int num_insns_saved = 0; 65214571Sdim 66214571Sdimconst char comment_chars[] = "#"; 67214571Sdimconst char line_comment_chars[] = ";#"; 68214571Sdimconst char line_separator_chars[] = ";"; 69214571Sdimconst char EXP_CHARS[] = "eE"; 70214571Sdimconst char FLT_CHARS[] = "dD"; 71214571Sdim 72214571Sdimstatic void mep_switch_to_vliw_mode (int); 73214571Sdimstatic void mep_switch_to_core_mode (int); 74214571Sdimstatic void mep_s_vtext (int); 75214571Sdimstatic void mep_noregerr (int); 76214571Sdim 77214571Sdim/* The target specific pseudo-ops which we support. */ 78214571Sdimconst pseudo_typeS md_pseudo_table[] = 79214571Sdim{ 80214571Sdim { "word", cons, 4 }, 81214571Sdim { "file", (void (*) (int)) dwarf2_directive_file, 0 }, 82214571Sdim { "loc", dwarf2_directive_loc, 0 }, 83214571Sdim { "vliw", mep_switch_to_vliw_mode, 0 }, 84214571Sdim { "core", mep_switch_to_core_mode, 0 }, 85214571Sdim { "vtext", mep_s_vtext, 0 }, 86214571Sdim { "noregerr", mep_noregerr, 0 }, 87214571Sdim { NULL, NULL, 0 } 88214571Sdim}; 89214571Sdim 90214571Sdim/* Relocations against symbols are done in two 91214571Sdim parts, with a HI relocation and a LO relocation. Each relocation 92214571Sdim has only 16 bits of space to store an addend. This means that in 93214571Sdim order for the linker to handle carries correctly, it must be able 94214571Sdim to locate both the HI and the LO relocation. This means that the 95214571Sdim relocations must appear in order in the relocation table. 96214571Sdim 97214571Sdim In order to implement this, we keep track of each unmatched HI 98214571Sdim relocation. We then sort them so that they immediately precede the 99214571Sdim corresponding LO relocation. */ 100214571Sdim 101214571Sdimstruct mep_hi_fixup 102214571Sdim{ 103214571Sdim struct mep_hi_fixup * next; /* Next HI fixup. */ 104214571Sdim fixS * fixp; /* This fixup. */ 105214571Sdim segT seg; /* The section this fixup is in. */ 106214571Sdim}; 107214571Sdim 108214571Sdim/* The list of unmatched HI relocs. */ 109214571Sdimstatic struct mep_hi_fixup * mep_hi_fixup_list; 110214571Sdim 111214571Sdim 112214571Sdim#define OPTION_EB (OPTION_MD_BASE + 0) 113214571Sdim#define OPTION_EL (OPTION_MD_BASE + 1) 114214571Sdim#define OPTION_CONFIG (OPTION_MD_BASE + 2) 115214571Sdim#define OPTION_AVERAGE (OPTION_MD_BASE + 3) 116214571Sdim#define OPTION_NOAVERAGE (OPTION_MD_BASE + 4) 117214571Sdim#define OPTION_MULT (OPTION_MD_BASE + 5) 118214571Sdim#define OPTION_NOMULT (OPTION_MD_BASE + 6) 119214571Sdim#define OPTION_DIV (OPTION_MD_BASE + 7) 120214571Sdim#define OPTION_NODIV (OPTION_MD_BASE + 8) 121214571Sdim#define OPTION_BITOPS (OPTION_MD_BASE + 9) 122214571Sdim#define OPTION_NOBITOPS (OPTION_MD_BASE + 10) 123214571Sdim#define OPTION_LEADZ (OPTION_MD_BASE + 11) 124214571Sdim#define OPTION_NOLEADZ (OPTION_MD_BASE + 12) 125214571Sdim#define OPTION_ABSDIFF (OPTION_MD_BASE + 13) 126214571Sdim#define OPTION_NOABSDIFF (OPTION_MD_BASE + 14) 127214571Sdim#define OPTION_MINMAX (OPTION_MD_BASE + 15) 128214571Sdim#define OPTION_NOMINMAX (OPTION_MD_BASE + 16) 129214571Sdim#define OPTION_CLIP (OPTION_MD_BASE + 17) 130214571Sdim#define OPTION_NOCLIP (OPTION_MD_BASE + 18) 131214571Sdim#define OPTION_SATUR (OPTION_MD_BASE + 19) 132214571Sdim#define OPTION_NOSATUR (OPTION_MD_BASE + 20) 133214571Sdim#define OPTION_COP32 (OPTION_MD_BASE + 21) 134214571Sdim#define OPTION_REPEAT (OPTION_MD_BASE + 25) 135214571Sdim#define OPTION_NOREPEAT (OPTION_MD_BASE + 26) 136214571Sdim#define OPTION_DEBUG (OPTION_MD_BASE + 27) 137214571Sdim#define OPTION_NODEBUG (OPTION_MD_BASE + 28) 138214571Sdim#define OPTION_LIBRARY (OPTION_MD_BASE + 29) 139214571Sdim 140214571Sdimstruct option md_longopts[] = { 141214571Sdim { "EB", no_argument, NULL, OPTION_EB}, 142214571Sdim { "EL", no_argument, NULL, OPTION_EL}, 143214571Sdim { "mconfig", required_argument, NULL, OPTION_CONFIG}, 144214571Sdim { "maverage", no_argument, NULL, OPTION_AVERAGE}, 145214571Sdim { "mno-average", no_argument, NULL, OPTION_NOAVERAGE}, 146214571Sdim { "mmult", no_argument, NULL, OPTION_MULT}, 147214571Sdim { "mno-mult", no_argument, NULL, OPTION_NOMULT}, 148214571Sdim { "mdiv", no_argument, NULL, OPTION_DIV}, 149214571Sdim { "mno-div", no_argument, NULL, OPTION_NODIV}, 150214571Sdim { "mbitops", no_argument, NULL, OPTION_BITOPS}, 151214571Sdim { "mno-bitops", no_argument, NULL, OPTION_NOBITOPS}, 152214571Sdim { "mleadz", no_argument, NULL, OPTION_LEADZ}, 153214571Sdim { "mno-leadz", no_argument, NULL, OPTION_NOLEADZ}, 154214571Sdim { "mabsdiff", no_argument, NULL, OPTION_ABSDIFF}, 155214571Sdim { "mno-absdiff", no_argument, NULL, OPTION_NOABSDIFF}, 156214571Sdim { "mminmax", no_argument, NULL, OPTION_MINMAX}, 157214571Sdim { "mno-minmax", no_argument, NULL, OPTION_NOMINMAX}, 158214571Sdim { "mclip", no_argument, NULL, OPTION_CLIP}, 159214571Sdim { "mno-clip", no_argument, NULL, OPTION_NOCLIP}, 160214571Sdim { "msatur", no_argument, NULL, OPTION_SATUR}, 161214571Sdim { "mno-satur", no_argument, NULL, OPTION_NOSATUR}, 162214571Sdim { "mcop32", no_argument, NULL, OPTION_COP32}, 163214571Sdim { "mdebug", no_argument, NULL, OPTION_DEBUG}, 164214571Sdim { "mno-debug", no_argument, NULL, OPTION_NODEBUG}, 165214571Sdim { "mlibrary", no_argument, NULL, OPTION_LIBRARY}, 166214571Sdim { NULL, 0, NULL, 0 } }; 167214571Sdimsize_t md_longopts_size = sizeof (md_longopts); 168214571Sdim 169214571Sdimconst char * md_shortopts = ""; 170214571Sdimstatic int optbits = 0; 171214571Sdimstatic int optbitset = 0; 172214571Sdim 173214571Sdimint 174214571Sdimmd_parse_option (int c, char *arg ATTRIBUTE_UNUSED) 175214571Sdim{ 176214571Sdim int i, idx; 177214571Sdim switch (c) 178214571Sdim { 179214571Sdim case OPTION_EB: 180214571Sdim target_big_endian = 1; 181214571Sdim break; 182214571Sdim case OPTION_EL: 183214571Sdim target_big_endian = 0; 184214571Sdim break; 185214571Sdim case OPTION_CONFIG: 186214571Sdim idx = 0; 187214571Sdim for (i=1; mep_config_map[i].name; i++) 188214571Sdim if (strcmp (mep_config_map[i].name, arg) == 0) 189214571Sdim { 190214571Sdim idx = i; 191214571Sdim break; 192214571Sdim } 193214571Sdim if (!idx) 194214571Sdim { 195214571Sdim fprintf (stderr, "Error: unknown configuration %s\n", arg); 196214571Sdim return 0; 197214571Sdim } 198214571Sdim mep_config_index = idx; 199214571Sdim target_big_endian = mep_config_map[idx].big_endian; 200214571Sdim break; 201214571Sdim case OPTION_AVERAGE: 202214571Sdim optbits |= 1 << CGEN_INSN_OPTIONAL_AVE_INSN; 203214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_AVE_INSN; 204214571Sdim break; 205214571Sdim case OPTION_NOAVERAGE: 206214571Sdim optbits &= ~(1 << CGEN_INSN_OPTIONAL_AVE_INSN); 207214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_AVE_INSN; 208214571Sdim break; 209214571Sdim case OPTION_MULT: 210214571Sdim optbits |= 1 << CGEN_INSN_OPTIONAL_MUL_INSN; 211214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_MUL_INSN; 212214571Sdim break; 213214571Sdim case OPTION_NOMULT: 214214571Sdim optbits &= ~(1 << CGEN_INSN_OPTIONAL_MUL_INSN); 215214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_MUL_INSN; 216214571Sdim break; 217214571Sdim case OPTION_DIV: 218214571Sdim optbits |= 1 << CGEN_INSN_OPTIONAL_DIV_INSN; 219214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_DIV_INSN; 220214571Sdim break; 221214571Sdim case OPTION_NODIV: 222214571Sdim optbits &= ~(1 << CGEN_INSN_OPTIONAL_DIV_INSN); 223214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_DIV_INSN; 224214571Sdim break; 225214571Sdim case OPTION_BITOPS: 226214571Sdim optbits |= 1 << CGEN_INSN_OPTIONAL_BIT_INSN; 227214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_BIT_INSN; 228214571Sdim break; 229214571Sdim case OPTION_NOBITOPS: 230214571Sdim optbits &= ~(1 << CGEN_INSN_OPTIONAL_BIT_INSN); 231214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_BIT_INSN; 232214571Sdim break; 233214571Sdim case OPTION_LEADZ: 234214571Sdim optbits |= 1 << CGEN_INSN_OPTIONAL_LDZ_INSN; 235214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_LDZ_INSN; 236214571Sdim break; 237214571Sdim case OPTION_NOLEADZ: 238214571Sdim optbits &= ~(1 << CGEN_INSN_OPTIONAL_LDZ_INSN); 239214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_LDZ_INSN; 240214571Sdim break; 241214571Sdim case OPTION_ABSDIFF: 242214571Sdim optbits |= 1 << CGEN_INSN_OPTIONAL_ABS_INSN; 243214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_ABS_INSN; 244214571Sdim break; 245214571Sdim case OPTION_NOABSDIFF: 246214571Sdim optbits &= ~(1 << CGEN_INSN_OPTIONAL_ABS_INSN); 247214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_ABS_INSN; 248214571Sdim break; 249214571Sdim case OPTION_MINMAX: 250214571Sdim optbits |= 1 << CGEN_INSN_OPTIONAL_MINMAX_INSN; 251214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_MINMAX_INSN; 252214571Sdim break; 253214571Sdim case OPTION_NOMINMAX: 254214571Sdim optbits &= ~(1 << CGEN_INSN_OPTIONAL_MINMAX_INSN); 255214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_MINMAX_INSN; 256214571Sdim break; 257214571Sdim case OPTION_CLIP: 258214571Sdim optbits |= 1 << CGEN_INSN_OPTIONAL_CLIP_INSN; 259214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_CLIP_INSN; 260214571Sdim break; 261214571Sdim case OPTION_NOCLIP: 262214571Sdim optbits &= ~(1 << CGEN_INSN_OPTIONAL_CLIP_INSN); 263214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_CLIP_INSN; 264214571Sdim break; 265214571Sdim case OPTION_SATUR: 266214571Sdim optbits |= 1 << CGEN_INSN_OPTIONAL_SAT_INSN; 267214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_SAT_INSN; 268214571Sdim break; 269214571Sdim case OPTION_NOSATUR: 270214571Sdim optbits &= ~(1 << CGEN_INSN_OPTIONAL_SAT_INSN); 271214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_SAT_INSN; 272214571Sdim break; 273214571Sdim case OPTION_COP32: 274214571Sdim optbits |= 1 << CGEN_INSN_OPTIONAL_CP_INSN; 275214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_CP_INSN; 276214571Sdim break; 277214571Sdim case OPTION_DEBUG: 278214571Sdim optbits |= 1 << CGEN_INSN_OPTIONAL_DEBUG_INSN; 279214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_DEBUG_INSN; 280214571Sdim break; 281214571Sdim case OPTION_NODEBUG: 282214571Sdim optbits &= ~(1 << CGEN_INSN_OPTIONAL_DEBUG_INSN); 283214571Sdim optbitset |= 1 << CGEN_INSN_OPTIONAL_DEBUG_INSN; 284214571Sdim break; 285214571Sdim case OPTION_LIBRARY: 286214571Sdim library_flag = EF_MEP_LIBRARY; 287214571Sdim break; 288214571Sdim case OPTION_REPEAT: 289214571Sdim case OPTION_NOREPEAT: 290214571Sdim break; 291214571Sdim default: 292214571Sdim return 0; 293214571Sdim } 294214571Sdim return 1; 295214571Sdim} 296214571Sdim 297214571Sdimvoid 298214571Sdimmd_show_usage (FILE *stream) 299214571Sdim{ 300214571Sdim fprintf (stream, _("MeP specific command line options:\n\ 301214571Sdim -EB assemble for a big endian system (default)\n\ 302214571Sdim -EL assemble for a little endian system\n\ 303214571Sdim -mconfig=<name> specify a chip configuration to use\n\ 304214571Sdim -maverage -mno-average -mmult -mno-mult -mdiv -mno-div\n\ 305214571Sdim -mbitops -mno-bitops -mleadz -mno-leadz -mabsdiff -mno-absdiff\n\ 306214571Sdim -mminmax -mno-minmax -mclip -mno-clip -msatur -mno-satur -mcop32\n\ 307214571Sdim enable/disable the given opcodes\n\ 308214571Sdim\n\ 309214571Sdim If -mconfig is given, the other -m options modify it. Otherwise,\n\ 310214571Sdim if no -m options are given, all core opcodes are enabled;\n\ 311214571Sdim if any enabling -m options are given, only those are enabled;\n\ 312214571Sdim if only disabling -m options are given, only those are disabled.\n\ 313214571Sdim")); 314214571Sdim if (mep_config_map[1].name) 315214571Sdim { 316214571Sdim int i; 317214571Sdim fprintf (stream, " -mconfig=STR specify the configuration to use\n"); 318214571Sdim fprintf (stream, " Configurations:"); 319214571Sdim for (i=0; mep_config_map[i].name; i++) 320214571Sdim fprintf (stream, " %s", mep_config_map[i].name); 321214571Sdim fprintf (stream, "\n"); 322214571Sdim } 323214571Sdim} 324214571Sdim 325214571Sdim 326214571Sdim 327214571Sdimstatic void 328214571Sdimmep_check_for_disabled_registers (mep_insn *insn) 329214571Sdim{ 330214571Sdim static int initted = 0; 331214571Sdim static int has_mul_div = 0; 332214571Sdim static int has_cop = 0; 333214571Sdim static int has_debug = 0; 334214571Sdim unsigned int b, r; 335214571Sdim 336214571Sdim if (allow_disabled_registers) 337214571Sdim return; 338214571Sdim 339214571Sdim#if !CGEN_INT_INSN_P 340214571Sdim if (target_big_endian) 341214571Sdim b = insn->buffer[0] * 256 + insn->buffer[1]; 342214571Sdim else 343214571Sdim b = insn->buffer[1] * 256 + insn->buffer[0]; 344214571Sdim#else 345214571Sdim b = insn->buffer[0]; 346214571Sdim#endif 347214571Sdim 348214571Sdim if ((b & 0xfffff00e) == 0x7008 /* stc */ 349214571Sdim || (b & 0xfffff00e) == 0x700a /* ldc */) 350214571Sdim { 351214571Sdim if (!initted) 352214571Sdim { 353214571Sdim initted = 1; 354214571Sdim if ((MEP_OMASK & (1 << CGEN_INSN_OPTIONAL_MUL_INSN)) 355214571Sdim || (MEP_OMASK & (1 << CGEN_INSN_OPTIONAL_DIV_INSN))) 356214571Sdim has_mul_div = 1; 357214571Sdim if (MEP_OMASK & (1 << CGEN_INSN_OPTIONAL_DEBUG_INSN)) 358214571Sdim has_debug = 1; 359214571Sdim if (MEP_OMASK & (1 << CGEN_INSN_OPTIONAL_CP_INSN)) 360214571Sdim has_cop = 1; 361214571Sdim } 362214571Sdim 363214571Sdim r = ((b & 0x00f0) >> 4) | ((b & 0x0001) << 4); 364214571Sdim switch (r) 365214571Sdim { 366214571Sdim case 7: /* $hi */ 367214571Sdim case 8: /* $lo */ 368214571Sdim if (!has_mul_div) 369214571Sdim as_bad ("$hi and $lo are disabled when MUL and DIV are off"); 370214571Sdim break; 371214571Sdim case 12: /* $mb0 */ 372214571Sdim case 13: /* $me0 */ 373214571Sdim case 14: /* $mb1 */ 374214571Sdim case 15: /* $me1 */ 375214571Sdim if (!has_cop) 376214571Sdim as_bad ("$mb0, $me0, $mb1, and $me1 are disabled when COP is off"); 377214571Sdim break; 378214571Sdim case 24: /* $dbg */ 379214571Sdim case 25: /* $depc */ 380214571Sdim if (!has_debug) 381214571Sdim as_bad ("$dbg and $depc are disabled when DEBUG is off"); 382214571Sdim break; 383214571Sdim } 384214571Sdim } 385214571Sdim} 386214571Sdim 387214571Sdimstatic int 388214571Sdimmep_machine (void) 389214571Sdim{ 390214571Sdim switch (MEP_CPU) 391214571Sdim { 392214571Sdim default: break; 393214571Sdim case EF_MEP_CPU_C2: return bfd_mach_mep; 394214571Sdim case EF_MEP_CPU_C3: return bfd_mach_mep; 395214571Sdim case EF_MEP_CPU_C4: return bfd_mach_mep; 396214571Sdim case EF_MEP_CPU_H1: return bfd_mach_mep_h1; 397214571Sdim } 398214571Sdim 399214571Sdim return bfd_mach_mep; 400214571Sdim} 401214571Sdim 402214571Sdim/* The MeP version of the cgen parse_operand function. The only difference 403214571Sdim from the standard version is that we want to avoid treating '$foo' and 404214571Sdim '($foo...)' as references to a symbol called '$foo'. The chances are 405214571Sdim that '$foo' is really a misspelt register. */ 406214571Sdim 407214571Sdimstatic const char * 408214571Sdimmep_parse_operand (CGEN_CPU_DESC cd, enum cgen_parse_operand_type want, 409214571Sdim const char **strP, int opindex, int opinfo, 410214571Sdim enum cgen_parse_operand_result *resultP, bfd_vma *valueP) 411214571Sdim{ 412214571Sdim if (want == CGEN_PARSE_OPERAND_INTEGER || want == CGEN_PARSE_OPERAND_ADDRESS) 413214571Sdim { 414214571Sdim const char *next; 415214571Sdim 416214571Sdim next = *strP; 417214571Sdim while (*next == '(') 418214571Sdim next++; 419214571Sdim if (*next == '$') 420214571Sdim return "Not a valid literal"; 421214571Sdim } 422214571Sdim return gas_cgen_parse_operand (cd, want, strP, opindex, opinfo, 423214571Sdim resultP, valueP); 424214571Sdim} 425214571Sdim 426214571Sdimvoid 427214571Sdimmd_begin () 428214571Sdim{ 429214571Sdim /* Initialize the `cgen' interface. */ 430214571Sdim 431214571Sdim /* If the user specifies no options, we default to allowing 432214571Sdim everything. If the user specifies any enabling options, we 433214571Sdim default to allowing only what is specified. If the user 434214571Sdim specifies only disabling options, we only disable what is 435214571Sdim specified. If the user specifies options and a config, the 436214571Sdim options modify the config. */ 437214571Sdim if (optbits && mep_config_index == 0) 438214571Sdim MEP_OMASK = optbits; 439214571Sdim else 440214571Sdim MEP_OMASK = (MEP_OMASK & ~optbitset) | optbits; 441214571Sdim 442214571Sdim /* Set the machine number and endian. */ 443214571Sdim gas_cgen_cpu_desc = mep_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, 0, 444214571Sdim CGEN_CPU_OPEN_ENDIAN, 445214571Sdim target_big_endian 446214571Sdim ? CGEN_ENDIAN_BIG 447214571Sdim : CGEN_ENDIAN_LITTLE, 448214571Sdim CGEN_CPU_OPEN_ISAS, 0, 449214571Sdim CGEN_CPU_OPEN_END); 450214571Sdim mep_cgen_init_asm (gas_cgen_cpu_desc); 451214571Sdim 452214571Sdim /* This is a callback from cgen to gas to parse operands. */ 453214571Sdim cgen_set_parse_operand_fn (gas_cgen_cpu_desc, mep_parse_operand); 454214571Sdim 455214571Sdim /* Identify the architecture. */ 456214571Sdim bfd_default_set_arch_mach (stdoutput, bfd_arch_mep, mep_machine ()); 457214571Sdim 458214571Sdim /* Store the configuration number and core. */ 459214571Sdim bfd_set_private_flags (stdoutput, MEP_CPU | MEP_CONFIG | library_flag); 460214571Sdim 461214571Sdim /* Initialize the array we'll be using to store fixups. */ 462214571Sdim gas_cgen_initialize_saved_fixups_array(); 463214571Sdim} 464214571Sdim 465214571Sdim/* Variant of mep_cgen_assemble_insn. Assemble insn STR of cpu CD as a 466214571Sdim coprocessor instruction, if possible, into FIELDS, BUF, and INSN. */ 467214571Sdim 468214571Sdimstatic const CGEN_INSN * 469214571Sdimmep_cgen_assemble_cop_insn (CGEN_CPU_DESC cd, 470214571Sdim const char *str, 471214571Sdim CGEN_FIELDS *fields, 472214571Sdim CGEN_INSN_BYTES_PTR buf, 473214571Sdim const struct cgen_insn *pinsn) 474214571Sdim{ 475214571Sdim const char *start; 476214571Sdim CGEN_INSN_LIST *ilist; 477214571Sdim const char *errmsg = NULL; 478214571Sdim 479214571Sdim /* The instructions are stored in hashed lists. */ 480214571Sdim ilist = CGEN_ASM_LOOKUP_INSN (gas_cgen_cpu_desc, 481214571Sdim CGEN_INSN_MNEMONIC (pinsn)); 482214571Sdim 483214571Sdim start = str; 484214571Sdim for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist)) 485214571Sdim { 486214571Sdim const CGEN_INSN *insn = ilist->insn; 487214571Sdim if (strcmp (CGEN_INSN_MNEMONIC (ilist->insn), 488214571Sdim CGEN_INSN_MNEMONIC (pinsn)) == 0 489214571Sdim && MEP_INSN_COP_P (ilist->insn) 490214571Sdim && mep_cgen_insn_supported (cd, insn)) 491214571Sdim { 492214571Sdim str = start; 493214571Sdim 494214571Sdim /* skip this insn if str doesn't look right lexically */ 495214571Sdim if (CGEN_INSN_RX (insn) != NULL && 496214571Sdim regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH) 497214571Sdim continue; 498214571Sdim 499214571Sdim /* Allow parse/insert handlers to obtain length of insn. */ 500214571Sdim CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn); 501214571Sdim 502214571Sdim errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields); 503214571Sdim if (errmsg != NULL) 504214571Sdim continue; 505214571Sdim 506214571Sdim errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf, 507214571Sdim (bfd_vma) 0); 508214571Sdim if (errmsg != NULL) 509214571Sdim continue; 510214571Sdim 511214571Sdim return insn; 512214571Sdim } 513214571Sdim } 514214571Sdim return pinsn; 515214571Sdim} 516214571Sdim 517214571Sdimstatic void 518214571Sdimmep_save_insn (mep_insn insn) 519214571Sdim{ 520214571Sdim /* Consider change MAX_SAVED_FIXUP_CHAINS to MAX_PARALLEL_INSNS. */ 521214571Sdim if (num_insns_saved < 0 || num_insns_saved >= MAX_SAVED_FIXUP_CHAINS) 522214571Sdim { 523214571Sdim as_fatal("index into saved_insns[] out of bounds."); 524214571Sdim return; 525214571Sdim } 526214571Sdim saved_insns[num_insns_saved] = insn; 527214571Sdim gas_cgen_save_fixups(num_insns_saved); 528214571Sdim num_insns_saved++; 529214571Sdim} 530214571Sdim 531214571Sdimstatic void 532214571Sdimmep_check_parallel32_scheduling (void) 533214571Sdim{ 534214571Sdim int insn0iscopro, insn1iscopro, insn0length, insn1length; 535214571Sdim 536214571Sdim /* More than two instructions means that either someone is referring to 537214571Sdim an internally parallel core or an internally parallel coprocessor, 538214571Sdim neither of which are supported at this time. */ 539214571Sdim if ( num_insns_saved > 2 ) 540214571Sdim as_fatal("Internally paralled cores and coprocessors not supported."); 541214571Sdim 542214571Sdim /* If there are no insns saved, that's ok. Just return. This will 543214571Sdim happen when mep_process_saved_insns is called when the end of the 544214571Sdim source file is reached and there are no insns left to be processed. */ 545214571Sdim if (num_insns_saved == 0) 546214571Sdim return; 547214571Sdim 548214571Sdim /* Check some of the attributes of the first insn. */ 549214571Sdim insn0iscopro = MEP_INSN_COP_P (saved_insns[0].insn); 550214571Sdim insn0length = CGEN_FIELDS_BITSIZE (& saved_insns[0].fields); 551214571Sdim 552214571Sdim if (num_insns_saved == 2) 553214571Sdim { 554214571Sdim /* Check some of the attributes of the first insn. */ 555214571Sdim insn1iscopro = MEP_INSN_COP_P (saved_insns[1].insn); 556214571Sdim insn1length = CGEN_FIELDS_BITSIZE (& saved_insns[1].fields); 557214571Sdim 558214571Sdim if ((insn0iscopro && !insn1iscopro) 559214571Sdim || (insn1iscopro && !insn0iscopro)) 560214571Sdim { 561214571Sdim /* We have one core and one copro insn. If their sizes 562214571Sdim add up to 32, then the combination is valid. */ 563214571Sdim if (insn0length + insn1length == 32) 564214571Sdim return; 565214571Sdim else 566214571Sdim as_bad ("core and copro insn lengths must total 32 bits."); 567214571Sdim } 568214571Sdim else 569214571Sdim as_bad ("vliw group must consist of 1 core and 1 copro insn."); 570214571Sdim } 571214571Sdim else 572214571Sdim { 573214571Sdim /* If we arrive here, we have one saved instruction. There are a 574214571Sdim number of possible cases: 575214571Sdim 576214571Sdim 1. The instruction is a 32 bit core or coprocessor insn and 577214571Sdim can be executed by itself. Valid. 578214571Sdim 579214571Sdim 2. The instrucion is a core instruction for which a cop nop 580214571Sdim exists. In this case, insert the cop nop into the saved 581214571Sdim insn array after the core insn and return. Valid. 582214571Sdim 583214571Sdim 3. The instruction is a coprocessor insn for which a core nop 584214571Sdim exists. In this case, move the coprocessor insn to the 585214571Sdim second element of the array and put the nop in the first 586214571Sdim element then return. Valid. 587214571Sdim 588214571Sdim 4. The instruction is a core or coprocessor instruction for 589214571Sdim which there is no matching coprocessor or core nop to use 590214571Sdim to form a valid vliw insn combination. In this case, we 591214571Sdim we have to abort. */ 592214571Sdim 593214571Sdim if (insn0length > 32) 594214571Sdim as_fatal ("Cannot use 48- or 64-bit insns with a 32 bit datapath."); 595214571Sdim 596214571Sdim if (insn0length == 32) 597214571Sdim return; 598214571Sdim 599214571Sdim /* Insn is smaller than datapath. If there are no matching 600214571Sdim nops for this insn, then terminate assembly. */ 601214571Sdim if (CGEN_INSN_ATTR_VALUE (saved_insns[0].insn, 602214571Sdim CGEN_INSN_VLIW32_NO_MATCHING_NOP)) 603214571Sdim as_fatal ("No valid nop."); 604214571Sdim 605214571Sdim /* At this point we know that we have a single 16-bit insn that has 606214571Sdim a matching nop. We have to assemble it and put it into the saved 607214571Sdim insn and fixup chain arrays. */ 608214571Sdim 609214571Sdim if (insn0iscopro) 610214571Sdim { 611214571Sdim char *errmsg; 612214571Sdim mep_insn insn; 613214571Sdim 614214571Sdim /* Move the insn and it's fixups to the second element of the 615214571Sdim saved insns arrary and insert a 16 bit core nope into the 616214571Sdim first element. */ 617214571Sdim insn.insn = mep_cgen_assemble_insn (gas_cgen_cpu_desc, "nop", 618214571Sdim &insn.fields, insn.buffer, 619214571Sdim &errmsg); 620214571Sdim if (!insn.insn) 621214571Sdim { 622214571Sdim as_bad ("%s", errmsg); 623214571Sdim return; 624214571Sdim } 625214571Sdim 626214571Sdim /* Move the insn in element 0 to element 1 and insert the 627214571Sdim nop into element 0. Move the fixups in element 0 to 628214571Sdim element 1 and save the current fixups to element 0. 629214571Sdim Really there aren't any fixups at this point because we're 630214571Sdim inserting a nop but we might as well be general so that 631214571Sdim if there's ever a need to insert a general insn, we'll 632214571Sdim have an example. */ 633214571Sdim saved_insns[1] = saved_insns[0]; 634214571Sdim saved_insns[0] = insn; 635214571Sdim num_insns_saved++; 636214571Sdim gas_cgen_swap_fixups (0); 637214571Sdim gas_cgen_save_fixups (1); 638214571Sdim } 639214571Sdim else 640214571Sdim { 641214571Sdim char * errmsg; 642214571Sdim mep_insn insn; 643214571Sdim int insn_num = saved_insns[0].insn->base->num; 644214571Sdim 645214571Sdim /* Use 32 bit branches and skip the nop. */ 646214571Sdim if (insn_num == MEP_INSN_BSR12 647214571Sdim || insn_num == MEP_INSN_BEQZ 648214571Sdim || insn_num == MEP_INSN_BNEZ) 649214571Sdim return; 650214571Sdim 651214571Sdim /* Insert a 16-bit coprocessor nop. Note that at the time */ 652214571Sdim /* this was done, no 16-bit coprocessor nop was defined. */ 653214571Sdim insn.insn = mep_cgen_assemble_insn (gas_cgen_cpu_desc, "cpnop16", 654214571Sdim &insn.fields, insn.buffer, 655214571Sdim &errmsg); 656214571Sdim if (!insn.insn) 657214571Sdim { 658214571Sdim as_bad ("%s", errmsg); 659214571Sdim return; 660214571Sdim } 661214571Sdim 662214571Sdim /* Now put the insn and fixups into the arrays. */ 663214571Sdim mep_save_insn (insn); 664214571Sdim } 665214571Sdim } 666214571Sdim} 667214571Sdim 668214571Sdimstatic void 669214571Sdimmep_check_parallel64_scheduling (void) 670214571Sdim{ 671214571Sdim int insn0iscopro, insn1iscopro, insn0length, insn1length; 672214571Sdim 673214571Sdim /* More than two instructions means that someone is referring to an 674214571Sdim internally parallel core or an internally parallel coprocessor. */ 675214571Sdim /* These are not currently supported. */ 676214571Sdim if (num_insns_saved > 2) 677214571Sdim as_fatal ("Internally parallel cores of coprocessors not supported."); 678214571Sdim 679214571Sdim /* If there are no insns saved, that's ok. Just return. This will 680214571Sdim happen when mep_process_saved_insns is called when the end of the 681214571Sdim source file is reached and there are no insns left to be processed. */ 682214571Sdim if (num_insns_saved == 0) 683214571Sdim return; 684214571Sdim 685214571Sdim /* Check some of the attributes of the first insn. */ 686214571Sdim insn0iscopro = MEP_INSN_COP_P (saved_insns[0].insn); 687214571Sdim insn0length = CGEN_FIELDS_BITSIZE (& saved_insns[0].fields); 688214571Sdim 689214571Sdim if (num_insns_saved == 2) 690214571Sdim { 691214571Sdim /* Check some of the attributes of the first insn. */ 692214571Sdim insn1iscopro = MEP_INSN_COP_P (saved_insns[1].insn); 693214571Sdim insn1length = CGEN_FIELDS_BITSIZE (& saved_insns[1].fields); 694214571Sdim 695214571Sdim if ((insn0iscopro && !insn1iscopro) 696214571Sdim || (insn1iscopro && !insn0iscopro)) 697214571Sdim { 698214571Sdim /* We have one core and one copro insn. If their sizes 699214571Sdim add up to 64, then the combination is valid. */ 700214571Sdim if (insn0length + insn1length == 64) 701214571Sdim return; 702214571Sdim else 703214571Sdim as_bad ("core and copro insn lengths must total 64 bits."); 704214571Sdim } 705214571Sdim else 706214571Sdim as_bad ("vliw group must consist of 1 core and 1 copro insn."); 707214571Sdim } 708214571Sdim else 709214571Sdim { 710214571Sdim /* If we arrive here, we have one saved instruction. There are a 711214571Sdim number of possible cases: 712214571Sdim 713214571Sdim 1. The instruction is a 64 bit coprocessor insn and can be 714214571Sdim executed by itself. Valid. 715214571Sdim 716214571Sdim 2. The instrucion is a core instruction for which a cop nop 717214571Sdim exists. In this case, insert the cop nop into the saved 718214571Sdim insn array after the core insn and return. Valid. 719214571Sdim 720214571Sdim 3. The instruction is a coprocessor insn for which a core nop 721214571Sdim exists. In this case, move the coprocessor insn to the 722214571Sdim second element of the array and put the nop in the first 723214571Sdim element then return. Valid. 724214571Sdim 725214571Sdim 4. The instruction is a core or coprocessor instruction for 726214571Sdim which there is no matching coprocessor or core nop to use 727214571Sdim to form a valid vliw insn combination. In this case, we 728214571Sdim we have to abort. */ 729214571Sdim 730214571Sdim /* If the insn is 64 bits long, it can run alone. The size check 731214571Sdim is done indepependantly of whether the insn is core or copro 732214571Sdim in case 64 bit coprocessor insns are added later. */ 733214571Sdim if (insn0length == 64) 734214571Sdim return; 735214571Sdim 736214571Sdim /* Insn is smaller than datapath. If there are no matching 737214571Sdim nops for this insn, then terminate assembly. */ 738214571Sdim if (CGEN_INSN_ATTR_VALUE (saved_insns[0].insn, 739214571Sdim CGEN_INSN_VLIW64_NO_MATCHING_NOP)) 740214571Sdim as_fatal ("No valid nop."); 741214571Sdim 742214571Sdim if (insn0iscopro) 743214571Sdim { 744214571Sdim char *errmsg; 745214571Sdim mep_insn insn; 746214571Sdim int i; 747214571Sdim 748214571Sdim /* Initialize the insn buffer. */ 749214571Sdim for (i = 0; i < 64; i++) 750214571Sdim insn.buffer[i] = '\0'; 751214571Sdim 752214571Sdim /* We have a coprocessor insn. At this point in time there 753214571Sdim are is 32-bit core nop. There is only a 16-bit core 754214571Sdim nop. The idea is to allow for a relatively arbitrary 755214571Sdim coprocessor to be specified. We aren't looking at 756214571Sdim trying to cover future changes in the core at this time 757214571Sdim since it is assumed that the core will remain fairly 758214571Sdim static. If there ever are 32 or 48 bit core nops added, 759214571Sdim they will require entries below. */ 760214571Sdim 761214571Sdim if (insn0length == 48) 762214571Sdim { 763214571Sdim /* Move the insn and fixups to the second element of the 764214571Sdim arrays then assemble and insert a 16 bit core nop. */ 765214571Sdim insn.insn = mep_cgen_assemble_insn (gas_cgen_cpu_desc, "nop", 766214571Sdim & insn.fields, insn.buffer, 767214571Sdim & errmsg); 768214571Sdim } 769214571Sdim else 770214571Sdim { 771214571Sdim /* If this is reached, then we have a single coprocessor 772214571Sdim insn that is not 48 bits long, but for which the assembler 773214571Sdim thinks there is a matching core nop. If a 32-bit core 774214571Sdim nop has been added, then make the necessary changes and 775214571Sdim handle its assembly and insertion here. Otherwise, 776214571Sdim go figure out why either: 777214571Sdim 778214571Sdim 1. The assembler thinks that there is a 32-bit core nop 779214571Sdim to match a 32-bit coprocessor insn, or 780214571Sdim 2. The assembler thinks that there is a 48-bit core nop 781214571Sdim to match a 16-bit coprocessor insn. */ 782214571Sdim 783214571Sdim as_fatal ("Assembler expects a non-existent core nop."); 784214571Sdim } 785214571Sdim 786214571Sdim if (!insn.insn) 787214571Sdim { 788214571Sdim as_bad ("%s", errmsg); 789214571Sdim return; 790214571Sdim } 791214571Sdim 792214571Sdim /* Move the insn in element 0 to element 1 and insert the 793214571Sdim nop into element 0. Move the fixups in element 0 to 794214571Sdim element 1 and save the current fixups to element 0. 795214571Sdim Really there aren't any fixups at this point because we're 796214571Sdim inserting a nop but we might as well be general so that 797214571Sdim if there's ever a need to insert a general insn, we'll 798214571Sdim have an example. */ 799214571Sdim 800214571Sdim saved_insns[1] = saved_insns[0]; 801214571Sdim saved_insns[0] = insn; 802214571Sdim num_insns_saved++; 803214571Sdim gas_cgen_swap_fixups(0); 804214571Sdim gas_cgen_save_fixups(1); 805214571Sdim 806214571Sdim } 807214571Sdim else 808214571Sdim { 809214571Sdim char * errmsg; 810214571Sdim mep_insn insn; 811214571Sdim int i; 812214571Sdim 813214571Sdim /* Initialize the insn buffer */ 814214571Sdim for (i = 0; i < 64; i++) 815214571Sdim insn.buffer[i] = '\0'; 816214571Sdim 817214571Sdim /* We have a core insn. We have to handle all possible nop 818214571Sdim lengths. If a coprocessor doesn't have a nop of a certain 819214571Sdim length but there exists core insns that when combined with 820214571Sdim a nop of that length would fill the datapath, those core 821214571Sdim insns will be flagged with the VLIW_NO_CORRESPONDING_NOP 822214571Sdim attribute. That will ensure that when used in a way that 823214571Sdim requires a nop to be inserted, assembly will terminate 824214571Sdim before reaching this section of code. This guarantees 825214571Sdim that cases below which would result in the attempted 826214571Sdim insertion of nop that doesn't exist will never be entered. */ 827214571Sdim if (insn0length == 16) 828214571Sdim { 829214571Sdim /* Insert 48 bit coprocessor nop. */ 830214571Sdim /* Assemble it and put it into the arrays. */ 831214571Sdim insn.insn = mep_cgen_assemble_insn (gas_cgen_cpu_desc, "cpnop48", 832214571Sdim &insn.fields, insn.buffer, 833214571Sdim &errmsg); 834214571Sdim } 835214571Sdim else if (insn0length == 32) 836214571Sdim { 837214571Sdim /* Insert 32 bit coprocessor nop. */ 838214571Sdim insn.insn = mep_cgen_assemble_insn (gas_cgen_cpu_desc, "cpnop32", 839214571Sdim &insn.fields, insn.buffer, 840214571Sdim &errmsg); 841214571Sdim } 842214571Sdim else if (insn0length == 48) 843214571Sdim { 844214571Sdim /* Insert 16 bit coprocessor nop. */ 845214571Sdim insn.insn = mep_cgen_assemble_insn (gas_cgen_cpu_desc, "cpnop16", 846214571Sdim &insn.fields, insn.buffer, 847214571Sdim &errmsg); 848214571Sdim } 849214571Sdim else 850214571Sdim /* Core insn has an invalid length. Something has gone wrong. */ 851214571Sdim as_fatal ("Core insn has invalid length! Something is wrong!"); 852214571Sdim 853214571Sdim if (!insn.insn) 854214571Sdim { 855214571Sdim as_bad ("%s", errmsg); 856214571Sdim return; 857214571Sdim } 858214571Sdim 859214571Sdim /* Now put the insn and fixups into the arrays. */ 860214571Sdim mep_save_insn (insn); 861214571Sdim } 862214571Sdim } 863214571Sdim} 864214571Sdim 865214571Sdim/* The scheduling functions are just filters for invalid combinations. 866214571Sdim If there is a violation, they terminate assembly. Otherise they 867214571Sdim just fall through. Succesful combinations cause no side effects 868214571Sdim other than valid nop insertion. */ 869214571Sdim 870214571Sdimstatic void 871214571Sdimmep_check_parallel_scheduling (void) 872214571Sdim{ 873214571Sdim /* This is where we will eventually read the config information 874214571Sdim and choose which scheduling checking function to call. */ 875214571Sdim if (MEP_VLIW64) 876214571Sdim mep_check_parallel64_scheduling (); 877214571Sdim else 878214571Sdim mep_check_parallel32_scheduling (); 879214571Sdim} 880214571Sdim 881214571Sdimstatic void 882214571Sdimmep_process_saved_insns (void) 883214571Sdim{ 884214571Sdim int i; 885214571Sdim 886214571Sdim gas_cgen_save_fixups (MAX_SAVED_FIXUP_CHAINS - 1); 887214571Sdim 888214571Sdim /* We have to check for valid scheduling here. */ 889214571Sdim mep_check_parallel_scheduling (); 890214571Sdim 891214571Sdim /* If the last call didn't cause assembly to terminate, we have 892214571Sdim a valid vliw insn/insn pair saved. Restore this instructions' 893214571Sdim fixups and process the insns. */ 894214571Sdim for (i = 0;i<num_insns_saved;i++) 895214571Sdim { 896214571Sdim gas_cgen_restore_fixups (i); 897214571Sdim gas_cgen_finish_insn (saved_insns[i].insn, saved_insns[i].buffer, 898214571Sdim CGEN_FIELDS_BITSIZE (& saved_insns[i].fields), 899214571Sdim 1, NULL); 900214571Sdim } 901214571Sdim gas_cgen_restore_fixups (MAX_SAVED_FIXUP_CHAINS - 1); 902214571Sdim 903214571Sdim /* Clear the fixups and reset the number insn saved to 0. */ 904214571Sdim gas_cgen_initialize_saved_fixups_array (); 905214571Sdim num_insns_saved = 0; 906214571Sdim listing_prev_line (); 907214571Sdim} 908214571Sdim 909214571Sdimvoid 910214571Sdimmd_assemble (char * str) 911214571Sdim{ 912214571Sdim static CGEN_BITSET* isas = NULL; 913214571Sdim char * errmsg; 914214571Sdim 915214571Sdim /* Initialize GAS's cgen interface for a new instruction. */ 916214571Sdim gas_cgen_init_parse (); 917214571Sdim 918214571Sdim /* There are two possible modes: core and vliw. We have to assemble 919214571Sdim differently for each. 920214571Sdim 921214571Sdim Core Mode: We assemble normally. All instructions are on a 922214571Sdim single line and are made up of one mnemonic and one 923214571Sdim set of operands. 924214571Sdim VLIW Mode: Vliw combinations are indicated as follows: 925214571Sdim 926214571Sdim core insn 927214571Sdim + copro insn 928214571Sdim 929214571Sdim We want to handle the general case where more than 930214571Sdim one instruction can be preceeded by a +. This will 931214571Sdim happen later if we add support for internally parallel 932214571Sdim coprocessors. We'll make the parsing nice and general 933214571Sdim so that it can handle an arbitrary number of insns 934214571Sdim with leading +'s. The actual checking for valid 935214571Sdim combinations is done elsewhere. */ 936214571Sdim 937214571Sdim /* Initialize the isa to refer to the core. */ 938214571Sdim if (isas == NULL) 939214571Sdim isas = cgen_bitset_copy (& MEP_CORE_ISA); 940214571Sdim else 941214571Sdim { 942214571Sdim cgen_bitset_clear (isas); 943214571Sdim cgen_bitset_union (isas, & MEP_CORE_ISA, isas); 944214571Sdim } 945214571Sdim gas_cgen_cpu_desc->isas = isas; 946214571Sdim 947214571Sdim if (mode == VLIW) 948214571Sdim { 949214571Sdim /* VLIW mode. */ 950214571Sdim 951214571Sdim int thisInsnIsCopro = 0; 952214571Sdim mep_insn insn; 953214571Sdim int i; 954214571Sdim 955214571Sdim /* Initialize the insn buffer */ 956214571Sdim 957214571Sdim if (! CGEN_INT_INSN_P) 958214571Sdim for (i=0; i < CGEN_MAX_INSN_SIZE; i++) 959214571Sdim insn.buffer[i]='\0'; 960214571Sdim 961214571Sdim /* Can't tell core / copro insns apart at parse time! */ 962214571Sdim cgen_bitset_union (isas, & MEP_COP_ISA, isas); 963214571Sdim 964214571Sdim /* Assemble the insn so we can examine its attributes. */ 965214571Sdim insn.insn = mep_cgen_assemble_insn (gas_cgen_cpu_desc, str, 966214571Sdim &insn.fields, insn.buffer, 967214571Sdim &errmsg); 968214571Sdim if (!insn.insn) 969214571Sdim { 970214571Sdim as_bad ("%s", errmsg); 971214571Sdim return; 972214571Sdim } 973214571Sdim mep_check_for_disabled_registers (&insn); 974214571Sdim 975214571Sdim /* Check to see if it's a coprocessor instruction. */ 976214571Sdim thisInsnIsCopro = MEP_INSN_COP_P (insn.insn); 977214571Sdim 978214571Sdim if (!thisInsnIsCopro) 979214571Sdim { 980214571Sdim insn.insn = mep_cgen_assemble_cop_insn (gas_cgen_cpu_desc, str, 981214571Sdim &insn.fields, insn.buffer, 982214571Sdim insn.insn); 983214571Sdim thisInsnIsCopro = MEP_INSN_COP_P (insn.insn); 984214571Sdim mep_check_for_disabled_registers (&insn); 985214571Sdim } 986214571Sdim 987214571Sdim if (pluspresent) 988214571Sdim { 989214571Sdim /* A plus was present. */ 990214571Sdim /* Check for a + with a core insn and abort if found. */ 991214571Sdim if (!thisInsnIsCopro) 992214571Sdim { 993214571Sdim as_fatal("A core insn cannot be preceeded by a +.\n"); 994214571Sdim return; 995214571Sdim } 996214571Sdim 997214571Sdim if (num_insns_saved > 0) 998214571Sdim { 999214571Sdim /* There are insns in the queue. Add this one. */ 1000214571Sdim mep_save_insn (insn); 1001214571Sdim } 1002214571Sdim else 1003214571Sdim { 1004214571Sdim /* There are no insns in the queue and a plus is present. 1005214571Sdim This is a syntax error. Let's not tolerate this. 1006214571Sdim We can relax this later if necessary. */ 1007214571Sdim as_bad (_("Invalid use of parallelization operator.")); 1008214571Sdim return; 1009214571Sdim } 1010214571Sdim } 1011214571Sdim else 1012214571Sdim { 1013214571Sdim /* No plus was present. */ 1014214571Sdim if (num_insns_saved > 0) 1015214571Sdim { 1016214571Sdim /* There are insns saved and we came across an insn without a 1017214571Sdim leading +. That's the signal to process the saved insns 1018214571Sdim before proceeding then treat the current insn as the first 1019214571Sdim in a new vliw group. */ 1020214571Sdim mep_process_saved_insns (); 1021214571Sdim num_insns_saved = 0; 1022214571Sdim /* mep_save_insn (insn); */ 1023214571Sdim } 1024214571Sdim mep_save_insn (insn); 1025214571Sdim#if 0 1026214571Sdim else 1027214571Sdim { 1028214571Sdim 1029214571Sdim /* Core Insn. Add it to the beginning of the queue. */ 1030214571Sdim mep_save_insn (insn); 1031214571Sdim /* gas_cgen_save_fixups(num_insns_saved); */ 1032214571Sdim } 1033214571Sdim#endif 1034214571Sdim } 1035214571Sdim 1036214571Sdim pluspresent = 0; 1037214571Sdim } 1038214571Sdim else 1039214571Sdim { 1040214571Sdim /* Core mode. */ 1041214571Sdim 1042214571Sdim /* Only single instructions are assembled in core mode. */ 1043214571Sdim mep_insn insn; 1044214571Sdim 1045214571Sdim /* If a leading '+' was present, issue an error. 1046214571Sdim That's not allowed in core mode. */ 1047214571Sdim if (pluspresent) 1048214571Sdim { 1049214571Sdim as_bad (_("Leading plus sign not allowed in core mode")); 1050214571Sdim return; 1051214571Sdim } 1052214571Sdim 1053214571Sdim insn.insn = mep_cgen_assemble_insn 1054214571Sdim (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg); 1055214571Sdim 1056214571Sdim if (!insn.insn) 1057214571Sdim { 1058214571Sdim as_bad ("%s", errmsg); 1059214571Sdim return; 1060214571Sdim } 1061214571Sdim gas_cgen_finish_insn (insn.insn, insn.buffer, 1062214571Sdim CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL); 1063214571Sdim mep_check_for_disabled_registers (&insn); 1064214571Sdim } 1065214571Sdim} 1066214571Sdim 1067214571SdimvalueT 1068214571Sdimmd_section_align (segT segment, valueT size) 1069214571Sdim{ 1070214571Sdim int align = bfd_get_section_alignment (stdoutput, segment); 1071214571Sdim return ((size + (1 << align) - 1) & (-1 << align)); 1072214571Sdim} 1073214571Sdim 1074214571Sdim 1075214571SdimsymbolS * 1076214571Sdimmd_undefined_symbol (char *name ATTRIBUTE_UNUSED) 1077214571Sdim{ 1078214571Sdim return 0; 1079214571Sdim} 1080214571Sdim 1081214571Sdim/* Interface to relax_segment. */ 1082214571Sdim 1083214571Sdim 1084214571Sdimconst relax_typeS md_relax_table[] = 1085214571Sdim{ 1086214571Sdim /* The fields are: 1087214571Sdim 1) most positive reach of this state, 1088214571Sdim 2) most negative reach of this state, 1089214571Sdim 3) how many bytes this mode will have in the variable part of the frag 1090214571Sdim 4) which index into the table to try if we can't fit into this one. */ 1091214571Sdim /* Note that we use "beq" because "jmp" has a peculiarity - it cannot 1092214571Sdim jump to addresses with any bits 27..24 set. So, we use beq as a 1093214571Sdim 17-bit pc-relative branch to avoid using jmp, just in case. */ 1094214571Sdim 1095214571Sdim /* 0 */ { 0, 0, 0, 0 }, /* unused */ 1096214571Sdim /* 1 */ { 0, 0, 0, 0 }, /* marker for "don't know yet" */ 1097214571Sdim 1098214571Sdim /* 2 */ { 2047, -2048, 0, 3 }, /* bsr12 */ 1099214571Sdim /* 3 */ { 0, 0, 2, 0 }, /* bsr16 */ 1100214571Sdim 1101214571Sdim /* 4 */ { 2047, -2048, 0, 5 }, /* bra */ 1102214571Sdim /* 5 */ { 65535, -65536, 2, 6 }, /* beq $0,$0 */ 1103214571Sdim /* 6 */ { 0, 0, 2, 0 }, /* jmp24 */ 1104214571Sdim 1105214571Sdim /* 7 */ { 65535, -65536, 0, 8 }, /* beqi */ 1106214571Sdim /* 8 */ { 0, 0, 4, 0 }, /* bnei/jmp */ 1107214571Sdim 1108214571Sdim /* 9 */ { 127, -128, 0, 10 }, /* beqz */ 1109214571Sdim /* 10 */ { 65535, -65536, 2, 11 }, /* beqi */ 1110214571Sdim /* 11 */ { 0, 0, 4, 0 }, /* bnei/jmp */ 1111214571Sdim 1112214571Sdim /* 12 */ { 65535, -65536, 0, 13 }, /* bnei */ 1113214571Sdim /* 13 */ { 0, 0, 4, 0 }, /* beqi/jmp */ 1114214571Sdim 1115214571Sdim /* 14 */ { 127, -128, 0, 15 }, /* bnez */ 1116214571Sdim /* 15 */ { 65535, -65536, 2, 16 }, /* bnei */ 1117214571Sdim /* 16 */ { 0, 0, 4, 0 }, /* beqi/jmp */ 1118214571Sdim 1119214571Sdim /* 17 */ { 65535, -65536, 0, 13 }, /* bgei */ 1120214571Sdim /* 18 */ { 0, 0, 4, 0 }, 1121214571Sdim /* 19 */ { 65535, -65536, 0, 13 }, /* blti */ 1122214571Sdim /* 20 */ { 0, 0, 4, 0 }, 1123214571Sdim /* 19 */ { 65535, -65536, 0, 13 }, /* bcpeq */ 1124214571Sdim /* 20 */ { 0, 0, 4, 0 }, 1125214571Sdim /* 19 */ { 65535, -65536, 0, 13 }, /* bcpne */ 1126214571Sdim /* 20 */ { 0, 0, 4, 0 }, 1127214571Sdim /* 19 */ { 65535, -65536, 0, 13 }, /* bcpat */ 1128214571Sdim /* 20 */ { 0, 0, 4, 0 }, 1129214571Sdim /* 19 */ { 65535, -65536, 0, 13 }, /* bcpaf */ 1130214571Sdim /* 20 */ { 0, 0, 4, 0 } 1131214571Sdim}; 1132214571Sdim 1133214571Sdim/* Pseudo-values for 64 bit "insns" which are combinations of two 32 1134214571Sdim bit insns. */ 1135214571Sdimtypedef enum { 1136214571Sdim MEP_PSEUDO64_NONE, 1137214571Sdim MEP_PSEUDO64_16BITCC, 1138214571Sdim MEP_PSEUDO64_32BITCC, 1139214571Sdim} MepPseudo64Values; 1140214571Sdim 1141214571Sdimstatic struct { 1142214571Sdim int insn; 1143214571Sdim int growth; 1144214571Sdim int insn_for_extern; 1145214571Sdim} subtype_mappings[] = { 1146214571Sdim { 0, 0, 0 }, 1147214571Sdim { 0, 0, 0 }, 1148214571Sdim { MEP_INSN_BSR12, 0, MEP_INSN_BSR24 }, 1149214571Sdim { MEP_INSN_BSR24, 2, MEP_INSN_BSR24 }, 1150214571Sdim { MEP_INSN_BRA, 0, MEP_INSN_BRA }, 1151214571Sdim { MEP_INSN_BEQ, 2, MEP_INSN_BEQ }, 1152214571Sdim { MEP_INSN_JMP, 2, MEP_INSN_JMP }, 1153214571Sdim { MEP_INSN_BEQI, 0, MEP_INSN_BEQI }, 1154214571Sdim { -1, 4, MEP_PSEUDO64_32BITCC }, 1155214571Sdim { MEP_INSN_BEQZ, 0, MEP_INSN_BEQZ }, 1156214571Sdim { MEP_INSN_BEQI, 2, MEP_INSN_BEQI }, 1157214571Sdim { -1, 4, MEP_PSEUDO64_16BITCC }, 1158214571Sdim { MEP_INSN_BNEI, 0, MEP_INSN_BNEI }, 1159214571Sdim { -1, 4, MEP_PSEUDO64_32BITCC }, 1160214571Sdim { MEP_INSN_BNEZ, 0, MEP_INSN_BNEZ }, 1161214571Sdim { MEP_INSN_BNEI, 2, MEP_INSN_BNEI }, 1162214571Sdim { -1, 4, MEP_PSEUDO64_16BITCC }, 1163214571Sdim { MEP_INSN_BGEI, 0, MEP_INSN_BGEI }, 1164214571Sdim { -1, 4, MEP_PSEUDO64_32BITCC }, 1165214571Sdim { MEP_INSN_BLTI, 0, MEP_INSN_BLTI }, 1166214571Sdim { -1, 4, MEP_PSEUDO64_32BITCC }, 1167214571Sdim { MEP_INSN_BCPEQ, 0, MEP_INSN_BCPEQ }, 1168214571Sdim { -1, 4, MEP_PSEUDO64_32BITCC }, 1169214571Sdim { MEP_INSN_BCPNE, 0, MEP_INSN_BCPNE }, 1170214571Sdim { -1, 4, MEP_PSEUDO64_32BITCC }, 1171214571Sdim { MEP_INSN_BCPAT, 0, MEP_INSN_BCPAT }, 1172214571Sdim { -1, 4, MEP_PSEUDO64_32BITCC }, 1173214571Sdim { MEP_INSN_BCPAF, 0, MEP_INSN_BCPAF }, 1174214571Sdim { -1, 4, MEP_PSEUDO64_32BITCC } 1175214571Sdim}; 1176214571Sdim#define NUM_MAPPINGS (sizeof (subtype_mappings) / sizeof (subtype_mappings[0])) 1177214571Sdim 1178214571Sdimvoid 1179214571Sdimmep_prepare_relax_scan (fragS *fragP, offsetT *aim, relax_substateT this_state) 1180214571Sdim{ 1181214571Sdim symbolS *symbolP = fragP->fr_symbol; 1182214571Sdim if (symbolP && !S_IS_DEFINED (symbolP)) 1183214571Sdim *aim = 0; 1184214571Sdim /* Adjust for MeP pcrel not being relative to the next opcode. */ 1185214571Sdim *aim += 2 + md_relax_table[this_state].rlx_length; 1186214571Sdim} 1187214571Sdim 1188214571Sdimstatic int 1189214571Sdiminsn_to_subtype (int insn) 1190214571Sdim{ 1191214571Sdim unsigned int i; 1192214571Sdim for (i=0; i<NUM_MAPPINGS; i++) 1193214571Sdim if (insn == subtype_mappings[i].insn) 1194214571Sdim return i; 1195214571Sdim abort (); 1196214571Sdim} 1197214571Sdim 1198214571Sdim/* Return an initial guess of the length by which a fragment must grow 1199214571Sdim to hold a branch to reach its destination. Also updates fr_type 1200214571Sdim and fr_subtype as necessary. 1201214571Sdim 1202214571Sdim Called just before doing relaxation. Any symbol that is now 1203214571Sdim undefined will not become defined. The guess for fr_var is 1204214571Sdim ACTUALLY the growth beyond fr_fix. Whatever we do to grow fr_fix 1205214571Sdim or fr_var contributes to our returned value. Although it may not 1206214571Sdim be explicit in the frag, pretend fr_var starts with a 0 value. */ 1207214571Sdim 1208214571Sdimint 1209214571Sdimmd_estimate_size_before_relax (fragS * fragP, segT segment) 1210214571Sdim{ 1211214571Sdim if (fragP->fr_subtype == 1) 1212214571Sdim fragP->fr_subtype = insn_to_subtype (fragP->fr_cgen.insn->base->num); 1213214571Sdim 1214214571Sdim if (S_GET_SEGMENT (fragP->fr_symbol) != segment) 1215214571Sdim { 1216214571Sdim int new_insn; 1217214571Sdim 1218214571Sdim new_insn = subtype_mappings[fragP->fr_subtype].insn_for_extern; 1219214571Sdim fragP->fr_subtype = insn_to_subtype (new_insn); 1220214571Sdim } 1221214571Sdim 1222214571Sdim if (MEP_VLIW && ! MEP_VLIW64 1223214571Sdim && (bfd_get_section_flags (stdoutput, segment) & SEC_MEP_VLIW)) 1224214571Sdim { 1225214571Sdim /* Use 32 bit branches for vliw32 so the vliw word is not split. */ 1226214571Sdim switch (fragP->fr_cgen.insn->base->num) 1227214571Sdim { 1228214571Sdim case MEP_INSN_BSR12: 1229214571Sdim fragP->fr_subtype = insn_to_subtype 1230214571Sdim (subtype_mappings[fragP->fr_subtype].insn_for_extern); 1231214571Sdim break; 1232214571Sdim case MEP_INSN_BEQZ: 1233214571Sdim fragP->fr_subtype ++; 1234214571Sdim break; 1235214571Sdim case MEP_INSN_BNEZ: 1236214571Sdim fragP->fr_subtype ++; 1237214571Sdim break; 1238214571Sdim } 1239214571Sdim } 1240214571Sdim 1241214571Sdim if (fragP->fr_cgen.insn->base 1242214571Sdim && fragP->fr_cgen.insn->base->num 1243214571Sdim != subtype_mappings[fragP->fr_subtype].insn) 1244214571Sdim { 1245214571Sdim int new_insn= subtype_mappings[fragP->fr_subtype].insn; 1246214571Sdim if (new_insn != -1) 1247214571Sdim { 1248214571Sdim fragP->fr_cgen.insn = (fragP->fr_cgen.insn 1249214571Sdim - fragP->fr_cgen.insn->base->num 1250214571Sdim + new_insn); 1251214571Sdim } 1252214571Sdim } 1253214571Sdim 1254214571Sdim return subtype_mappings[fragP->fr_subtype].growth; 1255214571Sdim} 1256214571Sdim 1257214571Sdim/* *fragP has been relaxed to its final size, and now needs to have 1258214571Sdim the bytes inside it modified to conform to the new size. 1259214571Sdim 1260214571Sdim Called after relaxation is finished. 1261214571Sdim fragP->fr_type == rs_machine_dependent. 1262214571Sdim fragP->fr_subtype is the subtype of what the address relaxed to. */ 1263214571Sdim 1264214571Sdimstatic int 1265214571Sdimtarget_address_for (fragS *frag) 1266214571Sdim{ 1267214571Sdim int rv = frag->fr_offset; 1268214571Sdim symbolS *sym = frag->fr_symbol; 1269214571Sdim 1270214571Sdim if (sym) 1271214571Sdim rv += S_GET_VALUE (sym); 1272214571Sdim 1273214571Sdim return rv; 1274214571Sdim} 1275214571Sdim 1276214571Sdimvoid 1277214571Sdimmd_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, 1278214571Sdim segT sec ATTRIBUTE_UNUSED, 1279214571Sdim fragS *fragP) 1280214571Sdim{ 1281214571Sdim int addend, rn, bit = 0; 1282214571Sdim int operand; 1283214571Sdim int where = fragP->fr_opcode - fragP->fr_literal; 1284214571Sdim int e = target_big_endian ? 0 : 1; 1285214571Sdim 1286214571Sdim addend = target_address_for (fragP) - (fragP->fr_address + where); 1287214571Sdim 1288214571Sdim if (subtype_mappings[fragP->fr_subtype].insn == -1) 1289214571Sdim { 1290214571Sdim fragP->fr_fix += subtype_mappings[fragP->fr_subtype].growth; 1291214571Sdim switch (subtype_mappings[fragP->fr_subtype].insn_for_extern) 1292214571Sdim { 1293214571Sdim case MEP_PSEUDO64_16BITCC: 1294214571Sdim fragP->fr_opcode[1^e] = ((fragP->fr_opcode[1^e] & 1) ^ 1) | 0x06; 1295214571Sdim fragP->fr_opcode[2^e] = 0xd8; 1296214571Sdim fragP->fr_opcode[3^e] = 0x08; 1297214571Sdim fragP->fr_opcode[4^e] = 0; 1298214571Sdim fragP->fr_opcode[5^e] = 0; 1299214571Sdim where += 2; 1300214571Sdim break; 1301214571Sdim case MEP_PSEUDO64_32BITCC: 1302214571Sdim if (fragP->fr_opcode[0^e] & 0x10) 1303214571Sdim fragP->fr_opcode[1^e] ^= 0x01; 1304214571Sdim else 1305214571Sdim fragP->fr_opcode[1^e] ^= 0x04; 1306214571Sdim fragP->fr_opcode[2^e] = 0; 1307214571Sdim fragP->fr_opcode[3^e] = 4; 1308214571Sdim fragP->fr_opcode[4^e] = 0xd8; 1309214571Sdim fragP->fr_opcode[5^e] = 0x08; 1310214571Sdim fragP->fr_opcode[6^e] = 0; 1311214571Sdim fragP->fr_opcode[7^e] = 0; 1312214571Sdim where += 4; 1313214571Sdim break; 1314214571Sdim default: 1315214571Sdim abort (); 1316214571Sdim } 1317214571Sdim fragP->fr_cgen.insn = (fragP->fr_cgen.insn 1318214571Sdim - fragP->fr_cgen.insn->base->num 1319214571Sdim + MEP_INSN_JMP); 1320214571Sdim operand = MEP_OPERAND_PCABS24A2; 1321214571Sdim } 1322214571Sdim else 1323214571Sdim switch (fragP->fr_cgen.insn->base->num) 1324214571Sdim { 1325214571Sdim case MEP_INSN_BSR12: 1326214571Sdim fragP->fr_opcode[0^e] = 0xb0 | ((addend >> 8) & 0x0f); 1327214571Sdim fragP->fr_opcode[1^e] = 0x01 | (addend & 0xfe); 1328214571Sdim operand = MEP_OPERAND_PCREL12A2; 1329214571Sdim break; 1330214571Sdim 1331214571Sdim case MEP_INSN_BSR24: 1332214571Sdim fragP->fr_fix += 2; 1333214571Sdim fragP->fr_opcode[0^e] = 0xd8 | ((addend >> 5) & 0x07); 1334214571Sdim fragP->fr_opcode[1^e] = 0x09 | ((addend << 3) & 0xf0); 1335214571Sdim fragP->fr_opcode[2^e] = 0x00 | ((addend >>16) & 0xff); 1336214571Sdim fragP->fr_opcode[3^e] = 0x00 | ((addend >> 8) & 0xff); 1337214571Sdim operand = MEP_OPERAND_PCREL24A2; 1338214571Sdim break; 1339214571Sdim 1340214571Sdim case MEP_INSN_BRA: 1341214571Sdim fragP->fr_opcode[0^e] = 0xb0 | ((addend >> 8) & 0x0f); 1342214571Sdim fragP->fr_opcode[1^e] = 0x00 | (addend & 0xfe); 1343214571Sdim operand = MEP_OPERAND_PCREL12A2; 1344214571Sdim break; 1345214571Sdim 1346214571Sdim case MEP_INSN_BEQ: 1347214571Sdim /* The default relax_frag doesn't change the state if there is no 1348214571Sdim growth, so we must manually handle converting out-of-range BEQ 1349214571Sdim instructions to JMP. */ 1350214571Sdim if (addend <= 65535 && addend >= -65536) 1351214571Sdim { 1352214571Sdim fragP->fr_fix += 2; 1353214571Sdim fragP->fr_opcode[0^e] = 0xe0; 1354214571Sdim fragP->fr_opcode[1^e] = 0x01; 1355214571Sdim fragP->fr_opcode[2^e] = 0x00 | ((addend >> 9) & 0xff); 1356214571Sdim fragP->fr_opcode[3^e] = 0x00 | ((addend >> 1) & 0xff); 1357214571Sdim operand = MEP_OPERAND_PCREL17A2; 1358214571Sdim break; 1359214571Sdim } 1360214571Sdim /* ...FALLTHROUGH... */ 1361214571Sdim 1362214571Sdim case MEP_INSN_JMP: 1363214571Sdim addend = target_address_for (fragP); 1364214571Sdim fragP->fr_fix += 2; 1365214571Sdim fragP->fr_opcode[0^e] = 0xd8 | ((addend >> 5) & 0x07); 1366214571Sdim fragP->fr_opcode[1^e] = 0x08 | ((addend << 3) & 0xf0); 1367214571Sdim fragP->fr_opcode[2^e] = 0x00 | ((addend >>16) & 0xff); 1368214571Sdim fragP->fr_opcode[3^e] = 0x00 | ((addend >> 8) & 0xff); 1369214571Sdim operand = MEP_OPERAND_PCABS24A2; 1370214571Sdim break; 1371214571Sdim 1372214571Sdim case MEP_INSN_BNEZ: 1373214571Sdim bit = 1; 1374214571Sdim case MEP_INSN_BEQZ: 1375214571Sdim fragP->fr_opcode[1^e] = bit | (addend & 0xfe); 1376214571Sdim operand = MEP_OPERAND_PCREL8A2; 1377214571Sdim break; 1378214571Sdim 1379214571Sdim case MEP_INSN_BNEI: 1380214571Sdim bit = 4; 1381214571Sdim case MEP_INSN_BEQI: 1382214571Sdim if (subtype_mappings[fragP->fr_subtype].growth) 1383214571Sdim { 1384214571Sdim fragP->fr_fix += subtype_mappings[fragP->fr_subtype].growth; 1385214571Sdim rn = fragP->fr_opcode[0^e] & 0x0f; 1386214571Sdim fragP->fr_opcode[0^e] = 0xe0 | rn; 1387214571Sdim fragP->fr_opcode[1^e] = bit; 1388214571Sdim } 1389214571Sdim fragP->fr_opcode[2^e] = 0x00 | ((addend >> 9) & 0xff); 1390214571Sdim fragP->fr_opcode[3^e] = 0x00 | ((addend >> 1) & 0xff); 1391214571Sdim operand = MEP_OPERAND_PCREL17A2; 1392214571Sdim break; 1393214571Sdim 1394214571Sdim case MEP_INSN_BLTI: 1395214571Sdim case MEP_INSN_BGEI: 1396214571Sdim case MEP_INSN_BCPEQ: 1397214571Sdim case MEP_INSN_BCPNE: 1398214571Sdim case MEP_INSN_BCPAT: 1399214571Sdim case MEP_INSN_BCPAF: 1400214571Sdim /* No opcode change needed, just operand. */ 1401214571Sdim fragP->fr_opcode[2^e] = (addend >> 9) & 0xff; 1402214571Sdim fragP->fr_opcode[3^e] = (addend >> 1) & 0xff; 1403214571Sdim operand = MEP_OPERAND_PCREL17A2; 1404214571Sdim break; 1405214571Sdim 1406214571Sdim default: 1407214571Sdim abort (); 1408214571Sdim } 1409214571Sdim 1410214571Sdim if (S_GET_SEGMENT (fragP->fr_symbol) != sec 1411214571Sdim || operand == MEP_OPERAND_PCABS24A2) 1412214571Sdim { 1413214571Sdim assert (fragP->fr_cgen.insn != 0); 1414214571Sdim gas_cgen_record_fixup (fragP, 1415214571Sdim where, 1416214571Sdim fragP->fr_cgen.insn, 1417214571Sdim (fragP->fr_fix - where) * 8, 1418214571Sdim cgen_operand_lookup_by_num (gas_cgen_cpu_desc, 1419214571Sdim operand), 1420214571Sdim fragP->fr_cgen.opinfo, 1421214571Sdim fragP->fr_symbol, fragP->fr_offset); 1422214571Sdim } 1423214571Sdim} 1424214571Sdim 1425214571Sdim 1426214571Sdim/* Functions concerning relocs. */ 1427214571Sdim 1428214571Sdimvoid 1429214571Sdimmep_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) 1430214571Sdim{ 1431214571Sdim /* If we already know the fixup value, adjust it in the same 1432214571Sdim way that the linker would have done. */ 1433214571Sdim if (fixP->fx_addsy == 0) 1434214571Sdim switch (fixP->fx_cgen.opinfo) 1435214571Sdim { 1436214571Sdim case BFD_RELOC_MEP_LOW16: 1437214571Sdim *valP = ((long)(*valP & 0xffff)) << 16 >> 16; 1438214571Sdim break; 1439214571Sdim case BFD_RELOC_MEP_HI16U: 1440214571Sdim *valP >>= 16; 1441214571Sdim break; 1442214571Sdim case BFD_RELOC_MEP_HI16S: 1443214571Sdim *valP = (*valP + 0x8000) >> 16; 1444214571Sdim break; 1445214571Sdim } 1446214571Sdim 1447214571Sdim /* Now call cgen's md_aply_fix. */ 1448214571Sdim gas_cgen_md_apply_fix (fixP, valP, seg); 1449214571Sdim} 1450214571Sdim 1451214571Sdimlong 1452214571Sdimmd_pcrel_from_section (fixS *fixP, segT sec) 1453214571Sdim{ 1454214571Sdim if (fixP->fx_addsy != (symbolS *) NULL 1455214571Sdim && (! S_IS_DEFINED (fixP->fx_addsy) 1456214571Sdim || S_GET_SEGMENT (fixP->fx_addsy) != sec)) 1457214571Sdim /* The symbol is undefined (or is defined but not in this section). 1458214571Sdim Let the linker figure it out. */ 1459214571Sdim return 0; 1460214571Sdim 1461214571Sdim /* Return the address of the opcode - cgen adjusts for opcode size 1462214571Sdim itself, to be consistent with the disassembler, which must do 1463214571Sdim so. */ 1464214571Sdim return fixP->fx_where + fixP->fx_frag->fr_address; 1465214571Sdim} 1466214571Sdim 1467214571Sdim/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP. 1468214571Sdim Returns BFD_RELOC_NONE if no reloc type can be found. 1469214571Sdim *FIXP may be modified if desired. */ 1470214571Sdim 1471214571Sdim#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) 1472214571Sdim#define MAP(n) case MEP_OPERAND_##n: return BFD_RELOC_MEP_##n; 1473214571Sdim#else 1474214571Sdim#define MAP(n) case MEP_OPERAND_/**/n: return BFD_RELOC_MEP_/**/n; 1475214571Sdim#endif 1476214571Sdim 1477214571Sdimbfd_reloc_code_real_type 1478214571Sdimmd_cgen_lookup_reloc (const CGEN_INSN *insn ATTRIBUTE_UNUSED, 1479214571Sdim const CGEN_OPERAND *operand, 1480214571Sdim fixS *fixP) 1481214571Sdim{ 1482214571Sdim enum bfd_reloc_code_real reloc = fixP->fx_cgen.opinfo; 1483214571Sdim static char printed[MEP_OPERAND_MAX] = { 0 }; 1484214571Sdim 1485214571Sdim /* If there's a reloc here, it's because the parser saw a %foo() and 1486214571Sdim is giving us the correct reloc to use, or because we converted to 1487214571Sdim a different size reloc below and want to avoid "converting" more 1488214571Sdim than once. */ 1489214571Sdim if (reloc && reloc != BFD_RELOC_NONE) 1490214571Sdim return reloc; 1491214571Sdim 1492214571Sdim switch (operand->type) 1493214571Sdim { 1494214571Sdim MAP (PCREL8A2); /* beqz */ 1495214571Sdim MAP (PCREL12A2); /* bsr16 */ 1496214571Sdim MAP (PCREL17A2); /* beqi */ 1497214571Sdim MAP (PCREL24A2); /* bsr24 */ 1498214571Sdim MAP (PCABS24A2); /* jmp */ 1499214571Sdim MAP (UIMM24); /* mov */ 1500214571Sdim MAP (ADDR24A4); /* sw/lw */ 1501214571Sdim 1502214571Sdim /* The rest of the relocs should be generated by the parser, 1503214571Sdim for things such as %tprel(), etc. */ 1504214571Sdim case MEP_OPERAND_SIMM16: 1505214571Sdim#ifdef OBJ_COMPLEX_RELC 1506214571Sdim /* coalescing this into RELOC_MEP_16 is actually a bug, 1507214571Sdim since it's a signed operand. let the relc code handle it. */ 1508214571Sdim return BFD_RELOC_RELC; 1509214571Sdim#endif 1510214571Sdim 1511214571Sdim case MEP_OPERAND_UIMM16: 1512214571Sdim case MEP_OPERAND_SDISP16: 1513214571Sdim case MEP_OPERAND_CODE16: 1514214571Sdim fixP->fx_where += 2; 1515214571Sdim /* to avoid doing the above add twice */ 1516214571Sdim fixP->fx_cgen.opinfo = BFD_RELOC_MEP_16; 1517214571Sdim return BFD_RELOC_MEP_16; 1518214571Sdim 1519214571Sdim default: 1520214571Sdim#ifdef OBJ_COMPLEX_RELC 1521214571Sdim /* this is not an error, yet. 1522214571Sdim pass it to the linker. */ 1523214571Sdim return BFD_RELOC_RELC; 1524214571Sdim#endif 1525214571Sdim if (printed[operand->type]) 1526214571Sdim return BFD_RELOC_NONE; 1527214571Sdim printed[operand->type] = 1; 1528214571Sdim 1529214571Sdim as_bad_where (fixP->fx_file, fixP->fx_line, 1530214571Sdim _("Don't know how to relocate plain operands of type %s"), 1531214571Sdim operand->name); 1532214571Sdim 1533214571Sdim /* Print some helpful hints for the user. */ 1534214571Sdim switch (operand->type) 1535214571Sdim { 1536214571Sdim case MEP_OPERAND_UDISP7: 1537214571Sdim case MEP_OPERAND_UDISP7A2: 1538214571Sdim case MEP_OPERAND_UDISP7A4: 1539214571Sdim as_bad_where (fixP->fx_file, fixP->fx_line, 1540214571Sdim _("Perhaps you are missing %%tpoff()?")); 1541214571Sdim break; 1542214571Sdim default: 1543214571Sdim break; 1544214571Sdim } 1545214571Sdim return BFD_RELOC_NONE; 1546214571Sdim } 1547214571Sdim} 1548214571Sdim 1549214571Sdim/* Called while parsing an instruction to create a fixup. 1550214571Sdim We need to check for HI16 relocs and queue them up for later sorting. */ 1551214571Sdim 1552214571SdimfixS * 1553214571Sdimmep_cgen_record_fixup_exp (fragS *frag, 1554214571Sdim int where, 1555214571Sdim const CGEN_INSN *insn, 1556214571Sdim int length, 1557214571Sdim const CGEN_OPERAND *operand, 1558214571Sdim int opinfo, 1559214571Sdim expressionS *exp) 1560214571Sdim{ 1561214571Sdim fixS * fixP = gas_cgen_record_fixup_exp (frag, where, insn, length, 1562214571Sdim operand, opinfo, exp); 1563214571Sdim return fixP; 1564214571Sdim} 1565214571Sdim 1566214571Sdim/* Return BFD reloc type from opinfo field in a fixS. 1567214571Sdim It's tricky using fx_r_type in mep_frob_file because the values 1568214571Sdim are BFD_RELOC_UNUSED + operand number. */ 1569214571Sdim#define FX_OPINFO_R_TYPE(f) ((f)->fx_cgen.opinfo) 1570214571Sdim 1571214571Sdim/* Sort any unmatched HI16 relocs so that they immediately precede 1572214571Sdim the corresponding LO16 reloc. This is called before md_apply_fix and 1573214571Sdim tc_gen_reloc. */ 1574214571Sdim 1575214571Sdimvoid 1576214571Sdimmep_frob_file () 1577214571Sdim{ 1578214571Sdim struct mep_hi_fixup * l; 1579214571Sdim 1580214571Sdim for (l = mep_hi_fixup_list; l != NULL; l = l->next) 1581214571Sdim { 1582214571Sdim segment_info_type * seginfo; 1583214571Sdim int pass; 1584214571Sdim 1585214571Sdim assert (FX_OPINFO_R_TYPE (l->fixp) == BFD_RELOC_HI16 1586214571Sdim || FX_OPINFO_R_TYPE (l->fixp) == BFD_RELOC_LO16); 1587214571Sdim 1588214571Sdim /* Check quickly whether the next fixup happens to be a matching low. */ 1589214571Sdim if (l->fixp->fx_next != NULL 1590214571Sdim && FX_OPINFO_R_TYPE (l->fixp->fx_next) == BFD_RELOC_LO16 1591214571Sdim && l->fixp->fx_addsy == l->fixp->fx_next->fx_addsy 1592214571Sdim && l->fixp->fx_offset == l->fixp->fx_next->fx_offset) 1593214571Sdim continue; 1594214571Sdim 1595214571Sdim /* Look through the fixups for this segment for a matching 1596214571Sdim `low'. When we find one, move the high just in front of it. 1597214571Sdim We do this in two passes. In the first pass, we try to find 1598214571Sdim a unique `low'. In the second pass, we permit multiple 1599214571Sdim high's relocs for a single `low'. */ 1600214571Sdim seginfo = seg_info (l->seg); 1601214571Sdim for (pass = 0; pass < 2; pass++) 1602214571Sdim { 1603214571Sdim fixS * f; 1604214571Sdim fixS * prev; 1605214571Sdim 1606214571Sdim prev = NULL; 1607214571Sdim for (f = seginfo->fix_root; f != NULL; f = f->fx_next) 1608214571Sdim { 1609214571Sdim /* Check whether this is a `low' fixup which matches l->fixp. */ 1610214571Sdim if (FX_OPINFO_R_TYPE (f) == BFD_RELOC_LO16 1611214571Sdim && f->fx_addsy == l->fixp->fx_addsy 1612214571Sdim && f->fx_offset == l->fixp->fx_offset 1613214571Sdim && (pass == 1 1614214571Sdim || prev == NULL 1615214571Sdim || (FX_OPINFO_R_TYPE (prev) != BFD_RELOC_HI16) 1616214571Sdim || prev->fx_addsy != f->fx_addsy 1617214571Sdim || prev->fx_offset != f->fx_offset)) 1618214571Sdim { 1619214571Sdim fixS ** pf; 1620214571Sdim 1621214571Sdim /* Move l->fixp before f. */ 1622214571Sdim for (pf = &seginfo->fix_root; 1623214571Sdim * pf != l->fixp; 1624214571Sdim pf = & (* pf)->fx_next) 1625214571Sdim assert (* pf != NULL); 1626214571Sdim 1627214571Sdim * pf = l->fixp->fx_next; 1628214571Sdim 1629214571Sdim l->fixp->fx_next = f; 1630214571Sdim if (prev == NULL) 1631214571Sdim seginfo->fix_root = l->fixp; 1632214571Sdim else 1633214571Sdim prev->fx_next = l->fixp; 1634214571Sdim 1635214571Sdim break; 1636214571Sdim } 1637214571Sdim 1638214571Sdim prev = f; 1639214571Sdim } 1640214571Sdim 1641214571Sdim if (f != NULL) 1642214571Sdim break; 1643214571Sdim 1644214571Sdim if (pass == 1) 1645214571Sdim as_warn_where (l->fixp->fx_file, l->fixp->fx_line, 1646214571Sdim _("Unmatched high relocation")); 1647214571Sdim } 1648214571Sdim } 1649214571Sdim} 1650214571Sdim 1651214571Sdim/* See whether we need to force a relocation into the output file. */ 1652214571Sdim 1653214571Sdimint 1654214571Sdimmep_force_relocation (fixS *fixp) 1655214571Sdim{ 1656214571Sdim if ( fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT 1657214571Sdim || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) 1658214571Sdim return 1; 1659214571Sdim 1660214571Sdim /* Allow branches to global symbols to be resolved at assembly time. 1661214571Sdim This is consistent with way relaxable branches are handled, since 1662214571Sdim branches to both global and local symbols are relaxed. It also 1663214571Sdim corresponds to the assumptions made in md_pcrel_from_section. */ 1664214571Sdim return S_FORCE_RELOC (fixp->fx_addsy, !fixp->fx_pcrel); 1665214571Sdim} 1666214571Sdim 1667214571Sdim/* Write a value out to the object file, using the appropriate endianness. */ 1668214571Sdim 1669214571Sdimvoid 1670214571Sdimmd_number_to_chars (char *buf, valueT val, int n) 1671214571Sdim{ 1672214571Sdim if (target_big_endian) 1673214571Sdim number_to_chars_bigendian (buf, val, n); 1674214571Sdim else 1675214571Sdim number_to_chars_littleendian (buf, val, n); 1676214571Sdim} 1677214571Sdim 1678214571Sdim/* Turn a string in input_line_pointer into a floating point constant 1679214571Sdim of type type, and store the appropriate bytes in *litP. The number 1680214571Sdim of LITTLENUMS emitted is stored in *sizeP . An error message is 1681214571Sdim returned, or NULL on OK. */ 1682214571Sdim 1683214571Sdim/* Equal to MAX_PRECISION in atof-ieee.c */ 1684214571Sdim#define MAX_LITTLENUMS 6 1685214571Sdim 1686214571Sdimchar * 1687214571Sdimmd_atof (int type, char *litP, int *sizeP) 1688214571Sdim{ 1689214571Sdim int i; 1690214571Sdim int prec; 1691214571Sdim LITTLENUM_TYPE words [MAX_LITTLENUMS]; 1692214571Sdim char * t; 1693214571Sdim 1694214571Sdim switch (type) 1695214571Sdim { 1696214571Sdim case 'f': 1697214571Sdim case 'F': 1698214571Sdim case 's': 1699214571Sdim case 'S': 1700214571Sdim prec = 2; 1701214571Sdim break; 1702214571Sdim 1703214571Sdim case 'd': 1704214571Sdim case 'D': 1705214571Sdim case 'r': 1706214571Sdim case 'R': 1707214571Sdim prec = 4; 1708214571Sdim break; 1709214571Sdim 1710214571Sdim /* FIXME: Some targets allow other format chars for bigger sizes here. */ 1711214571Sdim default: 1712214571Sdim *sizeP = 0; 1713214571Sdim return _("Bad call to md_atof()"); 1714214571Sdim } 1715214571Sdim 1716214571Sdim t = atof_ieee (input_line_pointer, type, words); 1717214571Sdim if (t) 1718214571Sdim input_line_pointer = t; 1719214571Sdim * sizeP = prec * sizeof (LITTLENUM_TYPE); 1720214571Sdim 1721214571Sdim for (i = 0; i < prec; i++) 1722214571Sdim { 1723214571Sdim md_number_to_chars (litP, (valueT) words[i], 1724214571Sdim sizeof (LITTLENUM_TYPE)); 1725214571Sdim litP += sizeof (LITTLENUM_TYPE); 1726214571Sdim } 1727214571Sdim 1728214571Sdim return 0; 1729214571Sdim} 1730214571Sdim 1731214571Sdim 1732214571Sdimbfd_boolean 1733214571Sdimmep_fix_adjustable (fixS *fixP) 1734214571Sdim{ 1735214571Sdim bfd_reloc_code_real_type reloc_type; 1736214571Sdim 1737214571Sdim if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) 1738214571Sdim { 1739214571Sdim const CGEN_INSN *insn = NULL; 1740214571Sdim int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; 1741214571Sdim const CGEN_OPERAND *operand 1742214571Sdim = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex); 1743214571Sdim reloc_type = md_cgen_lookup_reloc (insn, operand, fixP); 1744214571Sdim } 1745214571Sdim else 1746214571Sdim reloc_type = fixP->fx_r_type; 1747214571Sdim 1748214571Sdim if (fixP->fx_addsy == NULL) 1749214571Sdim return 1; 1750214571Sdim 1751214571Sdim /* Prevent all adjustments to global symbols. */ 1752214571Sdim if (S_IS_EXTERNAL (fixP->fx_addsy)) 1753214571Sdim return 0; 1754214571Sdim 1755214571Sdim if (S_IS_WEAK (fixP->fx_addsy)) 1756214571Sdim return 0; 1757214571Sdim 1758214571Sdim /* We need the symbol name for the VTABLE entries */ 1759214571Sdim if (reloc_type == BFD_RELOC_VTABLE_INHERIT 1760214571Sdim || reloc_type == BFD_RELOC_VTABLE_ENTRY) 1761214571Sdim return 0; 1762214571Sdim 1763214571Sdim return 1; 1764214571Sdim} 1765214571Sdim 1766214571Sdimint 1767214571Sdimmep_elf_section_letter (int letter, char **ptrmsg) 1768214571Sdim{ 1769214571Sdim if (letter == 'v') 1770214571Sdim return SHF_MEP_VLIW; 1771214571Sdim 1772214571Sdim *ptrmsg = _("Bad .section directive: want a,v,w,x,M,S in string"); 1773214571Sdim return 0; 1774214571Sdim} 1775214571Sdim 1776214571Sdimflagword 1777214571Sdimmep_elf_section_flags (flagword flags, int attr, int type ATTRIBUTE_UNUSED) 1778214571Sdim{ 1779214571Sdim if (attr & SHF_MEP_VLIW) 1780214571Sdim flags |= SEC_MEP_VLIW; 1781214571Sdim return flags; 1782214571Sdim} 1783214571Sdim 1784214571Sdim/* In vliw mode, the default section is .vtext. We have to be able 1785214571Sdim to switch into .vtext using only the .vtext directive. */ 1786214571Sdim 1787214571Sdimstatic segT 1788214571Sdimmep_vtext_section (void) 1789214571Sdim{ 1790214571Sdim static segT vtext_section; 1791214571Sdim 1792214571Sdim if (! vtext_section) 1793214571Sdim { 1794214571Sdim flagword applicable = bfd_applicable_section_flags (stdoutput); 1795214571Sdim vtext_section = subseg_new (VTEXT_SECTION_NAME, 0); 1796214571Sdim bfd_set_section_flags (stdoutput, vtext_section, 1797214571Sdim applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC 1798214571Sdim | SEC_CODE | SEC_READONLY 1799214571Sdim | SEC_MEP_VLIW)); 1800214571Sdim } 1801214571Sdim 1802214571Sdim return vtext_section; 1803214571Sdim} 1804214571Sdim 1805214571Sdimstatic void 1806214571Sdimmep_s_vtext (int ignore ATTRIBUTE_UNUSED) 1807214571Sdim{ 1808214571Sdim int temp; 1809214571Sdim 1810214571Sdim /* Record previous_section and previous_subsection. */ 1811214571Sdim obj_elf_section_change_hook (); 1812214571Sdim 1813214571Sdim temp = get_absolute_expression (); 1814214571Sdim subseg_set (mep_vtext_section (), (subsegT) temp); 1815214571Sdim demand_empty_rest_of_line (); 1816214571Sdim} 1817214571Sdim 1818214571Sdimstatic void 1819214571Sdimmep_switch_to_core_mode (int dummy ATTRIBUTE_UNUSED) 1820214571Sdim{ 1821214571Sdim mep_process_saved_insns (); 1822214571Sdim pluspresent = 0; 1823214571Sdim mode = CORE; 1824214571Sdim} 1825214571Sdim 1826214571Sdimstatic void 1827214571Sdimmep_switch_to_vliw_mode (int dummy ATTRIBUTE_UNUSED) 1828214571Sdim{ 1829214571Sdim if (! MEP_VLIW) 1830214571Sdim as_bad (_(".vliw unavailable when VLIW is disabled.")); 1831214571Sdim mode = VLIW; 1832214571Sdim /* Switch into .vtext here too. */ 1833214571Sdim /* mep_s_vtext(); */ 1834214571Sdim} 1835214571Sdim 1836214571Sdim/* This is an undocumented pseudo-op used to disable gas's 1837214571Sdim "disabled_registers" check. Used for code which checks for those 1838214571Sdim registers at runtime. */ 1839214571Sdimstatic void 1840214571Sdimmep_noregerr (int i ATTRIBUTE_UNUSED) 1841214571Sdim{ 1842214571Sdim allow_disabled_registers = 1; 1843214571Sdim} 1844214571Sdim 1845214571Sdim/* mep_unrecognized_line: This is called when a line that can't be parsed 1846214571Sdim is encountered. We use it to check for a leading '+' sign which indicates 1847214571Sdim that the current instruction is a coprocessor instruction that is to be 1848214571Sdim parallelized with a previous core insn. This function accepts the '+' and 1849214571Sdim rejects all other characters that might indicate garbage at the beginning 1850214571Sdim of the line. The '+' character gets lost as the calling loop continues, 1851214571Sdim so we need to indicate that we saw it. */ 1852214571Sdim 1853214571Sdimint 1854214571Sdimmep_unrecognized_line (int ch) 1855214571Sdim{ 1856214571Sdim switch (ch) 1857214571Sdim { 1858214571Sdim case '+': 1859214571Sdim pluspresent = 1; 1860214571Sdim return 1; /* '+' indicates an instruction to be parallelized. */ 1861214571Sdim default: 1862214571Sdim return 0; /* If it's not a '+', the line can't be parsed. */ 1863214571Sdim } 1864214571Sdim} 1865214571Sdim 1866214571Sdimvoid 1867214571Sdimmep_cleanup (void) 1868214571Sdim{ 1869214571Sdim /* Take care of any insns left to be parallelized when the file ends. 1870214571Sdim This is mainly here to handle the case where the file ends with an 1871214571Sdim insn preceeded by a + or the file ends unexpectedly. */ 1872214571Sdim if (mode == VLIW) 1873214571Sdim mep_process_saved_insns (); 1874214571Sdim} 1875214571Sdim 1876214571Sdimint 1877214571Sdimmep_flush_pending_output (void) 1878214571Sdim{ 1879214571Sdim if (mode == VLIW) 1880214571Sdim { 1881214571Sdim mep_process_saved_insns (); 1882214571Sdim pluspresent = 0; 1883214571Sdim } 1884214571Sdim 1885214571Sdim return 1; 1886214571Sdim} 1887