1/* m32c opcode support.  -*- C -*-
2
3   Copyright 2005, 2007, 2009, 2010 Free Software Foundation, Inc.
4
5   Contributed by Red Hat Inc; developed under contract from Renesas
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/* This file is an addendum to m32c.cpu.  Heavy use of C code isn't
26   appropriate in .cpu files, so it resides here.  This especially applies
27   to assembly/disassembly where parsing/printing can be quite involved.
28   Such things aren't really part of the specification of the cpu, per se,
29   so .cpu files provide the general framework and .opc files handle the
30   nitty-gritty details as necessary.
31
32   Each section is delimited with start and end markers.
33
34   <arch>-opc.h additions use: "-- opc.h"
35   <arch>-opc.c additions use: "-- opc.c"
36   <arch>-asm.c additions use: "-- asm.c"
37   <arch>-dis.c additions use: "-- dis.c"
38   <arch>-ibd.h additions use: "-- ibd.h".  */
39
40/* -- opc.h */
41
42/* Needed for RTL's 'ext' and 'trunc' operators.  */
43#include "cgen/basic-modes.h"
44#include "cgen/basic-ops.h"
45
46/* We can't use the default hash size because many bits are used by
47   operands.  */
48#define CGEN_DIS_HASH_SIZE 1
49#define CGEN_DIS_HASH(buf, value) 0
50#define CGEN_VERBOSE_ASSEMBLER_ERRORS
51#define CGEN_VALIDATE_INSN_SUPPORTED
52
53extern int m32c_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *);
54
55#define CGEN_ASM_HASH_SIZE 0xffff
56#define CGEN_ASM_HASH(mnem) m32c_asm_hash ((mnem))
57
58/* -- */
59
60/* -- opc.c */
61static unsigned int
62m32c_asm_hash (const char *mnem)
63{
64  unsigned int h;
65
66  /* The length of the mnemonic for the Jcnd insns is 1.  Hash jsri.  */
67  if (mnem[0] == 'j' && mnem[1] != 's')
68    return 'j';
69
70  /* Don't hash scCND  */
71  if (mnem[0] == 's' && mnem[1] == 'c')
72    return 's';
73
74  /* Don't hash bmCND  */
75  if (mnem[0] == 'b' && mnem[1] == 'm')
76    return 'b';
77
78  for (h = 0; *mnem && *mnem != ' ' && *mnem != ':'; ++mnem)
79    h += *mnem;
80  return h % CGEN_ASM_HASH_SIZE;
81}
82
83/* -- asm.c */
84#include "safe-ctype.h"
85
86#define MACH_M32C 5           /* Must match md_begin.  */
87
88static int
89m32c_cgen_isa_register (const char **strp)
90 {
91   int u;
92   const char *s = *strp;
93   static char * m32c_register_names [] =
94     {
95       "r0", "r1", "r2", "r3", "r0l", "r0h", "r1l", "r1h",
96       "a0", "a1", "r2r0", "r3r1", "sp", "fb", "dct0", "dct1", "flg", "svf",
97       "drc0", "drc1", "dmd0", "dmd1", "intb", "svp", "vct", "isp", "dma0",
98       "dma1", "dra0", "dra1", "dsa0", "dsa1", 0
99     };
100
101   for (u = 0; m32c_register_names[u]; u++)
102     {
103       int len = strlen (m32c_register_names[u]);
104
105       if (memcmp (m32c_register_names[u], s, len) == 0
106             && (s[len] == 0 || ! ISALNUM (s[len])))
107        return 1;
108     }
109   return 0;
110}
111
112#define PARSE_UNSIGNED                                                                    \
113  do                                                                                      \
114    {                                                                                     \
115      /* Don't successfully parse literals beginning with '['.  */    \
116      if (**strp == '[')                                                        \
117          return "Invalid literal"; /* Anything -- will not be seen.  */        \
118                                                                                          \
119      errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, & value);\
120      if (errmsg)                                                               \
121          return errmsg;                                                                  \
122    }                                                                                     \
123  while (0)
124
125#define PARSE_SIGNED                                                                      \
126  do                                                                                      \
127    {                                                                                     \
128      /* Don't successfully parse literals beginning with '['.  */    \
129      if (**strp == '[')                                                        \
130          return "Invalid literal"; /* Anything -- will not be seen.  */        \
131                                                                                          \
132      errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);  \
133      if (errmsg)                                                               \
134          return errmsg;                                                                  \
135    }                                                                                     \
136  while (0)
137
138static const char *
139parse_unsigned6 (CGEN_CPU_DESC cd, const char **strp,
140                     int opindex, unsigned long *valuep)
141{
142  const char *errmsg = 0;
143  unsigned long value;
144
145  PARSE_UNSIGNED;
146
147  if (value > 0x3f)
148    return _("imm:6 immediate is out of range");
149
150  *valuep = value;
151  return 0;
152}
153
154static const char *
155parse_unsigned8 (CGEN_CPU_DESC cd, const char **strp,
156                     int opindex, unsigned long *valuep)
157{
158  const char *errmsg = 0;
159  unsigned long value = 0;
160  long have_zero = 0;
161
162  if (strncasecmp (*strp, "%dsp8(", 6) == 0)
163    {
164      enum cgen_parse_operand_result result_type;
165      bfd_vma val;
166
167      *strp += 6;
168      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_8,
169                                           & result_type, & val);
170      if (**strp != ')')
171          return _("missing `)'");
172      (*strp) ++;
173
174      if (errmsg == NULL
175            && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
176          return _("%dsp8() takes a symbolic address, not a number");
177
178      value = val;
179      *valuep = value;
180      return errmsg;
181    }
182
183  if (strncmp (*strp, "0x0", 3) == 0
184      || (**strp == '0' && *(*strp + 1) != 'x'))
185    have_zero = 1;
186
187  PARSE_UNSIGNED;
188
189  if (value > 0xff)
190    return _("dsp:8 immediate is out of range");
191
192  /* If this field may require a relocation then use larger dsp16.  */
193  if (! have_zero && value == 0)
194    return _("dsp:8 immediate is out of range");
195
196  *valuep = value;
197  return 0;
198}
199
200static const char *
201parse_signed4 (CGEN_CPU_DESC cd, const char **strp,
202                 int opindex, signed long *valuep)
203{
204  const char *errmsg = 0;
205  signed long value;
206  long have_zero = 0;
207
208  if (strncmp (*strp, "0x0", 3) == 0
209      || (**strp == '0' && *(*strp + 1) != 'x'))
210    have_zero = 1;
211
212  PARSE_SIGNED;
213
214  if (value < -8 || value > 7)
215    return _("Immediate is out of range -8 to 7");
216
217  /* If this field may require a relocation then use larger dsp16.  */
218  if (! have_zero && value == 0)
219    return _("Immediate is out of range -8 to 7");
220
221  *valuep = value;
222  return 0;
223}
224
225static const char *
226parse_signed4n (CGEN_CPU_DESC cd, const char **strp,
227                    int opindex, signed long *valuep)
228{
229  const char *errmsg = 0;
230  signed long value;
231  long have_zero = 0;
232
233  if (strncmp (*strp, "0x0", 3) == 0
234      || (**strp == '0' && *(*strp + 1) != 'x'))
235    have_zero = 1;
236
237  PARSE_SIGNED;
238
239  if (value < -7 || value > 8)
240    return _("Immediate is out of range -7 to 8");
241
242  /* If this field may require a relocation then use larger dsp16.  */
243  if (! have_zero && value == 0)
244    return _("Immediate is out of range -7 to 8");
245
246  *valuep = -value;
247  return 0;
248}
249
250static const char *
251parse_signed8 (CGEN_CPU_DESC cd, const char **strp,
252                 int opindex, signed long *valuep)
253{
254  const char *errmsg = 0;
255  signed long value = 0;
256
257  if (strncasecmp (*strp, "%hi8(", 5) == 0)
258    {
259      enum cgen_parse_operand_result result_type;
260      bfd_vma val;
261
262      *strp += 5;
263      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32C_HI8,
264                                           & result_type, & val);
265      if (**strp != ')')
266          return _("missing `)'");
267      (*strp) ++;
268
269      if (errmsg == NULL
270            && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
271          val >>= 16;
272
273      value = val;
274      *valuep = value;
275      return errmsg;
276    }
277
278  PARSE_SIGNED;
279
280  if (value <= 255 && value > 127)
281    value -= 0x100;
282
283  if (value < -128 || value > 127)
284    return _("dsp:8 immediate is out of range");
285
286  *valuep = value;
287  return 0;
288}
289
290static const char *
291parse_unsigned16 (CGEN_CPU_DESC cd, const char **strp,
292                     int opindex, unsigned long *valuep)
293{
294  const char *errmsg = 0;
295  unsigned long value = 0;
296  long have_zero = 0;
297
298  if (strncasecmp (*strp, "%dsp16(", 7) == 0)
299    {
300      enum cgen_parse_operand_result result_type;
301      bfd_vma val;
302
303      *strp += 7;
304      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_16,
305                                           & result_type, & val);
306      if (**strp != ')')
307          return _("missing `)'");
308      (*strp) ++;
309
310      if (errmsg == NULL
311            && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
312          return _("%dsp16() takes a symbolic address, not a number");
313
314      value = val;
315      *valuep = value;
316      return errmsg;
317    }
318
319  /* Don't successfully parse literals beginning with '['.  */
320  if (**strp == '[')
321    return "Invalid literal"; /* Anything -- will not be seen.  */
322
323  /* Don't successfully parse register names.  */
324  if (m32c_cgen_isa_register (strp))
325    return "Invalid literal"; /* Anything -- will not be seen.  */
326
327  if (strncmp (*strp, "0x0", 3) == 0
328      || (**strp == '0' && *(*strp + 1) != 'x'))
329    have_zero = 1;
330
331  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, & value);
332  if (errmsg)
333    return errmsg;
334
335  if (value > 0xffff)
336    return _("dsp:16 immediate is out of range");
337
338  /* If this field may require a relocation then use larger dsp24.  */
339  if (cd->machs == MACH_M32C && ! have_zero && value == 0
340      && (strncmp (*strp, "[a", 2) == 0
341            || **strp == ','
342            || **strp == 0))
343    return _("dsp:16 immediate is out of range");
344
345  *valuep = value;
346  return 0;
347}
348
349static const char *
350parse_signed16 (CGEN_CPU_DESC cd, const char **strp,
351                 int opindex, signed long *valuep)
352{
353  const char *errmsg = 0;
354  signed long value = 0;
355
356  if (strncasecmp (*strp, "%lo16(", 6) == 0)
357    {
358      enum cgen_parse_operand_result result_type;
359      bfd_vma val;
360
361      *strp += 6;
362      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16,
363                                           & result_type, & val);
364      if (**strp != ')')
365          return _("missing `)'");
366      (*strp) ++;
367
368      if (errmsg == NULL
369            && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
370          val &= 0xffff;
371
372      value = val;
373      *valuep = value;
374      return errmsg;
375    }
376
377  if (strncasecmp (*strp, "%hi16(", 6) == 0)
378    {
379      enum cgen_parse_operand_result result_type;
380      bfd_vma val;
381
382      *strp += 6;
383      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_HI16,
384                                           & result_type, & val);
385      if (**strp != ')')
386          return _("missing `)'");
387      (*strp) ++;
388
389      if (errmsg == NULL
390            && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
391          val >>= 16;
392
393      value = val;
394      *valuep = value;
395      return errmsg;
396    }
397
398  PARSE_SIGNED;
399
400  if (value <= 65535 && value > 32767)
401    value -= 0x10000;
402
403  if (value < -32768 || value > 32767)
404    return _("dsp:16 immediate is out of range");
405
406  *valuep = value;
407  return 0;
408}
409
410static const char *
411parse_unsigned20 (CGEN_CPU_DESC cd, const char **strp,
412                     int opindex, unsigned long *valuep)
413{
414  const char *errmsg = 0;
415  unsigned long value;
416
417  /* Don't successfully parse literals beginning with '['.  */
418  if (**strp == '[')
419    return "Invalid literal"; /* Anything -- will not be seen.  */
420
421  /* Don't successfully parse register names.  */
422  if (m32c_cgen_isa_register (strp))
423    return "Invalid literal"; /* Anything -- will not be seen.  */
424
425  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, & value);
426  if (errmsg)
427    return errmsg;
428
429  if (value > 0xfffff)
430    return _("dsp:20 immediate is out of range");
431
432  *valuep = value;
433  return 0;
434}
435
436static const char *
437parse_unsigned24 (CGEN_CPU_DESC cd, const char **strp,
438                     int opindex, unsigned long *valuep)
439{
440  const char *errmsg = 0;
441  unsigned long value;
442
443  /* Don't successfully parse literals beginning with '['.  */
444  if (**strp == '[')
445    return "Invalid literal"; /* Anything -- will not be seen.  */
446
447  /* Don't successfully parse register names.  */
448  if (m32c_cgen_isa_register (strp))
449    return "Invalid literal"; /* Anything -- will not be seen.  */
450
451  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, & value);
452  if (errmsg)
453    return errmsg;
454
455  if (value > 0xffffff)
456    return _("dsp:24 immediate is out of range");
457
458  *valuep = value;
459  return 0;
460}
461
462/* This should only be used for #imm->reg.  */
463static const char *
464parse_signed24 (CGEN_CPU_DESC cd, const char **strp,
465                     int opindex, signed long *valuep)
466{
467  const char *errmsg = 0;
468  signed long value;
469
470  PARSE_SIGNED;
471
472  if (value <= 0xffffff && value > 0x7fffff)
473    value -= 0x1000000;
474
475  if (value > 0xffffff)
476    return _("dsp:24 immediate is out of range");
477
478  *valuep = value;
479  return 0;
480}
481
482static const char *
483parse_signed32 (CGEN_CPU_DESC cd, const char **strp,
484                    int opindex, signed long *valuep)
485{
486  const char *errmsg = 0;
487  signed long value;
488
489  errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
490  if (errmsg)
491    return errmsg;
492
493  *valuep = value;
494  return 0;
495}
496
497static const char *
498parse_imm1_S (CGEN_CPU_DESC cd, const char **strp,
499               int opindex, signed long *valuep)
500{
501  const char *errmsg = 0;
502  signed long value;
503
504  errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
505  if (errmsg)
506    return errmsg;
507
508  if (value < 1 || value > 2)
509    return _("immediate is out of range 1-2");
510
511  *valuep = value;
512  return 0;
513}
514
515static const char *
516parse_imm3_S (CGEN_CPU_DESC cd, const char **strp,
517               int opindex, signed long *valuep)
518{
519  const char *errmsg = 0;
520  signed long value;
521
522  errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
523  if (errmsg)
524    return errmsg;
525
526  if (value < 1 || value > 8)
527    return _("immediate is out of range 1-8");
528
529  *valuep = value;
530  return 0;
531}
532
533static const char *
534parse_bit3_S (CGEN_CPU_DESC cd, const char **strp,
535               int opindex, signed long *valuep)
536{
537  const char *errmsg = 0;
538  signed long value;
539
540  errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value);
541  if (errmsg)
542    return errmsg;
543
544  if (value < 0 || value > 7)
545    return _("immediate is out of range 0-7");
546
547  *valuep = value;
548  return 0;
549}
550
551static const char *
552parse_lab_5_3 (CGEN_CPU_DESC cd,
553                 const char **strp,
554                 int opindex ATTRIBUTE_UNUSED,
555                 int opinfo,
556                 enum cgen_parse_operand_result *type_addr,
557                 bfd_vma *valuep)
558{
559  const char *errmsg = 0;
560  bfd_vma value;
561  enum cgen_parse_operand_result op_res;
562
563  errmsg = cgen_parse_address (cd, strp, M32C_OPERAND_LAB_5_3,
564                                     opinfo, & op_res, & value);
565
566  if (type_addr)
567    *type_addr = op_res;
568
569  if (op_res == CGEN_PARSE_OPERAND_RESULT_QUEUED)
570    {
571      /* This is a hack; the field cannot handle near-zero signed
572           offsets that CGEN wants to put in to indicate an "empty"
573           operand at first.  */
574      *valuep = 2;
575      return 0;
576    }
577  if (errmsg)
578    return errmsg;
579
580  if (value < 2 || value > 9)
581    return _("immediate is out of range 2-9");
582
583  *valuep = value;
584  return 0;
585}
586
587static const char *
588parse_Bitno16R (CGEN_CPU_DESC cd, const char **strp,
589                    int opindex, unsigned long *valuep)
590{
591  const char *errmsg = 0;
592  unsigned long value;
593
594  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, & value);
595  if (errmsg)
596    return errmsg;
597
598  if (value > 15)
599    return _("Bit number for indexing general register is out of range 0-15");
600
601  *valuep = value;
602  return 0;
603}
604
605static const char *
606parse_unsigned_bitbase (CGEN_CPU_DESC cd, const char **strp,
607                              int opindex, unsigned long *valuep,
608                              unsigned bits, int allow_syms)
609{
610  const char *errmsg = 0;
611  unsigned long bit;
612  unsigned long base;
613  const char *newp = *strp;
614  unsigned long long bitbase;
615  long have_zero = 0;
616
617  errmsg = cgen_parse_unsigned_integer (cd, & newp, opindex, & bit);
618  if (errmsg)
619    return errmsg;
620
621  if (*newp != ',')
622    return "Missing base for bit,base:8";
623
624  ++newp;
625
626  if (strncmp (newp, "0x0", 3) == 0
627      || (newp[0] == '0' && newp[1] != 'x'))
628    have_zero = 1;
629
630  errmsg = cgen_parse_unsigned_integer (cd, & newp, opindex, & base);
631  if (errmsg)
632    return errmsg;
633
634  bitbase = (unsigned long long) bit + ((unsigned long long) base * 8);
635
636  if (bitbase >= (1ull << bits))
637    return _("bit,base is out of range");
638
639  /* If this field may require a relocation then use larger displacement.  */
640  if (! have_zero && base == 0)
641    {
642      switch (allow_syms) {
643      case 0:
644          return _("bit,base out of range for symbol");
645      case 1:
646          break;
647      case 2:
648          if (strncmp (newp, "[sb]", 4) != 0)
649            return _("bit,base out of range for symbol");
650          break;
651      }
652    }
653
654  *valuep = bitbase;
655  *strp = newp;
656  return 0;
657}
658
659static const char *
660parse_signed_bitbase (CGEN_CPU_DESC cd, const char **strp,
661                          int opindex, signed long *valuep,
662                          unsigned bits, int allow_syms)
663{
664  const char *errmsg = 0;
665  unsigned long bit;
666  signed long base;
667  const char *newp = *strp;
668  long long bitbase;
669  long long limit;
670  long have_zero = 0;
671
672  errmsg = cgen_parse_unsigned_integer (cd, & newp, opindex, & bit);
673  if (errmsg)
674    return errmsg;
675
676  if (*newp != ',')
677    return "Missing base for bit,base:8";
678
679  ++newp;
680
681  if (strncmp (newp, "0x0", 3) == 0
682      || (newp[0] == '0' && newp[1] != 'x'))
683    have_zero = 1;
684
685  errmsg = cgen_parse_signed_integer (cd, & newp, opindex, & base);
686  if (errmsg)
687    return errmsg;
688
689  bitbase = (long long)bit + ((long long)base * 8);
690
691  limit = 1ll << (bits - 1);
692  if (bitbase < -limit || bitbase >= limit)
693    return _("bit,base is out of range");
694
695  /* If this field may require a relocation then use larger displacement.  */
696  if (! have_zero && base == 0 && ! allow_syms)
697    return _("bit,base out of range for symbol");
698
699  *valuep = bitbase;
700  *strp = newp;
701  return 0;
702}
703
704static const char *
705parse_unsigned_bitbase8 (CGEN_CPU_DESC cd, const char **strp,
706                               int opindex, unsigned long *valuep)
707{
708  return parse_unsigned_bitbase (cd, strp, opindex, valuep, 8, 0);
709}
710
711static const char *
712parse_unsigned_bitbase11 (CGEN_CPU_DESC cd, const char **strp,
713                               int opindex, unsigned long *valuep)
714{
715  return parse_unsigned_bitbase (cd, strp, opindex, valuep, 11, 0);
716}
717
718static const char *
719parse_unsigned_bitbase16 (CGEN_CPU_DESC cd, const char **strp,
720                                int opindex, unsigned long *valuep)
721{
722  return parse_unsigned_bitbase (cd, strp, opindex, valuep, 16, 1);
723}
724
725static const char *
726parse_unsigned_bitbase19 (CGEN_CPU_DESC cd, const char **strp,
727                               int opindex, unsigned long *valuep)
728{
729  return parse_unsigned_bitbase (cd, strp, opindex, valuep, 19, 2);
730}
731
732static const char *
733parse_unsigned_bitbase27 (CGEN_CPU_DESC cd, const char **strp,
734                               int opindex, unsigned long *valuep)
735{
736  return parse_unsigned_bitbase (cd, strp, opindex, valuep, 27, 1);
737}
738
739static const char *
740parse_signed_bitbase8 (CGEN_CPU_DESC cd, const char **strp,
741                           int opindex, signed long *valuep)
742{
743  return parse_signed_bitbase (cd, strp, opindex, valuep, 8, 1);
744}
745
746static const char *
747parse_signed_bitbase11 (CGEN_CPU_DESC cd, const char **strp,
748                           int opindex, signed long *valuep)
749{
750  return parse_signed_bitbase (cd, strp, opindex, valuep, 11, 0);
751}
752
753static const char *
754parse_signed_bitbase19 (CGEN_CPU_DESC cd, const char **strp,
755                           int opindex, signed long *valuep)
756{
757  return parse_signed_bitbase (cd, strp, opindex, valuep, 19, 1);
758}
759
760/* Parse the suffix as :<char> or as nothing followed by a whitespace.  */
761
762static const char *
763parse_suffix (const char **strp, char suffix)
764{
765  const char *newp = *strp;
766
767  if (**strp == ':' && TOLOWER (*(*strp + 1)) == suffix)
768    newp = *strp + 2;
769
770  if (ISSPACE (*newp))
771    {
772      *strp = newp;
773      return 0;
774    }
775
776  return "Invalid suffix"; /* Anything -- will not be seen.  */
777}
778
779static const char *
780parse_S (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, const char **strp,
781           int opindex ATTRIBUTE_UNUSED, signed long *valuep ATTRIBUTE_UNUSED)
782{
783  return parse_suffix (strp, 's');
784}
785
786static const char *
787parse_G (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, const char **strp,
788           int opindex ATTRIBUTE_UNUSED, signed long *valuep ATTRIBUTE_UNUSED)
789{
790  return parse_suffix (strp, 'g');
791}
792
793static const char *
794parse_Q (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, const char **strp,
795           int opindex ATTRIBUTE_UNUSED, signed long *valuep ATTRIBUTE_UNUSED)
796{
797  return parse_suffix (strp, 'q');
798}
799
800static const char *
801parse_Z (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, const char **strp,
802           int opindex ATTRIBUTE_UNUSED, signed long *valuep ATTRIBUTE_UNUSED)
803{
804  return parse_suffix (strp, 'z');
805}
806
807/* Parse an empty suffix. Fail if the next char is ':'.  */
808
809static const char *
810parse_X (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, const char **strp,
811           int opindex ATTRIBUTE_UNUSED, signed long *valuep ATTRIBUTE_UNUSED)
812{
813  if (**strp == ':')
814    return "Unexpected suffix";
815  return 0;
816}
817
818static const char *
819parse_r0l_r0h (CGEN_CPU_DESC cd, const char **strp,
820                 int opindex ATTRIBUTE_UNUSED, signed long *valuep)
821{
822  const char *errmsg;
823  signed long value;
824  signed long junk;
825  const char *newp = *strp;
826
827  /* Parse r0[hl].  */
828  errmsg = cgen_parse_keyword (cd, & newp, & m32c_cgen_opval_h_r0l_r0h, & value);
829  if (errmsg)
830    return errmsg;
831
832  if (*newp != ',')
833    return _("not a valid r0l/r0h pair");
834  ++newp;
835
836  /* Parse the second register in the pair.  */
837  if (value == 0) /* r0l */
838    errmsg = cgen_parse_keyword (cd, & newp, & m32c_cgen_opval_h_r0h, & junk);
839  else
840    errmsg = cgen_parse_keyword (cd, & newp, & m32c_cgen_opval_h_r0l, & junk);
841  if (errmsg)
842    return errmsg;
843
844  *strp = newp;
845  *valuep = ! value;
846  return 0;
847}
848
849/* Accept .b or .w in any case.  */
850
851static const char *
852parse_size (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, const char **strp,
853              int opindex ATTRIBUTE_UNUSED, signed long *valuep ATTRIBUTE_UNUSED)
854{
855  if (**strp == '.'
856      && (*(*strp + 1) == 'b' || *(*strp + 1) == 'B'
857            || *(*strp + 1) == 'w' || *(*strp + 1) == 'W'))
858    {
859      *strp += 2;
860      return NULL;
861    }
862
863  return _("Invalid size specifier");
864}
865
866/* Special check to ensure that instruction exists for given machine.  */
867
868int
869m32c_cgen_insn_supported (CGEN_CPU_DESC cd,
870                                const CGEN_INSN *insn)
871{
872  int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH);
873  CGEN_BITSET isas = CGEN_INSN_BITSET_ATTR_VALUE (insn, CGEN_INSN_ISA);
874
875  /* If attributes are absent, assume no restriction.  */
876  if (machs == 0)
877    machs = ~0;
878
879  return ((machs & cd->machs)
880          && cgen_bitset_intersect_p (& isas, cd->isas));
881}
882
883/* Parse a set of registers, R0,R1,A0,A1,SB,FB.  */
884
885static const char *
886parse_regset (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
887                const char **strp,
888                int opindex ATTRIBUTE_UNUSED,
889                unsigned long *valuep,
890                int push)
891{
892  const char *errmsg = 0;
893  int regno = 0;
894
895  *valuep = 0;
896  while (**strp && **strp != ')')
897    {
898      if (**strp == 'r' || **strp == 'R')
899          {
900            ++*strp;
901            regno = **strp - '0';
902            if (regno > 4)
903              errmsg = _("Register number is not valid");
904          }
905      else if (**strp == 'a' || **strp == 'A')
906          {
907            ++*strp;
908            regno = **strp - '0';
909            if (regno > 2)
910              errmsg = _("Register number is not valid");
911            regno = **strp - '0' + 4;
912          }
913
914      else if (strncasecmp (*strp, "sb", 2) == 0 || strncasecmp (*strp, "SB", 2) == 0)
915          {
916            regno = 6;
917            ++*strp;
918          }
919
920      else if (strncasecmp (*strp, "fb", 2) == 0 || strncasecmp (*strp, "FB", 2) == 0)
921          {
922            regno = 7;
923            ++*strp;
924          }
925
926      if (push) /* Mask is reversed for push.  */
927          *valuep |= 0x80 >> regno;
928      else
929          *valuep |= 1 << regno;
930
931      ++*strp;
932      if (**strp == ',')
933        {
934          if (*(*strp + 1) == ')')
935            break;
936          ++*strp;
937        }
938    }
939
940  if (!*strp)
941    errmsg = _("Register list is not valid");
942
943  return errmsg;
944}
945
946#define POP  0
947#define PUSH 1
948
949static const char *
950parse_pop_regset (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
951                      const char **strp,
952                      int opindex ATTRIBUTE_UNUSED,
953                      unsigned long *valuep)
954{
955  return parse_regset (cd, strp, opindex, valuep, POP);
956}
957
958static const char *
959parse_push_regset (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
960                       const char **strp,
961                       int opindex ATTRIBUTE_UNUSED,
962                       unsigned long *valuep)
963{
964  return parse_regset (cd, strp, opindex, valuep, PUSH);
965}
966
967/* -- dis.c */
968
969#include "elf/m32c.h"
970#include "elf-bfd.h"
971
972/* Always print the short insn format suffix as ':<char>'.  */
973
974static void
975print_suffix (void * dis_info, char suffix)
976{
977  disassemble_info *info = dis_info;
978
979  (*info->fprintf_func) (info->stream, ":%c", suffix);
980}
981
982static void
983print_S (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
984           void * dis_info,
985           long value ATTRIBUTE_UNUSED,
986           unsigned int attrs ATTRIBUTE_UNUSED,
987           bfd_vma pc ATTRIBUTE_UNUSED,
988           int length ATTRIBUTE_UNUSED)
989{
990  print_suffix (dis_info, 's');
991}
992
993
994static void
995print_G (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
996           void * dis_info,
997           long value ATTRIBUTE_UNUSED,
998           unsigned int attrs ATTRIBUTE_UNUSED,
999           bfd_vma pc ATTRIBUTE_UNUSED,
1000           int length ATTRIBUTE_UNUSED)
1001{
1002  print_suffix (dis_info, 'g');
1003}
1004
1005static void
1006print_Q (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1007           void * dis_info,
1008           long value ATTRIBUTE_UNUSED,
1009           unsigned int attrs ATTRIBUTE_UNUSED,
1010           bfd_vma pc ATTRIBUTE_UNUSED,
1011           int length ATTRIBUTE_UNUSED)
1012{
1013  print_suffix (dis_info, 'q');
1014}
1015
1016static void
1017print_Z (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1018           void * dis_info,
1019           long value ATTRIBUTE_UNUSED,
1020           unsigned int attrs ATTRIBUTE_UNUSED,
1021           bfd_vma pc ATTRIBUTE_UNUSED,
1022           int length ATTRIBUTE_UNUSED)
1023{
1024  print_suffix (dis_info, 'z');
1025}
1026
1027/* Print the empty suffix.  */
1028
1029static void
1030print_X (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1031           void * dis_info ATTRIBUTE_UNUSED,
1032           long value ATTRIBUTE_UNUSED,
1033           unsigned int attrs ATTRIBUTE_UNUSED,
1034           bfd_vma pc ATTRIBUTE_UNUSED,
1035           int length ATTRIBUTE_UNUSED)
1036{
1037  return;
1038}
1039
1040static void
1041print_r0l_r0h (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1042                 void * dis_info,
1043                 long value,
1044                 unsigned int attrs ATTRIBUTE_UNUSED,
1045                 bfd_vma pc ATTRIBUTE_UNUSED,
1046                 int length ATTRIBUTE_UNUSED)
1047{
1048  disassemble_info *info = dis_info;
1049
1050  if (value == 0)
1051    (*info->fprintf_func) (info->stream, "r0h,r0l");
1052  else
1053    (*info->fprintf_func) (info->stream, "r0l,r0h");
1054}
1055
1056static void
1057print_unsigned_bitbase (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1058                              void * dis_info,
1059                              unsigned long value,
1060                              unsigned int attrs ATTRIBUTE_UNUSED,
1061                              bfd_vma pc ATTRIBUTE_UNUSED,
1062                              int length ATTRIBUTE_UNUSED)
1063{
1064  disassemble_info *info = dis_info;
1065
1066  (*info->fprintf_func) (info->stream, "%ld,0x%lx", value & 0x7, value >> 3);
1067}
1068
1069static void
1070print_signed_bitbase (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1071                          void * dis_info,
1072                          signed long value,
1073                          unsigned int attrs ATTRIBUTE_UNUSED,
1074                          bfd_vma pc ATTRIBUTE_UNUSED,
1075                          int length ATTRIBUTE_UNUSED)
1076{
1077  disassemble_info *info = dis_info;
1078
1079  (*info->fprintf_func) (info->stream, "%ld,%ld", value & 0x7, value >> 3);
1080}
1081
1082static void
1083print_size (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1084              void * dis_info,
1085              long value ATTRIBUTE_UNUSED,
1086              unsigned int attrs ATTRIBUTE_UNUSED,
1087              bfd_vma pc ATTRIBUTE_UNUSED,
1088              int length ATTRIBUTE_UNUSED)
1089{
1090  /* Always print the size as '.w'.  */
1091  disassemble_info *info = dis_info;
1092
1093  (*info->fprintf_func) (info->stream, ".w");
1094}
1095
1096#define POP  0
1097#define PUSH 1
1098
1099static void print_pop_regset  (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
1100static void print_push_regset (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
1101
1102/* Print a set of registers, R0,R1,A0,A1,SB,FB.  */
1103
1104static void
1105print_regset (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1106                void * dis_info,
1107                long value,
1108                unsigned int attrs ATTRIBUTE_UNUSED,
1109                bfd_vma pc ATTRIBUTE_UNUSED,
1110                int length ATTRIBUTE_UNUSED,
1111                int push)
1112{
1113  static char * m16c_register_names [] =
1114  {
1115    "r0", "r1", "r2", "r3", "a0", "a1", "sb", "fb"
1116  };
1117  disassemble_info *info = dis_info;
1118  int mask;
1119  int reg_index = 0;
1120  char* comma = "";
1121
1122  if (push)
1123    mask = 0x80;
1124  else
1125    mask = 1;
1126
1127  if (value & mask)
1128    {
1129      (*info->fprintf_func) (info->stream, "%s", m16c_register_names [0]);
1130      comma = ",";
1131    }
1132
1133  for (reg_index = 1; reg_index <= 7; ++reg_index)
1134    {
1135      if (push)
1136        mask >>= 1;
1137      else
1138        mask <<= 1;
1139
1140      if (value & mask)
1141        {
1142          (*info->fprintf_func) (info->stream, "%s%s", comma,
1143                                         m16c_register_names [reg_index]);
1144          comma = ",";
1145        }
1146    }
1147}
1148
1149static void
1150print_pop_regset (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1151                      void * dis_info,
1152                      long value,
1153                      unsigned int attrs ATTRIBUTE_UNUSED,
1154                      bfd_vma pc ATTRIBUTE_UNUSED,
1155                      int length ATTRIBUTE_UNUSED)
1156{
1157  print_regset (cd, dis_info, value, attrs, pc, length, POP);
1158}
1159
1160static void
1161print_push_regset (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1162                       void * dis_info,
1163                       long value,
1164                       unsigned int attrs ATTRIBUTE_UNUSED,
1165                       bfd_vma pc ATTRIBUTE_UNUSED,
1166                       int length ATTRIBUTE_UNUSED)
1167{
1168  print_regset (cd, dis_info, value, attrs, pc, length, PUSH);
1169}
1170
1171static void
1172print_signed4n (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1173                    void * dis_info,
1174                    signed long value,
1175                    unsigned int attrs ATTRIBUTE_UNUSED,
1176                    bfd_vma pc ATTRIBUTE_UNUSED,
1177                    int length ATTRIBUTE_UNUSED)
1178{
1179  disassemble_info *info = dis_info;
1180
1181  (*info->fprintf_func) (info->stream, "%ld", -value);
1182}
1183