Upload Tizen:Base source
[external/binutils.git] / gas / config / tc-mt.c
1 /* tc-mt.c -- Assembler for the Morpho Technologies mt .
2    Copyright (C) 2005, 2006, 2007, 2010 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   (void) last_insn_had_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
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 *
340 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
341 {
342     return NULL;
343 }
344 \f
345 int
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
361 md_convert_frag (bfd   * abfd  ATTRIBUTE_UNUSED,
362                  segT    sec   ATTRIBUTE_UNUSED,
363                  fragS * fragP ATTRIBUTE_UNUSED)
364 {
365 }
366
367 \f
368 /* Functions concerning relocs.  */
369
370 long
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
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
431 md_number_to_chars (char * buf, valueT val, int n)
432 {
433   number_to_chars_bigendian (buf, val, n);
434 }
435
436 char *
437 md_atof (int type, char * litP, int * sizeP)
438 {
439   return ieee_md_atof (type, litP, sizeP, FALSE);
440 }
441
442 /* See whether we need to force a relocation into the output file.  */
443
444 int
445 mt_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
446 {
447   return 0;
448 }
449
450 void
451 mt_apply_fix (fixS *fixP, valueT *valueP, segT seg)
452 {
453   if ((fixP->fx_pcrel != 0) && (fixP->fx_r_type == BFD_RELOC_32))
454     fixP->fx_r_type = BFD_RELOC_32_PCREL;
455
456   gas_cgen_md_apply_fix (fixP, valueP, seg);
457 }
458
459 bfd_boolean
460 mt_fix_adjustable (fixS * fixP)
461 {
462   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
463     {
464       const CGEN_INSN *insn = NULL;
465       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
466       const CGEN_OPERAND *operand;
467
468       operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
469       md_cgen_lookup_reloc (insn, operand, fixP);
470     }
471
472   if (fixP->fx_addsy == NULL)
473     return TRUE;
474   
475   /* Prevent all adjustments to global symbols.  */
476   if (S_IS_EXTERNAL (fixP->fx_addsy))
477     return FALSE;
478   
479   if (S_IS_WEAK (fixP->fx_addsy))
480     return FALSE;
481   
482   return 1;
483 }