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