m32r.opc revision 1.1.1.1 1 /* M32R opcode support. -*- C -*-
2
3 Copyright 1998, 1999, 2000, 2001, 2004, 2005, 2007, 2009
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 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
13 the Free Software Foundation; either version 3 of the License, or
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
23 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
24 MA 02110-1301, USA. */
25
26
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"
40 <arch>-ibd.h additions use: "-- ibd.h" */
41
42 /* -- opc.h */
44
45 #undef CGEN_DIS_HASH_SIZE
46 #define CGEN_DIS_HASH_SIZE 256
47 #undef CGEN_DIS_HASH
48 #if 0
49 #define X(b) (((unsigned char *) (b))[0] & 0xf0)
50 #define CGEN_DIS_HASH(buffer, value) \
51 (X (buffer) | \
52 (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
53 : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
54 : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
55 : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
56 #else
57 #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value)
58 extern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT);
59 #endif
60
61 /* -- */
62
63 /* -- opc.c */
65 unsigned int
66 m32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value)
67 {
68 unsigned int x;
69
70 if (value & 0xffff0000) /* 32bit instructions. */
71 value = (value >> 16) & 0xffff;
72
73 x = (value >> 8) & 0xf0;
74 if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
75 return x;
76
77 if (x == 0x70 || x == 0xf0)
78 return x | ((value >> 8) & 0x0f);
79
80 if (x == 0x30)
81 return x | ((value & 0x70) >> 4);
82 else
83 return x | ((value & 0xf0) >> 4);
84 }
85
86 /* -- */
87
88 /* -- 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
243 /* -- dis.c */
245
246 /* Print signed operands with '#' prefixes. */
247
248 static void
249 print_signed_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
250 void * dis_info,
251 long value,
252 unsigned int attrs ATTRIBUTE_UNUSED,
253 bfd_vma pc ATTRIBUTE_UNUSED,
254 int length ATTRIBUTE_UNUSED)
255 {
256 disassemble_info *info = (disassemble_info *) dis_info;
257
258 (*info->fprintf_func) (info->stream, "#");
259 (*info->fprintf_func) (info->stream, "%ld", value);
260 }
261
262 /* Print unsigned operands with '#' prefixes. */
263
264 static void
265 print_unsigned_with_hash_prefix (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
266 void * dis_info,
267 long value,
268 unsigned int attrs ATTRIBUTE_UNUSED,
269 bfd_vma pc ATTRIBUTE_UNUSED,
270 int length ATTRIBUTE_UNUSED)
271 {
272 disassemble_info *info = (disassemble_info *) dis_info;
273
274 (*info->fprintf_func) (info->stream, "#");
275 (*info->fprintf_func) (info->stream, "0x%lx", value);
276 }
277
278 /* Handle '#' prefixes as operands. */
279
280 static void
281 print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
282 void * dis_info,
283 long value ATTRIBUTE_UNUSED,
284 unsigned int attrs ATTRIBUTE_UNUSED,
285 bfd_vma pc ATTRIBUTE_UNUSED,
286 int length ATTRIBUTE_UNUSED)
287 {
288 disassemble_info *info = (disassemble_info *) dis_info;
289
290 (*info->fprintf_func) (info->stream, "#");
291 }
292
293 #undef CGEN_PRINT_INSN
294 #define CGEN_PRINT_INSN my_print_insn
295
296 static int
297 my_print_insn (CGEN_CPU_DESC cd,
298 bfd_vma pc,
299 disassemble_info *info)
300 {
301 bfd_byte buffer[CGEN_MAX_INSN_SIZE];
302 bfd_byte *buf = buffer;
303 int status;
304 int buflen = (pc & 3) == 0 ? 4 : 2;
305 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
306 bfd_byte *x;
307
308 /* Read the base part of the insn. */
309
310 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
311 buf, buflen, info);
312 if (status != 0)
313 {
314 (*info->memory_error_func) (status, pc, info);
315 return -1;
316 }
317
318 /* 32 bit insn? */
319 x = (big_p ? &buf[0] : &buf[3]);
320 if ((pc & 3) == 0 && (*x & 0x80) != 0)
321 return print_insn (cd, pc, info, buf, buflen);
322
323 /* Print the first insn. */
324 if ((pc & 3) == 0)
325 {
326 buf += (big_p ? 0 : 2);
327 if (print_insn (cd, pc, info, buf, 2) == 0)
328 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
329 buf += (big_p ? 2 : -2);
330 }
331
332 x = (big_p ? &buf[0] : &buf[1]);
333 if (*x & 0x80)
334 {
335 /* Parallel. */
336 (*info->fprintf_func) (info->stream, " || ");
337 *x &= 0x7f;
338 }
339 else
340 (*info->fprintf_func) (info->stream, " -> ");
341
342 /* The "& 3" is to pass a consistent address.
343 Parallel insns arguably both begin on the word boundary.
344 Also, branch insns are calculated relative to the word boundary. */
345 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
346 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
347
348 return (pc & 3) ? 2 : 4;
349 }
350
351 /* -- */
352