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