OSDN Git Service

e459bc843196f7412ec7a49af0146645c69e2d7a
[pf3gnuchains/pf3gnuchains4x.git] / gas / config / tc-ms1.c
1 /* tc-ms1.c -- Assembler for the Morpho Technologies ms-I.
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/ms1-desc.h"
27 #include "opcodes/ms1-opc.h"
28 #include "cgen.h"
29 #include "elf/common.h"
30 #include "elf/ms1.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 ms1_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 \f
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 ms1_mach = bfd_mach_ms1;
87 static unsigned ms1_mach_bitmask = 0;
88
89 /* Flags to set in the elf header */
90 static flagword ms1_flags = EF_MS1_CPU_MRISC;
91
92 /* The architecture to use.  */
93 enum ms1_architectures
94   {
95     ms1_64_001,
96     ms1_16_002,
97     ms1_16_003
98   };
99
100 /* MS1 architecture we are using for this output file.  */
101 static enum ms1_architectures ms1_arch = ms1_64_001;
102
103 int
104 md_parse_option (int c ATTRIBUTE_UNUSED, char * arg)
105 {
106   switch (c)
107     {
108     case OPTION_MARCH:
109       if (strcasecmp (arg, "MS1-64-001") == 0)
110         {
111           ms1_flags = (ms1_flags & ~EF_MS1_CPU_MASK) | EF_MS1_CPU_MRISC;
112           ms1_mach = bfd_mach_ms1;
113           ms1_mach_bitmask = 1 << MACH_MS1;
114           ms1_arch = ms1_64_001;
115         }
116       else if (strcasecmp (arg, "MS1-16-002") == 0)
117         {
118           ms1_flags = (ms1_flags & ~EF_MS1_CPU_MASK) | EF_MS1_CPU_MRISC;
119           ms1_mach = bfd_mach_ms1;
120           ms1_mach_bitmask = 1 << MACH_MS1;
121           ms1_arch = ms1_16_002;
122         }
123       else if (strcasecmp (arg, "MS1-16-003") == 0)
124         {
125           ms1_flags = (ms1_flags & ~EF_MS1_CPU_MASK) | EF_MS1_CPU_MRISC2;
126           ms1_mach = bfd_mach_mrisc2;
127           ms1_mach_bitmask = 1 << MACH_MS1_003;
128           ms1_arch = ms1_16_003;
129         }
130     case OPTION_NO_SCHED_REST:
131       no_scheduling_restrictions = 1;
132       break;
133     default:
134       return 0;
135     }
136
137   return 1;
138 }
139
140
141 void
142 md_show_usage (FILE * stream)
143 {
144   fprintf (stream, _("MS1 specific command line options:\n"));
145   fprintf (stream, _("  -march=ms1-64-001         allow ms1-64-001 instructions (default) \n"));
146   fprintf (stream, _("  -march=ms1-16-002         allow ms1-16-002 instructions \n"));
147   fprintf (stream, _("  -march=ms1-16-003         allow ms1-16-003 instructions \n"));
148   fprintf (stream, _("  -nosched                  disable scheduling restrictions \n"));
149 }
150
151 \f
152 void
153 md_begin (void)
154 {
155   /* Initialize the `cgen' interface.  */
156   
157   /* Set the machine number and endian.  */
158   gas_cgen_cpu_desc = ms1_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, ms1_mach_bitmask,
159                                            CGEN_CPU_OPEN_ENDIAN,
160                                            CGEN_ENDIAN_BIG,
161                                            CGEN_CPU_OPEN_END);
162   ms1_cgen_init_asm (gas_cgen_cpu_desc);
163
164   /* This is a callback from cgen to gas to parse operands.  */
165   cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
166
167   /* Set the ELF flags if desired. */
168   if (ms1_flags)
169     bfd_set_private_flags (stdoutput, ms1_flags);
170
171   /* Set the machine type.  */
172   bfd_default_set_arch_mach (stdoutput, bfd_arch_ms1, ms1_mach);
173 }
174
175 void
176 md_assemble (char * str)
177 {
178   static long delayed_load_register = 0;
179   static int last_insn_had_delay_slot = 0;
180   static int last_insn_in_noncond_delay_slot = 0;
181   static int last_insn_has_load_delay = 0;
182   static int last_insn_was_memory_access = 0;
183   static int last_insn_was_io_insn = 0;
184   static int last_insn_was_arithmetic_or_logic = 0;
185   static int last_insn_was_branch_insn = 0;
186   static int last_insn_was_conditional_branch_insn = 0;
187
188   ms1_insn insn;
189   char * errmsg;
190
191   /* Initialize GAS's cgen interface for a new instruction.  */
192   gas_cgen_init_parse ();
193
194   insn.insn = ms1_cgen_assemble_insn
195       (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
196
197   if (!insn.insn)
198     {
199       as_bad ("%s", errmsg);
200       return;
201     }
202
203   /* Doesn't really matter what we pass for RELAX_P here.  */
204   gas_cgen_finish_insn (insn.insn, insn.buffer,
205                         CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
206
207
208   /* Handle Scheduling Restrictions.  */
209   if (!no_scheduling_restrictions)
210     {
211       /* Detect consecutive Memory Accesses.  */
212       if (last_insn_was_memory_access
213           && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS)
214           && ms1_mach == ms1_64_001)
215         as_warn (_("instruction %s may not follow another memory access instruction."),
216                  CGEN_INSN_NAME (insn.insn));
217
218       /* Detect consecutive I/O Instructions.  */
219       else if (last_insn_was_io_insn
220                && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN))
221         as_warn (_("instruction %s may not follow another I/O instruction."),
222                  CGEN_INSN_NAME (insn.insn));
223
224       /* Detect consecutive branch instructions.  */
225       else if (last_insn_was_branch_insn
226                && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN))
227         as_warn (_("%s may not occupy the delay slot of another branch insn."),
228                  CGEN_INSN_NAME (insn.insn));
229
230       /* Detect data dependencies on delayed loads: memory and input insns.  */
231       if (last_insn_has_load_delay && delayed_load_register)
232         {
233           if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
234               && insn.fields.f_sr1 == delayed_load_register)
235             as_warn (_("operand references R%ld of previous load."),
236                      insn.fields.f_sr1);
237
238           if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
239               && insn.fields.f_sr2 == delayed_load_register)
240             as_warn (_("operand references R%ld of previous load."),
241                      insn.fields.f_sr2);
242         }
243
244       /* Detect data dependency between conditional branch instruction
245          and an immediately preceding arithmetic or logical instruction.  */
246       if (last_insn_was_arithmetic_or_logic
247           && !last_insn_in_noncond_delay_slot
248           && (delayed_load_register != 0)
249           && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
250           && ms1_arch == ms1_64_001)
251         {
252           if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
253               && insn.fields.f_sr1 == delayed_load_register)
254             as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
255                      insn.fields.f_sr1);
256
257           if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
258               && insn.fields.f_sr2 == delayed_load_register)
259             as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
260                      insn.fields.f_sr2);
261         }
262     }
263
264   /* Keep track of details of this insn for processing next insn.  */
265   last_insn_in_noncond_delay_slot = last_insn_was_branch_insn
266     && !last_insn_was_conditional_branch_insn;
267
268   last_insn_had_delay_slot =
269     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
270
271   last_insn_has_load_delay =
272     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY);
273
274   last_insn_was_memory_access =
275     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS);
276
277   last_insn_was_io_insn =
278     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN);
279
280   last_insn_was_arithmetic_or_logic =
281     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_AL_INSN);
282
283   last_insn_was_branch_insn =
284     CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN);
285   
286   last_insn_was_conditional_branch_insn =
287   CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
288     && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2);
289   
290   if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDR))
291      delayed_load_register = insn.fields.f_dr; 
292   else if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDRRR))
293      delayed_load_register = insn.fields.f_drrr; 
294   else  /* Insns has no destination register.  */
295      delayed_load_register = 0; 
296
297   /* Generate dwarf2 line numbers.  */
298   dwarf2_emit_insn (4); 
299 }
300
301 valueT
302 md_section_align (segT segment, valueT size)
303 {
304   int align = bfd_get_section_alignment (stdoutput, segment);
305
306   return ((size + (1 << align) - 1) & (-1 << align));
307 }
308
309 symbolS *
310 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
311 {
312     return NULL;
313 }
314 \f
315 int
316 md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
317                                segT    segment ATTRIBUTE_UNUSED)
318 {
319   as_fatal (_("md_estimate_size_before_relax\n"));
320   return 1;
321
322
323 /* *fragP has been relaxed to its final size, and now needs to have
324    the bytes inside it modified to conform to the new size.
325
326    Called after relaxation is finished.
327    fragP->fr_type == rs_machine_dependent.
328    fragP->fr_subtype is the subtype of what the address relaxed to.  */
329
330 void
331 md_convert_frag (bfd   * abfd  ATTRIBUTE_UNUSED,
332                  segT    sec   ATTRIBUTE_UNUSED,
333                  fragS * fragP ATTRIBUTE_UNUSED)
334 {
335 }
336
337 \f
338 /* Functions concerning relocs.  */
339
340 long
341 md_pcrel_from_section (fixS *fixP, segT sec)
342 {
343   if (fixP->fx_addsy != (symbolS *) NULL
344       && (!S_IS_DEFINED (fixP->fx_addsy)
345           || S_GET_SEGMENT (fixP->fx_addsy) != sec))
346     /* The symbol is undefined (or is defined but not in this section).
347        Let the linker figure it out.  */
348     return 0;
349
350   /* Return the address of the opcode - cgen adjusts for opcode size
351      itself, to be consistent with the disassembler, which must do
352      so.  */
353   return fixP->fx_where + fixP->fx_frag->fr_address;
354 }
355
356
357 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
358    Returns BFD_RELOC_NONE if no reloc type can be found.
359    *FIXP may be modified if desired.  */
360
361 bfd_reloc_code_real_type
362 md_cgen_lookup_reloc (const CGEN_INSN *    insn     ATTRIBUTE_UNUSED,
363                       const CGEN_OPERAND * operand,
364                       fixS *               fixP     ATTRIBUTE_UNUSED)
365 {
366   bfd_reloc_code_real_type result;
367
368   result = BFD_RELOC_NONE;
369
370   switch (operand->type)
371     {
372     case MS1_OPERAND_IMM16O:
373       result = BFD_RELOC_16_PCREL;
374       fixP->fx_pcrel = 1;
375       /* fixP->fx_no_overflow = 1; */
376       break;
377     case MS1_OPERAND_IMM16:
378     case MS1_OPERAND_IMM16Z:
379       /* These may have been processed at parse time.  */
380       if (fixP->fx_cgen.opinfo != 0)
381         result = fixP->fx_cgen.opinfo;
382       fixP->fx_no_overflow = 1;
383       break;
384     default:
385       result = BFD_RELOC_NONE;
386       break;
387     }
388
389   return result;
390 }
391
392 /* Write a value out to the object file, using the appropriate endianness.  */
393
394 void
395 md_number_to_chars (char * buf, valueT val, int n)
396 {
397   number_to_chars_bigendian (buf, val, n);
398 }
399
400 /* Turn a string in input_line_pointer into a floating point constant of type
401    type, and store the appropriate bytes in *litP.  The number of LITTLENUMS
402    emitted is stored in *sizeP .  An error message is returned, or NULL on OK.  */
403
404 /* Equal to MAX_PRECISION in atof-ieee.c.  */
405 #define MAX_LITTLENUMS 6
406
407 char *
408 md_atof (type, litP, sizeP)
409      char   type;
410      char * litP;
411      int *  sizeP;
412 {
413   int              prec;
414   LITTLENUM_TYPE   words [MAX_LITTLENUMS];
415   LITTLENUM_TYPE * wordP;
416   char *           t;
417
418   switch (type)
419     {
420     case 'f':
421     case 'F':
422     case 's':
423     case 'S':
424       prec = 2;
425       break;
426
427     case 'd':
428     case 'D':
429     case 'r':
430     case 'R':
431       prec = 4;
432       break;
433
434    /* FIXME: Some targets allow other format chars for bigger sizes here.  */
435
436     default:
437       * sizeP = 0;
438       return _("Bad call to md_atof()");
439     }
440
441   t = atof_ieee (input_line_pointer, type, words);
442   if (t)
443     input_line_pointer = t;
444   * sizeP = prec * sizeof (LITTLENUM_TYPE);
445
446   /* This loops outputs the LITTLENUMs in REVERSE order;
447      in accord with the ms1 endianness.  */
448   for (wordP = words; prec--;)
449     {
450       md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
451       litP += sizeof (LITTLENUM_TYPE);
452     }
453      
454   return 0;
455 }
456
457 /* See whether we need to force a relocation into the output file.  */
458
459 int
460 ms1_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
461 {
462   return 0;
463 }
464
465 void
466 ms1_apply_fix (fixS *fixP, valueT *valueP, segT seg)
467 {
468   if ((fixP->fx_pcrel != 0) && (fixP->fx_r_type == BFD_RELOC_32))
469     fixP->fx_r_type = BFD_RELOC_32_PCREL;
470
471   gas_cgen_md_apply_fix (fixP, valueP, seg);
472 }
473
474 bfd_boolean
475 ms1_fix_adjustable (fixS * fixP)
476 {
477   bfd_reloc_code_real_type reloc_type;
478
479   if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
480     {
481       const CGEN_INSN *insn = NULL;
482       int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
483       const CGEN_OPERAND *operand;
484
485       operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
486       reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
487     }
488   else
489     reloc_type = fixP->fx_r_type;
490
491   if (fixP->fx_addsy == NULL)
492     return TRUE;
493   
494   /* Prevent all adjustments to global symbols.  */
495   if (S_IS_EXTERNAL (fixP->fx_addsy))
496     return FALSE;
497   
498   if (S_IS_WEAK (fixP->fx_addsy))
499     return FALSE;
500   
501   return 1;
502 }