* m32r.opc (parse_slo16): Fix bad application of previous patch.
[external/binutils.git] / cpu / m32r.opc
1 /* M32R opcode support.  -*- C -*-
2
3    Copyright 1998, 1999, 2000, 2001, 2004, 2005
4    Free Software Foundation, Inc.
5
6    Contributed by Red Hat Inc; developed under contract from
7    Mitsubishi Electric Corporation.
8
9    This file is part of the GNU Binutils.
10
11    Contributed by Red Hat Inc; developed under contract from Fujitsu.
12
13    This file is part of the GNU Binutils.
14
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.
19
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.
24
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,
28    MA 02110-1301, USA.  */
29
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.
36
37    Each section is delimited with start and end markers.
38
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"  */
44 \f
45 /* -- opc.h */
46
47 #undef  CGEN_DIS_HASH_SIZE
48 #define CGEN_DIS_HASH_SIZE 256
49 #undef  CGEN_DIS_HASH
50 #if 0
51 #define X(b) (((unsigned char *) (b))[0] & 0xf0)
52 #define CGEN_DIS_HASH(buffer, value) \
53 (X (buffer) | \
54  (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
55   : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
56   : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
57   : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
58 #else
59 #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value)
60 extern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT);
61 #endif
62
63 /* -- */
64 \f
65 /* -- opc.c */
66 unsigned int
67 m32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, 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 * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
91
92 /* Handle '#' prefixes (i.e. skip over them).  */
93
94 static const char *
95 parse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
96             const char **strp,
97             int opindex ATTRIBUTE_UNUSED,
98             long *valuep ATTRIBUTE_UNUSED)
99 {
100   if (**strp == '#')
101     ++*strp;
102   return NULL;
103 }
104
105 /* Handle shigh(), high().  */
106
107 static const char *
108 parse_hi16 (CGEN_CPU_DESC cd,
109             const char **strp,
110             int opindex,
111             unsigned long *valuep)
112 {
113   const char *errmsg;
114   enum cgen_parse_operand_result result_type;
115   bfd_vma value;
116
117   if (**strp == '#')
118     ++*strp;
119
120   if (strncasecmp (*strp, "high(", 5) == 0)
121     {
122       *strp += 5;
123       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
124                                    & result_type, & value);
125       if (**strp != ')')
126         return MISSING_CLOSING_PARENTHESIS;
127       ++*strp;
128       if (errmsg == NULL
129           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
130         value >>= 16;
131       *valuep = value;
132       return errmsg;
133     }
134   else if (strncasecmp (*strp, "shigh(", 6) == 0)
135     {
136       *strp += 6;
137       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
138                                    & result_type, & value);
139       if (**strp != ')')
140         return MISSING_CLOSING_PARENTHESIS;
141       ++*strp;
142       if (errmsg == NULL
143           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
144         {
145           value = value + (value & 0x8000 ? 0x10000 : 0);
146           value >>= 16;
147         }
148       *valuep = value;
149       return errmsg;
150     }
151
152   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
153 }
154
155 /* Handle low() in a signed context.  Also handle sda().
156    The signedness of the value doesn't matter to low(), but this also
157    handles the case where low() isn't present.  */
158
159 static const char *
160 parse_slo16 (CGEN_CPU_DESC cd,
161              const char ** strp,
162              int opindex,
163              long * valuep)
164 {
165   const char *errmsg;
166   enum cgen_parse_operand_result result_type;
167   bfd_vma value;
168
169   if (**strp == '#')
170     ++*strp;
171
172   if (strncasecmp (*strp, "low(", 4) == 0)
173     {
174       *strp += 4;
175       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
176                                    & result_type, & value);
177       if (**strp != ')')
178         return MISSING_CLOSING_PARENTHESIS;
179       ++*strp;
180       if (errmsg == NULL
181           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
182         value = ((value & 0xffff) ^ 0x8000) - 0x8000;    
183       *valuep = value;
184       return errmsg;
185     }
186
187   if (strncasecmp (*strp, "sda(", 4) == 0)
188     {
189       *strp += 4;
190       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
191                                    NULL, & value);
192       if (**strp != ')')
193         return MISSING_CLOSING_PARENTHESIS;
194       ++*strp;
195       *valuep = value;
196       return errmsg;
197     }
198
199   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
200 }
201
202 /* Handle low() in an unsigned context.
203    The signedness of the value doesn't matter to low(), but this also
204    handles the case where low() isn't present.  */
205
206 static const char *
207 parse_ulo16 (CGEN_CPU_DESC cd,
208              const char **strp,
209              int opindex,
210              unsigned long *valuep)
211 {
212   const char *errmsg;
213   enum cgen_parse_operand_result result_type;
214   bfd_vma value;
215
216   if (**strp == '#')
217     ++*strp;
218
219   if (strncasecmp (*strp, "low(", 4) == 0)
220     {
221       *strp += 4;
222       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
223                                    & result_type, & value);
224       if (**strp != ')')
225         return MISSING_CLOSING_PARENTHESIS;
226       ++*strp;
227       if (errmsg == NULL
228           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
229         value &= 0xffff;
230       *valuep = value;
231       return errmsg;
232     }
233
234   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
235 }
236
237 /* -- */
238 \f
239 /* -- dis.c */
240 /* Immediate values are prefixed with '#'.  */
241
242 #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length)   \
243   do                                                            \
244     {                                                           \
245       if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX))   \
246         (*info->fprintf_func) (info->stream, "#");              \
247     }                                                           \
248   while (0)
249
250 /* Handle '#' prefixes as operands.  */
251
252 static void
253 print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
254             void * dis_info,
255             long value ATTRIBUTE_UNUSED,
256             unsigned int attrs ATTRIBUTE_UNUSED,
257             bfd_vma pc ATTRIBUTE_UNUSED,
258             int length ATTRIBUTE_UNUSED)
259 {
260   disassemble_info *info = (disassemble_info *) dis_info;
261
262   (*info->fprintf_func) (info->stream, "#");
263 }
264
265 #undef  CGEN_PRINT_INSN
266 #define CGEN_PRINT_INSN my_print_insn
267
268 static int
269 my_print_insn (CGEN_CPU_DESC cd,
270                bfd_vma pc,
271                disassemble_info *info)
272 {
273   bfd_byte buffer[CGEN_MAX_INSN_SIZE];
274   bfd_byte *buf = buffer;
275   int status;
276   int buflen = (pc & 3) == 0 ? 4 : 2;
277   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
278   bfd_byte *x;
279
280   /* Read the base part of the insn.  */
281
282   status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
283                                       buf, buflen, info);
284   if (status != 0)
285     {
286       (*info->memory_error_func) (status, pc, info);
287       return -1;
288     }
289
290   /* 32 bit insn?  */
291   x = (big_p ? &buf[0] : &buf[3]);
292   if ((pc & 3) == 0 && (*x & 0x80) != 0)
293     return print_insn (cd, pc, info, buf, buflen);
294
295   /* Print the first insn.  */
296   if ((pc & 3) == 0)
297     {
298       buf += (big_p ? 0 : 2);
299       if (print_insn (cd, pc, info, buf, 2) == 0)
300         (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
301       buf += (big_p ? 2 : -2);
302     }
303
304   x = (big_p ? &buf[0] : &buf[1]);
305   if (*x & 0x80)
306     {
307       /* Parallel.  */
308       (*info->fprintf_func) (info->stream, " || ");
309       *x &= 0x7f;
310     }
311   else
312     (*info->fprintf_func) (info->stream, " -> ");
313
314   /* The "& 3" is to pass a consistent address.
315      Parallel insns arguably both begin on the word boundary.
316      Also, branch insns are calculated relative to the word boundary.  */
317   if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
318     (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
319
320   return (pc & 3) ? 2 : 4;
321 }
322
323 /* -- */