* m32r.opc (parse_slo16): Fix bad application of previous patch.
[deliverable/binutils-gdb.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 /* -- */
This page took 0.036071 seconds and 4 git commands to generate.