1 /* tc-mt.c -- Assembler for the Morpho Technologies mt .
2 Copyright (C) 2005-2016 Free Software Foundation, Inc.
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 3, 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. */
22 #include "dwarf2dbg.h"
25 #include "opcodes/mt-desc.h"
26 #include "opcodes/mt-opc.h"
28 #include "elf/common.h"
31 /* Structure to hold all of the different components
32 describing an individual instruction. */
35 const CGEN_INSN
* insn
;
36 const CGEN_INSN
* orig_insn
;
39 CGEN_INSN_INT buffer
[1];
40 #define INSN_VALUE(buf) (*(buf))
42 unsigned char buffer
[CGEN_MAX_INSN_SIZE
];
43 #define INSN_VALUE(buf) (buf)
48 fixS
* fixups
[GAS_CGEN_MAX_FIXUPS
];
49 int indices
[MAX_OPERAND_INSTANCES
];
54 const char comment_chars
[] = ";";
55 const char line_comment_chars
[] = "#";
56 const char line_separator_chars
[] = "";
57 const char EXP_CHARS
[] = "eE";
58 const char FLT_CHARS
[] = "dD";
60 /* The target specific pseudo-ops which we support. */
61 const pseudo_typeS md_pseudo_table
[] =
69 static int no_scheduling_restrictions
= 0;
71 struct option md_longopts
[] =
73 #define OPTION_NO_SCHED_REST (OPTION_MD_BASE)
74 { "nosched", no_argument
, NULL
, OPTION_NO_SCHED_REST
},
75 #define OPTION_MARCH (OPTION_MD_BASE + 1)
76 { "march", required_argument
, NULL
, OPTION_MARCH
},
77 { NULL
, no_argument
, NULL
, 0 },
79 size_t md_longopts_size
= sizeof (md_longopts
);
81 const char * md_shortopts
= "";
83 /* Mach selected from command line. */
84 static int mt_mach
= bfd_mach_ms1
;
85 static unsigned mt_mach_bitmask
= 1 << MACH_MS1
;
87 /* Flags to set in the elf header */
88 static flagword mt_flags
= EF_MT_CPU_MRISC
;
90 /* The architecture to use. */
99 /* MT architecture we are using for this output file. */
100 static enum mt_architectures mt_arch
= ms1_16_002
;
103 md_parse_option (int c ATTRIBUTE_UNUSED
, const char * arg
)
108 if (strcmp (arg
, "ms1-64-001") == 0)
110 mt_flags
= (mt_flags
& ~EF_MT_CPU_MASK
) | EF_MT_CPU_MRISC
;
111 mt_mach
= bfd_mach_ms1
;
112 mt_mach_bitmask
= 1 << MACH_MS1
;
113 mt_arch
= ms1_64_001
;
115 else if (strcmp (arg
, "ms1-16-002") == 0)
117 mt_flags
= (mt_flags
& ~EF_MT_CPU_MASK
) | EF_MT_CPU_MRISC
;
118 mt_mach
= bfd_mach_ms1
;
119 mt_mach_bitmask
= 1 << MACH_MS1
;
120 mt_arch
= ms1_16_002
;
122 else if (strcmp (arg
, "ms1-16-003") == 0)
124 mt_flags
= (mt_flags
& ~EF_MT_CPU_MASK
) | EF_MT_CPU_MRISC2
;
125 mt_mach
= bfd_mach_mrisc2
;
126 mt_mach_bitmask
= 1 << MACH_MS1_003
;
127 mt_arch
= ms1_16_003
;
129 else if (strcmp (arg
, "ms2") == 0)
131 mt_flags
= (mt_flags
& ~EF_MT_CPU_MASK
) | EF_MT_CPU_MS2
;
132 mt_mach
= bfd_mach_mrisc2
;
133 mt_mach_bitmask
= 1 << MACH_MS2
;
136 case OPTION_NO_SCHED_REST
:
137 no_scheduling_restrictions
= 1;
148 md_show_usage (FILE * stream
)
150 fprintf (stream
, _("MT specific command line options:\n"));
151 fprintf (stream
, _(" -march=ms1-64-001 allow ms1-64-001 instructions\n"));
152 fprintf (stream
, _(" -march=ms1-16-002 allow ms1-16-002 instructions (default)\n"));
153 fprintf (stream
, _(" -march=ms1-16-003 allow ms1-16-003 instructions\n"));
154 fprintf (stream
, _(" -march=ms2 allow ms2 instructions \n"));
155 fprintf (stream
, _(" -nosched disable scheduling restrictions\n"));
162 /* Initialize the `cgen' interface. */
164 /* Set the machine number and endian. */
165 gas_cgen_cpu_desc
= mt_cgen_cpu_open (CGEN_CPU_OPEN_MACHS
, mt_mach_bitmask
,
166 CGEN_CPU_OPEN_ENDIAN
,
169 mt_cgen_init_asm (gas_cgen_cpu_desc
);
171 /* This is a callback from cgen to gas to parse operands. */
172 cgen_set_parse_operand_fn (gas_cgen_cpu_desc
, gas_cgen_parse_operand
);
174 /* Set the ELF flags if desired. */
176 bfd_set_private_flags (stdoutput
, mt_flags
);
178 /* Set the machine type. */
179 bfd_default_set_arch_mach (stdoutput
, bfd_arch_mt
, mt_mach
);
183 md_assemble (char * str
)
185 static long delayed_load_register
= 0;
186 static long prev_delayed_load_register
= 0;
187 static int last_insn_had_delay_slot
= 0;
188 static int last_insn_in_noncond_delay_slot
= 0;
189 static int last_insn_has_load_delay
= 0;
190 static int last_insn_was_memory_access
= 0;
191 static int last_insn_was_io_insn
= 0;
192 static int last_insn_was_arithmetic_or_logic
= 0;
193 static int last_insn_was_branch_insn
= 0;
194 static int last_insn_was_conditional_branch_insn
= 0;
199 /* Initialize GAS's cgen interface for a new instruction. */
200 gas_cgen_init_parse ();
202 insn
.insn
= mt_cgen_assemble_insn
203 (gas_cgen_cpu_desc
, str
, & insn
.fields
, insn
.buffer
, & errmsg
);
207 as_bad ("%s", errmsg
);
211 /* Doesn't really matter what we pass for RELAX_P here. */
212 gas_cgen_finish_insn (insn
.insn
, insn
.buffer
,
213 CGEN_FIELDS_BITSIZE (& insn
.fields
), 1, NULL
);
216 /* Handle Scheduling Restrictions. */
217 if (!no_scheduling_restrictions
)
219 /* Detect consecutive Memory Accesses. */
220 if (last_insn_was_memory_access
221 && CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_MEMORY_ACCESS
)
222 && mt_mach
== ms1_64_001
)
223 as_warn (_("instruction %s may not follow another memory access instruction."),
224 CGEN_INSN_NAME (insn
.insn
));
226 /* Detect consecutive I/O Instructions. */
227 else if (last_insn_was_io_insn
228 && CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_IO_INSN
))
229 as_warn (_("instruction %s may not follow another I/O instruction."),
230 CGEN_INSN_NAME (insn
.insn
));
232 /* Detect consecutive branch instructions. */
233 else if (last_insn_was_branch_insn
234 && CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_BR_INSN
))
235 as_warn (_("%s may not occupy the delay slot of another branch insn."),
236 CGEN_INSN_NAME (insn
.insn
));
238 /* Detect data dependencies on delayed loads: memory and input insns. */
239 if (last_insn_has_load_delay
&& delayed_load_register
)
241 if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR1
)
242 && insn
.fields
.f_sr1
== delayed_load_register
)
243 as_warn (_("operand references R%ld of previous load."),
246 if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR2
)
247 && insn
.fields
.f_sr2
== delayed_load_register
)
248 as_warn (_("operand references R%ld of previous load."),
252 /* Detect JAL/RETI hazard */
254 && CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_JAL_HAZARD
))
256 if ((CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR1
)
257 && insn
.fields
.f_sr1
== delayed_load_register
)
258 || (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR2
)
259 && insn
.fields
.f_sr2
== delayed_load_register
))
260 as_warn (_("operand references R%ld of previous instruction."),
261 delayed_load_register
);
262 else if ((CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR1
)
263 && insn
.fields
.f_sr1
== prev_delayed_load_register
)
264 || (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR2
)
265 && insn
.fields
.f_sr2
== prev_delayed_load_register
))
266 as_warn (_("operand references R%ld of instruction before previous."),
267 prev_delayed_load_register
);
270 /* Detect data dependency between conditional branch instruction
271 and an immediately preceding arithmetic or logical instruction. */
272 if (last_insn_was_arithmetic_or_logic
273 && !last_insn_in_noncond_delay_slot
274 && (delayed_load_register
!= 0)
275 && CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_BR_INSN
)
276 && mt_arch
== ms1_64_001
)
278 if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR1
)
279 && insn
.fields
.f_sr1
== delayed_load_register
)
280 as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
283 if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR2
)
284 && insn
.fields
.f_sr2
== delayed_load_register
)
285 as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
290 /* Keep track of details of this insn for processing next insn. */
291 last_insn_in_noncond_delay_slot
= last_insn_was_branch_insn
292 && !last_insn_was_conditional_branch_insn
;
294 last_insn_had_delay_slot
=
295 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_DELAY_SLOT
);
296 (void) last_insn_had_delay_slot
;
298 last_insn_has_load_delay
=
299 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_LOAD_DELAY
);
301 last_insn_was_memory_access
=
302 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_MEMORY_ACCESS
);
304 last_insn_was_io_insn
=
305 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_IO_INSN
);
307 last_insn_was_arithmetic_or_logic
=
308 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_AL_INSN
);
310 last_insn_was_branch_insn
=
311 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_BR_INSN
);
313 last_insn_was_conditional_branch_insn
=
314 CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_BR_INSN
)
315 && CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRSR2
);
317 prev_delayed_load_register
= delayed_load_register
;
319 if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRDR
))
320 delayed_load_register
= insn
.fields
.f_dr
;
321 else if (CGEN_INSN_ATTR_VALUE (insn
.insn
, CGEN_INSN_USES_FRDRRR
))
322 delayed_load_register
= insn
.fields
.f_drrr
;
323 else /* Insns has no destination register. */
324 delayed_load_register
= 0;
326 /* Generate dwarf2 line numbers. */
327 dwarf2_emit_insn (4);
331 md_section_align (segT segment
, valueT size
)
333 int align
= bfd_get_section_alignment (stdoutput
, segment
);
335 return ((size
+ (1 << align
) - 1) & -(1 << align
));
339 md_undefined_symbol (char * name ATTRIBUTE_UNUSED
)
345 md_estimate_size_before_relax (fragS
* fragP ATTRIBUTE_UNUSED
,
346 segT segment ATTRIBUTE_UNUSED
)
348 as_fatal (_("md_estimate_size_before_relax\n"));
352 /* *fragP has been relaxed to its final size, and now needs to have
353 the bytes inside it modified to conform to the new size.
355 Called after relaxation is finished.
356 fragP->fr_type == rs_machine_dependent.
357 fragP->fr_subtype is the subtype of what the address relaxed to. */
360 md_convert_frag (bfd
* abfd ATTRIBUTE_UNUSED
,
361 segT sec ATTRIBUTE_UNUSED
,
362 fragS
* fragP ATTRIBUTE_UNUSED
)
367 /* Functions concerning relocs. */
370 md_pcrel_from_section (fixS
*fixP
, segT sec
)
372 if (fixP
->fx_addsy
!= (symbolS
*) NULL
373 && (!S_IS_DEFINED (fixP
->fx_addsy
)
374 || S_GET_SEGMENT (fixP
->fx_addsy
) != sec
))
375 /* The symbol is undefined (or is defined but not in this section).
376 Let the linker figure it out. */
379 /* Return the address of the opcode - cgen adjusts for opcode size
380 itself, to be consistent with the disassembler, which must do
382 return fixP
->fx_where
+ fixP
->fx_frag
->fr_address
;
386 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
387 Returns BFD_RELOC_NONE if no reloc type can be found.
388 *FIXP may be modified if desired. */
390 bfd_reloc_code_real_type
391 md_cgen_lookup_reloc (const CGEN_INSN
* insn ATTRIBUTE_UNUSED
,
392 const CGEN_OPERAND
* operand
,
393 fixS
* fixP ATTRIBUTE_UNUSED
)
395 bfd_reloc_code_real_type result
;
397 result
= BFD_RELOC_NONE
;
399 switch (operand
->type
)
401 case MT_OPERAND_IMM16O
:
402 result
= BFD_RELOC_16_PCREL
;
404 /* fixP->fx_no_overflow = 1; */
406 case MT_OPERAND_IMM16
:
407 case MT_OPERAND_IMM16Z
:
408 /* These may have been processed at parse time. */
409 if (fixP
->fx_cgen
.opinfo
!= 0)
410 result
= fixP
->fx_cgen
.opinfo
;
411 fixP
->fx_no_overflow
= 1;
413 case MT_OPERAND_LOOPSIZE
:
414 result
= BFD_RELOC_MT_PCINSN8
;
416 /* Adjust for the delay slot, which is not part of the loop */
417 fixP
->fx_offset
-= 8;
420 result
= BFD_RELOC_NONE
;
427 /* Write a value out to the object file, using the appropriate endianness. */
430 md_number_to_chars (char * buf
, valueT val
, int n
)
432 number_to_chars_bigendian (buf
, val
, n
);
436 md_atof (int type
, char * litP
, int * sizeP
)
438 return ieee_md_atof (type
, litP
, sizeP
, FALSE
);
441 /* See whether we need to force a relocation into the output file. */
444 mt_force_relocation (fixS
* fixp ATTRIBUTE_UNUSED
)
450 mt_apply_fix (fixS
*fixP
, valueT
*valueP
, segT seg
)
452 if ((fixP
->fx_pcrel
!= 0) && (fixP
->fx_r_type
== BFD_RELOC_32
))
453 fixP
->fx_r_type
= BFD_RELOC_32_PCREL
;
455 gas_cgen_md_apply_fix (fixP
, valueP
, seg
);
459 mt_fix_adjustable (fixS
* fixP
)
461 if ((int) fixP
->fx_r_type
>= (int) BFD_RELOC_UNUSED
)
463 const CGEN_INSN
*insn
= NULL
;
464 int opindex
= (int) fixP
->fx_r_type
- (int) BFD_RELOC_UNUSED
;
465 const CGEN_OPERAND
*operand
;
467 operand
= cgen_operand_lookup_by_num(gas_cgen_cpu_desc
, opindex
);
468 md_cgen_lookup_reloc (insn
, operand
, fixP
);
471 if (fixP
->fx_addsy
== NULL
)
474 /* Prevent all adjustments to global symbols. */
475 if (S_IS_EXTERNAL (fixP
->fx_addsy
))
478 if (S_IS_WEAK (fixP
->fx_addsy
))