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