* dwarf2dbg.c (struct line_entry): Replace frag and frag_ofs
[binutils.git] / gas / config / tc-ms1.c
blobe459bc843196f7412ec7a49af0146645c69e2d7a
1 /* tc-ms1.c -- Assembler for the Morpho Technologies ms-I.
2 Copyright (C) 2005 Free Software Foundation.
4 This file is part of GAS, the GNU Assembler.
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.
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.
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. */
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"
33 /* Structure to hold all of the different components
34 describing an individual instruction. */
35 typedef struct
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];
53 ms1_insn;
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";
62 /* The target specific pseudo-ops which we support. */
63 const pseudo_typeS md_pseudo_table[] =
65 { "word", cons, 4 },
66 { NULL, NULL, 0 }
71 static int no_scheduling_restrictions = 0;
73 struct option md_longopts[] =
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 },
81 size_t md_longopts_size = sizeof (md_longopts);
83 const char * md_shortopts = "";
85 /* Mach selected from command line. */
86 static int ms1_mach = bfd_mach_ms1;
87 static unsigned ms1_mach_bitmask = 0;
89 /* Flags to set in the elf header */
90 static flagword ms1_flags = EF_MS1_CPU_MRISC;
92 /* The architecture to use. */
93 enum ms1_architectures
95 ms1_64_001,
96 ms1_16_002,
97 ms1_16_003
100 /* MS1 architecture we are using for this output file. */
101 static enum ms1_architectures ms1_arch = ms1_64_001;
104 md_parse_option (int c ATTRIBUTE_UNUSED, char * arg)
106 switch (c)
108 case OPTION_MARCH:
109 if (strcasecmp (arg, "MS1-64-001") == 0)
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;
116 else if (strcasecmp (arg, "MS1-16-002") == 0)
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;
123 else if (strcasecmp (arg, "MS1-16-003") == 0)
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;
130 case OPTION_NO_SCHED_REST:
131 no_scheduling_restrictions = 1;
132 break;
133 default:
134 return 0;
137 return 1;
141 void
142 md_show_usage (FILE * stream)
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"));
152 void
153 md_begin (void)
155 /* Initialize the `cgen' interface. */
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);
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);
167 /* Set the ELF flags if desired. */
168 if (ms1_flags)
169 bfd_set_private_flags (stdoutput, ms1_flags);
171 /* Set the machine type. */
172 bfd_default_set_arch_mach (stdoutput, bfd_arch_ms1, ms1_mach);
175 void
176 md_assemble (char * str)
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;
188 ms1_insn insn;
189 char * errmsg;
191 /* Initialize GAS's cgen interface for a new instruction. */
192 gas_cgen_init_parse ();
194 insn.insn = ms1_cgen_assemble_insn
195 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
197 if (!insn.insn)
199 as_bad ("%s", errmsg);
200 return;
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);
208 /* Handle Scheduling Restrictions. */
209 if (!no_scheduling_restrictions)
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));
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));
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));
230 /* Detect data dependencies on delayed loads: memory and input insns. */
231 if (last_insn_has_load_delay && delayed_load_register)
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);
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);
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)
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);
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);
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;
268 last_insn_had_delay_slot =
269 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
271 last_insn_has_load_delay =
272 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY);
274 last_insn_was_memory_access =
275 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS);
277 last_insn_was_io_insn =
278 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN);
280 last_insn_was_arithmetic_or_logic =
281 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_AL_INSN);
283 last_insn_was_branch_insn =
284 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN);
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);
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;
297 /* Generate dwarf2 line numbers. */
298 dwarf2_emit_insn (4);
301 valueT
302 md_section_align (segT segment, valueT size)
304 int align = bfd_get_section_alignment (stdoutput, segment);
306 return ((size + (1 << align) - 1) & (-1 << align));
309 symbolS *
310 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
312 return NULL;
316 md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
317 segT segment ATTRIBUTE_UNUSED)
319 as_fatal (_("md_estimate_size_before_relax\n"));
320 return 1;
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.
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. */
330 void
331 md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
332 segT sec ATTRIBUTE_UNUSED,
333 fragS * fragP ATTRIBUTE_UNUSED)
338 /* Functions concerning relocs. */
340 long
341 md_pcrel_from_section (fixS *fixP, segT sec)
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;
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;
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. */
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)
366 bfd_reloc_code_real_type result;
368 result = BFD_RELOC_NONE;
370 switch (operand->type)
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;
389 return result;
392 /* Write a value out to the object file, using the appropriate endianness. */
394 void
395 md_number_to_chars (char * buf, valueT val, int n)
397 number_to_chars_bigendian (buf, val, n);
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. */
404 /* Equal to MAX_PRECISION in atof-ieee.c. */
405 #define MAX_LITTLENUMS 6
407 char *
408 md_atof (type, litP, sizeP)
409 char type;
410 char * litP;
411 int * sizeP;
413 int prec;
414 LITTLENUM_TYPE words [MAX_LITTLENUMS];
415 LITTLENUM_TYPE * wordP;
416 char * t;
418 switch (type)
420 case 'f':
421 case 'F':
422 case 's':
423 case 'S':
424 prec = 2;
425 break;
427 case 'd':
428 case 'D':
429 case 'r':
430 case 'R':
431 prec = 4;
432 break;
434 /* FIXME: Some targets allow other format chars for bigger sizes here. */
436 default:
437 * sizeP = 0;
438 return _("Bad call to md_atof()");
441 t = atof_ieee (input_line_pointer, type, words);
442 if (t)
443 input_line_pointer = t;
444 * sizeP = prec * sizeof (LITTLENUM_TYPE);
446 /* This loops outputs the LITTLENUMs in REVERSE order;
447 in accord with the ms1 endianness. */
448 for (wordP = words; prec--;)
450 md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE));
451 litP += sizeof (LITTLENUM_TYPE);
454 return 0;
457 /* See whether we need to force a relocation into the output file. */
460 ms1_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
462 return 0;
465 void
466 ms1_apply_fix (fixS *fixP, valueT *valueP, segT seg)
468 if ((fixP->fx_pcrel != 0) && (fixP->fx_r_type == BFD_RELOC_32))
469 fixP->fx_r_type = BFD_RELOC_32_PCREL;
471 gas_cgen_md_apply_fix (fixP, valueP, seg);
474 bfd_boolean
475 ms1_fix_adjustable (fixS * fixP)
477 bfd_reloc_code_real_type reloc_type;
479 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
481 const CGEN_INSN *insn = NULL;
482 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
483 const CGEN_OPERAND *operand;
485 operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
486 reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
488 else
489 reloc_type = fixP->fx_r_type;
491 if (fixP->fx_addsy == NULL)
492 return TRUE;
494 /* Prevent all adjustments to global symbols. */
495 if (S_IS_EXTERNAL (fixP->fx_addsy))
496 return FALSE;
498 if (S_IS_WEAK (fixP->fx_addsy))
499 return FALSE;
501 return 1;