* m32r.opc (parse_slo16): Fix bad application of previous patch.
[deliverable/binutils-gdb.git] / cpu / m32r.opc
CommitLineData
e866a257
AC
1/* M32R opcode support. -*- C -*-
2
33b71eeb
NC
3 Copyright 1998, 1999, 2000, 2001, 2004, 2005
4 Free Software Foundation, Inc.
e866a257
AC
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
47b0e7ad
NC
27 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
28 MA 02110-1301, USA. */
e866a257 29
e866a257
AC
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"
f4453dfa 43 <arch>-ibd.h additions use: "-- ibd.h" */
e866a257
AC
44\f
45/* -- opc.h */
46
47#undef CGEN_DIS_HASH_SIZE
48#define CGEN_DIS_HASH_SIZE 256
49#undef CGEN_DIS_HASH
8ee9a8b2 50#if 0
e866a257
AC
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)))
8ee9a8b2 58#else
47b0e7ad
NC
59#define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value)
60extern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT);
8ee9a8b2 61#endif
e866a257 62
8ee9a8b2
NC
63/* -- */
64\f
65/* -- opc.c */
66unsigned int
47b0e7ad 67m32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value)
8ee9a8b2
NC
68{
69 unsigned int x;
47b0e7ad
NC
70
71 if (value & 0xffff0000) /* 32bit instructions. */
8ee9a8b2 72 value = (value >> 16) & 0xffff;
47b0e7ad
NC
73
74 x = (value >> 8) & 0xf0;
8ee9a8b2
NC
75 if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
76 return x;
47b0e7ad 77
8ee9a8b2 78 if (x == 0x70 || x == 0xf0)
47b0e7ad
NC
79 return x | ((value >> 8) & 0x0f);
80
8ee9a8b2
NC
81 if (x == 0x30)
82 return x | ((value & 0x70) >> 4);
83 else
84 return x | ((value & 0xf0) >> 4);
85}
47b0e7ad 86
e866a257
AC
87/* -- */
88\f
89/* -- asm.c */
47b0e7ad 90static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
e866a257
AC
91
92/* Handle '#' prefixes (i.e. skip over them). */
93
94static const char *
47b0e7ad
NC
95parse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
96 const char **strp,
97 int opindex ATTRIBUTE_UNUSED,
98 long *valuep ATTRIBUTE_UNUSED)
e866a257
AC
99{
100 if (**strp == '#')
101 ++*strp;
102 return NULL;
103}
104
105/* Handle shigh(), high(). */
106
107static const char *
47b0e7ad
NC
108parse_hi16 (CGEN_CPU_DESC cd,
109 const char **strp,
110 int opindex,
111 unsigned long *valuep)
e866a257
AC
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,
47b0e7ad 124 & result_type, & value);
e866a257 125 if (**strp != ')')
47b0e7ad 126 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
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,
47b0e7ad 138 & result_type, & value);
e866a257 139 if (**strp != ')')
47b0e7ad 140 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
141 ++*strp;
142 if (errmsg == NULL
143 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
f4453dfa
NC
144 {
145 value = value + (value & 0x8000 ? 0x10000 : 0);
146 value >>= 16;
147 }
e866a257
AC
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
159static const char *
47b0e7ad
NC
160parse_slo16 (CGEN_CPU_DESC cd,
161 const char ** strp,
162 int opindex,
163 long * valuep)
e866a257
AC
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,
47b0e7ad 176 & result_type, & value);
e866a257 177 if (**strp != ')')
47b0e7ad 178 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
179 ++*strp;
180 if (errmsg == NULL
181 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
e74eb924 182 value = ((value & 0xffff) ^ 0x8000) - 0x8000;
e866a257
AC
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,
47b0e7ad 191 NULL, & value);
e866a257 192 if (**strp != ')')
47b0e7ad 193 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
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
206static const char *
47b0e7ad
NC
207parse_ulo16 (CGEN_CPU_DESC cd,
208 const char **strp,
209 int opindex,
210 unsigned long *valuep)
e866a257
AC
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,
47b0e7ad 223 & result_type, & value);
e866a257 224 if (**strp != ')')
47b0e7ad 225 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
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 */
e866a257
AC
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
252static void
47b0e7ad
NC
253print_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)
e866a257
AC
259{
260 disassemble_info *info = (disassemble_info *) dis_info;
47b0e7ad 261
e866a257
AC
262 (*info->fprintf_func) (info->stream, "#");
263}
264
265#undef CGEN_PRINT_INSN
266#define CGEN_PRINT_INSN my_print_insn
267
268static int
47b0e7ad
NC
269my_print_insn (CGEN_CPU_DESC cd,
270 bfd_vma pc,
271 disassemble_info *info)
e866a257 272{
47b0e7ad
NC
273 bfd_byte buffer[CGEN_MAX_INSN_SIZE];
274 bfd_byte *buf = buffer;
e866a257
AC
275 int status;
276 int buflen = (pc & 3) == 0 ? 4 : 2;
8ee9a8b2 277 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
47b0e7ad 278 bfd_byte *x;
e866a257
AC
279
280 /* Read the base part of the insn. */
281
8ee9a8b2
NC
282 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
283 buf, buflen, info);
e866a257
AC
284 if (status != 0)
285 {
286 (*info->memory_error_func) (status, pc, info);
287 return -1;
288 }
289
290 /* 32 bit insn? */
8ee9a8b2
NC
291 x = (big_p ? &buf[0] : &buf[3]);
292 if ((pc & 3) == 0 && (*x & 0x80) != 0)
e866a257
AC
293 return print_insn (cd, pc, info, buf, buflen);
294
295 /* Print the first insn. */
296 if ((pc & 3) == 0)
297 {
8ee9a8b2 298 buf += (big_p ? 0 : 2);
e866a257
AC
299 if (print_insn (cd, pc, info, buf, 2) == 0)
300 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
8ee9a8b2 301 buf += (big_p ? 2 : -2);
e866a257
AC
302 }
303
8ee9a8b2
NC
304 x = (big_p ? &buf[0] : &buf[1]);
305 if (*x & 0x80)
e866a257
AC
306 {
307 /* Parallel. */
308 (*info->fprintf_func) (info->stream, " || ");
8ee9a8b2 309 *x &= 0x7f;
e866a257
AC
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.115192 seconds and 4 git commands to generate.