* dwarf2dbg.c (struct line_entry): Replace frag and frag_ofs
[binutils-gdb.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 }