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