1/* Morpho Technologies mRISC opcode support, for GNU Binutils.  -*- C -*-
2   Copyright 2001, 2007, 2008, 2009 Free Software Foundation, Inc.
3
4   Contributed by Red Hat Inc; developed under contract from
5   Morpho Technologies.
6
7   This file is part of the GNU Binutils.
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 3 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22   MA 02110-1301, USA.  */
23
24
25/* Each section is delimited with start and end markers.
26
27   <arch>-opc.h additions use: "-- opc.h"
28   <arch>-opc.c additions use: "-- opc.c"
29   <arch>-asm.c additions use: "-- asm.c"
30   <arch>-dis.c additions use: "-- dis.c"
31   <arch>-ibd.h additions use: "-- ibd.h"  */
32
33/* -- opc.h */
34
35/* Check applicability of instructions against machines.  */
36#define CGEN_VALIDATE_INSN_SUPPORTED
37
38/* Allows reason codes to be output when assembler errors occur.  */
39#define CGEN_VERBOSE_ASSEMBLER_ERRORS
40
41/* Override disassembly hashing - there are variable bits in the top
42   byte of these instructions.  */
43#define CGEN_DIS_HASH_SIZE 8
44#define CGEN_DIS_HASH(buf, value) (((* (unsigned char *) (buf)) >> 5) % CGEN_DIS_HASH_SIZE)
45
46#define CGEN_ASM_HASH_SIZE 127
47#define CGEN_ASM_HASH(insn) mt_asm_hash (insn)
48
49extern unsigned int mt_asm_hash (const char *);
50
51extern int mt_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
52
53
54/* -- opc.c */
55#include "safe-ctype.h"
56
57/* Special check to ensure that instruction exists for given machine.  */
58
59int
60mt_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn)
61{
62  int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
63
64  /* No mach attribute?  Assume it's supported for all machs.  */
65  if (machs == 0)
66    return 1;
67  
68  return ((machs & cd->machs) != 0);
69}
70
71/* A better hash function for instruction mnemonics.  */
72
73unsigned int
74mt_asm_hash (const char* insn)
75{
76  unsigned int hash;
77  const char* m = insn;
78
79  for (hash = 0; *m && ! ISSPACE (*m); m++)
80    hash = (hash * 23) ^ (0x1F & TOLOWER (*m));
81
82  /* printf ("%s %d\n", insn, (hash % CGEN_ASM_HASH_SIZE)); */
83
84  return hash % CGEN_ASM_HASH_SIZE;
85}
86
87
88/* -- asm.c */
89/* Range checking for signed numbers.  Returns 0 if acceptable
90   and 1 if the value is out of bounds for a signed quantity.  */
91
92static int 
93signed_out_of_bounds (long val)
94{
95  if ((val < -32768) || (val > 32767))
96    return 1;
97  return 0;
98}
99
100static const char *
101parse_loopsize (CGEN_CPU_DESC cd,
102		const char **strp,
103		int opindex,
104		void *arg)
105{
106  signed long * valuep = (signed long *) arg;
107  const char *errmsg;
108  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
109  enum cgen_parse_operand_result result_type;
110  bfd_vma value;
111
112  /* Is it a control transfer instructions?  */ 
113  if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_LOOPSIZE)
114    {
115      code = BFD_RELOC_MT_PCINSN8;
116      errmsg = cgen_parse_address (cd, strp, opindex, code,
117                                   & result_type, & value);
118      *valuep = value;
119      return errmsg;
120    }
121
122  abort ();
123}
124
125static const char *
126parse_imm16 (CGEN_CPU_DESC cd,
127	     const char **strp,
128	     int opindex,
129	     void *arg)
130{
131  signed long * valuep = (signed long *) arg;
132  const char *errmsg;
133  enum cgen_parse_operand_result result_type;
134  bfd_reloc_code_real_type code = BFD_RELOC_NONE;
135  bfd_vma value;
136
137  /* Is it a control transfer instructions?  */ 
138  if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16O)
139    {
140      code = BFD_RELOC_16_PCREL;
141      errmsg = cgen_parse_address (cd, strp, opindex, code,
142                                   & result_type, & value);
143      if (errmsg == NULL)
144	{
145	  if (signed_out_of_bounds (value))
146	    errmsg = _("Operand out of range. Must be between -32768 and 32767.");
147	}
148      *valuep = value;
149      return errmsg;
150    }
151
152  /* If it's not a control transfer instruction, then
153     we have to check for %OP relocating operators.  */
154  if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16L)
155    ;
156  else if (strncmp (*strp, "%hi16", 5) == 0)
157    {
158      *strp += 5;
159      code = BFD_RELOC_HI16;
160    }
161  else if (strncmp (*strp, "%lo16", 5) == 0)
162    {
163      *strp += 5;
164      code = BFD_RELOC_LO16;
165    }
166
167  /* If we found a %OP relocating operator, then parse it as an address.
168     If not, we need to parse it as an integer, either signed or unsigned
169     depending on which operand type we have.  */
170  if (code != BFD_RELOC_NONE)
171    {
172       /* %OP relocating operator found.  */
173       errmsg = cgen_parse_address (cd, strp, opindex, code,
174                                   & result_type, & value);
175       if (errmsg == NULL)
176	 {
177           switch (result_type)
178	     {
179	     case (CGEN_PARSE_OPERAND_RESULT_NUMBER):
180	       if (code == BFD_RELOC_HI16)
181		 value = (value >> 16) & 0xFFFF;
182	       else if (code == BFD_RELOC_LO16)
183		 value = value  & 0xFFFF;
184	       else 
185		 errmsg = _("Biiiig Trouble in parse_imm16!");
186	       break;
187
188	     case (CGEN_PARSE_OPERAND_RESULT_QUEUED):
189	       /* No special processing for this case.  */
190	       break;
191
192	     default:
193	       errmsg = _("The percent-operator's operand is not a symbol");
194	       break;
195             }
196	 }
197       *valuep = value;
198    }
199  else
200    {
201      /* Parse hex values like 0xffff as unsigned, and sign extend
202	 them manually.  */
203      int parse_signed = (opindex == (CGEN_OPERAND_TYPE)MT_OPERAND_IMM16);
204
205      if ((*strp)[0] == '0'
206	  && ((*strp)[1] == 'x' || (*strp)[1] == 'X'))
207	parse_signed = 0;
208
209      /* No relocating operator.  Parse as an number.  */
210      if (parse_signed)
211	{
212          /* Parse as as signed integer.  */
213 
214          errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep);
215
216          if (errmsg == NULL) 
217	    {
218#if 0
219	      /* Manual range checking is needed for the signed case.  */
220	      if (*valuep & 0x8000)
221                value = 0xffff0000 | *valuep;
222	      else 
223                value = *valuep;
224
225	      if (signed_out_of_bounds (value))
226	        errmsg = _("Operand out of range. Must be between -32768 and 32767.");
227	      /* Truncate to 16 bits. This is necessary
228		 because cgen will have sign extended *valuep.  */
229	      *valuep &= 0xFFFF; 
230#endif
231	    }
232	}
233      else  
234	{
235          /* MT_OPERAND_IMM16Z.  Parse as an unsigned integer.  */
236          errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, (unsigned long *) valuep);
237
238	  if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16
239	      && *valuep >= 0x8000
240	      && *valuep <= 0xffff)
241	    *valuep -= 0x10000;
242	}
243    }
244
245  return errmsg;
246}
247
248
249static const char *
250parse_dup (CGEN_CPU_DESC cd,
251	   const char **strp,
252	   int opindex,
253	   unsigned long *valuep)
254{
255  const char *errmsg = NULL;
256
257  if (strncmp (*strp, "dup", 3) == 0 || strncmp (*strp, "DUP", 3) == 0)
258    {
259      *strp += 3;
260      *valuep = 1;
261    }
262  else if (strncmp (*strp, "xx", 2) == 0 || strncmp (*strp, "XX", 2) == 0)
263    {
264      *strp += 2;
265      *valuep = 0;
266    }
267  else
268    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
269
270  return errmsg;
271}
272
273
274static const char *
275parse_ball (CGEN_CPU_DESC cd,
276	    const char **strp,
277	    int opindex,
278	    unsigned long *valuep)
279{
280  const char *errmsg = NULL;
281
282  if (strncmp (*strp, "all", 3) == 0 || strncmp (*strp, "ALL", 3) == 0)
283    {
284      *strp += 3;
285      *valuep = 1;
286    }
287  else if (strncmp (*strp, "one", 3) == 0 || strncmp (*strp, "ONE", 3) == 0)
288    {
289      *strp += 3;
290      *valuep = 0;
291    }
292  else
293    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
294
295  return errmsg;
296}
297
298static const char *
299parse_xmode (CGEN_CPU_DESC cd,
300	     const char **strp,
301	     int opindex,
302	     unsigned long *valuep)
303{
304  const char *errmsg = NULL;
305
306  if (strncmp (*strp, "pm", 2) == 0 || strncmp (*strp, "PM", 2) == 0)
307    {
308      *strp += 2;
309      *valuep = 1;
310    }
311  else if (strncmp (*strp, "xm", 2) == 0 || strncmp (*strp, "XM", 2) == 0)
312    {
313      *strp += 2;
314      *valuep = 0;
315    }
316  else
317    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
318
319  return errmsg;
320}
321
322static const char *
323parse_rc (CGEN_CPU_DESC cd,
324	  const char **strp,
325	  int opindex,
326	  unsigned long *valuep)
327{
328  const char *errmsg = NULL;
329
330  if (strncmp (*strp, "r", 1) == 0 || strncmp (*strp, "R", 1) == 0)
331    {
332      *strp += 1;
333      *valuep = 1;
334    }
335  else if (strncmp (*strp, "c", 1) == 0 || strncmp (*strp, "C", 1) == 0)
336    {
337      *strp += 1;
338      *valuep = 0;
339    }
340  else
341    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
342
343  return errmsg;
344}
345
346static const char *
347parse_cbrb (CGEN_CPU_DESC cd,
348	    const char **strp,
349	    int opindex,
350	    unsigned long *valuep)
351{
352  const char *errmsg = NULL;
353
354  if (strncmp (*strp, "rb", 2) == 0 || strncmp (*strp, "RB", 2) == 0)
355    {
356      *strp += 2;
357      *valuep = 1;
358    }
359  else if (strncmp (*strp, "cb", 2) == 0 || strncmp (*strp, "CB", 2) == 0)
360    {
361      *strp += 2;
362      *valuep = 0;
363    }
364  else
365    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
366
367  return errmsg;
368}
369
370static const char *
371parse_rbbc (CGEN_CPU_DESC cd,
372	    const char **strp,
373	    int opindex,
374	    unsigned long *valuep)
375{
376  const char *errmsg = NULL;
377
378  if (strncmp (*strp, "rt", 2) == 0 || strncmp (*strp, "RT", 2) == 0)
379    {
380      *strp += 2;
381      *valuep = 0;
382    }
383  else if (strncmp (*strp, "br1", 3) == 0 || strncmp (*strp, "BR1", 3) == 0)
384    {
385      *strp += 3;
386      *valuep = 1;
387    }
388  else if (strncmp (*strp, "br2", 3) == 0 || strncmp (*strp, "BR2", 3) == 0)
389    {
390      *strp += 3;
391      *valuep = 2;
392    }
393  else if (strncmp (*strp, "cs", 2) == 0 || strncmp (*strp, "CS", 2) == 0)
394    {
395      *strp += 2;
396      *valuep = 3;
397    }
398  else
399    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
400
401  return errmsg;
402}
403
404static const char *
405parse_type (CGEN_CPU_DESC cd,
406	    const char **strp,
407	    int opindex,
408	    unsigned long *valuep)
409{
410  const char *errmsg = NULL;
411
412  if (strncmp (*strp, "odd", 3) == 0 || strncmp (*strp, "ODD", 3) == 0)
413    {
414      *strp += 3;
415      *valuep = 0;
416    }
417  else if (strncmp (*strp, "even", 4) == 0 || strncmp (*strp, "EVEN", 4) == 0)
418    {
419      *strp += 4;
420      *valuep = 1;
421    }
422  else if (strncmp (*strp, "oe", 2) == 0 || strncmp (*strp, "OE", 2) == 0)
423    {
424      *strp += 2;
425      *valuep = 2;
426    }
427  else
428    errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
429
430 if ((errmsg == NULL) && (*valuep == 3))
431    errmsg = _("invalid operand.  type may have values 0,1,2 only.");
432
433  return errmsg;
434}
435
436/* -- dis.c */
437static void print_dollarhex (CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int);
438static void print_pcrel (CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int);
439
440static void
441print_dollarhex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
442		 void * dis_info,
443		 long value,
444		 unsigned int attrs ATTRIBUTE_UNUSED,
445		 bfd_vma pc ATTRIBUTE_UNUSED,
446		 int length ATTRIBUTE_UNUSED)
447{
448  disassemble_info *info = (disassemble_info *) dis_info;
449
450  info->fprintf_func (info->stream, "$%lx", value);
451
452  if (0)
453    print_normal (cd, dis_info, value, attrs, pc, length);
454}
455
456static void
457print_pcrel (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
458	     void * dis_info,
459	     long value,
460	     unsigned int attrs ATTRIBUTE_UNUSED,
461	     bfd_vma pc ATTRIBUTE_UNUSED,
462	     int length ATTRIBUTE_UNUSED)
463{
464  print_address (cd, dis_info, value + pc, attrs, pc, length);
465}
466
467/* -- */
468
469
470
471
472
473