1 /* tc-mt.c -- Assembler for the Morpho Technologies mt .
2    Copyright (C) 2005-2021 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 
69 static int no_scheduling_restrictions = 0;
70 
71 struct option md_longopts[] =
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 };
79 size_t md_longopts_size = sizeof (md_longopts);
80 
81 const char * md_shortopts = "";
82 
83 /* Mach selected from command line.  */
84 static int mt_mach = bfd_mach_ms1;
85 static unsigned mt_mach_bitmask = 1 << MACH_MS1;
86 
87 /* Flags to set in the elf header */
88 static flagword mt_flags = EF_MT_CPU_MRISC;
89 
90 /* The architecture to use.  */
91 enum mt_architectures
92   {
93     ms1_64_001,
94     ms1_16_002,
95     ms1_16_003,
96     ms2
97   };
98 
99 /* MT architecture we are using for this output file.  */
100 static enum mt_architectures mt_arch = ms1_16_002;
101 
102 int
md_parse_option(int c ATTRIBUTE_UNUSED,const char * arg)103 md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg)
104 {
105   switch (c)
106     {
107     case OPTION_MARCH:
108       if (strcmp (arg, "ms1-64-001") == 0)
109  	{
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;
114  	}
115       else if (strcmp (arg, "ms1-16-002") == 0)
116  	{
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;
121  	}
122       else if (strcmp (arg, "ms1-16-003") == 0)
123  	{
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;
128  	}
129       else if (strcmp (arg, "ms2") == 0)
130  	{
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;
135  	}
136       break;
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 
148 void
md_show_usage(FILE * stream)149 md_show_usage (FILE * stream)
150 {
151   fprintf (stream, _("MT specific command line options:\n"));
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"));
155   fprintf (stream, _("  -march=ms2                allow ms2 instructions \n"));
156   fprintf (stream, _("  -nosched                  disable scheduling restrictions\n"));
157 }
158 
159 
160 void
md_begin(void)161 md_begin (void)
162 {
163   /* Initialize the `cgen' interface.  */
164 
165   /* Set the machine number and endian.  */
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);
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. */
176   if (mt_flags)
177     bfd_set_private_flags (stdoutput, mt_flags);
178 
179   /* Set the machine type.  */
180   bfd_default_set_arch_mach (stdoutput, bfd_arch_mt, mt_mach);
181 
182   literal_prefix_dollar_hex = true;
183 }
184 
185 void
md_assemble(char * str)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 instruction."),
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 instruction 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   (void) last_insn_had_delay_slot;
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);
315 
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);
319 
320   prev_delayed_load_register = delayed_load_register;
321 
322   if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDR))
323      delayed_load_register = insn.fields.f_dr;
324   else if (CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_USES_FRDRRR))
325      delayed_load_register = insn.fields.f_drrr;
326   else  /* Insns has no destination register.  */
327      delayed_load_register = 0;
328 
329   /* Generate dwarf2 line numbers.  */
330   dwarf2_emit_insn (4);
331 }
332 
333 valueT
md_section_align(segT segment,valueT size)334 md_section_align (segT segment, valueT size)
335 {
336   int align = bfd_section_alignment (segment);
337 
338   return ((size + (1 << align) - 1) & -(1 << align));
339 }
340 
341 symbolS *
md_undefined_symbol(char * name ATTRIBUTE_UNUSED)342 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
343 {
344     return NULL;
345 }
346 
347 int
md_estimate_size_before_relax(fragS * fragP ATTRIBUTE_UNUSED,segT segment ATTRIBUTE_UNUSED)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
md_convert_frag(bfd * abfd ATTRIBUTE_UNUSED,segT sec ATTRIBUTE_UNUSED,fragS * fragP ATTRIBUTE_UNUSED)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.  */
371 
372 long
md_pcrel_from_section(fixS * fixP,segT sec)373 md_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 
393 bfd_reloc_code_real_type
md_cgen_lookup_reloc(const CGEN_INSN * insn ATTRIBUTE_UNUSED,const CGEN_OPERAND * operand,fixS * fixP ATTRIBUTE_UNUSED)394 md_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     {
404     case MT_OPERAND_IMM16O:
405       result = BFD_RELOC_16_PCREL;
406       fixP->fx_pcrel = 1;
407       /* fixP->fx_no_overflow = 1; */
408       break;
409     case MT_OPERAND_IMM16:
410     case MT_OPERAND_IMM16Z:
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;
416     case MT_OPERAND_LOOPSIZE:
417       result = BFD_RELOC_MT_PCINSN8;
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;
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 
432 void
md_number_to_chars(char * buf,valueT val,int n)433 md_number_to_chars (char * buf, valueT val, int n)
434 {
435   number_to_chars_bigendian (buf, val, n);
436 }
437 
438 const char *
md_atof(int type,char * litP,int * sizeP)439 md_atof (int type, char * litP, int * sizeP)
440 {
441   return ieee_md_atof (type, litP, sizeP, false);
442 }
443 
444 /* See whether we need to force a relocation into the output file.  */
445 
446 int
mt_force_relocation(fixS * fixp ATTRIBUTE_UNUSED)447 mt_force_relocation (fixS * fixp ATTRIBUTE_UNUSED)
448 {
449   return 0;
450 }
451 
452 void
mt_apply_fix(fixS * fixP,valueT * valueP,segT seg)453 mt_apply_fix (fixS *fixP, valueT *valueP, segT seg)
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 
461 bool
mt_fix_adjustable(fixS * fixP)462 mt_fix_adjustable (fixS * fixP)
463 {
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);
471       md_cgen_lookup_reloc (insn, operand, fixP);
472     }
473 
474   if (fixP->fx_addsy == NULL)
475     return true;
476 
477   /* Prevent all adjustments to global symbols.  */
478   if (S_IS_EXTERNAL (fixP->fx_addsy))
479     return false;
480 
481   if (S_IS_WEAK (fixP->fx_addsy))
482     return false;
483 
484   return true;
485 }
486