toplevel--
[deliverable/binutils-gdb.git] / opcodes / m32r-dis.c
CommitLineData
9c03036a
DE
1/* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
3
4This file is used to generate m32r-dis.c.
5
6Copyright (C) 1996, 1997 Free Software Foundation, Inc.
7
8This file is part of the GNU Binutils and GDB, the GNU debugger.
9
10This program is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 2, or (at your option)
13any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23
23cf992f 24#include "sysdep.h"
9c03036a
DE
25#include <stdio.h>
26#include "ansidecl.h"
27#include "dis-asm.h"
9c03036a 28#include "bfd.h"
23cf992f 29#include "m32r-opc.h"
9c03036a
DE
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
46static int print_insn PARAMS ((bfd_vma, disassemble_info *, char *, int));
47
48static int extract_insn_normal
23cf992f 49 PARAMS ((const CGEN_INSN *, void *, cgen_insn_t, CGEN_FIELDS *));
9c03036a 50static void print_insn_normal
23cf992f
NC
51 PARAMS ((void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int));
52
53CGEN_INLINE void
54m32r_cgen_print_operand
55 PARAMS ((int opindex, disassemble_info * info, CGEN_FIELDS * fields, void const * attrs, bfd_vma pc, int length));
56
9c03036a
DE
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
63static int
64extract_normal (buf_ctrl, insn_value, attrs, start, length, shift, total_length, valuep)
23cf992f
NC
65 void * buf_ctrl;
66 cgen_insn_t insn_value;
9c03036a 67 unsigned int attrs;
23cf992f
NC
68 int start;
69 int length;
70 int shift;
71 int total_length;
72 long * valuep;
9c03036a
DE
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
23cf992f 97 * valuep = value;
9c03036a
DE
98 return 1;
99}
100
101/* Default print handler. */
102
103static void
104print_normal (dis_info, value, attrs, pc, length)
23cf992f
NC
105 void * dis_info;
106 long value;
107 unsigned int attrs;
9c03036a 108 unsigned long pc; /* FIXME: should be bfd_vma */
23cf992f 109 int length;
9c03036a 110{
23cf992f 111 disassemble_info * info = dis_info;
9c03036a
DE
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
130static void
131print_keyword (dis_info, keyword_table, value, attrs)
23cf992f
NC
132 void * dis_info;
133 CGEN_KEYWORD * keyword_table;
134 long value;
135 CGEN_ATTR * attrs;
9c03036a 136{
23cf992f
NC
137 disassemble_info * info = dis_info;
138 const CGEN_KEYWORD_ENTRY * ke;
9c03036a
DE
139
140 ke = cgen_keyword_lookup_value (keyword_table, value);
23cf992f 141 info->fprintf_func (info->stream, "%s", ke == NULL ? "???" : ke->name);
9c03036a
DE
142}
143\f
144/* -- disassembler routines inserted here */
9c03036a
DE
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
152static int
153extract_insn_normal (insn, buf_ctrl, insn_value, fields)
23cf992f
NC
154 const CGEN_INSN * insn;
155 void * buf_ctrl;
156 cgen_insn_t insn_value;
157 CGEN_FIELDS * fields;
9c03036a 158{
23cf992f
NC
159 const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
160 const unsigned char * syn;
9c03036a 161
9c03036a
DE
162 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
163
164 CGEN_INIT_EXTRACT ();
165
23cf992f 166 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
9c03036a
DE
167 {
168 int length;
169
23cf992f 170 if (CGEN_SYNTAX_CHAR_P (* syn))
9c03036a
DE
171 continue;
172
23cf992f 173 length = m32r_cgen_extract_operand (CGEN_SYNTAX_FIELD (* syn),
9c03036a
DE
174 buf_ctrl, insn_value, fields);
175 if (length == 0)
176 return 0;
177 }
178
23cf992f
NC
179 /* We recognized and successfully extracted this insn. */
180 return CGEN_INSN_BITSIZE (insn);
9c03036a
DE
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
189static void
190print_insn_normal (dis_info, insn, fields, pc, length)
23cf992f
NC
191 void * dis_info;
192 const CGEN_INSN * insn;
193 CGEN_FIELDS * fields;
194 bfd_vma pc;
195 int length;
9c03036a 196{
23cf992f
NC
197 const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
198 disassemble_info * info = dis_info;
199 const unsigned char * syn;
9c03036a
DE
200
201 CGEN_INIT_PRINT ();
202
23cf992f 203 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
9c03036a 204 {
23cf992f
NC
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))
9c03036a 211 {
23cf992f 212 info->fprintf_func (info->stream, "%c", CGEN_SYNTAX_CHAR (* syn));
9c03036a
DE
213 continue;
214 }
215
216 /* We have an operand. */
23cf992f 217 m32r_cgen_print_operand (CGEN_SYNTAX_FIELD (* syn), info,
9c03036a
DE
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
232static int
233print_insn (pc, info, buf, buflen)
23cf992f
NC
234 bfd_vma pc;
235 disassemble_info * info;
236 char * buf;
237 int buflen;
9c03036a 238{
23cf992f
NC
239 int i;
240 unsigned long insn_value;
241 const CGEN_INSN_LIST * insn_list;
242 int extra_bytes;
243
9c03036a
DE
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
23cf992f
NC
259 /* Special case - a 32 bit instruction which is actually two 16 bit instructions
260 being executed in parallel. */
261 if (buflen == 32
262 && ((insn_value & 0x80008000) == 0x00008000))
263 {
264 if (info->endian == BFD_ENDIAN_BIG)
265 {
266 static char buf2 [4];
267
268 print_insn (pc, info, buf, 16);
269
270 info->fprintf_func (info->stream, " || ");
271
272 buf2 [0] = buf [2] & ~ 0x80;
273 buf2 [1] = buf [3];
274 buf2 [2] = 0;
275 buf2 [3] = 0;
276 buf = buf2;
277
278 insn_value <<= 17;
279 insn_value >>= 1;
280 }
281 else
282 {
283 print_insn (pc, info, buf + 2, 16);
284
285 info->fprintf_func (info->stream, " || ");
286
287 insn_value &= 0x7fff;
288 }
289
290 pc += 2;
291 extra_bytes = 2;
292 }
293 else
294 extra_bytes = 0;
295
9c03036a
DE
296 /* The instructions are stored in hash lists.
297 Pick the first one and keep trying until we find the right one. */
298
299 insn_list = CGEN_DIS_LOOKUP_INSN (buf, insn_value);
23cf992f 300
9c03036a
DE
301 while (insn_list != NULL)
302 {
23cf992f
NC
303 const CGEN_INSN * insn = insn_list->insn;
304 unsigned long value;
9c03036a
DE
305
306#if 0 /* not needed as insn shouldn't be in hash lists if not supported */
307 /* Supported by this cpu? */
308 if (! m32r_cgen_insn_supported (insn))
309 continue;
310#endif
311
23cf992f
NC
312 /* If we are looking at a 16 bit insn we may have to adjust the value being examined. */
313 value = insn_value;
314 if (CGEN_INSN_BITSIZE (insn) == 16)
315 {
316 /* If this is a big endian target,
317 and we have read 32 bits for the instruction value,
318 then we must examine the top 16 bits, not the bottom. */
319 if (buflen == 32 && info->endian == BFD_ENDIAN_BIG)
320 value >>= 16;
321 }
322
9c03036a
DE
323 /* Basic bit mask must be correct. */
324 /* ??? May wish to allow target to defer this check until the extract
325 handler. */
23cf992f 326 if ((value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
9c03036a 327 {
23cf992f
NC
328 CGEN_FIELDS fields;
329 int length;
330
9c03036a
DE
331 /* Printing is handled in two passes. The first pass parses the
332 machine insn and extracts the fields. The second pass prints
333 them. */
334
23cf992f 335 length = CGEN_EXTRACT_FN (insn) (insn, NULL, value, & fields);
9c03036a
DE
336 if (length > 0)
337 {
23cf992f
NC
338 CGEN_PRINT_FN (insn) (info, insn, & fields, pc, length);
339
9c03036a 340 /* length is in bits, result is in bytes */
23cf992f 341 return (length / 8) + extra_bytes;
9c03036a
DE
342 }
343 }
23cf992f 344
9c03036a
DE
345 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
346 }
347
23cf992f 348 return extra_bytes;
9c03036a
DE
349}
350
351/* Main entry point.
352 Print one instruction from PC on INFO->STREAM.
353 Return the size of the instruction (in bytes). */
354
355int
356print_insn_m32r (pc, info)
23cf992f
NC
357 bfd_vma pc;
358 disassemble_info * info;
9c03036a 359{
23cf992f
NC
360 char buffer [CGEN_MAX_INSN_SIZE];
361 int status;
362 int length;
363 static int initialized = 0;
364 static int current_mach = 0;
365 static int current_bigend = 0;
366 int mach = info->mach;
367 int bigend = info->endian == BFD_ENDIAN_BIG;
9c03036a
DE
368
369 /* If we haven't initialized yet, or if we've switched cpu's, initialize. */
23cf992f 370 if (!initialized || mach != current_mach || bigend != current_bigend)
9c03036a 371 {
23cf992f
NC
372 initialized = 1;
373 current_mach = mach;
374 current_bigend = bigend;
375
376 m32r_cgen_init_dis (mach, bigend ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
9c03036a
DE
377 }
378
379 /* Read enough of the insn so we can look it up in the hash lists. */
380
23cf992f 381 status = info->read_memory_func (pc, buffer, CGEN_BASE_INSN_SIZE, info);
9c03036a
DE
382 if (status != 0)
383 {
23cf992f
NC
384 /* Try reading a 16 bit instruction. */
385 info->bytes_per_chunk = 2;
386 status = info->read_memory_func (pc, buffer, CGEN_BASE_INSN_SIZE / 2, info);
387 buffer [2] = buffer [3] = 0;
388 }
389 if (status != 0)
390 {
391 info->memory_error_func (status, pc, info);
9c03036a
DE
392 return -1;
393 }
394
395 /* We try to have as much common code as possible.
396 But at this point some targets need to take over. */
397 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
23cf992f 398 but if not possible try to move this hook elsewhere rather than
9c03036a
DE
399 have two hooks. */
400 length = CGEN_PRINT_INSN (pc, info, buffer, CGEN_BASE_INSN_BITSIZE);
23cf992f 401
9c03036a
DE
402 if (length)
403 return length;
404
23cf992f
NC
405 info->fprintf_func (info->stream, UNKNOWN_INSN_MSG);
406
9c03036a
DE
407 return CGEN_DEFAULT_INSN_SIZE;
408}
23cf992f
NC
409
410/* Get the generate machine specific code. */
411#include "m32r-dis.in"
This page took 0.058 seconds and 4 git commands to generate.