* m32c.cpu (mul.l): New.
[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)
e277c00b
AM
130 {
131 value >>= 16;
132 value &= 0xffff;
133 }
e866a257
AC
134 *valuep = value;
135 return errmsg;
136 }
137 else if (strncasecmp (*strp, "shigh(", 6) == 0)
138 {
139 *strp += 6;
140 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
47b0e7ad 141 & result_type, & value);
e866a257 142 if (**strp != ')')
47b0e7ad 143 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
144 ++*strp;
145 if (errmsg == NULL
146 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
f4453dfa 147 {
e277c00b 148 value += 0x8000;
f4453dfa 149 value >>= 16;
e277c00b 150 value &= 0xffff;
f4453dfa 151 }
e866a257
AC
152 *valuep = value;
153 return errmsg;
154 }
155
156 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
157}
158
159/* Handle low() in a signed context. Also handle sda().
160 The signedness of the value doesn't matter to low(), but this also
161 handles the case where low() isn't present. */
162
163static const char *
47b0e7ad
NC
164parse_slo16 (CGEN_CPU_DESC cd,
165 const char ** strp,
166 int opindex,
167 long * valuep)
e866a257
AC
168{
169 const char *errmsg;
170 enum cgen_parse_operand_result result_type;
171 bfd_vma value;
172
173 if (**strp == '#')
174 ++*strp;
175
176 if (strncasecmp (*strp, "low(", 4) == 0)
177 {
178 *strp += 4;
179 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
47b0e7ad 180 & result_type, & value);
e866a257 181 if (**strp != ')')
47b0e7ad 182 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
183 ++*strp;
184 if (errmsg == NULL
185 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
e74eb924 186 value = ((value & 0xffff) ^ 0x8000) - 0x8000;
e866a257
AC
187 *valuep = value;
188 return errmsg;
189 }
190
191 if (strncasecmp (*strp, "sda(", 4) == 0)
192 {
193 *strp += 4;
194 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
47b0e7ad 195 NULL, & value);
e866a257 196 if (**strp != ')')
47b0e7ad 197 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
198 ++*strp;
199 *valuep = value;
200 return errmsg;
201 }
202
203 return cgen_parse_signed_integer (cd, strp, opindex, valuep);
204}
205
206/* Handle low() in an unsigned context.
207 The signedness of the value doesn't matter to low(), but this also
208 handles the case where low() isn't present. */
209
210static const char *
47b0e7ad
NC
211parse_ulo16 (CGEN_CPU_DESC cd,
212 const char **strp,
213 int opindex,
214 unsigned long *valuep)
e866a257
AC
215{
216 const char *errmsg;
217 enum cgen_parse_operand_result result_type;
218 bfd_vma value;
219
220 if (**strp == '#')
221 ++*strp;
222
223 if (strncasecmp (*strp, "low(", 4) == 0)
224 {
225 *strp += 4;
226 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
47b0e7ad 227 & result_type, & value);
e866a257 228 if (**strp != ')')
47b0e7ad 229 return MISSING_CLOSING_PARENTHESIS;
e866a257
AC
230 ++*strp;
231 if (errmsg == NULL
232 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
233 value &= 0xffff;
234 *valuep = value;
235 return errmsg;
236 }
237
238 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
239}
240
241/* -- */
242\f
243/* -- dis.c */
e866a257
AC
244/* Immediate values are prefixed with '#'. */
245
246#define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length) \
247 do \
248 { \
249 if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX)) \
250 (*info->fprintf_func) (info->stream, "#"); \
251 } \
252 while (0)
253
254/* Handle '#' prefixes as operands. */
255
256static void
47b0e7ad
NC
257print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
258 void * dis_info,
259 long value ATTRIBUTE_UNUSED,
260 unsigned int attrs ATTRIBUTE_UNUSED,
261 bfd_vma pc ATTRIBUTE_UNUSED,
262 int length ATTRIBUTE_UNUSED)
e866a257
AC
263{
264 disassemble_info *info = (disassemble_info *) dis_info;
47b0e7ad 265
e866a257
AC
266 (*info->fprintf_func) (info->stream, "#");
267}
268
269#undef CGEN_PRINT_INSN
270#define CGEN_PRINT_INSN my_print_insn
271
272static int
47b0e7ad
NC
273my_print_insn (CGEN_CPU_DESC cd,
274 bfd_vma pc,
275 disassemble_info *info)
e866a257 276{
47b0e7ad
NC
277 bfd_byte buffer[CGEN_MAX_INSN_SIZE];
278 bfd_byte *buf = buffer;
e866a257
AC
279 int status;
280 int buflen = (pc & 3) == 0 ? 4 : 2;
8ee9a8b2 281 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
47b0e7ad 282 bfd_byte *x;
e866a257
AC
283
284 /* Read the base part of the insn. */
285
8ee9a8b2
NC
286 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
287 buf, buflen, info);
e866a257
AC
288 if (status != 0)
289 {
290 (*info->memory_error_func) (status, pc, info);
291 return -1;
292 }
293
294 /* 32 bit insn? */
8ee9a8b2
NC
295 x = (big_p ? &buf[0] : &buf[3]);
296 if ((pc & 3) == 0 && (*x & 0x80) != 0)
e866a257
AC
297 return print_insn (cd, pc, info, buf, buflen);
298
299 /* Print the first insn. */
300 if ((pc & 3) == 0)
301 {
8ee9a8b2 302 buf += (big_p ? 0 : 2);
e866a257
AC
303 if (print_insn (cd, pc, info, buf, 2) == 0)
304 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
8ee9a8b2 305 buf += (big_p ? 2 : -2);
e866a257
AC
306 }
307
8ee9a8b2
NC
308 x = (big_p ? &buf[0] : &buf[1]);
309 if (*x & 0x80)
e866a257
AC
310 {
311 /* Parallel. */
312 (*info->fprintf_func) (info->stream, " || ");
8ee9a8b2 313 *x &= 0x7f;
e866a257
AC
314 }
315 else
316 (*info->fprintf_func) (info->stream, " -> ");
317
318 /* The "& 3" is to pass a consistent address.
319 Parallel insns arguably both begin on the word boundary.
320 Also, branch insns are calculated relative to the word boundary. */
321 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
322 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
323
324 return (pc & 3) ? 2 : 4;
325}
326
327/* -- */
This page took 0.116739 seconds and 4 git commands to generate.