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