1/* Morpho Technologies mRISC opcode support, for GNU Binutils.  -*- C -*-
2   Copyright 2001, 2007, 2008, 2009, 2012 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
438print_dollarhex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
439                     void * dis_info,
440                     long value,
441                     unsigned int attrs ATTRIBUTE_UNUSED,
442                     bfd_vma pc ATTRIBUTE_UNUSED,
443                     int length ATTRIBUTE_UNUSED)
444{
445  disassemble_info *info = (disassemble_info *) dis_info;
446
447  info->fprintf_func (info->stream, "$%lx", value & 0xffffffff);
448
449  if (0)
450    print_normal (cd, dis_info, value, attrs, pc, length);
451}
452
453static void
454print_pcrel (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
455               void * dis_info,
456               long value,
457               unsigned int attrs ATTRIBUTE_UNUSED,
458               bfd_vma pc ATTRIBUTE_UNUSED,
459               int length ATTRIBUTE_UNUSED)
460{
461  print_address (cd, dis_info, value + pc, attrs, pc, length);
462}
463
464/* -- */
465
466
467
468
469
470