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