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