tc-mt.c revision 1.1 1 /* tc-mt.c -- Assembler for the Morpho Technologies mt .
2 Copyright (C) 2005, 2006, 2007 Free Software Foundation.
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 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
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 #include "libbfd.h"
31
32 /* Structure to hold all of the different components
33 describing an individual instruction. */
34 typedef 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 }
52 mt_insn;
53
54
55 const char comment_chars[] = ";";
56 const char line_comment_chars[] = "#";
57 const char line_separator_chars[] = "";
58 const char EXP_CHARS[] = "eE";
59 const char FLT_CHARS[] = "dD";
60
61 /* The target specific pseudo-ops which we support. */
62 const pseudo_typeS md_pseudo_table[] =
63 {
64 { "word", cons, 4 },
65 { NULL, NULL, 0 }
66 };
67
68
69
71 static int no_scheduling_restrictions = 0;
72
73 struct option md_longopts[] =
74 {
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 },
80 };
81 size_t md_longopts_size = sizeof (md_longopts);
82
83 const char * md_shortopts = "";
84
85 /* Mach selected from command line. */
86 static int mt_mach = bfd_mach_ms1;
87 static unsigned mt_mach_bitmask = 1 << MACH_MS1;
88
89 /* Flags to set in the elf header */
90 static flagword mt_flags = EF_MT_CPU_MRISC;
91
92 /* The architecture to use. */
93 enum mt_architectures
94 {
95 ms1_64_001,
96 ms1_16_002,
97 ms1_16_003,
98 ms2
99 };
100
101 /* MT architecture we are using for this output file. */
102 static enum mt_architectures mt_arch = ms1_16_002;
103
104 int
105 md_parse_option (int c ATTRIBUTE_UNUSED, char * arg)
106 {
107 switch (c)
108 {
109 case OPTION_MARCH:
110 if (strcmp (arg, "ms1-64-001") == 0)
111 {
112 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
113 mt_mach = bfd_mach_ms1;
114 mt_mach_bitmask = 1 << MACH_MS1;
115 mt_arch = ms1_64_001;
116 }
117 else if (strcmp (arg, "ms1-16-002") == 0)
118 {
119 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC;
120 mt_mach = bfd_mach_ms1;
121 mt_mach_bitmask = 1 << MACH_MS1;
122 mt_arch = ms1_16_002;
123 }
124 else if (strcmp (arg, "ms1-16-003") == 0)
125 {
126 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MRISC2;
127 mt_mach = bfd_mach_mrisc2;
128 mt_mach_bitmask = 1 << MACH_MS1_003;
129 mt_arch = ms1_16_003;
130 }
131 else if (strcmp (arg, "ms2") == 0)
132 {
133 mt_flags = (mt_flags & ~EF_MT_CPU_MASK) | EF_MT_CPU_MS2;
134 mt_mach = bfd_mach_mrisc2;
135 mt_mach_bitmask = 1 << MACH_MS2;
136 mt_arch = ms2;
137 }
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
185 void
186 md_assemble (char * str)
187 {
188 static long delayed_load_register = 0;
189 static long prev_delayed_load_register = 0;
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
199 mt_insn insn;
200 char * errmsg;
201
202 /* Initialize GAS's cgen interface for a new instruction. */
203 gas_cgen_init_parse ();
204
205 insn.insn = mt_cgen_assemble_insn
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)
225 && mt_mach == ms1_64_001)
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
255 /* Detect JAL/RETI hazard */
256 if (mt_mach == ms2
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))
263 as_warn (_("operand references R%ld of previous instrutcion."),
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))
269 as_warn (_("operand references R%ld of instructcion before previous."),
270 prev_delayed_load_register);
271 }
272
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)
279 && mt_arch == ms1_64_001)
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);
299
300 last_insn_has_load_delay =
301 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_LOAD_DELAY);
302
303 last_insn_was_memory_access =
304 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_MEMORY_ACCESS);
305
306 last_insn_was_io_insn =
307 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_IO_INSN);
308
309 last_insn_was_arithmetic_or_logic =
310 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_AL_INSN);
311
312 last_insn_was_branch_insn =
313 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN);
314
315 last_insn_was_conditional_branch_insn =
316 CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_BR_INSN)
317 && CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRSR2);
318
319 prev_delayed_load_register = delayed_load_register;
320
321 if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDR))
322 delayed_load_register = insn.fields.f_dr;
323 else if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDRRR))
324 delayed_load_register = insn.fields.f_drrr;
325 else /* Insns has no destination register. */
326 delayed_load_register = 0;
327
328 /* Generate dwarf2 line numbers. */
329 dwarf2_emit_insn (4);
330 }
331
332 valueT
333 md_section_align (segT segment, valueT size)
334 {
335 int align = bfd_get_section_alignment (stdoutput, segment);
336
337 return ((size + (1 << align) - 1) & (-1 << align));
338 }
339
340 symbolS *
341 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
342 {
343 return NULL;
344 }
345
346 int
348 md_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;
353 }
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
362 void
363 md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
364 segT sec ATTRIBUTE_UNUSED,
365 fragS * fragP ATTRIBUTE_UNUSED)
366 {
367 }
368
369
370 /* Functions concerning relocs. */
372
373 long
374 md_pcrel_from_section (fixS *fixP, segT sec)
375 {
376 if (fixP->fx_addsy != (symbolS *) NULL
377 && (!S_IS_DEFINED (fixP->fx_addsy)
378 || S_GET_SEGMENT (fixP->fx_addsy) != sec))
379 /* The symbol is undefined (or is defined but not in this section).
380 Let the linker figure it out. */
381 return 0;
382
383 /* Return the address of the opcode - cgen adjusts for opcode size
384 itself, to be consistent with the disassembler, which must do
385 so. */
386 return fixP->fx_where + fixP->fx_frag->fr_address;
387 }
388
389
390 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
391 Returns BFD_RELOC_NONE if no reloc type can be found.
392 *FIXP may be modified if desired. */
393
394 bfd_reloc_code_real_type
395 md_cgen_lookup_reloc (const CGEN_INSN * insn ATTRIBUTE_UNUSED,
396 const CGEN_OPERAND * operand,
397 fixS * fixP ATTRIBUTE_UNUSED)
398 {
399 bfd_reloc_code_real_type result;
400
401 result = BFD_RELOC_NONE;
402
403 switch (operand->type)
404 {
405 case MT_OPERAND_IMM16O:
406 result = BFD_RELOC_16_PCREL;
407 fixP->fx_pcrel = 1;
408 /* fixP->fx_no_overflow = 1; */
409 break;
410 case MT_OPERAND_IMM16:
411 case MT_OPERAND_IMM16Z:
412 /* These may have been processed at parse time. */
413 if (fixP->fx_cgen.opinfo != 0)
414 result = fixP->fx_cgen.opinfo;
415 fixP->fx_no_overflow = 1;
416 break;
417 case MT_OPERAND_LOOPSIZE:
418 result = BFD_RELOC_MT_PCINSN8;
419 fixP->fx_pcrel = 1;
420 /* Adjust for the delay slot, which is not part of the loop */
421 fixP->fx_offset -= 8;
422 break;
423 default:
424 result = BFD_RELOC_NONE;
425 break;
426 }
427
428 return result;
429 }
430
431 /* Write a value out to the object file, using the appropriate endianness. */
432
433 void
434 md_number_to_chars (char * buf, valueT val, int n)
435 {
436 number_to_chars_bigendian (buf, val, n);
437 }
438
439 char *
440 md_atof (int type, char * litP, int * sizeP)
441 {
442 return ieee_md_atof (type, litP, sizeP, FALSE);
443 }
444
445 /* See whether we need to force a relocation into the output file. */
446
447 int
448 mt_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
449 {
450 return 0;
451 }
452
453 void
454 mt_apply_fix (fixS *fixP, valueT *valueP, segT seg)
455 {
456 if ((fixP->fx_pcrel != 0) && (fixP->fx_r_type == BFD_RELOC_32))
457 fixP->fx_r_type = BFD_RELOC_32_PCREL;
458
459 gas_cgen_md_apply_fix (fixP, valueP, seg);
460 }
461
462 bfd_boolean
463 mt_fix_adjustable (fixS * fixP)
464 {
465 bfd_reloc_code_real_type reloc_type;
466
467 if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED)
468 {
469 const CGEN_INSN *insn = NULL;
470 int opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED;
471 const CGEN_OPERAND *operand;
472
473 operand = cgen_operand_lookup_by_num(gas_cgen_cpu_desc, opindex);
474 reloc_type = md_cgen_lookup_reloc (insn, operand, fixP);
475 }
476 else
477 reloc_type = fixP->fx_r_type;
478
479 if (fixP->fx_addsy == NULL)
480 return TRUE;
481
482 /* Prevent all adjustments to global symbols. */
483 if (S_IS_EXTERNAL (fixP->fx_addsy))
484 return FALSE;
485
486 if (S_IS_WEAK (fixP->fx_addsy))
487 return FALSE;
488
489 return 1;
490 }
491