Only look for two parallel instructions when we are at a 32 bit boundary
[deliverable/binutils-gdb.git] / opcodes / m32r-dis.c
1 /* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
3
4 This file is used to generate m32r-dis.c.
5
6 Copyright (C) 1996, 1997 Free Software Foundation, Inc.
7
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23
24 #include "sysdep.h"
25 #include <stdio.h>
26 #include "ansidecl.h"
27 #include "dis-asm.h"
28 #include "bfd.h"
29 #include "m32r-opc.h"
30
31 /* ??? The layout of this stuff is still work in progress.
32 For speed in assembly/disassembly, we use inline functions. That of course
33 will only work for GCC. When this stuff is finished, we can decide whether
34 to keep the inline functions (and only get the performance increase when
35 compiled with GCC), or switch to macros, or use something else.
36 */
37
38 /* Default text to print if an instruction isn't recognized. */
39 #define UNKNOWN_INSN_MSG "*unknown*"
40
41 /* FIXME: Machine generate. */
42 #ifndef CGEN_PCREL_OFFSET
43 #define CGEN_PCREL_OFFSET 0
44 #endif
45
46 static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int));
47
48 static int extract_insn_normal
49 PARAMS ((const CGEN_INSN *, void *, cgen_insn_t, CGEN_FIELDS *));
50 static void print_insn_normal
51 PARAMS ((void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int));
52
53 CGEN_INLINE void
54 m32r_cgen_print_operand
55 PARAMS ((int opindex, disassemble_info * info, CGEN_FIELDS * fields, void const * attrs, bfd_vma pc, int length));
56
57 \f
58 /* Default extraction routine.
59
60 ATTRS is a mask of the boolean attributes. We only need `unsigned',
61 but for generality we take a bitmask of all of them. */
62
63 static int
64 extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep)
65 void * buf_ctrl;
66 cgen_insn_t insn_value;
67 unsigned int attrs;
68 int start;
69 int length;
70 int shift;
71 int total_length;
72 long * valuep;
73 {
74 long value;
75
76 #ifdef CGEN_INT_INSN
77 #if 0
78 value = ((insn_value >> (CGEN_BASE_INSN_BITSIZE - (start + length)))
79 & ((1 << length) - 1));
80 #else
81 value = ((insn_value >> (total_length - (start + length)))
82 & ((1 << length) - 1));
83 #endif
84 if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
85 && (value & (1 << (length - 1))))
86 value -= 1 << length;
87 #else
88 /* FIXME: unfinished */
89 #endif
90
91 /* This is backwards as we undo the effects of insert_normal. */
92 if (shift < 0)
93 value >>= -shift;
94 else
95 value <<= shift;
96
97 * valuep = value;
98 return 1;
99 }
100
101 /* Default print handler. */
102
103 static void
104 print_normal (dis_info, value, attrs, pc, length)
105 void * dis_info;
106 long value;
107 unsigned int attrs;
108 unsigned long pc; /* FIXME: should be bfd_vma */
109 int length;
110 {
111 disassemble_info * info = dis_info;
112
113 /* Print the operand as directed by the attributes. */
114 if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_FAKE))
115 ; /* nothing to do (??? at least not yet) */
116 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_PCREL_ADDR))
117 (*info->print_address_func) (pc + CGEN_PCREL_OFFSET + value, info);
118 /* ??? Not all cases of this are currently caught. */
119 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_ABS_ADDR))
120 /* FIXME: Why & 0xffffffff? */
121 (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
122 else if (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
123 (*info->fprintf_func) (info->stream, "0x%lx", value);
124 else
125 (*info->fprintf_func) (info->stream, "%ld", value);
126 }
127
128 /* Keyword print handler. */
129
130 static void
131 print_keyword (dis_info, keyword_table, value, attrs)
132 void * dis_info;
133 CGEN_KEYWORD * keyword_table;
134 long value;
135 CGEN_ATTR * attrs;
136 {
137 disassemble_info * info = dis_info;
138 const CGEN_KEYWORD_ENTRY * ke;
139
140 ke = cgen_keyword_lookup_value (keyword_table, value);
141 info->fprintf_func (info->stream, "%s", ke == NULL ? "???" : ke->name);
142 }
143 \f
144 /* -- disassembler routines inserted here */
145 \f
146 /* Default insn extractor.
147
148 The extracted fields are stored in DIS_FLDS.
149 BUF_CTRL is used to handle reading variable length insns (FIXME: not done).
150 Return the length of the insn in bits, or 0 if no match. */
151
152 static int
153 extract_insn_normal (insn, buf_ctrl, insn_value, fields)
154 const CGEN_INSN * insn;
155 void * buf_ctrl;
156 cgen_insn_t insn_value;
157 CGEN_FIELDS * fields;
158 {
159 const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
160 const unsigned char * syn;
161
162 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
163
164 CGEN_INIT_EXTRACT ();
165
166 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
167 {
168 int length;
169
170 if (CGEN_SYNTAX_CHAR_P (* syn))
171 continue;
172
173 length = m32r_cgen_extract_operand (CGEN_SYNTAX_FIELD (* syn),
174 buf_ctrl, insn_value, fields);
175 if (length == 0)
176 return 0;
177 }
178
179 /* We recognized and successfully extracted this insn. */
180 return CGEN_INSN_BITSIZE (insn);
181 }
182
183 /* Default insn printer.
184
185 DIS_INFO is defined as `void *' so the disassembler needn't know anything
186 about disassemble_info.
187 */
188
189 static void
190 print_insn_normal (dis_info, insn, fields, pc, length)
191 void * dis_info;
192 const CGEN_INSN * insn;
193 CGEN_FIELDS * fields;
194 bfd_vma pc;
195 int length;
196 {
197 const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
198 disassemble_info * info = dis_info;
199 const unsigned char * syn;
200
201 CGEN_INIT_PRINT ();
202
203 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
204 {
205 if (CGEN_SYNTAX_MNEMONIC_P (* syn))
206 {
207 info->fprintf_func (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
208 continue;
209 }
210 if (CGEN_SYNTAX_CHAR_P (* syn))
211 {
212 info->fprintf_func (info->stream, "%c", CGEN_SYNTAX_CHAR (* syn));
213 continue;
214 }
215
216 /* We have an operand. */
217 m32r_cgen_print_operand (CGEN_SYNTAX_FIELD (* syn), info,
218 fields, CGEN_INSN_ATTRS (insn), pc, length);
219 }
220 }
221 \f
222 /* Default value for CGEN_PRINT_INSN.
223 Given BUFLEN bytes (target byte order) read into BUF, look up the
224 insn in the instruction table and disassemble it.
225
226 The result is the size of the insn in bytes. */
227
228 #ifndef CGEN_PRINT_INSN
229 #define CGEN_PRINT_INSN print_insn
230 #endif
231
232 static int
233 print_insn (pc, info, buf, buflen)
234 bfd_vma pc;
235 disassemble_info * info;
236 char * buf;
237 int buflen;
238 {
239 int i;
240 unsigned long insn_value;
241 const CGEN_INSN_LIST * insn_list;
242 int extra_bytes;
243
244 switch (buflen)
245 {
246 case 8:
247 insn_value = buf[0];
248 break;
249 case 16:
250 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
251 break;
252 case 32:
253 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
254 break;
255 default:
256 abort ();
257 }
258
259 /* Special case - a 32 bit instruction which is actually two 16 bit instructions
260 being executed in parallel. */
261 if (buflen == 32
262 && (pc & 0x3) == 0
263 && ((insn_value & 0x80008000) == 0x00008000))
264 {
265 if (info->endian == BFD_ENDIAN_BIG)
266 {
267 static char buf2 [4];
268
269 print_insn (pc, info, buf, 16);
270
271 info->fprintf_func (info->stream, " || ");
272
273 buf2 [0] = buf [2] & ~ 0x80;
274 buf2 [1] = buf [3];
275 buf2 [2] = 0;
276 buf2 [3] = 0;
277 buf = buf2;
278
279 insn_value <<= 17;
280 insn_value >>= 1;
281 }
282 else
283 {
284 print_insn (pc, info, buf + 2, 16);
285
286 info->fprintf_func (info->stream, " || ");
287
288 insn_value &= 0x7fff;
289 }
290
291 pc += 2;
292 extra_bytes = 2;
293 }
294 else
295 extra_bytes = 0;
296
297 /* The instructions are stored in hash lists.
298 Pick the first one and keep trying until we find the right one. */
299
300 insn_list = CGEN_DIS_LOOKUP_INSN (buf, insn_value);
301
302 while (insn_list != NULL)
303 {
304 const CGEN_INSN * insn = insn_list->insn;
305 unsigned long value;
306
307 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
308 /* Supported by this cpu? */
309 if (! m32r_cgen_insn_supported (insn))
310 continue;
311 #endif
312
313 /* If we are looking at a 16 bit insn we may have to adjust the value being examined. */
314 value = insn_value;
315 if (CGEN_INSN_BITSIZE (insn) == 16)
316 {
317 /* If this is a big endian target,
318 and we have read 32 bits for the instruction value,
319 then we must examine the top 16 bits, not the bottom. */
320 if (buflen == 32 && info->endian == BFD_ENDIAN_BIG)
321 value >>= 16;
322 }
323
324 /* Basic bit mask must be correct. */
325 /* ??? May wish to allow target to defer this check until the extract
326 handler. */
327 if ((value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
328 {
329 CGEN_FIELDS fields;
330 int length;
331
332 /* Printing is handled in two passes. The first pass parses the
333 machine insn and extracts the fields. The second pass prints
334 them. */
335
336 length = CGEN_EXTRACT_FN (insn) (insn, NULL, value, & fields);
337 if (length > 0)
338 {
339 CGEN_PRINT_FN (insn) (info, insn, & fields, pc, length);
340
341 /* length is in bits, result is in bytes */
342 return (length / 8) + extra_bytes;
343 }
344 }
345
346 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
347 }
348
349 return extra_bytes;
350 }
351
352 /* Main entry point.
353 Print one instruction from PC on INFO->STREAM.
354 Return the size of the instruction (in bytes). */
355
356 int
357 print_insn_m32r (pc, info)
358 bfd_vma pc;
359 disassemble_info * info;
360 {
361 char buffer [CGEN_MAX_INSN_SIZE];
362 int status;
363 int length;
364 static int initialized = 0;
365 static int current_mach = 0;
366 static int current_bigend = 0;
367 int mach = info->mach;
368 int bigend = info->endian == BFD_ENDIAN_BIG;
369
370 /* If we haven't initialized yet, or if we've switched cpu's, initialize. */
371 if (!initialized || mach != current_mach || bigend != current_bigend)
372 {
373 initialized = 1;
374 current_mach = mach;
375 current_bigend = bigend;
376
377 m32r_cgen_init_dis (mach, bigend ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
378 }
379
380 /* Read enough of the insn so we can look it up in the hash lists. */
381
382 status = info->read_memory_func (pc, buffer, CGEN_BASE_INSN_SIZE, info);
383 if (status != 0)
384 {
385 /* Try reading a 16 bit instruction. */
386 info->bytes_per_chunk = 2;
387 status = info->read_memory_func (pc, buffer, CGEN_BASE_INSN_SIZE / 2, info);
388 buffer [2] = buffer [3] = 0;
389 }
390 if (status != 0)
391 {
392 info->memory_error_func (status, pc, info);
393 return -1;
394 }
395
396 /* We try to have as much common code as possible.
397 But at this point some targets need to take over. */
398 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
399 but if not possible try to move this hook elsewhere rather than
400 have two hooks. */
401 length = CGEN_PRINT_INSN (pc, info, buffer, CGEN_BASE_INSN_BITSIZE);
402
403 if (length)
404 return length;
405
406 info->fprintf_func (info->stream, UNKNOWN_INSN_MSG);
407
408 return CGEN_DEFAULT_INSN_SIZE;
409 }
410
411 /* Get the generate machine specific code. */
412 #include "m32r-dis.in"
This page took 0.061931 seconds and 5 git commands to generate.