remove some duplicate #include's.
[deliverable/binutils-gdb.git] / gas / config / tc-mt.c
1 /* tc-mt.c -- Assembler for the Morpho Technologies mt .
2 Copyright (C) 2005, 2006 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 "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 }
This page took 0.040654 seconds and 4 git commands to generate.