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