2005-10-28 Dave Brolley <brolley@redhat.com>
[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 {
131 value >>= 16;
132 value &= 0xffff;
133 }
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,
141 & result_type, & value);
142 if (**strp != ')')
143 return MISSING_CLOSING_PARENTHESIS;
144 ++*strp;
145 if (errmsg == NULL
146 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
147 {
148 value += 0x8000;
149 value >>= 16;
150 value &= 0xffff;
151 }
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
163 static const char *
164 parse_slo16 (CGEN_CPU_DESC cd,
165 const char ** strp,
166 int opindex,
167 long * valuep)
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,
180 & result_type, & value);
181 if (**strp != ')')
182 return MISSING_CLOSING_PARENTHESIS;
183 ++*strp;
184 if (errmsg == NULL
185 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
186 value = ((value & 0xffff) ^ 0x8000) - 0x8000;
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,
195 NULL, & value);
196 if (**strp != ')')
197 return MISSING_CLOSING_PARENTHESIS;
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
210 static const char *
211 parse_ulo16 (CGEN_CPU_DESC cd,
212 const char **strp,
213 int opindex,
214 unsigned long *valuep)
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,
227 & result_type, & value);
228 if (**strp != ')')
229 return MISSING_CLOSING_PARENTHESIS;
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 */
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
256 static void
257 print_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)
263 {
264 disassemble_info *info = (disassemble_info *) dis_info;
265
266 (*info->fprintf_func) (info->stream, "#");
267 }
268
269 #undef CGEN_PRINT_INSN
270 #define CGEN_PRINT_INSN my_print_insn
271
272 static int
273 my_print_insn (CGEN_CPU_DESC cd,
274 bfd_vma pc,
275 disassemble_info *info)
276 {
277 bfd_byte buffer[CGEN_MAX_INSN_SIZE];
278 bfd_byte *buf = buffer;
279 int status;
280 int buflen = (pc & 3) == 0 ? 4 : 2;
281 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
282 bfd_byte *x;
283
284 /* Read the base part of the insn. */
285
286 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
287 buf, buflen, info);
288 if (status != 0)
289 {
290 (*info->memory_error_func) (status, pc, info);
291 return -1;
292 }
293
294 /* 32 bit insn? */
295 x = (big_p ? &buf[0] : &buf[3]);
296 if ((pc & 3) == 0 && (*x & 0x80) != 0)
297 return print_insn (cd, pc, info, buf, buflen);
298
299 /* Print the first insn. */
300 if ((pc & 3) == 0)
301 {
302 buf += (big_p ? 0 : 2);
303 if (print_insn (cd, pc, info, buf, 2) == 0)
304 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
305 buf += (big_p ? 2 : -2);
306 }
307
308 x = (big_p ? &buf[0] : &buf[1]);
309 if (*x & 0x80)
310 {
311 /* Parallel. */
312 (*info->fprintf_func) (info->stream, " || ");
313 *x &= 0x7f;
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.036429 seconds and 4 git commands to generate.