OSDN Git Service

Fix bug parsing shigh(0xffff8000)
[pf3gnuchains/sourceware.git] / cpu / m32r.opc
1 /* M32R opcode support.  -*- C -*-
2
3    Copyright 1998, 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
4
5    Contributed by Red Hat Inc; developed under contract from
6    Mitsubishi Electric Corporation.
7
8    This file is part of the GNU Binutils.
9
10    Contributed by Red Hat Inc; developed under contract from Fujitsu.
11
12    This file is part of the GNU Binutils.
13
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.
18
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.
23
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.  */
27
28 /* This file is an addendum to m32r.cpu.  Heavy use of C code isn't
29    appropriate in .cpu files, so it resides here.  This especially applies
30    to assembly/disassembly where parsing/printing can be quite involved.
31    Such things aren't really part of the specification of the cpu, per se,
32    so .cpu files provide the general framework and .opc files handle the
33    nitty-gritty details as necessary.
34
35    Each section is delimited with start and end markers.
36
37    <arch>-opc.h additions use: "-- opc.h"
38    <arch>-opc.c additions use: "-- opc.c"
39    <arch>-asm.c additions use: "-- asm.c"
40    <arch>-dis.c additions use: "-- dis.c"
41    <arch>-ibd.h additions use: "-- ibd.h"  */
42 \f
43 /* -- opc.h */
44
45 #undef  CGEN_DIS_HASH_SIZE
46 #define CGEN_DIS_HASH_SIZE 256
47 #undef  CGEN_DIS_HASH
48 #if 0
49 #define X(b) (((unsigned char *) (b))[0] & 0xf0)
50 #define CGEN_DIS_HASH(buffer, value) \
51 (X (buffer) | \
52  (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
53   : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
54   : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
55   : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
56 #else
57 #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash(buffer, value)
58 extern unsigned int m32r_cgen_dis_hash(const char *, CGEN_INSN_INT);
59 #endif
60
61 /* -- */
62 \f
63 /* -- opc.c */
64 unsigned int
65 m32r_cgen_dis_hash (buf, value)
66      const char * buf ATTRIBUTE_UNUSED;
67      CGEN_INSN_INT value;
68 {
69   unsigned int x;
70                                                                                 
71   if (value & 0xffff0000) /* 32bit instructions */
72     value = (value >> 16) & 0xffff;
73                                                                                 
74   x = (value>>8) & 0xf0;
75   if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
76     return x;
77                                                                                 
78   if (x == 0x70 || x == 0xf0)
79     return x | ((value>>8) & 0x0f);
80                                                                                 
81   if (x == 0x30)
82     return x | ((value & 0x70) >> 4);
83   else
84     return x | ((value & 0xf0) >> 4);
85 }
86                                                                                 
87 /* -- */
88 \f
89 /* -- asm.c */
90 static const char * parse_hash
91   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
92 static const char * parse_hi16
93   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
94 static const char * parse_slo16
95   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
96 static const char * parse_ulo16
97   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
98
99 /* Handle '#' prefixes (i.e. skip over them).  */
100
101 static const char *
102 parse_hash (cd, strp, opindex, valuep)
103      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
104      const char **strp;
105      int opindex ATTRIBUTE_UNUSED;
106      unsigned long *valuep ATTRIBUTE_UNUSED;
107 {
108   if (**strp == '#')
109     ++*strp;
110   return NULL;
111 }
112
113 /* Handle shigh(), high().  */
114
115 static const char *
116 parse_hi16 (cd, strp, opindex, valuep)
117      CGEN_CPU_DESC cd;
118      const char **strp;
119      int opindex;
120      unsigned long *valuep;
121 {
122   const char *errmsg;
123   enum cgen_parse_operand_result result_type;
124   bfd_vma value;
125
126   if (**strp == '#')
127     ++*strp;
128
129   if (strncasecmp (*strp, "high(", 5) == 0)
130     {
131       *strp += 5;
132       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
133                                    &result_type, &value);
134       if (**strp != ')')
135         return "missing `)'";
136       ++*strp;
137       if (errmsg == NULL
138           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
139         value >>= 16;
140       *valuep = value;
141       return errmsg;
142     }
143   else if (strncasecmp (*strp, "shigh(", 6) == 0)
144     {
145       *strp += 6;
146       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
147                                    &result_type, &value);
148       if (**strp != ')')
149         return "missing `)'";
150       ++*strp;
151       if (errmsg == NULL
152           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
153         {
154           value = value + (value & 0x8000 ? 0x10000 : 0);
155           value >>= 16;
156         }
157       *valuep = value;
158       return errmsg;
159     }
160
161   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
162 }
163
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.  */
167
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;
174 {
175   const char *errmsg;
176   enum cgen_parse_operand_result result_type;
177   bfd_vma value;
178
179   if (**strp == '#')
180     ++*strp;
181
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     }
200
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     }
212
213   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
214 }
215
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.  */
219
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;
226 {
227   const char *errmsg;
228   enum cgen_parse_operand_result result_type;
229   bfd_vma value;
230
231   if (**strp == '#')
232     ++*strp;
233
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     }
248
249   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
250 }
251
252 /* -- */
253 \f
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 *));
257
258 /* Immediate values are prefixed with '#'.  */
259
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)
267
268 /* Handle '#' prefixes as operands.  */
269
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;
278 {
279   disassemble_info *info = (disassemble_info *) dis_info;
280   (*info->fprintf_func) (info->stream, "#");
281 }
282
283 #undef  CGEN_PRINT_INSN
284 #define CGEN_PRINT_INSN my_print_insn
285
286 static int
287 my_print_insn (cd, pc, info)
288      CGEN_CPU_DESC cd;
289      bfd_vma pc;
290      disassemble_info *info;
291 {
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;
298
299   /* Read the base part of the insn.  */
300
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     }
308
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);
313
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     }
322
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, " -> ");
332
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);
338
339   return (pc & 3) ? 2 : 4;
340 }
341
342 /* -- */