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