48d272fb64bf7f7001bc6954ea0e5afea141d997
[deliverable/binutils-gdb.git] / gas / config / tc-mt.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/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 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 = 1 << MACH_MS1;
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 ms2
99 };
100
101 /* MS1 architecture we are using for this output file. */
102 static enum ms1_architectures ms1_arch = ms1_64_001;
103
104 int
105 md_parse_option (int c ATTRIBUTE_UNUSED, char * arg)
106 {
107 switch (c)
108 {
109 case OPTION_MARCH:
110 if (strcasecmp (arg, "MS1-64-001") == 0)
111 {
112 ms1_flags = (ms1_flags & ~EF_MS1_CPU_MASK) | EF_MS1_CPU_MRISC;
113 ms1_mach = bfd_mach_ms1;
114 ms1_mach_bitmask = 1 << MACH_MS1;
115 ms1_arch = ms1_64_001;
116 }
117 else if (strcasecmp (arg, "MS1-16-002") == 0)
118 {
119 ms1_flags = (ms1_flags & ~EF_MS1_CPU_MASK) | EF_MS1_CPU_MRISC;
120 ms1_mach = bfd_mach_ms1;
121 ms1_mach_bitmask = 1 << MACH_MS1;
122 ms1_arch = ms1_16_002;
123 }
124 else if (strcasecmp (arg, "MS1-16-003") == 0)
125 {
126 ms1_flags = (ms1_flags & ~EF_MS1_CPU_MASK) | EF_MS1_CPU_MRISC2;
127 ms1_mach = bfd_mach_mrisc2;
128 ms1_mach_bitmask = 1 << MACH_MS1_003;
129 ms1_arch = ms1_16_003;
130 }
131 else if (strcasecmp (arg, "MS2") == 0)
132 {
133 ms1_flags = (ms1_flags & ~EF_MS1_CPU_MASK) | EF_MS1_CPU_MS2;
134 ms1_mach = bfd_mach_mrisc2;
135 ms1_mach_bitmask = 1 << MACH_MS2;
136 ms1_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
150 md_show_usage (FILE * stream)
151 {
152 fprintf (stream, _("MS1 specific command line options:\n"));
153 fprintf (stream, _(" -march=ms1-64-001 allow ms1-64-001 instructions (default) \n"));
154 fprintf (stream, _(" -march=ms1-16-002 allow ms1-16-002 instructions \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 \f
161 void
162 md_begin (void)
163 {
164 /* Initialize the `cgen' interface. */
165
166 /* Set the machine number and endian. */
167 gas_cgen_cpu_desc = ms1_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, ms1_mach_bitmask,
168 CGEN_CPU_OPEN_ENDIAN,
169 CGEN_ENDIAN_BIG,
170 CGEN_CPU_OPEN_END);
171 ms1_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 (ms1_flags)
178 bfd_set_private_flags (stdoutput, ms1_flags);
179
180 /* Set the machine type. */
181 bfd_default_set_arch_mach (stdoutput, bfd_arch_ms1, ms1_mach);
182 }
183
184 void
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 ms1_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 = ms1_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 && ms1_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 (ms1_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 && ms1_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
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 MS1_OPERAND_IMM16O:
403 result = BFD_RELOC_16_PCREL;
404 fixP->fx_pcrel = 1;
405 /* fixP->fx_no_overflow = 1; */
406 break;
407 case MS1_OPERAND_IMM16:
408 case MS1_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 MS1_OPERAND_LOOPSIZE:
415 result = BFD_RELOC_MS1_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 /* 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 *
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 ms1 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
496 ms1_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
497 {
498 return 0;
499 }
500
501 void
502 ms1_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
511 ms1_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 }
This page took 0.045025 seconds and 3 git commands to generate.