2004-02-23 Andrew Stubbs <andrew.stubbs@superh.com>
[binutils.git] / cpu / m32r.opc
blob6764223f2bf43b87d47ca33c81aa13b5c25cd67f
1 /* M32R opcode support.  -*- C -*-
3    Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
5    Contributed by Red Hat Inc; developed under contract from
6    Mitsubishi Electric Corporation.
8    This file is part of the GNU Binutils.
10    Contributed by Red Hat Inc; developed under contract from Fujitsu.
12    This file is part of the GNU Binutils.
14    This program is free software; you can redistribute it and/or modify
15    it under the terms of the GNU General Public License as published by
16    the Free Software Foundation; either version 2 of the License, or
17    (at your option) any later version.
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22    GNU General Public License for more details.
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 /* This file is an addendum to m32r.cpu.  Heavy use of C code isn't
31    appropriate in .cpu files, so it resides here.  This especially applies
32    to assembly/disassembly where parsing/printing can be quite involved.
33    Such things aren't really part of the specification of the cpu, per se,
34    so .cpu files provide the general framework and .opc files handle the
35    nitty-gritty details as necessary.
37    Each section is delimited with start and end markers.
39    <arch>-opc.h additions use: "-- opc.h"
40    <arch>-opc.c additions use: "-- opc.c"
41    <arch>-asm.c additions use: "-- asm.c"
42    <arch>-dis.c additions use: "-- dis.c"
43    <arch>-ibd.h additions use: "-- ibd.h"
46 /* -- opc.h */
48 #undef  CGEN_DIS_HASH_SIZE
49 #define CGEN_DIS_HASH_SIZE 256
50 #undef  CGEN_DIS_HASH
51 #if 0
52 #define X(b) (((unsigned char *) (b))[0] & 0xf0)
53 #define CGEN_DIS_HASH(buffer, value) \
54 (X (buffer) | \
55  (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
56   : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
57   : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
58   : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
59 #else
60 #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash(buffer, value)
61 extern unsigned int m32r_cgen_dis_hash(const char *, CGEN_INSN_INT);
62 #endif
64 /* -- */
66 /* -- opc.c */
67 unsigned int
68 m32r_cgen_dis_hash (buf, value)
69      const char * buf ATTRIBUTE_UNUSED;
70      CGEN_INSN_INT value;
72   unsigned int x;
73                                                                                 
74   if (value & 0xffff0000) /* 32bit instructions */
75     value = (value >> 16) & 0xffff;
76                                                                                 
77   x = (value>>8) & 0xf0;
78   if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
79     return x;
80                                                                                 
81   if (x == 0x70 || x == 0xf0)
82     return x | ((value>>8) & 0x0f);
83                                                                                 
84   if (x == 0x30)
85     return x | ((value & 0x70) >> 4);
86   else
87     return x | ((value & 0xf0) >> 4);
89                                                                                 
90 /* -- */
92 /* -- asm.c */
93 static const char * parse_hash
94   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
95 static const char * parse_hi16
96   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
97 static const char * parse_slo16
98   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
99 static const char * parse_ulo16
100   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
102 /* Handle '#' prefixes (i.e. skip over them).  */
104 static const char *
105 parse_hash (cd, strp, opindex, valuep)
106      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
107      const char **strp;
108      int opindex ATTRIBUTE_UNUSED;
109      unsigned long *valuep ATTRIBUTE_UNUSED;
111   if (**strp == '#')
112     ++*strp;
113   return NULL;
116 /* Handle shigh(), high().  */
118 static const char *
119 parse_hi16 (cd, strp, opindex, valuep)
120      CGEN_CPU_DESC cd;
121      const char **strp;
122      int opindex;
123      unsigned long *valuep;
125   const char *errmsg;
126   enum cgen_parse_operand_result result_type;
127   bfd_vma value;
129   if (**strp == '#')
130     ++*strp;
132   if (strncasecmp (*strp, "high(", 5) == 0)
133     {
134       *strp += 5;
135       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
136                                    &result_type, &value);
137       if (**strp != ')')
138         return "missing `)'";
139       ++*strp;
140       if (errmsg == NULL
141           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
142         value >>= 16;
143       *valuep = value;
144       return errmsg;
145     }
146   else if (strncasecmp (*strp, "shigh(", 6) == 0)
147     {
148       *strp += 6;
149       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
150                                    &result_type, &value);
151       if (**strp != ')')
152         return "missing `)'";
153       ++*strp;
154       if (errmsg == NULL
155           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
156         value = (value >> 16) + (value & 0x8000 ? 1 : 0);
157       *valuep = value;
158       return errmsg;
159     }
161   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
164 /* Handle low() in a signed context.  Also handle sda().
165    The signedness of the value doesn't matter to low(), but this also
166    handles the case where low() isn't present.  */
168 static const char *
169 parse_slo16 (cd, strp, opindex, valuep)
170      CGEN_CPU_DESC cd;
171      const char **strp;
172      int opindex;
173      long *valuep;
175   const char *errmsg;
176   enum cgen_parse_operand_result result_type;
177   bfd_vma value;
179   if (**strp == '#')
180     ++*strp;
182   if (strncasecmp (*strp, "low(", 4) == 0)
183     {
184       *strp += 4;
185       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
186                                    &result_type, &value);
187       if (**strp != ')')
188         return "missing `)'";
189       ++*strp;
190       if (errmsg == NULL
191           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
192         {
193           value &= 0xffff;
194           if (value & 0x8000)
195              value |= 0xffff0000;
196         }
197       *valuep = value;
198       return errmsg;
199     }
201   if (strncasecmp (*strp, "sda(", 4) == 0)
202     {
203       *strp += 4;
204       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
205                                    NULL, &value);
206       if (**strp != ')')
207         return "missing `)'";
208       ++*strp;
209       *valuep = value;
210       return errmsg;
211     }
213   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
216 /* Handle low() in an unsigned context.
217    The signedness of the value doesn't matter to low(), but this also
218    handles the case where low() isn't present.  */
220 static const char *
221 parse_ulo16 (cd, strp, opindex, valuep)
222      CGEN_CPU_DESC cd;
223      const char **strp;
224      int opindex;
225      unsigned long *valuep;
227   const char *errmsg;
228   enum cgen_parse_operand_result result_type;
229   bfd_vma value;
231   if (**strp == '#')
232     ++*strp;
234   if (strncasecmp (*strp, "low(", 4) == 0)
235     {
236       *strp += 4;
237       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
238                                    &result_type, &value);
239       if (**strp != ')')
240         return "missing `)'";
241       ++*strp;
242       if (errmsg == NULL
243           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
244         value &= 0xffff;
245       *valuep = value;
246       return errmsg;
247     }
249   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
252 /* -- */
254 /* -- dis.c */
255 static void print_hash PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
256 static int my_print_insn PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
258 /* Immediate values are prefixed with '#'.  */
260 #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length)   \
261   do                                                            \
262     {                                                           \
263       if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX))   \
264         (*info->fprintf_func) (info->stream, "#");              \
265     }                                                           \
266   while (0)
268 /* Handle '#' prefixes as operands.  */
270 static void
271 print_hash (cd, dis_info, value, attrs, pc, length)
272      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
273      PTR dis_info;
274      long value ATTRIBUTE_UNUSED;
275      unsigned int attrs ATTRIBUTE_UNUSED;
276      bfd_vma pc ATTRIBUTE_UNUSED;
277      int length ATTRIBUTE_UNUSED;
279   disassemble_info *info = (disassemble_info *) dis_info;
280   (*info->fprintf_func) (info->stream, "#");
283 #undef  CGEN_PRINT_INSN
284 #define CGEN_PRINT_INSN my_print_insn
286 static int
287 my_print_insn (cd, pc, info)
288      CGEN_CPU_DESC cd;
289      bfd_vma pc;
290      disassemble_info *info;
292   char buffer[CGEN_MAX_INSN_SIZE];
293   char *buf = buffer;
294   int status;
295   int buflen = (pc & 3) == 0 ? 4 : 2;
296   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
297   char *x;
299   /* Read the base part of the insn.  */
301   status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
302                                       buf, buflen, info);
303   if (status != 0)
304     {
305       (*info->memory_error_func) (status, pc, info);
306       return -1;
307     }
309   /* 32 bit insn?  */
310   x = (big_p ? &buf[0] : &buf[3]);
311   if ((pc & 3) == 0 && (*x & 0x80) != 0)
312     return print_insn (cd, pc, info, buf, buflen);
314   /* Print the first insn.  */
315   if ((pc & 3) == 0)
316     {
317       buf += (big_p ? 0 : 2);
318       if (print_insn (cd, pc, info, buf, 2) == 0)
319         (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
320       buf += (big_p ? 2 : -2);
321     }
323   x = (big_p ? &buf[0] : &buf[1]);
324   if (*x & 0x80)
325     {
326       /* Parallel.  */
327       (*info->fprintf_func) (info->stream, " || ");
328       *x &= 0x7f;
329     }
330   else
331     (*info->fprintf_func) (info->stream, " -> ");
333   /* The "& 3" is to pass a consistent address.
334      Parallel insns arguably both begin on the word boundary.
335      Also, branch insns are calculated relative to the word boundary.  */
336   if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
337     (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
339   return (pc & 3) ? 2 : 4;
342 /* -- */