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
[] =
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
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
)
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;
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"));
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
,
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. */
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
);
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;
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
);
199 as_bad ("%s", errmsg
);
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."),
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."),
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."),
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."),
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);
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
));
310 md_undefined_symbol (char * name ATTRIBUTE_UNUSED
)
316 md_estimate_size_before_relax (fragS
* fragP ATTRIBUTE_UNUSED
,
317 segT segment ATTRIBUTE_UNUSED
)
319 as_fatal (_("md_estimate_size_before_relax\n"));
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. */
331 md_convert_frag (bfd
* abfd ATTRIBUTE_UNUSED
,
332 segT sec ATTRIBUTE_UNUSED
,
333 fragS
* fragP ATTRIBUTE_UNUSED
)
338 /* Functions concerning relocs. */
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. */
350 /* Return the address of the opcode - cgen adjusts for opcode size
351 itself, to be consistent with the disassembler, which must do
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
;
375 /* fixP->fx_no_overflow = 1; */
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;
385 result
= BFD_RELOC_NONE
;
392 /* Write a value out to the object file, using the appropriate endianness. */
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
408 md_atof (type
, litP
, sizeP
)
414 LITTLENUM_TYPE words
[MAX_LITTLENUMS
];
415 LITTLENUM_TYPE
* wordP
;
434 /* FIXME: Some targets allow other format chars for bigger sizes here. */
438 return _("Bad call to md_atof()");
441 t
= atof_ieee (input_line_pointer
, type
, words
);
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
);
457 /* See whether we need to force a relocation into the output file. */
460 ms1_force_relocation (fixS
* fixp ATTRIBUTE_UNUSED
)
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
);
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
);
489 reloc_type
= fixP
->fx_r_type
;
491 if (fixP
->fx_addsy
== NULL
)
494 /* Prevent all adjustments to global symbols. */
495 if (S_IS_EXTERNAL (fixP
->fx_addsy
))
498 if (S_IS_WEAK (fixP
->fx_addsy
))