* strsignal.c (psignal): Change second parameter to const char *.
[deliverable/binutils-gdb.git] / gas / config / tc-mt.c
CommitLineData
d031aafb 1/* tc-mt.c -- Assembler for the Morpho Technologies mt .
87975d2a 2 Copyright (C) 2005, 2006, 2007, 2010 Free Software Foundation.
a0defb2e
AH
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
ec2655a6 8 the Free Software Foundation; either version 3, or (at your option)
a0defb2e
AH
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
a0defb2e
AH
21#include "as.h"
22#include "dwarf2dbg.h"
23#include "subsegs.h"
24#include "symcat.h"
d031aafb
NS
25#include "opcodes/mt-desc.h"
26#include "opcodes/mt-opc.h"
a0defb2e
AH
27#include "cgen.h"
28#include "elf/common.h"
4970f871 29#include "elf/mt.h"
a0defb2e
AH
30#include "libbfd.h"
31
32/* Structure to hold all of the different components
33 describing an individual instruction. */
34typedef struct
35{
36 const CGEN_INSN * insn;
37 const CGEN_INSN * orig_insn;
38 CGEN_FIELDS fields;
39#if CGEN_INT_INSN_P
40 CGEN_INSN_INT buffer [1];
41#define INSN_VALUE(buf) (*(buf))
42#else
43 unsigned char buffer [CGEN_MAX_INSN_SIZE];
44#define INSN_VALUE(buf) (buf)
45#endif
46 char * addr;
47 fragS * frag;
48 int num_fixups;
49 fixS * fixups [GAS_CGEN_MAX_FIXUPS];
50 int indices [MAX_OPERAND_INSTANCES];
51}
d031aafb 52mt_insn;
a0defb2e
AH
53
54
55const char comment_chars[] = ";";
56const char line_comment_chars[] = "#";
57const char line_separator_chars[] = "";
58const char EXP_CHARS[] = "eE";
59const char FLT_CHARS[] = "dD";
60
61/* The target specific pseudo-ops which we support. */
62const pseudo_typeS md_pseudo_table[] =
63{
64 { "word", cons, 4 },
a0defb2e
AH
65 { NULL, NULL, 0 }
66};
67
68\f
69
70static int no_scheduling_restrictions = 0;
71
72struct option md_longopts[] =
73{
74#define OPTION_NO_SCHED_REST (OPTION_MD_BASE)
75 { "nosched", no_argument, NULL, OPTION_NO_SCHED_REST },
76#define OPTION_MARCH (OPTION_MD_BASE + 1)
77 { "march", required_argument, NULL, OPTION_MARCH},
78 { NULL, no_argument, NULL, 0 },
79};
80size_t md_longopts_size = sizeof (md_longopts);
81
82const char * md_shortopts = "";
83
84/* Mach selected from command line. */
d031aafb
NS
85static int mt_mach = bfd_mach_ms1;
86static unsigned mt_mach_bitmask = 1 << MACH_MS1;
a0defb2e
AH
87
88/* Flags to set in the elf header */
d031aafb 89static flagword mt_flags = EF_MT_CPU_MRISC;
a0defb2e
AH
90
91/* The architecture to use. */
d031aafb 92enum mt_architectures
a0defb2e
AH
93 {
94 ms1_64_001,
95 ms1_16_002,
6f84a2a6
NS
96 ms1_16_003,
97 ms2
a0defb2e
AH
98 };
99
d031aafb 100/* MT architecture we are using for this output file. */
f07efa0b 101static enum mt_architectures mt_arch = ms1_16_002;
a0defb2e
AH
102
103int
104md_parse_option (int c ATTRIBUTE_UNUSED, char * arg)
105{
106 switch (c)
107 {
108 case OPTION_MARCH:
f07efa0b 109 if (strcmp (arg, "ms1-64-001") == 0)
a0defb2e 110 {
d031aafb
NS
111 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
112 mt_mach = bfd_mach_ms1;
113 mt_mach_bitmask = 1 << MACH_MS1;
114 mt_arch = ms1_64_001;
a0defb2e 115 }
f07efa0b 116 else if (strcmp (arg, "ms1-16-002") == 0)
a0defb2e 117 {
d031aafb
NS
118 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
119 mt_mach = bfd_mach_ms1;
120 mt_mach_bitmask = 1 << MACH_MS1;
121 mt_arch = ms1_16_002;
a0defb2e 122 }
f07efa0b 123 else if (strcmp (arg, "ms1-16-003") == 0)
a0defb2e 124 {
d031aafb
NS
125 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC2;
126 mt_mach = bfd_mach_mrisc2;
127 mt_mach_bitmask = 1 << MACH_MS1_003;
128 mt_arch = ms1_16_003;
a0defb2e 129 }
f07efa0b 130 else if (strcmp (arg, "ms2") == 0)
6f84a2a6 131 {
d031aafb
NS
132 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MS2;
133 mt_mach = bfd_mach_mrisc2;
134 mt_mach_bitmask = 1 << MACH_MS2;
135 mt_arch = ms2;
6f84a2a6 136 }
a0defb2e
AH
137 case OPTION_NO_SCHED_REST:
138 no_scheduling_restrictions = 1;
139 break;
140 default:
141 return 0;
142 }
143
144 return 1;
145}
146
147
148void
149md_show_usage (FILE * stream)
150{
d031aafb 151 fprintf (stream, _("MT specific command line options:\n"));
f07efa0b
NS
152 fprintf (stream, _(" -march=ms1-64-001 allow ms1-64-001 instructions\n"));
153 fprintf (stream, _(" -march=ms1-16-002 allow ms1-16-002 instructions (default)\n"));
154 fprintf (stream, _(" -march=ms1-16-003 allow ms1-16-003 instructions\n"));
6f84a2a6 155 fprintf (stream, _(" -march=ms2 allow ms2 instructions \n"));
f07efa0b 156 fprintf (stream, _(" -nosched disable scheduling restrictions\n"));
a0defb2e
AH
157}
158
159\f
160void
161md_begin (void)
162{
163 /* Initialize the `cgen' interface. */
164
165 /* Set the machine number and endian. */
d031aafb
NS
166 gas_cgen_cpu_desc = mt_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, mt_mach_bitmask,
167 CGEN_CPU_OPEN_ENDIAN,
168 CGEN_ENDIAN_BIG,
169 CGEN_CPU_OPEN_END);
170 mt_cgen_init_asm (gas_cgen_cpu_desc);
a0defb2e
AH
171
172 /* This is a callback from cgen to gas to parse operands. */
173 cgen_set_parse_operand_fn (gas_cgen_cpu_desc, gas_cgen_parse_operand);
174
175 /* Set the ELF flags if desired. */
d031aafb
NS
176 if (mt_flags)
177 bfd_set_private_flags (stdoutput, mt_flags);
a0defb2e
AH
178
179 /* Set the machine type. */
d031aafb 180 bfd_default_set_arch_mach (stdoutput, bfd_arch_mt, mt_mach);
a0defb2e
AH
181}
182
183void
184md_assemble (char * str)
185{
186 static long delayed_load_register = 0;
6f84a2a6 187 static long prev_delayed_load_register = 0;
a0defb2e
AH
188 static int last_insn_had_delay_slot = 0;
189 static int last_insn_in_noncond_delay_slot = 0;
190 static int last_insn_has_load_delay = 0;
191 static int last_insn_was_memory_access = 0;
192 static int last_insn_was_io_insn = 0;
193 static int last_insn_was_arithmetic_or_logic = 0;
194 static int last_insn_was_branch_insn = 0;
195 static int last_insn_was_conditional_branch_insn = 0;
196
d031aafb 197 mt_insn insn;
a0defb2e
AH
198 char * errmsg;
199
200 /* Initialize GAS's cgen interface for a new instruction. */
201 gas_cgen_init_parse ();
202
d031aafb 203 insn.insn = mt_cgen_assemble_insn
a0defb2e
AH
204 (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
205
206 if (!insn.insn)
207 {
208 as_bad ("%s", errmsg);
209 return;
210 }
211
212 /* Doesn't really matter what we pass for RELAX_P here. */
213 gas_cgen_finish_insn (insn.insn, insn.buffer,
214 CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
215
216
217 /* Handle Scheduling Restrictions. */
218 if (!no_scheduling_restrictions)
219 {
220 /* Detect consecutive Memory Accesses. */
221 if (last_insn_was_memory_access
222 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS)
d031aafb 223 && mt_mach == ms1_64_001)
a0defb2e
AH
224 as_warn (_("instruction %s may not follow another memory access instruction."),
225 CGEN_INSN_NAME (insn.insn));
226
227 /* Detect consecutive I/O Instructions. */
228 else if (last_insn_was_io_insn
229 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN))
230 as_warn (_("instruction %s may not follow another I/O instruction."),
231 CGEN_INSN_NAME (insn.insn));
232
233 /* Detect consecutive branch instructions. */
234 else if (last_insn_was_branch_insn
235 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN))
236 as_warn (_("%s may not occupy the delay slot of another branch insn."),
237 CGEN_INSN_NAME (insn.insn));
238
239 /* Detect data dependencies on delayed loads: memory and input insns. */
240 if (last_insn_has_load_delay && delayed_load_register)
241 {
242 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
243 && insn.fields.f_sr1 == delayed_load_register)
244 as_warn (_("operand references R%ld of previous load."),
245 insn.fields.f_sr1);
246
247 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
248 && insn.fields.f_sr2 == delayed_load_register)
249 as_warn (_("operand references R%ld of previous load."),
250 insn.fields.f_sr2);
251 }
252
6f84a2a6 253 /* Detect JAL/RETI hazard */
d031aafb 254 if (mt_mach == ms2
6f84a2a6
NS
255 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_JAL_HAZARD))
256 {
257 if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
258 && insn.fields.f_sr1 == delayed_load_register)
259 || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
260 && insn.fields.f_sr2 == delayed_load_register))
261 as_warn (_("operand references R%ld of previous instrutcion."),
262 delayed_load_register);
263 else if ((CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
264 && insn.fields.f_sr1 == prev_delayed_load_register)
265 || (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
266 && insn.fields.f_sr2 == prev_delayed_load_register))
267 as_warn (_("operand references R%ld of instructcion before previous."),
268 prev_delayed_load_register);
269 }
270
a0defb2e
AH
271 /* Detect data dependency between conditional branch instruction
272 and an immediately preceding arithmetic or logical instruction. */
273 if (last_insn_was_arithmetic_or_logic
274 && !last_insn_in_noncond_delay_slot
275 && (delayed_load_register != 0)
276 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
d031aafb 277 && mt_arch == ms1_64_001)
a0defb2e
AH
278 {
279 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR1)
280 && insn.fields.f_sr1 == delayed_load_register)
281 as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
282 insn.fields.f_sr1);
283
284 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2)
285 && insn.fields.f_sr2 == delayed_load_register)
286 as_warn (_("conditional branch or jal insn's operand references R%ld of previous arithmetic or logic insn."),
287 insn.fields.f_sr2);
288 }
289 }
290
291 /* Keep track of details of this insn for processing next insn. */
292 last_insn_in_noncond_delay_slot = last_insn_was_branch_insn
293 && !last_insn_was_conditional_branch_insn;
294
295 last_insn_had_delay_slot =
296 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
87975d2a 297 (void) last_insn_had_delay_slot;
a0defb2e
AH
298
299 last_insn_has_load_delay =
300 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY);
301
302 last_insn_was_memory_access =
303 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS);
304
305 last_insn_was_io_insn =
306 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN);
307
308 last_insn_was_arithmetic_or_logic =
309 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_AL_INSN);
310
311 last_insn_was_branch_insn =
312 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN);
313
314 last_insn_was_conditional_branch_insn =
315 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
316 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2);
317
6f84a2a6
NS
318 prev_delayed_load_register = delayed_load_register;
319
a0defb2e
AH
320 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDR))
321 delayed_load_register = insn.fields.f_dr;
322 else if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDRRR))
323 delayed_load_register = insn.fields.f_drrr;
324 else /* Insns has no destination register. */
325 delayed_load_register = 0;
326
327 /* Generate dwarf2 line numbers. */
328 dwarf2_emit_insn (4);
329}
330
331valueT
332md_section_align (segT segment, valueT size)
333{
334 int align = bfd_get_section_alignment (stdoutput, segment);
335
336 return ((size + (1 << align) - 1) & (-1 << align));
337}
338
339symbolS *
340md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
341{
342 return NULL;
343}
344\f
345int
346md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
347 segT segment ATTRIBUTE_UNUSED)
348{
349 as_fatal (_("md_estimate_size_before_relax\n"));
350 return 1;
351}
352
353/* *fragP has been relaxed to its final size, and now needs to have
354 the bytes inside it modified to conform to the new size.
355
356 Called after relaxation is finished.
357 fragP->fr_type == rs_machine_dependent.
358 fragP->fr_subtype is the subtype of what the address relaxed to. */
359
360void
361md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
362 segT sec ATTRIBUTE_UNUSED,
363 fragS * fragP ATTRIBUTE_UNUSED)
364{
365}
366
367\f
368/* Functions concerning relocs. */
369
370long
371md_pcrel_from_section (fixS *fixP, segT sec)
372{
373 if (fixP->fx_addsy != (symbolS *) NULL
374 && (!S_IS_DEFINED (fixP->fx_addsy)
375 || S_GET_SEGMENT (fixP->fx_addsy) != sec))
376 /* The symbol is undefined (or is defined but not in this section).
377 Let the linker figure it out. */
378 return 0;
379
380 /* Return the address of the opcode - cgen adjusts for opcode size
381 itself, to be consistent with the disassembler, which must do
382 so. */
383 return fixP->fx_where + fixP->fx_frag->fr_address;
384}
385
386
387/* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
388 Returns BFD_RELOC_NONE if no reloc type can be found.
389 *FIXP may be modified if desired. */
390
391bfd_reloc_code_real_type
392md_cgen_lookup_reloc (const CGEN_INSN * insn ATTRIBUTE_UNUSED,
393 const CGEN_OPERAND * operand,
394 fixS * fixP ATTRIBUTE_UNUSED)
395{
396 bfd_reloc_code_real_type result;
397
398 result = BFD_RELOC_NONE;
399
400 switch (operand->type)
401 {
d031aafb 402 case MT_OPERAND_IMM16O:
a0defb2e
AH
403 result = BFD_RELOC_16_PCREL;
404 fixP->fx_pcrel = 1;
405 /* fixP->fx_no_overflow = 1; */
406 break;
d031aafb
NS
407 case MT_OPERAND_IMM16:
408 case MT_OPERAND_IMM16Z:
a0defb2e
AH
409 /* These may have been processed at parse time. */
410 if (fixP->fx_cgen.opinfo != 0)
411 result = fixP->fx_cgen.opinfo;
412 fixP->fx_no_overflow = 1;
413 break;
d031aafb
NS
414 case MT_OPERAND_LOOPSIZE:
415 result = BFD_RELOC_MT_PCINSN8;
6f84a2a6
NS
416 fixP->fx_pcrel = 1;
417 /* Adjust for the delay slot, which is not part of the loop */
418 fixP->fx_offset -= 8;
419 break;
a0defb2e
AH
420 default:
421 result = BFD_RELOC_NONE;
422 break;
423 }
424
425 return result;
426}
427
428/* Write a value out to the object file, using the appropriate endianness. */
429
430void
431md_number_to_chars (char * buf, valueT val, int n)
432{
433 number_to_chars_bigendian (buf, val, n);
434}
435
a0defb2e 436char *
499ac353 437md_atof (int type, char * litP, int * sizeP)
a0defb2e 438{
499ac353 439 return ieee_md_atof (type, litP, sizeP, FALSE);
a0defb2e
AH
440}
441
442/* See whether we need to force a relocation into the output file. */
443
444int
d031aafb 445mt_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
a0defb2e
AH
446{
447 return 0;
448}
449
450void
d031aafb 451mt_apply_fix (fixS *fixP, valueT *valueP, segT seg)
a0defb2e
AH
452{
453 if ((fixP->fx_pcrel != 0) && (fixP->fx_r_type == BFD_RELOC_32))
454 fixP->fx_r_type = BFD_RELOC_32_PCREL;
455
456 gas_cgen_md_apply_fix (fixP, valueP, seg);
457}
458
459bfd_boolean
d031aafb 460mt_fix_adjustable (fixS * fixP)
a0defb2e 461{
a0defb2e
AH
462 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
463 {
464 const CGEN_INSN *insn = NULL;
465 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
466 const CGEN_OPERAND *operand;
467
468 operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
87975d2a 469 md_cgen_lookup_reloc (insn, operand, fixP);
a0defb2e 470 }
a0defb2e
AH
471
472 if (fixP->fx_addsy == NULL)
473 return TRUE;
474
475 /* Prevent all adjustments to global symbols. */
476 if (S_IS_EXTERNAL (fixP->fx_addsy))
477 return FALSE;
478
479 if (S_IS_WEAK (fixP->fx_addsy))
480 return FALSE;
481
482 return 1;
483}
This page took 0.257259 seconds and 4 git commands to generate.