gdb: fix vfork with multiple threads
[deliverable/binutils-gdb.git] / cpu / m32r.opc
CommitLineData
e866a257
AC
1/* M32R opcode support. -*- C -*-
2
aa820537 3 Copyright 1998, 1999, 2000, 2001, 2004, 2005, 2007, 2009
33b71eeb 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
e866a257
AC
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
9b201bb5 13 the Free Software Foundation; either version 3 of the License, or
e866a257
AC
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
47b0e7ad
NC
23 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
24 MA 02110-1301, USA. */
e866a257 25
9b201bb5 26
e866a257
AC
27/* This file is an addendum to m32r.cpu. Heavy use of C code isn't
28 appropriate in .cpu files, so it resides here. This especially applies
29 to assembly/disassembly where parsing/printing can be quite involved.
30 Such things aren't really part of the specification of the cpu, per se,
31 so .cpu files provide the general framework and .opc files handle the
32 nitty-gritty details as necessary.
33
34 Each section is delimited with start and end markers.
35
36 <arch>-opc.h additions use: "-- opc.h"
37 <arch>-opc.c additions use: "-- opc.c"
38 <arch>-asm.c additions use: "-- asm.c"
39 <arch>-dis.c additions use: "-- dis.c"
f4453dfa 40 <arch>-ibd.h additions use: "-- ibd.h" */
e866a257
AC
41\f
42/* -- opc.h */
43
44#undef CGEN_DIS_HASH_SIZE
45#define CGEN_DIS_HASH_SIZE 256
46#undef CGEN_DIS_HASH
8ee9a8b2 47#if 0
e866a257
AC
48#define X(b) (((unsigned char *) (b))[0] & 0xf0)
49#define CGEN_DIS_HASH(buffer, value) \
50(X (buffer) | \
51 (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
52 : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
53 : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
54 : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
8ee9a8b2 55#else
47b0e7ad
NC
56#define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value)
57extern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT);
8ee9a8b2 58#endif
e866a257 59
8ee9a8b2
NC
60/* -- */
61\f
62/* -- opc.c */
63unsigned int
47b0e7ad 64m32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value)
8ee9a8b2
NC
65{
66 unsigned int x;
47b0e7ad
NC
67
68 if (value & 0xffff0000) /* 32bit instructions. */
8ee9a8b2 69 value = (value >> 16) & 0xffff;
47b0e7ad
NC
70
71 x = (value >> 8) & 0xf0;
8ee9a8b2
NC
72 if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
73 return x;
47b0e7ad 74
8ee9a8b2 75 if (x == 0x70 || x == 0xf0)
47b0e7ad
NC
76 return x | ((value >> 8) & 0x0f);
77
8ee9a8b2
NC
78 if (x == 0x30)
79 return x | ((value & 0x70) >> 4);
80 else
81 return x | ((value & 0xf0) >> 4);
82}
47b0e7ad 83
e866a257
AC
84/* -- */
85\f
86/* -- asm.c */
47b0e7ad 87static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
e866a257
AC
88
89/* Handle '#' prefixes (i.e. skip over them). */
90
91static const char *
47b0e7ad
NC
92parse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
93 const char **strp,
94 int opindex ATTRIBUTE_UNUSED,
95 long *valuep ATTRIBUTE_UNUSED)
e866a257
AC
96{
97 if (**strp == '#')
98 ++*strp;
99 return NULL;
100}
101
102/* Handle shigh(), high(). */
103
104static const char *
47b0e7ad
NC
105parse_hi16 (CGEN_CPU_DESC cd,
106 const char **strp,
107 int opindex,
108 unsigned long *valuep)
e866a257
AC
109{
110 const char *errmsg;
111 enum cgen_parse_operand_result result_type;
112 bfd_vma value;
113
114 if (**strp == '#')
115 ++*strp;
116
117 if (strncasecmp (*strp, "high(", 5) == 0)
118 {
119 *strp += 5;
120 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
47b0e7ad 121 & result_type, & value);
e866a257 122 if (**strp != ')')
47b0e7ad 123 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
124 ++*strp;
125 if (errmsg == NULL
a5da764d 126 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
e277c00b
AM
127 {
128 value >>= 16;
129 value &= 0xffff;
130 }
e866a257
AC
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,
a5da764d 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)
a5da764d
AM
144 {
145 value += 0x8000;
146 value >>= 16;
e277c00b 147 value &= 0xffff;
a5da764d 148 }
e866a257
AC
149 *valuep = value;
150 return errmsg;
151 }
152
153 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
154}
155
156/* Handle low() in a signed context. Also handle sda().
157 The signedness of the value doesn't matter to low(), but this also
158 handles the case where low() isn't present. */
159
160static const char *
47b0e7ad
NC
161parse_slo16 (CGEN_CPU_DESC cd,
162 const char ** strp,
163 int opindex,
164 long * valuep)
e866a257
AC
165{
166 const char *errmsg;
167 enum cgen_parse_operand_result result_type;
168 bfd_vma value;
169
170 if (**strp == '#')
171 ++*strp;
172
173 if (strncasecmp (*strp, "low(", 4) == 0)
174 {
175 *strp += 4;
176 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
47b0e7ad 177 & result_type, & value);
e866a257 178 if (**strp != ')')
47b0e7ad 179 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
180 ++*strp;
181 if (errmsg == NULL
182 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
a5da764d 183 value = ((value & 0xffff) ^ 0x8000) - 0x8000;
e866a257
AC
184 *valuep = value;
185 return errmsg;
186 }
187
188 if (strncasecmp (*strp, "sda(", 4) == 0)
189 {
190 *strp += 4;
191 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
47b0e7ad 192 NULL, & value);
e866a257 193 if (**strp != ')')
47b0e7ad 194 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
195 ++*strp;
196 *valuep = value;
197 return errmsg;
198 }
199
200 return cgen_parse_signed_integer (cd, strp, opindex, valuep);
201}
202
203/* Handle low() in an unsigned context.
204 The signedness of the value doesn't matter to low(), but this also
205 handles the case where low() isn't present. */
206
207static const char *
47b0e7ad
NC
208parse_ulo16 (CGEN_CPU_DESC cd,
209 const char **strp,
210 int opindex,
211 unsigned long *valuep)
e866a257
AC
212{
213 const char *errmsg;
214 enum cgen_parse_operand_result result_type;
215 bfd_vma value;
216
217 if (**strp == '#')
218 ++*strp;
219
220 if (strncasecmp (*strp, "low(", 4) == 0)
221 {
222 *strp += 4;
223 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
47b0e7ad 224 & result_type, & value);
e866a257 225 if (**strp != ')')
47b0e7ad 226 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
227 ++*strp;
228 if (errmsg == NULL
229 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
230 value &= 0xffff;
231 *valuep = value;
232 return errmsg;
233 }
234
235 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
236}
237
238/* -- */
239\f
240/* -- dis.c */
5ff58fb0
DE
241
242/* Print signed operands with '#' prefixes. */
243
244static void
245print_signed_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
246 void * dis_info,
247 long value,
248 unsigned int attrs ATTRIBUTE_UNUSED,
249 bfd_vma pc ATTRIBUTE_UNUSED,
250 int length ATTRIBUTE_UNUSED)
251{
252 disassemble_info *info = (disassemble_info *) dis_info;
253
254 (*info->fprintf_func) (info->stream, "#");
255 (*info->fprintf_func) (info->stream, "%ld", value);
256}
257
258/* Print unsigned operands with '#' prefixes. */
259
260static void
261print_unsigned_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
262 void * dis_info,
263 long value,
264 unsigned int attrs ATTRIBUTE_UNUSED,
265 bfd_vma pc ATTRIBUTE_UNUSED,
266 int length ATTRIBUTE_UNUSED)
267{
268 disassemble_info *info = (disassemble_info *) dis_info;
269
270 (*info->fprintf_func) (info->stream, "#");
271 (*info->fprintf_func) (info->stream, "0x%lx", value);
272}
e866a257
AC
273
274/* Handle '#' prefixes as operands. */
275
276static void
47b0e7ad
NC
277print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
278 void * dis_info,
279 long value ATTRIBUTE_UNUSED,
280 unsigned int attrs ATTRIBUTE_UNUSED,
281 bfd_vma pc ATTRIBUTE_UNUSED,
282 int length ATTRIBUTE_UNUSED)
e866a257
AC
283{
284 disassemble_info *info = (disassemble_info *) dis_info;
47b0e7ad 285
e866a257
AC
286 (*info->fprintf_func) (info->stream, "#");
287}
288
289#undef CGEN_PRINT_INSN
290#define CGEN_PRINT_INSN my_print_insn
291
292static int
47b0e7ad
NC
293my_print_insn (CGEN_CPU_DESC cd,
294 bfd_vma pc,
295 disassemble_info *info)
e866a257 296{
47b0e7ad
NC
297 bfd_byte buffer[CGEN_MAX_INSN_SIZE];
298 bfd_byte *buf = buffer;
e866a257
AC
299 int status;
300 int buflen = (pc & 3) == 0 ? 4 : 2;
8ee9a8b2 301 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
47b0e7ad 302 bfd_byte *x;
e866a257
AC
303
304 /* Read the base part of the insn. */
305
8ee9a8b2 306 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
a5da764d 307 buf, buflen, info);
e866a257
AC
308 if (status != 0)
309 {
310 (*info->memory_error_func) (status, pc, info);
311 return -1;
312 }
313
314 /* 32 bit insn? */
8ee9a8b2
NC
315 x = (big_p ? &buf[0] : &buf[3]);
316 if ((pc & 3) == 0 && (*x & 0x80) != 0)
e866a257
AC
317 return print_insn (cd, pc, info, buf, buflen);
318
319 /* Print the first insn. */
320 if ((pc & 3) == 0)
321 {
8ee9a8b2 322 buf += (big_p ? 0 : 2);
e866a257
AC
323 if (print_insn (cd, pc, info, buf, 2) == 0)
324 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
8ee9a8b2 325 buf += (big_p ? 2 : -2);
e866a257
AC
326 }
327
8ee9a8b2
NC
328 x = (big_p ? &buf[0] : &buf[1]);
329 if (*x & 0x80)
e866a257
AC
330 {
331 /* Parallel. */
332 (*info->fprintf_func) (info->stream, " || ");
8ee9a8b2 333 *x &= 0x7f;
e866a257
AC
334 }
335 else
336 (*info->fprintf_func) (info->stream, " -> ");
337
338 /* The "& 3" is to pass a consistent address.
339 Parallel insns arguably both begin on the word boundary.
340 Also, branch insns are calculated relative to the word boundary. */
341 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
342 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
343
344 return (pc & 3) ? 2 : 4;
345}
346
347/* -- */
This page took 0.675034 seconds and 4 git commands to generate.