This commit was generated by cvs2svn to track changes on a CVS vendor
[deliverable/binutils-gdb.git] / opcodes / cgen-dis.in
CommitLineData
bfc10abe
DE
1/* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
3
1c8f439e 4THIS FILE IS USED TO GENERATE @prefix@-dis.c.
bfc10abe 5
1c8f439e 6Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
bfc10abe
DE
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
1c8f439e
DE
21along with this program; if not, write to the Free Software Foundation, Inc.,
2259 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
bfc10abe
DE
23
24#include "sysdep.h"
25#include <stdio.h>
26#include "ansidecl.h"
27#include "dis-asm.h"
28#include "bfd.h"
833d2990 29#include "symcat.h"
1c8f439e
DE
30#include "@prefix@-opc.h"
31#include "opintl.h"
bfc10abe 32
1c8f439e
DE
33#undef INLINE
34#ifdef __GNUC__
35#define INLINE __inline__
36#else
37#define INLINE
bfc10abe
DE
38#endif
39
1c8f439e
DE
40/* Default text to print if an instruction isn't recognized. */
41#define UNKNOWN_INSN_MSG _("*unknown*")
42
43static int extract_normal
44 PARAMS ((CGEN_OPCODE_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_BYTES,
45 unsigned int, int, int, int, long *));
46static void print_normal
47 PARAMS ((CGEN_OPCODE_DESC, PTR, long, unsigned int, bfd_vma, int));
48static void print_address
49 PARAMS ((CGEN_OPCODE_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
50static void print_keyword
51 PARAMS ((CGEN_OPCODE_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
bfc10abe 52static int extract_insn_normal
1c8f439e
DE
53 PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
54 unsigned long, CGEN_FIELDS *, bfd_vma));
bfc10abe 55static void print_insn_normal
1c8f439e
DE
56 PARAMS ((CGEN_OPCODE_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
57 bfd_vma, int));
58static int print_insn PARAMS ((CGEN_OPCODE_DESC, bfd_vma,
59 disassemble_info *, char *, int));
60static int default_print_insn
61 PARAMS ((CGEN_OPCODE_DESC, bfd_vma, disassemble_info *));
62\f
63/* -- disassembler routines inserted here */
bfc10abe 64\f
1c8f439e
DE
65#if ! CGEN_INT_INSN_P
66
67/* Subroutine of extract_normal. */
68
69static INLINE long
70extract_1 (od, ex_info, start, length, word_length, bufp)
71 CGEN_OPCODE_DESC od;
72 CGEN_EXTRACT_INFO *info;
73 int start,length,word_length;
74 unsigned char *bufp;
75{
76 unsigned long x,mask;
77 int shift;
78 int big_p = CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG;
79
80 /* FIXME: Need to use ex_info to ensure bytes have been fetched. */
81
82 switch (word_length)
83 {
84 case 8:
85 x = *bufp;
86 break;
87 case 16:
88 if (big_p)
89 x = bfd_getb16 (bufp);
90 else
91 x = bfd_getl16 (bufp);
92 break;
93 case 24:
94 /* ??? This may need reworking as these cases don't necessarily
95 want the first byte and the last two bytes handled like this. */
96 if (big_p)
97 x = (bfd_getb8 (bufp) << 16) | bfd_getb16 (bufp + 1);
98 else
99 x = bfd_getl16 (bufp) | (bfd_getb8 (bufp + 2) << 16);
100 break;
101 case 32:
102 if (big_p)
103 x = bfd_getb32 (bufp);
104 else
105 x = bfd_getl32 (bufp);
106 break;
107 default :
108 abort ();
109 }
110
111 /* Written this way to avoid undefined behaviour. */
112 mask = (((1L << (length - 1)) - 1) << 1) | 1;
113 if (CGEN_INSN_LSB0_P)
114 shift = start;
115 else
116 shift = (word_length - (start + length));
117 return (x >> shift) & mask;
118}
119
120#endif /* ! CGEN_INT_INSN_P */
121
bfc10abe
DE
122/* Default extraction routine.
123
124 ATTRS is a mask of the boolean attributes. We only need `unsigned',
125 but for generality we take a bitmask of all of them. */
126
1c8f439e
DE
127/* ??? This doesn't handle bfd_vma's. Create another function when
128 necessary. */
129
bfc10abe 130static int
1c8f439e
DE
131extract_normal (od, ex_info, insn_value, attrs, start, length, total_length, valuep)
132 CGEN_OPCODE_DESC od;
133 CGEN_EXTRACT_INFO *ex_info;
134 CGEN_INSN_BYTES insn_value;
bfc10abe 135 unsigned int attrs;
1c8f439e 136 int start, length, total_length;
bfc10abe
DE
137 long *valuep;
138{
1c8f439e
DE
139 unsigned long value;
140
141 /* If LENGTH is zero, this operand doesn't contribute to the value
142 so give it a standard value of zero. */
143 if (length == 0)
144 {
145 *valuep = 0;
146 return 1;
147 }
148
149#if CGEN_INT_INSN_P
150
151 {
152 /* Written this way to avoid undefined behaviour. */
153 unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
154
155 if (CGEN_INSN_LSB0_P)
156 value = insn_value >> start;
157 else
158 value = insn_value >> (total_length - (start + length));
159 value &= mask;
160 /* sign extend? */
161 if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
162 && (value & (1L << (length - 1))))
163 value |= ~mask;
164 }
bfc10abe 165
bfc10abe 166#else
bfc10abe 167
1c8f439e
DE
168 /* The hard case is probably too slow for the normal cases.
169 It's certainly more difficult to understand than the normal case.
170 Thus this is split into two. Keep it that way. The hard case is defined
171 to be when a field straddles a (loosely defined) word boundary
172 (??? which may require target specific help to determine). */
173
174#if 0 /*wip*/
175
176#define HARD_CASE_P 0 /* FIXME:wip */
177
178 if (HARD_CASE_P)
179 {
180 }
181#endif
bfc10abe 182 else
1c8f439e
DE
183 {
184 unsigned char *bufp = (unsigned char *) insn_value;
185
186 if (length > 32)
187 abort ();
188
189 /* Adjust start,total_length,bufp to point to the pseudo-word that holds
190 the value. For example in a 48 bit insn where the value to insert
191 (say an immediate value) is the last 16 bits then word_length here
192 would be 16. To handle a 24 bit insn with an 18 bit immediate,
193 extract_1 handles 24 bits (using a combination of bfd_get8,16). */
194
195 if (total_length > 32)
196 {
197 int needed_width = start % 8 + length;
198 int fetch_length = (needed_width <= 8 ? 8
199 : needed_width <= 16 ? 16
200 : 32);
201
202 if (CGEN_INSN_LSB0_P)
203 {
204 if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
205 {
206 abort (); /* wip */
207 }
208 else
209 {
210 int offset = start & ~7;
211
212 bufp += offset / 8;
213 start -= offset;
214 total_length -= offset;
215 }
216 }
217 else
218 {
219 if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
220 {
221 int offset = start & ~7;
222
223 bufp += offset / 8;
224 start -= offset;
225 total_length -= offset;
226 }
227 else
228 {
229 abort (); /* wip */
230 }
231 }
232 }
233
234 /* FIXME: which bytes are being extracted have been lost. */
235 value = extract_1 (od, ex_info, start, length, total_length, bufp);
236 }
237
238#endif /* ! CGEN_INT_INSN_P */
bfc10abe
DE
239
240 *valuep = value;
833d2990
DE
241
242 /* FIXME: for now */
bfc10abe
DE
243 return 1;
244}
245
246/* Default print handler. */
247
248static void
1c8f439e
DE
249print_normal (od, dis_info, value, attrs, pc, length)
250 CGEN_OPCODE_DESC od;
ab0bd049 251 PTR dis_info;
bfc10abe
DE
252 long value;
253 unsigned int attrs;
1c8f439e 254 bfd_vma pc;
bfc10abe
DE
255 int length;
256{
1c8f439e
DE
257 disassemble_info *info = (disassemble_info *) dis_info;
258
259#ifdef CGEN_PRINT_NORMAL
260 CGEN_PRINT_NORMAL (od, info, value, attrs, pc, length);
261#endif
bfc10abe
DE
262
263 /* Print the operand as directed by the attributes. */
1c8f439e
DE
264 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
265 ; /* nothing to do */
266 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
bfc10abe
DE
267 (*info->fprintf_func) (info->stream, "0x%lx", value);
268 else
269 (*info->fprintf_func) (info->stream, "%ld", value);
270}
271
1c8f439e
DE
272/* Default address handler. */
273
274static void
275print_address (od, dis_info, value, attrs, pc, length)
276 CGEN_OPCODE_DESC od;
277 PTR dis_info;
278 bfd_vma value;
279 unsigned int attrs;
280 bfd_vma pc;
281 int length;
282{
283 disassemble_info *info = (disassemble_info *) dis_info;
284
285#ifdef CGEN_PRINT_ADDRESS
286 CGEN_PRINT_ADDRESS (od, info, value, attrs, pc, length);
287#endif
288
289 /* Print the operand as directed by the attributes. */
290 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
291 ; /* nothing to do */
292 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
293 (*info->print_address_func) (value, info);
294 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
295 (*info->print_address_func) (value, info);
296 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
297 (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
298 else
299 (*info->fprintf_func) (info->stream, "%ld", (long) value);
300}
301
bfc10abe
DE
302/* Keyword print handler. */
303
304static void
1c8f439e
DE
305print_keyword (od, dis_info, keyword_table, value, attrs)
306 CGEN_OPCODE_DESC od;
ab0bd049 307 PTR dis_info;
bfc10abe
DE
308 CGEN_KEYWORD *keyword_table;
309 long value;
1c8f439e 310 unsigned int attrs;
bfc10abe 311{
1c8f439e 312 disassemble_info *info = (disassemble_info *) dis_info;
bfc10abe
DE
313 const CGEN_KEYWORD_ENTRY *ke;
314
315 ke = cgen_keyword_lookup_value (keyword_table, value);
316 if (ke != NULL)
317 (*info->fprintf_func) (info->stream, "%s", ke->name);
318 else
319 (*info->fprintf_func) (info->stream, "???");
320}
321\f
bfc10abe
DE
322/* Default insn extractor.
323
1c8f439e
DE
324 INSN_VALUE is the first CGEN_BASE_INSN_SIZE bytes, translated to host order.
325 The extracted fields are stored in FIELDS.
326 EX_INFO is used to handle reading variable length insns.
327 Return the length of the insn in bits, or 0 if no match,
328 or -1 if an error occurs fetching data (memory_error_func will have
329 been called). */
bfc10abe
DE
330
331static int
1c8f439e
DE
332extract_insn_normal (od, insn, ex_info, insn_value, fields, pc)
333 CGEN_OPCODE_DESC od;
bfc10abe 334 const CGEN_INSN *insn;
1c8f439e
DE
335 CGEN_EXTRACT_INFO *ex_info;
336 unsigned long insn_value;
bfc10abe 337 CGEN_FIELDS *fields;
1c8f439e 338 bfd_vma pc;
bfc10abe
DE
339{
340 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
341 const unsigned char *syn;
342
343 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
344
1c8f439e 345 CGEN_INIT_EXTRACT (od);
bfc10abe
DE
346
347 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
348 {
349 int length;
350
351 if (CGEN_SYNTAX_CHAR_P (*syn))
352 continue;
353
1c8f439e
DE
354 length = @arch@_cgen_extract_operand (od, CGEN_SYNTAX_FIELD (*syn),
355 ex_info, insn_value, fields, pc);
356 if (length <= 0)
357 return length;
bfc10abe
DE
358 }
359
360 /* We recognized and successfully extracted this insn. */
361 return CGEN_INSN_BITSIZE (insn);
362}
363
364/* Default insn printer.
365
ab0bd049 366 DIS_INFO is defined as `PTR' so the disassembler needn't know anything
1c8f439e 367 about disassemble_info. */
bfc10abe
DE
368
369static void
1c8f439e
DE
370print_insn_normal (od, dis_info, insn, fields, pc, length)
371 CGEN_OPCODE_DESC od;
ab0bd049 372 PTR dis_info;
bfc10abe
DE
373 const CGEN_INSN *insn;
374 CGEN_FIELDS *fields;
375 bfd_vma pc;
376 int length;
377{
378 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
1c8f439e 379 disassemble_info *info = (disassemble_info *) dis_info;
bfc10abe
DE
380 const unsigned char *syn;
381
1c8f439e 382 CGEN_INIT_PRINT (od);
bfc10abe
DE
383
384 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
385 {
386 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
387 {
388 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
389 continue;
390 }
391 if (CGEN_SYNTAX_CHAR_P (*syn))
392 {
393 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
394 continue;
395 }
396
397 /* We have an operand. */
1c8f439e
DE
398 @arch@_cgen_print_operand (od, CGEN_SYNTAX_FIELD (*syn), info,
399 fields, CGEN_INSN_ATTRS (insn), pc, length);
bfc10abe
DE
400 }
401}
402\f
1c8f439e
DE
403/* Utility to print an insn.
404 BUF is the base part of the insn, target byte order, BUFLEN bytes long.
405 The result is the size of the insn in bytes or zero for an unknown insn
406 or -1 if an error occurs fetching data (memory_error_func will have
407 been called). */
bfc10abe
DE
408
409static int
1c8f439e
DE
410print_insn (od, pc, info, buf, buflen)
411 CGEN_OPCODE_DESC od;
bfc10abe
DE
412 bfd_vma pc;
413 disassemble_info *info;
414 char *buf;
415 int buflen;
416{
bfc10abe
DE
417 unsigned long insn_value;
418 const CGEN_INSN_LIST *insn_list;
1c8f439e
DE
419 CGEN_EXTRACT_INFO ex_info;
420
421 ex_info.dis_info = info;
422 ex_info.valid = (1 << CGEN_BASE_INSN_SIZE) - 1;
423 ex_info.bytes = buf;
bfc10abe
DE
424
425 switch (buflen)
426 {
1c8f439e 427 case 1:
bfc10abe
DE
428 insn_value = buf[0];
429 break;
1c8f439e 430 case 2:
bfc10abe
DE
431 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
432 break;
1c8f439e 433 case 4:
bfc10abe
DE
434 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
435 break;
436 default:
437 abort ();
438 }
439
440 /* The instructions are stored in hash lists.
441 Pick the first one and keep trying until we find the right one. */
442
1c8f439e 443 insn_list = CGEN_DIS_LOOKUP_INSN (od, buf, insn_value);
bfc10abe
DE
444 while (insn_list != NULL)
445 {
446 const CGEN_INSN *insn = insn_list->insn;
bfc10abe
DE
447 CGEN_FIELDS fields;
448 int length;
449
450#if 0 /* not needed as insn shouldn't be in hash lists if not supported */
451 /* Supported by this cpu? */
1c8f439e 452 if (! @arch@_cgen_insn_supported (od, insn))
bfc10abe
DE
453 continue;
454#endif
455
456 /* Basic bit mask must be correct. */
457 /* ??? May wish to allow target to defer this check until the extract
458 handler. */
459 if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
460 {
461 /* Printing is handled in two passes. The first pass parses the
462 machine insn and extracts the fields. The second pass prints
463 them. */
464
1c8f439e
DE
465 length = (*CGEN_EXTRACT_FN (insn)) (od, insn, &ex_info, insn_value,
466 &fields, pc);
467 /* length < 0 -> error */
468 if (length < 0)
469 return length;
bfc10abe
DE
470 if (length > 0)
471 {
1c8f439e 472 (*CGEN_PRINT_FN (insn)) (od, info, insn, &fields, pc, length);
bfc10abe
DE
473 /* length is in bits, result is in bytes */
474 return length / 8;
475 }
476 }
477
478 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
479 }
480
481 return 0;
482}
483
1c8f439e
DE
484/* Default value for CGEN_PRINT_INSN.
485 The result is the size of the insn in bytes or zero for an unknown insn
486 or -1 if an error occured fetching bytes. */
487
488#ifndef CGEN_PRINT_INSN
489#define CGEN_PRINT_INSN default_print_insn
490#endif
491
492static int
493default_print_insn (od, pc, info)
494 CGEN_OPCODE_DESC od;
495 bfd_vma pc;
496 disassemble_info *info;
497{
498 char buf[CGEN_MAX_INSN_SIZE];
499 int status;
500
501 /* Read the base part of the insn. */
502
503 status = (*info->read_memory_func) (pc, buf, CGEN_BASE_INSN_SIZE, info);
504 if (status != 0)
505 {
506 (*info->memory_error_func) (status, pc, info);
507 return -1;
508 }
509
510 return print_insn (od, pc, info, buf, CGEN_BASE_INSN_SIZE);
511}
512
bfc10abe
DE
513/* Main entry point.
514 Print one instruction from PC on INFO->STREAM.
515 Return the size of the instruction (in bytes). */
516
517int
518print_insn_@arch@ (pc, info)
519 bfd_vma pc;
520 disassemble_info *info;
521{
1c8f439e
DE
522 int length;
523 static CGEN_OPCODE_DESC od = 0;
bfc10abe
DE
524 int mach = info->mach;
525 int big_p = info->endian == BFD_ENDIAN_BIG;
526
1c8f439e
DE
527 /* If we haven't initialized yet, initialize the opcode table. */
528 if (! od)
bfc10abe 529 {
1c8f439e
DE
530 od = @arch@_cgen_opcode_open (mach,
531 big_p ?
532 CGEN_ENDIAN_BIG
533 : CGEN_ENDIAN_LITTLE);
534 @arch@_cgen_init_dis (od);
bfc10abe 535 }
1c8f439e
DE
536 /* If we've switched cpu's, re-initialize. */
537 /* ??? Perhaps we should use BFD_ENDIAN. */
538 else if (mach != CGEN_OPCODE_MACH (od)
539 || (CGEN_OPCODE_ENDIAN (od)
540 != (big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE)))
bfc10abe 541 {
1c8f439e 542 cgen_set_cpu (od, mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
bfc10abe
DE
543 }
544
545 /* We try to have as much common code as possible.
546 But at this point some targets need to take over. */
547 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
548 but if not possible try to move this hook elsewhere rather than
549 have two hooks. */
1c8f439e
DE
550 length = CGEN_PRINT_INSN (od, pc, info);
551 if (length > 0)
bfc10abe 552 return length;
1c8f439e
DE
553 if (length < 0)
554 return -1;
bfc10abe
DE
555
556 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
557 return CGEN_DEFAULT_INSN_SIZE;
558}
This page took 0.077197 seconds and 4 git commands to generate.