source: vendor/binutils/current/opcodes/xstormy16-dis.c

Last change on this file was 608, checked in by (none), 22 years ago

This commit was manufactured by cvs2svn to create branch 'GNU'.

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 17.9 KB
Line 
1/* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
3
4THIS FILE IS MACHINE GENERATED WITH CGEN.
5- the resultant file is machine generated, cgen-dis.in isn't
6
7Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
8Free Software Foundation, Inc.
9
10This file is part of the GNU Binutils and GDB, the GNU debugger.
11
12This program is free software; you can redistribute it and/or modify
13it under the terms of the GNU General Public License as published by
14the Free Software Foundation; either version 2, or (at your option)
15any later version.
16
17This program is distributed in the hope that it will be useful,
18but WITHOUT ANY WARRANTY; without even the implied warranty of
19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License
23along with this program; if not, write to the Free Software Foundation, Inc.,
2459 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25
26/* ??? Eventually more and more of this stuff can go to cpu-independent files.
27 Keep that in mind. */
28
29#include "sysdep.h"
30#include <stdio.h>
31#include "ansidecl.h"
32#include "dis-asm.h"
33#include "bfd.h"
34#include "symcat.h"
35#include "libiberty.h"
36#include "xstormy16-desc.h"
37#include "xstormy16-opc.h"
38#include "opintl.h"
39
40/* Default text to print if an instruction isn't recognized. */
41#define UNKNOWN_INSN_MSG _("*unknown*")
42
43static void print_normal
44 PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned int, bfd_vma, int));
45static void print_address
46 PARAMS ((CGEN_CPU_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
47static void print_keyword
48 PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
49static void print_insn_normal
50 PARAMS ((CGEN_CPU_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
51 bfd_vma, int));
52static int print_insn
53 PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, unsigned));
54static int default_print_insn
55 PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
56static int read_insn
57 PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, int,
58 CGEN_EXTRACT_INFO *, unsigned long *));
59
60
61/* -- disassembler routines inserted here */
62
63
64void xstormy16_cgen_print_operand
65 PARAMS ((CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *,
66 void const *, bfd_vma, int));
67
68/* Main entry point for printing operands.
69 XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
70 of dis-asm.h on cgen.h.
71
72 This function is basically just a big switch statement. Earlier versions
73 used tables to look up the function to use, but
74 - if the table contains both assembler and disassembler functions then
75 the disassembler contains much of the assembler and vice-versa,
76 - there's a lot of inlining possibilities as things grow,
77 - using a switch statement avoids the function call overhead.
78
79 This function could be moved into `print_insn_normal', but keeping it
80 separate makes clear the interface between `print_insn_normal' and each of
81 the handlers. */
82
83void
84xstormy16_cgen_print_operand (cd, opindex, xinfo, fields, attrs, pc, length)
85 CGEN_CPU_DESC cd;
86 int opindex;
87 PTR xinfo;
88 CGEN_FIELDS *fields;
89 void const *attrs ATTRIBUTE_UNUSED;
90 bfd_vma pc;
91 int length;
92{
93 disassemble_info *info = (disassemble_info *) xinfo;
94
95 switch (opindex)
96 {
97 case XSTORMY16_OPERAND_RB :
98 print_keyword (cd, info, & xstormy16_cgen_opval_gr_Rb_names, fields->f_Rb, 0);
99 break;
100 case XSTORMY16_OPERAND_RBJ :
101 print_keyword (cd, info, & xstormy16_cgen_opval_gr_Rb_names, fields->f_Rbj, 0);
102 break;
103 case XSTORMY16_OPERAND_RD :
104 print_keyword (cd, info, & xstormy16_cgen_opval_gr_names, fields->f_Rd, 0);
105 break;
106 case XSTORMY16_OPERAND_RDM :
107 print_keyword (cd, info, & xstormy16_cgen_opval_gr_names, fields->f_Rdm, 0);
108 break;
109 case XSTORMY16_OPERAND_RM :
110 print_keyword (cd, info, & xstormy16_cgen_opval_gr_names, fields->f_Rm, 0);
111 break;
112 case XSTORMY16_OPERAND_RS :
113 print_keyword (cd, info, & xstormy16_cgen_opval_gr_names, fields->f_Rs, 0);
114 break;
115 case XSTORMY16_OPERAND_ABS24 :
116 print_normal (cd, info, fields->f_abs24, 0|(1<<CGEN_OPERAND_ABS_ADDR)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
117 break;
118 case XSTORMY16_OPERAND_BCOND2 :
119 print_keyword (cd, info, & xstormy16_cgen_opval_h_branchcond, fields->f_op2, 0);
120 break;
121 case XSTORMY16_OPERAND_BCOND5 :
122 print_keyword (cd, info, & xstormy16_cgen_opval_h_branchcond, fields->f_op5, 0);
123 break;
124 case XSTORMY16_OPERAND_HMEM8 :
125 print_normal (cd, info, fields->f_hmem8, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
126 break;
127 case XSTORMY16_OPERAND_IMM12 :
128 print_normal (cd, info, fields->f_imm12, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
129 break;
130 case XSTORMY16_OPERAND_IMM16 :
131 print_normal (cd, info, fields->f_imm16, 0|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
132 break;
133 case XSTORMY16_OPERAND_IMM2 :
134 print_normal (cd, info, fields->f_imm2, 0, pc, length);
135 break;
136 case XSTORMY16_OPERAND_IMM3 :
137 print_normal (cd, info, fields->f_imm3, 0, pc, length);
138 break;
139 case XSTORMY16_OPERAND_IMM3B :
140 print_normal (cd, info, fields->f_imm3b, 0, pc, length);
141 break;
142 case XSTORMY16_OPERAND_IMM4 :
143 print_normal (cd, info, fields->f_imm4, 0, pc, length);
144 break;
145 case XSTORMY16_OPERAND_IMM8 :
146 print_normal (cd, info, fields->f_imm8, 0, pc, length);
147 break;
148 case XSTORMY16_OPERAND_IMM8SMALL :
149 print_normal (cd, info, fields->f_imm8, 0, pc, length);
150 break;
151 case XSTORMY16_OPERAND_LMEM8 :
152 print_normal (cd, info, fields->f_lmem8, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
153 break;
154 case XSTORMY16_OPERAND_REL12 :
155 print_normal (cd, info, fields->f_rel12, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
156 break;
157 case XSTORMY16_OPERAND_REL12A :
158 print_normal (cd, info, fields->f_rel12a, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
159 break;
160 case XSTORMY16_OPERAND_REL8_2 :
161 print_normal (cd, info, fields->f_rel8_2, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
162 break;
163 case XSTORMY16_OPERAND_REL8_4 :
164 print_normal (cd, info, fields->f_rel8_4, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
165 break;
166 case XSTORMY16_OPERAND_WS2 :
167 print_keyword (cd, info, & xstormy16_cgen_opval_h_wordsize, fields->f_op2m, 0);
168 break;
169
170 default :
171 /* xgettext:c-format */
172 fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
173 opindex);
174 abort ();
175 }
176}
177
178cgen_print_fn * const xstormy16_cgen_print_handlers[] =
179{
180 print_insn_normal,
181};
182
183
184void
185xstormy16_cgen_init_dis (cd)
186 CGEN_CPU_DESC cd;
187{
188 xstormy16_cgen_init_opcode_table (cd);
189 xstormy16_cgen_init_ibld_table (cd);
190 cd->print_handlers = & xstormy16_cgen_print_handlers[0];
191 cd->print_operand = xstormy16_cgen_print_operand;
192}
193
194
195
196/* Default print handler. */
197
198static void
199print_normal (cd, dis_info, value, attrs, pc, length)
200 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
201 PTR dis_info;
202 long value;
203 unsigned int attrs;
204 bfd_vma pc ATTRIBUTE_UNUSED;
205 int length ATTRIBUTE_UNUSED;
206{
207 disassemble_info *info = (disassemble_info *) dis_info;
208
209#ifdef CGEN_PRINT_NORMAL
210 CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
211#endif
212
213 /* Print the operand as directed by the attributes. */
214 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
215 ; /* nothing to do */
216 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
217 (*info->fprintf_func) (info->stream, "%ld", value);
218 else
219 (*info->fprintf_func) (info->stream, "0x%lx", value);
220}
221
222/* Default address handler. */
223
224static void
225print_address (cd, dis_info, value, attrs, pc, length)
226 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
227 PTR dis_info;
228 bfd_vma value;
229 unsigned int attrs;
230 bfd_vma pc ATTRIBUTE_UNUSED;
231 int length ATTRIBUTE_UNUSED;
232{
233 disassemble_info *info = (disassemble_info *) dis_info;
234
235#ifdef CGEN_PRINT_ADDRESS
236 CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
237#endif
238
239 /* Print the operand as directed by the attributes. */
240 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
241 ; /* nothing to do */
242 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
243 (*info->print_address_func) (value, info);
244 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
245 (*info->print_address_func) (value, info);
246 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
247 (*info->fprintf_func) (info->stream, "%ld", (long) value);
248 else
249 (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
250}
251
252/* Keyword print handler. */
253
254static void
255print_keyword (cd, dis_info, keyword_table, value, attrs)
256 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
257 PTR dis_info;
258 CGEN_KEYWORD *keyword_table;
259 long value;
260 unsigned int attrs ATTRIBUTE_UNUSED;
261{
262 disassemble_info *info = (disassemble_info *) dis_info;
263 const CGEN_KEYWORD_ENTRY *ke;
264
265 ke = cgen_keyword_lookup_value (keyword_table, value);
266 if (ke != NULL)
267 (*info->fprintf_func) (info->stream, "%s", ke->name);
268 else
269 (*info->fprintf_func) (info->stream, "???");
270}
271
272
273/* Default insn printer.
274
275 DIS_INFO is defined as `PTR' so the disassembler needn't know anything
276 about disassemble_info. */
277
278static void
279print_insn_normal (cd, dis_info, insn, fields, pc, length)
280 CGEN_CPU_DESC cd;
281 PTR dis_info;
282 const CGEN_INSN *insn;
283 CGEN_FIELDS *fields;
284 bfd_vma pc;
285 int length;
286{
287 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
288 disassemble_info *info = (disassemble_info *) dis_info;
289 const CGEN_SYNTAX_CHAR_TYPE *syn;
290
291 CGEN_INIT_PRINT (cd);
292
293 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
294 {
295 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
296 {
297 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
298 continue;
299 }
300 if (CGEN_SYNTAX_CHAR_P (*syn))
301 {
302 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
303 continue;
304 }
305
306 /* We have an operand. */
307 xstormy16_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
308 fields, CGEN_INSN_ATTRS (insn), pc, length);
309 }
310}
311
312
313/* Subroutine of print_insn. Reads an insn into the given buffers and updates
314 the extract info.
315 Returns 0 if all is well, non-zero otherwise. */
316
317static int
318read_insn (cd, pc, info, buf, buflen, ex_info, insn_value)
319 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
320 bfd_vma pc;
321 disassemble_info *info;
322 char *buf;
323 int buflen;
324 CGEN_EXTRACT_INFO *ex_info;
325 unsigned long *insn_value;
326{
327 int status = (*info->read_memory_func) (pc, buf, buflen, info);
328 if (status != 0)
329 {
330 (*info->memory_error_func) (status, pc, info);
331 return -1;
332 }
333
334 ex_info->dis_info = info;
335 ex_info->valid = (1 << buflen) - 1;
336 ex_info->insn_bytes = buf;
337
338 *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
339 return 0;
340}
341
342/* Utility to print an insn.
343 BUF is the base part of the insn, target byte order, BUFLEN bytes long.
344 The result is the size of the insn in bytes or zero for an unknown insn
345 or -1 if an error occurs fetching data (memory_error_func will have
346 been called). */
347
348static int
349print_insn (cd, pc, info, buf, buflen)
350 CGEN_CPU_DESC cd;
351 bfd_vma pc;
352 disassemble_info *info;
353 char *buf;
354 unsigned int buflen;
355{
356 CGEN_INSN_INT insn_value;
357 const CGEN_INSN_LIST *insn_list;
358 CGEN_EXTRACT_INFO ex_info;
359 int basesize;
360
361 /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
362 basesize = cd->base_insn_bitsize < buflen * 8 ?
363 cd->base_insn_bitsize : buflen * 8;
364 insn_value = cgen_get_insn_value (cd, buf, basesize);
365
366
367 /* Fill in ex_info fields like read_insn would. Don't actually call
368 read_insn, since the incoming buffer is already read (and possibly
369 modified a la m32r). */
370 ex_info.valid = (1 << buflen) - 1;
371 ex_info.dis_info = info;
372 ex_info.insn_bytes = buf;
373
374 /* The instructions are stored in hash lists.
375 Pick the first one and keep trying until we find the right one. */
376
377 insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value);
378 while (insn_list != NULL)
379 {
380 const CGEN_INSN *insn = insn_list->insn;
381 CGEN_FIELDS fields;
382 int length;
383 unsigned long insn_value_cropped;
384
385#ifdef CGEN_VALIDATE_INSN_SUPPORTED
386 /* Not needed as insn shouldn't be in hash lists if not supported. */
387 /* Supported by this cpu? */
388 if (! xstormy16_cgen_insn_supported (cd, insn))
389 {
390 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
391 continue;
392 }
393#endif
394
395 /* Basic bit mask must be correct. */
396 /* ??? May wish to allow target to defer this check until the extract
397 handler. */
398
399 /* Base size may exceed this instruction's size. Extract the
400 relevant part from the buffer. */
401 if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
402 (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
403 insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
404 info->endian == BFD_ENDIAN_BIG);
405 else
406 insn_value_cropped = insn_value;
407
408 if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
409 == CGEN_INSN_BASE_VALUE (insn))
410 {
411 /* Printing is handled in two passes. The first pass parses the
412 machine insn and extracts the fields. The second pass prints
413 them. */
414
415 /* Make sure the entire insn is loaded into insn_value, if it
416 can fit. */
417 if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
418 (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
419 {
420 unsigned long full_insn_value;
421 int rc = read_insn (cd, pc, info, buf,
422 CGEN_INSN_BITSIZE (insn) / 8,
423 & ex_info, & full_insn_value);
424 if (rc != 0)
425 return rc;
426 length = CGEN_EXTRACT_FN (cd, insn)
427 (cd, insn, &ex_info, full_insn_value, &fields, pc);
428 }
429 else
430 length = CGEN_EXTRACT_FN (cd, insn)
431 (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
432
433 /* length < 0 -> error */
434 if (length < 0)
435 return length;
436 if (length > 0)
437 {
438 CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
439 /* length is in bits, result is in bytes */
440 return length / 8;
441 }
442 }
443
444 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
445 }
446
447 return 0;
448}
449
450/* Default value for CGEN_PRINT_INSN.
451 The result is the size of the insn in bytes or zero for an unknown insn
452 or -1 if an error occured fetching bytes. */
453
454#ifndef CGEN_PRINT_INSN
455#define CGEN_PRINT_INSN default_print_insn
456#endif
457
458static int
459default_print_insn (cd, pc, info)
460 CGEN_CPU_DESC cd;
461 bfd_vma pc;
462 disassemble_info *info;
463{
464 char buf[CGEN_MAX_INSN_SIZE];
465 int buflen;
466 int status;
467
468 /* Attempt to read the base part of the insn. */
469 buflen = cd->base_insn_bitsize / 8;
470 status = (*info->read_memory_func) (pc, buf, buflen, info);
471
472 /* Try again with the minimum part, if min < base. */
473 if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
474 {
475 buflen = cd->min_insn_bitsize / 8;
476 status = (*info->read_memory_func) (pc, buf, buflen, info);
477 }
478
479 if (status != 0)
480 {
481 (*info->memory_error_func) (status, pc, info);
482 return -1;
483 }
484
485 return print_insn (cd, pc, info, buf, buflen);
486}
487
488/* Main entry point.
489 Print one instruction from PC on INFO->STREAM.
490 Return the size of the instruction (in bytes). */
491
492typedef struct cpu_desc_list {
493 struct cpu_desc_list *next;
494 int isa;
495 int mach;
496 int endian;
497 CGEN_CPU_DESC cd;
498} cpu_desc_list;
499
500int
501print_insn_xstormy16 (pc, info)
502 bfd_vma pc;
503 disassemble_info *info;
504{
505 static cpu_desc_list *cd_list = 0;
506 cpu_desc_list *cl = 0;
507 static CGEN_CPU_DESC cd = 0;
508 static int prev_isa;
509 static int prev_mach;
510 static int prev_endian;
511 int length;
512 int isa,mach;
513 int endian = (info->endian == BFD_ENDIAN_BIG
514 ? CGEN_ENDIAN_BIG
515 : CGEN_ENDIAN_LITTLE);
516 enum bfd_architecture arch;
517
518 /* ??? gdb will set mach but leave the architecture as "unknown" */
519#ifndef CGEN_BFD_ARCH
520#define CGEN_BFD_ARCH bfd_arch_xstormy16
521#endif
522 arch = info->arch;
523 if (arch == bfd_arch_unknown)
524 arch = CGEN_BFD_ARCH;
525
526 /* There's no standard way to compute the machine or isa number
527 so we leave it to the target. */
528#ifdef CGEN_COMPUTE_MACH
529 mach = CGEN_COMPUTE_MACH (info);
530#else
531 mach = info->mach;
532#endif
533
534#ifdef CGEN_COMPUTE_ISA
535 isa = CGEN_COMPUTE_ISA (info);
536#else
537 isa = info->insn_sets;
538#endif
539
540 /* If we've switched cpu's, try to find a handle we've used before */
541 if (cd
542 && (isa != prev_isa
543 || mach != prev_mach
544 || endian != prev_endian))
545 {
546 cd = 0;
547 for (cl = cd_list; cl; cl = cl->next)
548 {
549 if (cl->isa == isa &&
550 cl->mach == mach &&
551 cl->endian == endian)
552 {
553 cd = cl->cd;
554 break;
555 }
556 }
557 }
558
559 /* If we haven't initialized yet, initialize the opcode table. */
560 if (! cd)
561 {
562 const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
563 const char *mach_name;
564
565 if (!arch_type)
566 abort ();
567 mach_name = arch_type->printable_name;
568
569 prev_isa = isa;
570 prev_mach = mach;
571 prev_endian = endian;
572 cd = xstormy16_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
573 CGEN_CPU_OPEN_BFDMACH, mach_name,
574 CGEN_CPU_OPEN_ENDIAN, prev_endian,
575 CGEN_CPU_OPEN_END);
576 if (!cd)
577 abort ();
578
579 /* save this away for future reference */
580 cl = xmalloc (sizeof (struct cpu_desc_list));
581 cl->cd = cd;
582 cl->isa = isa;
583 cl->mach = mach;
584 cl->endian = endian;
585 cl->next = cd_list;
586 cd_list = cl;
587
588 xstormy16_cgen_init_dis (cd);
589 }
590
591 /* We try to have as much common code as possible.
592 But at this point some targets need to take over. */
593 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
594 but if not possible try to move this hook elsewhere rather than
595 have two hooks. */
596 length = CGEN_PRINT_INSN (cd, pc, info);
597 if (length > 0)
598 return length;
599 if (length < 0)
600 return -1;
601
602 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
603 return cd->default_insn_bitsize / 8;
604}
Note: See TracBrowser for help on using the repository browser.