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