]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - cpu/m32r.opc
update copyright dates
[thirdparty/binutils-gdb.git] / cpu / m32r.opc
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 \f
42 /* -- opc.h */
43
44 #undef CGEN_DIS_HASH_SIZE
45 #define CGEN_DIS_HASH_SIZE 256
46 #undef CGEN_DIS_HASH
47 #if 0
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)))
55 #else
56 #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value)
57 extern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT);
58 #endif
59
60 /* -- */
61 \f
62 /* -- opc.c */
63 unsigned int
64 m32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value)
65 {
66 unsigned int x;
67
68 if (value & 0xffff0000) /* 32bit instructions. */
69 value = (value >> 16) & 0xffff;
70
71 x = (value >> 8) & 0xf0;
72 if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
73 return x;
74
75 if (x == 0x70 || x == 0xf0)
76 return x | ((value >> 8) & 0x0f);
77
78 if (x == 0x30)
79 return x | ((value & 0x70) >> 4);
80 else
81 return x | ((value & 0xf0) >> 4);
82 }
83
84 /* -- */
85 \f
86 /* -- asm.c */
87 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
88
89 /* Handle '#' prefixes (i.e. skip over them). */
90
91 static const char *
92 parse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
93 const char **strp,
94 int opindex ATTRIBUTE_UNUSED,
95 long *valuep ATTRIBUTE_UNUSED)
96 {
97 if (**strp == '#')
98 ++*strp;
99 return NULL;
100 }
101
102 /* Handle shigh(), high(). */
103
104 static const char *
105 parse_hi16 (CGEN_CPU_DESC cd,
106 const char **strp,
107 int opindex,
108 unsigned long *valuep)
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,
121 & result_type, & value);
122 if (**strp != ')')
123 return MISSING_CLOSING_PARENTHESIS;
124 ++*strp;
125 if (errmsg == NULL
126 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
127 {
128 value >>= 16;
129 value &= 0xffff;
130 }
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,
138 & result_type, & value);
139 if (**strp != ')')
140 return MISSING_CLOSING_PARENTHESIS;
141 ++*strp;
142 if (errmsg == NULL
143 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
144 {
145 value += 0x8000;
146 value >>= 16;
147 value &= 0xffff;
148 }
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
160 static const char *
161 parse_slo16 (CGEN_CPU_DESC cd,
162 const char ** strp,
163 int opindex,
164 long * valuep)
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,
177 & result_type, & value);
178 if (**strp != ')')
179 return MISSING_CLOSING_PARENTHESIS;
180 ++*strp;
181 if (errmsg == NULL
182 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
183 value = ((value & 0xffff) ^ 0x8000) - 0x8000;
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,
192 NULL, & value);
193 if (**strp != ')')
194 return MISSING_CLOSING_PARENTHESIS;
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
207 static const char *
208 parse_ulo16 (CGEN_CPU_DESC cd,
209 const char **strp,
210 int opindex,
211 unsigned long *valuep)
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,
224 & result_type, & value);
225 if (**strp != ')')
226 return MISSING_CLOSING_PARENTHESIS;
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 */
241 /* Immediate values are prefixed with '#'. */
242
243 #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length) \
244 do \
245 { \
246 if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX)) \
247 (*info->fprintf_func) (info->stream, "#"); \
248 } \
249 while (0)
250
251 /* Handle '#' prefixes as operands. */
252
253 static void
254 print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
255 void * dis_info,
256 long value ATTRIBUTE_UNUSED,
257 unsigned int attrs ATTRIBUTE_UNUSED,
258 bfd_vma pc ATTRIBUTE_UNUSED,
259 int length ATTRIBUTE_UNUSED)
260 {
261 disassemble_info *info = (disassemble_info *) dis_info;
262
263 (*info->fprintf_func) (info->stream, "#");
264 }
265
266 #undef CGEN_PRINT_INSN
267 #define CGEN_PRINT_INSN my_print_insn
268
269 static int
270 my_print_insn (CGEN_CPU_DESC cd,
271 bfd_vma pc,
272 disassemble_info *info)
273 {
274 bfd_byte buffer[CGEN_MAX_INSN_SIZE];
275 bfd_byte *buf = buffer;
276 int status;
277 int buflen = (pc & 3) == 0 ? 4 : 2;
278 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
279 bfd_byte *x;
280
281 /* Read the base part of the insn. */
282
283 status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
284 buf, buflen, info);
285 if (status != 0)
286 {
287 (*info->memory_error_func) (status, pc, info);
288 return -1;
289 }
290
291 /* 32 bit insn? */
292 x = (big_p ? &buf[0] : &buf[3]);
293 if ((pc & 3) == 0 && (*x & 0x80) != 0)
294 return print_insn (cd, pc, info, buf, buflen);
295
296 /* Print the first insn. */
297 if ((pc & 3) == 0)
298 {
299 buf += (big_p ? 0 : 2);
300 if (print_insn (cd, pc, info, buf, 2) == 0)
301 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
302 buf += (big_p ? 2 : -2);
303 }
304
305 x = (big_p ? &buf[0] : &buf[1]);
306 if (*x & 0x80)
307 {
308 /* Parallel. */
309 (*info->fprintf_func) (info->stream, " || ");
310 *x &= 0x7f;
311 }
312 else
313 (*info->fprintf_func) (info->stream, " -> ");
314
315 /* The "& 3" is to pass a consistent address.
316 Parallel insns arguably both begin on the word boundary.
317 Also, branch insns are calculated relative to the word boundary. */
318 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
319 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
320
321 return (pc & 3) ? 2 : 4;
322 }
323
324 /* -- */