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