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)
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. */
23 #include "dwarf2dbg.h"
26 #include "opcodes/ms1-desc.h"
27 #include "opcodes/ms1-opc.h"
29 #include "elf/common.h"
33 /* Structure to hold all of the different components
34 describing an individual instruction. */
37 const CGEN_INSN
* insn
;
38 const CGEN_INSN
* orig_insn
;
41 CGEN_INSN_INT buffer
[1];
42 #define INSN_VALUE(buf) (*(buf))
44 unsigned char buffer
[CGEN_MAX_INSN_SIZE
];
45 #define INSN_VALUE(buf) (buf)
50 fixS
* fixups
[GAS_CGEN_MAX_FIXUPS
];
51 int indices
[MAX_OPERAND_INSTANCES
];
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
[] =
66 { "file", (void (*) (int)) dwarf2_directive_file
, 0 },
67 { "loc", dwarf2_directive_loc
, 0 },
73 static int no_scheduling_restrictions
= 0;
75 struct option md_longopts
[] =
77 #define OPTION_NO_SCHED_REST (OPTION_MD_BASE)
78 { "nosched", no_argument
, NULL
, OPTION_NO_SCHED_REST
},
79 #define OPTION_MARCH (OPTION_MD_BASE + 1)
80 { "march", required_argument
, NULL
, OPTION_MARCH
},
81 { NULL
, no_argument
, NULL
, 0 },
83 size_t md_longopts_size
= sizeof (md_longopts
);
85 const char * md_shortopts
= "";
87 /* Mach selected from command line. */
88 static int ms1_mach
= bfd_mach_ms1
;
89 static unsigned ms1_mach_bitmask
= 0;
91 /* Flags to set in the elf header */
92 static flagword ms1_flags
= EF_MS1_CPU_MRISC
;
94 /* The architecture to use. */
95 enum ms1_architectures
102 /* MS1 architecture we are using for this output file. */
103 static enum ms1_architectures ms1_arch
= ms1_64_001
;
106 md_parse_option (int c ATTRIBUTE_UNUSED
, char * arg
)
111 if (strcasecmp (arg
, "MS1-64-001") == 0)
113 ms1_flags
= (ms1_flags
& ~EF_MS1_CPU_MASK
) | EF_MS1_CPU_MRISC
;
114 ms1_mach
= bfd_mach_ms1
;
115 ms1_mach_bitmask
= 1 << MACH_MS1
;
116 ms1_arch
= ms1_64_001
;
118 else if (strcasecmp (arg
, "MS1-16-002") == 0)
120 ms1_flags
= (ms1_flags
& ~EF_MS1_CPU_MASK
) | EF_MS1_CPU_MRISC
;
121 ms1_mach
= bfd_mach_ms1
;
122 ms1_mach_bitmask
= 1 << MACH_MS1
;
123 ms1_arch
= ms1_16_002
;
125 else if (strcasecmp (arg
, "MS1-16-003") == 0)
127 ms1_flags
= (ms1_flags
& ~EF_MS1_CPU_MASK
) | EF_MS1_CPU_MRISC2
;
128 ms1_mach
= bfd_mach_mrisc2
;
129 ms1_mach_bitmask
= 1 << MACH_MS1_003
;
130 ms1_arch
= ms1_16_003
;
132 case OPTION_NO_SCHED_REST
:
133 no_scheduling_restrictions
= 1;
144 md_show_usage (FILE * stream
)
146 fprintf (stream
, _("MS1 specific command line options:\n"));
147 fprintf (stream
, _(" -march=ms1-64-001 allow ms1-64-001 instructions (default) \n"));
148 fprintf (stream
, _(" -march=ms1-16-002 allow ms1-16-002 instructions \n"));
149 fprintf (stream
, _(" -march=ms1-16-003 allow ms1-16-003 instructions \n"));
150 fprintf (stream
, _(" -nosched disable scheduling restrictions \n"));
157 /* Initialize the `cgen' interface. */
159 /* Set the machine number and endian. */
160 gas_cgen_cpu_desc
= ms1_cgen_cpu_open (CGEN_CPU_OPEN_MACHS
, ms1_mach_bitmask
,
161 CGEN_CPU_OPEN_ENDIAN
,
164 ms1_cgen_init_asm (gas_cgen_cpu_desc
);
166 /* This is a callback from cgen to gas to parse operands. */
167 cgen_set_parse_operand_fn (gas_cgen_cpu_desc
, gas_cgen_parse_operand
);
169 /* Set the ELF flags if desired. */
171 bfd_set_private_flags (stdoutput
, ms1_flags
);
173 /* Set the machine type. */
174 bfd_default_set_arch_mach (stdoutput
, bfd_arch_ms1
, ms1_mach
);
178 md_assemble (char * str
)
180 static long delayed_load_register
= 0;
181 static int last_insn_had_delay_slot
= 0;
182 static int last_insn_in_noncond_delay_slot
= 0;
183 static int last_insn_has_load_delay
= 0;
184 static int last_insn_was_memory_access
= 0;
185 static int last_insn_was_io_insn
= 0;
186 static int last_insn_was_arithmetic_or_logic
= 0;
187 static int last_insn_was_branch_insn
= 0;
188 static int last_insn_was_conditional_branch_insn
= 0;
193 /* Initialize GAS's cgen interface for a new instruction. */
194 gas_cgen_init_parse ();
196 insn
.insn
= ms1_cgen_assemble_insn
197 (gas_cgen_cpu_desc
, str
, & insn
.fields
, insn
.buffer
, & errmsg
);
201 as_bad ("%s", errmsg
);
205 /* Doesn't really matter what we pass for RELAX_P here. */
206 gas_cgen_finish_insn (insn
.insn
, insn
.buffer
,
207 CGEN_FIELDS_BITSIZE (& insn
.fields
), 1, NULL
);
210 /* Handle Scheduling Restrictions. */
211 if (!no_scheduling_restrictions
)
213 /* Detect consecutive Memory Accesses. */
214 if (last_insn_was_memory_access
215 && CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_MEMORY_ACCESS
)
216 && ms1_mach
== ms1_64_001
)
217 as_warn (_("instruction %s may not follow another memory access instruction."),
218 CGEN_INSN_NAME (insn
.insn
));
220 /* Detect consecutive I/O Instructions. */
221 else if (last_insn_was_io_insn
222 && CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_IO_INSN
))
223 as_warn (_("instruction %s may not follow another I/O instruction."),
224 CGEN_INSN_NAME (insn
.insn
));
226 /* Detect consecutive branch instructions. */
227 else if (last_insn_was_branch_insn
228 && CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_BR_INSN
))
229 as_warn (_("%s may not occupy the delay slot of another branch insn."),
230 CGEN_INSN_NAME (insn
.insn
));
232 /* Detect data dependencies on delayed loads: memory and input insns. */
233 if (last_insn_has_load_delay
&& delayed_load_register
)
235 if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR1
)
236 && insn
.fields
.f_sr1
== delayed_load_register
)
237 as_warn (_("operand references R%ld of previous load."),
240 if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR2
)
241 && insn
.fields
.f_sr2
== delayed_load_register
)
242 as_warn (_("operand references R%ld of previous load."),
246 /* Detect data dependency between conditional branch instruction
247 and an immediately preceding arithmetic or logical instruction. */
248 if (last_insn_was_arithmetic_or_logic
249 && !last_insn_in_noncond_delay_slot
250 && (delayed_load_register
!= 0)
251 && CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_BR_INSN
)
252 && ms1_arch
== ms1_64_001
)
254 if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR1
)
255 && insn
.fields
.f_sr1
== delayed_load_register
)
256 as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
259 if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR2
)
260 && insn
.fields
.f_sr2
== delayed_load_register
)
261 as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
266 /* Keep track of details of this insn for processing next insn. */
267 last_insn_in_noncond_delay_slot
= last_insn_was_branch_insn
268 && !last_insn_was_conditional_branch_insn
;
270 last_insn_had_delay_slot
=
271 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_DELAY_SLOT
);
273 last_insn_has_load_delay
=
274 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_LOAD_DELAY
);
276 last_insn_was_memory_access
=
277 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_MEMORY_ACCESS
);
279 last_insn_was_io_insn
=
280 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_IO_INSN
);
282 last_insn_was_arithmetic_or_logic
=
283 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_AL_INSN
);
285 last_insn_was_branch_insn
=
286 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_BR_INSN
);
288 last_insn_was_conditional_branch_insn
=
289 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_BR_INSN
)
290 && CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR2
);
292 if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRDR
))
293 delayed_load_register
= insn
.fields
.f_dr
;
294 else if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRDRRR
))
295 delayed_load_register
= insn
.fields
.f_drrr
;
296 else /* Insns has no destination register. */
297 delayed_load_register
= 0;
299 /* Generate dwarf2 line numbers. */
300 dwarf2_emit_insn (4);
304 md_section_align (segT segment
, valueT size
)
306 int align
= bfd_get_section_alignment (stdoutput
, segment
);
308 return ((size
+ (1 << align
) - 1) & (-1 << align
));
312 md_undefined_symbol (char * name ATTRIBUTE_UNUSED
)
318 md_estimate_size_before_relax (fragS
* fragP ATTRIBUTE_UNUSED
,
319 segT segment ATTRIBUTE_UNUSED
)
321 as_fatal (_("md_estimate_size_before_relax\n"));
325 /* *fragP has been relaxed to its final size, and now needs to have
326 the bytes inside it modified to conform to the new size.
328 Called after relaxation is finished.
329 fragP->fr_type == rs_machine_dependent.
330 fragP->fr_subtype is the subtype of what the address relaxed to. */
333 md_convert_frag (bfd
* abfd ATTRIBUTE_UNUSED
,
334 segT sec ATTRIBUTE_UNUSED
,
335 fragS
* fragP ATTRIBUTE_UNUSED
)
340 /* Functions concerning relocs. */
343 md_pcrel_from_section (fixS
*fixP
, segT sec
)
345 if (fixP
->fx_addsy
!= (symbolS
*) NULL
346 && (!S_IS_DEFINED (fixP
->fx_addsy
)
347 || S_GET_SEGMENT (fixP
->fx_addsy
) != sec
))
348 /* The symbol is undefined (or is defined but not in this section).
349 Let the linker figure it out. */
352 /* Return the address of the opcode - cgen adjusts for opcode size
353 itself, to be consistent with the disassembler, which must do
355 return fixP
->fx_where
+ fixP
->fx_frag
->fr_address
;
359 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
360 Returns BFD_RELOC_NONE if no reloc type can be found.
361 *FIXP may be modified if desired. */
363 bfd_reloc_code_real_type
364 md_cgen_lookup_reloc (const CGEN_INSN
* insn ATTRIBUTE_UNUSED
,
365 const CGEN_OPERAND
* operand
,
366 fixS
* fixP ATTRIBUTE_UNUSED
)
368 bfd_reloc_code_real_type result
;
370 result
= BFD_RELOC_NONE
;
372 switch (operand
->type
)
374 case MS1_OPERAND_IMM16O
:
375 result
= BFD_RELOC_16_PCREL
;
377 /* fixP->fx_no_overflow = 1; */
379 case MS1_OPERAND_IMM16
:
380 case MS1_OPERAND_IMM16Z
:
381 /* These may have been processed at parse time. */
382 if (fixP
->fx_cgen
.opinfo
!= 0)
383 result
= fixP
->fx_cgen
.opinfo
;
384 fixP
->fx_no_overflow
= 1;
387 result
= BFD_RELOC_NONE
;
394 /* Write a value out to the object file, using the appropriate endianness. */
397 md_number_to_chars (char * buf
, valueT val
, int n
)
399 number_to_chars_bigendian (buf
, val
, n
);
402 /* Turn a string in input_line_pointer into a floating point constant of type
403 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
404 emitted is stored in *sizeP . An error message is returned, or NULL on OK. */
406 /* Equal to MAX_PRECISION in atof-ieee.c. */
407 #define MAX_LITTLENUMS 6
410 md_atof (type
, litP
, sizeP
)
416 LITTLENUM_TYPE words
[MAX_LITTLENUMS
];
417 LITTLENUM_TYPE
* wordP
;
436 /* FIXME: Some targets allow other format chars for bigger sizes here. */
440 return _("Bad call to md_atof()");
443 t
= atof_ieee (input_line_pointer
, type
, words
);
445 input_line_pointer
= t
;
446 * sizeP
= prec
* sizeof (LITTLENUM_TYPE
);
448 /* This loops outputs the LITTLENUMs in REVERSE order;
449 in accord with the ms1 endianness. */
450 for (wordP
= words
; prec
--;)
452 md_number_to_chars (litP
, (valueT
) (*wordP
++), sizeof (LITTLENUM_TYPE
));
453 litP
+= sizeof (LITTLENUM_TYPE
);
459 /* See whether we need to force a relocation into the output file. */
462 ms1_force_relocation (fixS
* fixp ATTRIBUTE_UNUSED
)
468 ms1_apply_fix (fixS
*fixP
, valueT
*valueP
, segT seg
)
470 if ((fixP
->fx_pcrel
!= 0) && (fixP
->fx_r_type
== BFD_RELOC_32
))
471 fixP
->fx_r_type
= BFD_RELOC_32_PCREL
;
473 gas_cgen_md_apply_fix (fixP
, valueP
, seg
);
477 ms1_fix_adjustable (fixS
* fixP
)
479 bfd_reloc_code_real_type reloc_type
;
481 if ((int) fixP
->fx_r_type
>= (int) BFD_RELOC_UNUSED
)
483 const CGEN_INSN
*insn
= NULL
;
484 int opindex
= (int) fixP
->fx_r_type
- (int) BFD_RELOC_UNUSED
;
485 const CGEN_OPERAND
*operand
;
487 operand
= cgen_operand_lookup_by_num(gas_cgen_cpu_desc
, opindex
);
488 reloc_type
= md_cgen_lookup_reloc (insn
, operand
, fixP
);
491 reloc_type
= fixP
->fx_r_type
;
493 if (fixP
->fx_addsy
== NULL
)
496 /* Prevent all adjustments to global symbols. */
497 if (S_IS_EXTERNAL (fixP
->fx_addsy
))
500 if (S_IS_WEAK (fixP
->fx_addsy
))