OSDN Git Service

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