cgen-dis.in revision 218822
1204431Sraj/* Disassembler interface for targets using CGEN. -*- C -*-
2204431Sraj   CGEN: Cpu tools GENerator
3204431Sraj
4204431Sraj   THIS FILE IS MACHINE GENERATED WITH CGEN.
5204431Sraj   - the resultant file is machine generated, cgen-dis.in isn't
6204431Sraj
7204431Sraj   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005
8204431Sraj   Free Software Foundation, Inc.
9204431Sraj
10204431Sraj   This file is part of the GNU Binutils and GDB, the GNU debugger.
11204431Sraj
12204431Sraj   This program is free software; you can redistribute it and/or modify
13204431Sraj   it under the terms of the GNU General Public License as published by
14204431Sraj   the Free Software Foundation; either version 2, or (at your option)
15204431Sraj   any later version.
16204431Sraj
17204431Sraj   This program is distributed in the hope that it will be useful,
18204431Sraj   but WITHOUT ANY WARRANTY; without even the implied warranty of
19204431Sraj   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20204431Sraj   GNU General Public License for more details.
21204431Sraj
22204431Sraj   You should have received a copy of the GNU General Public License
23204431Sraj   along with this program; if not, write to the Free Software Foundation, Inc.,
24204431Sraj   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
25204431Sraj
26204431Sraj/* ??? Eventually more and more of this stuff can go to cpu-independent files.
27238742Simp   Keep that in mind.  */
28204431Sraj
29238742Simp#include "sysdep.h"
30238742Simp#include <stdio.h>
31238742Simp#include "ansidecl.h"
32266130Sian#include "dis-asm.h"
33266130Sian#include "bfd.h"
34266130Sian#include "symcat.h"
35238742Simp#include "libiberty.h"
36266130Sian#include "@prefix@-desc.h"
37238742Simp#include "@prefix@-opc.h"
38238742Simp#include "opintl.h"
39266130Sian
40238742Simp/* Default text to print if an instruction isn't recognized.  */
41238742Simp#define UNKNOWN_INSN_MSG _("*unknown*")
42238742Simp
43238742Simpstatic void print_normal
44238742Simp  (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
45266130Sianstatic void print_address
46266130Sian  (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
47266130Sianstatic void print_keyword
48266130Sian  (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
49266130Sianstatic void print_insn_normal
50266130Sian  (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
51266130Sianstatic int print_insn
52266130Sian  (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
53238742Simpstatic int default_print_insn
54238742Simp  (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
55204431Srajstatic int read_insn
56204431Sraj  (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
57238742Simp   unsigned long *);
58238742Simp
59204431Sraj/* -- disassembler routines inserted here.  */
60204431Sraj
61204431Sraj/* Default print handler.  */
62204431Sraj
63204431Srajstatic void
64204431Srajprint_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
65266130Sian	      void *dis_info,
66266130Sian	      long value,
67266130Sian	      unsigned int attrs,
68266130Sian	      bfd_vma pc ATTRIBUTE_UNUSED,
69266130Sian	      int length ATTRIBUTE_UNUSED)
70266130Sian{
71266130Sian  disassemble_info *info = (disassemble_info *) dis_info;
72266130Sian
73266130Sian#ifdef CGEN_PRINT_NORMAL
74266130Sian  CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
75266130Sian#endif
76266130Sian
77204431Sraj  /* Print the operand as directed by the attributes.  */
78204431Sraj  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
79204431Sraj    ; /* nothing to do */
80204431Sraj  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
81204431Sraj    (*info->fprintf_func) (info->stream, "%ld", value);
82204431Sraj  else
83204431Sraj    (*info->fprintf_func) (info->stream, "0x%lx", value);
84204431Sraj}
85204431Sraj
86204431Sraj/* Default address handler.  */
87204431Sraj
88204431Srajstatic void
89204431Srajprint_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
90204431Sraj	       void *dis_info,
91204431Sraj	       bfd_vma value,
92204431Sraj	       unsigned int attrs,
93204431Sraj	       bfd_vma pc ATTRIBUTE_UNUSED,
94204431Sraj	       int length ATTRIBUTE_UNUSED)
95204431Sraj{
96204431Sraj  disassemble_info *info = (disassemble_info *) dis_info;
97204431Sraj
98204431Sraj#ifdef CGEN_PRINT_ADDRESS
99204431Sraj  CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
100204431Sraj#endif
101204431Sraj
102204431Sraj  /* Print the operand as directed by the attributes.  */
103204431Sraj  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
104204431Sraj    ; /* Nothing to do.  */
105204431Sraj  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
106204431Sraj    (*info->print_address_func) (value, info);
107204431Sraj  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
108204431Sraj    (*info->print_address_func) (value, info);
109204431Sraj  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
110204431Sraj    (*info->fprintf_func) (info->stream, "%ld", (long) value);
111204431Sraj  else
112204431Sraj    (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
113204431Sraj}
114204431Sraj
115204431Sraj/* Keyword print handler.  */
116204431Sraj
117266130Sianstatic void
118266130Sianprint_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
119266130Sian	       void *dis_info,
120266130Sian	       CGEN_KEYWORD *keyword_table,
121266130Sian	       long value,
122266130Sian	       unsigned int attrs ATTRIBUTE_UNUSED)
123266130Sian{
124266130Sian  disassemble_info *info = (disassemble_info *) dis_info;
125266130Sian  const CGEN_KEYWORD_ENTRY *ke;
126266130Sian
127266130Sian  ke = cgen_keyword_lookup_value (keyword_table, value);
128238742Simp  if (ke != NULL)
129204431Sraj    (*info->fprintf_func) (info->stream, "%s", ke->name);
130204431Sraj  else
131204431Sraj    (*info->fprintf_func) (info->stream, "???");
132204431Sraj}
133204431Sraj
134204431Sraj/* Default insn printer.
135204431Sraj
136204431Sraj   DIS_INFO is defined as `void *' so the disassembler needn't know anything
137238742Simp   about disassemble_info.  */
138238742Simp
139238742Simpstatic void
140238742Simpprint_insn_normal (CGEN_CPU_DESC cd,
141238742Simp		   void *dis_info,
142238742Simp		   const CGEN_INSN *insn,
143266130Sian		   CGEN_FIELDS *fields,
144266130Sian		   bfd_vma pc,
145238742Simp		   int length)
146266130Sian{
147238742Simp  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
148238742Simp  disassemble_info *info = (disassemble_info *) dis_info;
149238742Simp  const CGEN_SYNTAX_CHAR_TYPE *syn;
150238742Simp
151238742Simp  CGEN_INIT_PRINT (cd);
152238742Simp
153238742Simp  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
154238742Simp    {
155238742Simp      if (CGEN_SYNTAX_MNEMONIC_P (*syn))
156238742Simp	{
157266130Sian	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
158266130Sian	  continue;
159266130Sian	}
160266130Sian      if (CGEN_SYNTAX_CHAR_P (*syn))
161266130Sian	{
162266130Sian	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
163238742Simp	  continue;
164266130Sian	}
165238742Simp
166238742Simp      /* We have an operand.  */
167266130Sian      @arch@_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
168238742Simp				 fields, CGEN_INSN_ATTRS (insn), pc, length);
169238742Simp    }
170238742Simp}
171266130Sian
172238742Simp/* Subroutine of print_insn. Reads an insn into the given buffers and updates
173238742Simp   the extract info.
174238742Simp   Returns 0 if all is well, non-zero otherwise.  */
175238742Simp
176238742Simpstatic int
177238742Simpread_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
178238742Simp	   bfd_vma pc,
179238742Simp	   disassemble_info *info,
180238742Simp	   bfd_byte *buf,
181238742Simp	   int buflen,
182238742Simp	   CGEN_EXTRACT_INFO *ex_info,
183238742Simp	   unsigned long *insn_value)
184238742Simp{
185238742Simp  int status = (*info->read_memory_func) (pc, buf, buflen, info);
186238742Simp
187238742Simp  if (status != 0)
188238742Simp    {
189238742Simp      (*info->memory_error_func) (status, pc, info);
190238742Simp      return -1;
191238742Simp    }
192266130Sian
193266130Sian  ex_info->dis_info = info;
194266130Sian  ex_info->valid = (1 << buflen) - 1;
195266130Sian  ex_info->insn_bytes = buf;
196266130Sian
197266130Sian  *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
198238742Simp  return 0;
199266130Sian}
200238742Simp
201238742Simp/* Utility to print an insn.
202238742Simp   BUF is the base part of the insn, target byte order, BUFLEN bytes long.
203238742Simp   The result is the size of the insn in bytes or zero for an unknown insn
204238742Simp   or -1 if an error occurs fetching data (memory_error_func will have
205238742Simp   been called).  */
206238742Simp
207238742Simpstatic int
208238742Simpprint_insn (CGEN_CPU_DESC cd,
209238742Simp	    bfd_vma pc,
210238742Simp	    disassemble_info *info,
211238742Simp	    bfd_byte *buf,
212238742Simp	    unsigned int buflen)
213238742Simp{
214238742Simp  CGEN_INSN_INT insn_value;
215238742Simp  const CGEN_INSN_LIST *insn_list;
216238742Simp  CGEN_EXTRACT_INFO ex_info;
217238742Simp  int basesize;
218238742Simp
219204431Sraj  /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
220204431Sraj  basesize = cd->base_insn_bitsize < buflen * 8 ?
221204431Sraj                                     cd->base_insn_bitsize : buflen * 8;
222204431Sraj  insn_value = cgen_get_insn_value (cd, buf, basesize);
223204431Sraj
224204431Sraj
225204431Sraj  /* Fill in ex_info fields like read_insn would.  Don't actually call
226204431Sraj     read_insn, since the incoming buffer is already read (and possibly
227204431Sraj     modified a la m32r).  */
228204431Sraj  ex_info.valid = (1 << buflen) - 1;
229204431Sraj  ex_info.dis_info = info;
230204431Sraj  ex_info.insn_bytes = buf;
231204431Sraj
232204431Sraj  /* The instructions are stored in hash lists.
233204431Sraj     Pick the first one and keep trying until we find the right one.  */
234204431Sraj
235204431Sraj  insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
236204431Sraj  while (insn_list != NULL)
237204431Sraj    {
238204431Sraj      const CGEN_INSN *insn = insn_list->insn;
239204431Sraj      CGEN_FIELDS fields;
240266130Sian      int length;
241266130Sian      unsigned long insn_value_cropped;
242266130Sian
243266130Sian#ifdef CGEN_VALIDATE_INSN_SUPPORTED 
244266130Sian      /* Not needed as insn shouldn't be in hash lists if not supported.  */
245266130Sian      /* Supported by this cpu?  */
246266130Sian      if (! @arch@_cgen_insn_supported (cd, insn))
247266130Sian        {
248266130Sian          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
249266130Sian	  continue;
250266130Sian        }
251266130Sian#endif
252266130Sian
253266130Sian      /* Basic bit mask must be correct.  */
254266130Sian      /* ??? May wish to allow target to defer this check until the extract
255266130Sian	 handler.  */
256266130Sian
257266130Sian      /* Base size may exceed this instruction's size.  Extract the
258266130Sian         relevant part from the buffer. */
259204431Sraj      if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
260204431Sraj	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
261204431Sraj	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 
262204431Sraj					   info->endian == BFD_ENDIAN_BIG);
263204431Sraj      else
264204431Sraj	insn_value_cropped = insn_value;
265204431Sraj
266204431Sraj      if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
267204431Sraj	  == CGEN_INSN_BASE_VALUE (insn))
268204431Sraj	{
269204431Sraj	  /* Printing is handled in two passes.  The first pass parses the
270204431Sraj	     machine insn and extracts the fields.  The second pass prints
271204431Sraj	     them.  */
272204431Sraj
273266130Sian	  /* Make sure the entire insn is loaded into insn_value, if it
274266130Sian	     can fit.  */
275266130Sian	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
276266130Sian	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
277266130Sian	    {
278266130Sian	      unsigned long full_insn_value;
279266130Sian	      int rc = read_insn (cd, pc, info, buf,
280266130Sian				  CGEN_INSN_BITSIZE (insn) / 8,
281266130Sian				  & ex_info, & full_insn_value);
282266130Sian	      if (rc != 0)
283266130Sian		return rc;
284266130Sian	      length = CGEN_EXTRACT_FN (cd, insn)
285266130Sian		(cd, insn, &ex_info, full_insn_value, &fields, pc);
286266130Sian	    }
287266130Sian	  else
288266130Sian	    length = CGEN_EXTRACT_FN (cd, insn)
289266130Sian	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
290266130Sian
291266130Sian	  /* Length < 0 -> error.  */
292266130Sian	  if (length < 0)
293266130Sian	    return length;
294266130Sian	  if (length > 0)
295266130Sian	    {
296266130Sian	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
297266130Sian	      /* Length is in bits, result is in bytes.  */
298266130Sian	      return length / 8;
299238742Simp	    }
300204431Sraj	}
301204431Sraj
302204431Sraj      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
303238742Simp    }
304238742Simp
305204431Sraj  return 0;
306204431Sraj}
307204431Sraj
308204431Sraj/* Default value for CGEN_PRINT_INSN.
309204431Sraj   The result is the size of the insn in bytes or zero for an unknown insn
310204431Sraj   or -1 if an error occured fetching bytes.  */
311204431Sraj
312204431Sraj#ifndef CGEN_PRINT_INSN
313204431Sraj#define CGEN_PRINT_INSN default_print_insn
314204431Sraj#endif
315204431Sraj
316204431Srajstatic int
317204431Srajdefault_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
318204431Sraj{
319204431Sraj  bfd_byte buf[CGEN_MAX_INSN_SIZE];
320204431Sraj  int buflen;
321204431Sraj  int status;
322204431Sraj
323204431Sraj  /* Attempt to read the base part of the insn.  */
324204431Sraj  buflen = cd->base_insn_bitsize / 8;
325204431Sraj  status = (*info->read_memory_func) (pc, buf, buflen, info);
326204431Sraj
327204431Sraj  /* Try again with the minimum part, if min < base.  */
328204431Sraj  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
329204431Sraj    {
330204431Sraj      buflen = cd->min_insn_bitsize / 8;
331204431Sraj      status = (*info->read_memory_func) (pc, buf, buflen, info);
332204431Sraj    }
333204431Sraj
334204431Sraj  if (status != 0)
335204431Sraj    {
336204431Sraj      (*info->memory_error_func) (status, pc, info);
337204431Sraj      return -1;
338204431Sraj    }
339204431Sraj
340204431Sraj  return print_insn (cd, pc, info, buf, buflen);
341204431Sraj}
342204431Sraj
343204431Sraj/* Main entry point.
344204431Sraj   Print one instruction from PC on INFO->STREAM.
345204431Sraj   Return the size of the instruction (in bytes).  */
346204431Sraj
347204431Srajtypedef struct cpu_desc_list
348204431Sraj{
349204431Sraj  struct cpu_desc_list *next;
350204431Sraj  CGEN_BITSET *isa;
351204431Sraj  int mach;
352204431Sraj  int endian;
353204431Sraj  CGEN_CPU_DESC cd;
354204431Sraj} cpu_desc_list;
355204431Sraj
356204431Srajint
357204431Srajprint_insn_@arch@ (bfd_vma pc, disassemble_info *info)
358204431Sraj{
359204431Sraj  static cpu_desc_list *cd_list = 0;
360204431Sraj  cpu_desc_list *cl = 0;
361204431Sraj  static CGEN_CPU_DESC cd = 0;
362204431Sraj  static CGEN_BITSET *prev_isa;
363204431Sraj  static int prev_mach;
364204431Sraj  static int prev_endian;
365204431Sraj  int length;
366204431Sraj  CGEN_BITSET *isa;
367204431Sraj  int mach;
368204431Sraj  int endian = (info->endian == BFD_ENDIAN_BIG
369204431Sraj		? CGEN_ENDIAN_BIG
370204431Sraj		: CGEN_ENDIAN_LITTLE);
371204431Sraj  enum bfd_architecture arch;
372204431Sraj
373204431Sraj  /* ??? gdb will set mach but leave the architecture as "unknown" */
374204431Sraj#ifndef CGEN_BFD_ARCH
375204431Sraj#define CGEN_BFD_ARCH bfd_arch_@arch@
376204431Sraj#endif
377204431Sraj  arch = info->arch;
378204431Sraj  if (arch == bfd_arch_unknown)
379204431Sraj    arch = CGEN_BFD_ARCH;
380238742Simp   
381238742Simp  /* There's no standard way to compute the machine or isa number
382238742Simp     so we leave it to the target.  */
383238742Simp#ifdef CGEN_COMPUTE_MACH
384238742Simp  mach = CGEN_COMPUTE_MACH (info);
385238742Simp#else
386238742Simp  mach = info->mach;
387238742Simp#endif
388238742Simp
389238742Simp#ifdef CGEN_COMPUTE_ISA
390238742Simp  {
391238742Simp    static CGEN_BITSET *permanent_isa;
392238742Simp
393238742Simp    if (!permanent_isa)
394238742Simp      permanent_isa = cgen_bitset_create (MAX_ISAS);
395238742Simp    isa = permanent_isa;
396238742Simp    cgen_bitset_clear (isa);
397238742Simp    cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
398238742Simp  }
399238742Simp#else
400238742Simp  isa = info->insn_sets;
401238742Simp#endif
402238742Simp
403238742Simp  /* If we've switched cpu's, try to find a handle we've used before */
404238742Simp  if (cd
405238742Simp      && (cgen_bitset_compare (isa, prev_isa) != 0
406238742Simp	  || mach != prev_mach
407238742Simp	  || endian != prev_endian))
408238742Simp    {
409238742Simp      cd = 0;
410238742Simp      for (cl = cd_list; cl; cl = cl->next)
411238742Simp	{
412238742Simp	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
413238742Simp	      cl->mach == mach &&
414238742Simp	      cl->endian == endian)
415238742Simp	    {
416238742Simp	      cd = cl->cd;
417238742Simp 	      prev_isa = cd->isas;
418238742Simp	      break;
419238742Simp	    }
420238742Simp	}
421238742Simp    } 
422238742Simp
423238742Simp  /* If we haven't initialized yet, initialize the opcode table.  */
424238742Simp  if (! cd)
425238742Simp    {
426238742Simp      const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
427238742Simp      const char *mach_name;
428238742Simp
429238742Simp      if (!arch_type)
430238742Simp	abort ();
431238742Simp      mach_name = arch_type->printable_name;
432238742Simp
433238742Simp      prev_isa = cgen_bitset_copy (isa);
434204431Sraj      prev_mach = mach;
435204431Sraj      prev_endian = endian;
436204431Sraj      cd = @arch@_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
437204431Sraj				 CGEN_CPU_OPEN_BFDMACH, mach_name,
438204431Sraj				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
439204431Sraj				 CGEN_CPU_OPEN_END);
440204431Sraj      if (!cd)
441204431Sraj	abort ();
442204431Sraj
443204431Sraj      /* Save this away for future reference.  */
444204431Sraj      cl = xmalloc (sizeof (struct cpu_desc_list));
445204431Sraj      cl->cd = cd;
446204431Sraj      cl->isa = prev_isa;
447204431Sraj      cl->mach = mach;
448204431Sraj      cl->endian = endian;
449204431Sraj      cl->next = cd_list;
450266130Sian      cd_list = cl;
451266130Sian
452266130Sian      @arch@_cgen_init_dis (cd);
453204431Sraj    }
454266130Sian
455204431Sraj  /* We try to have as much common code as possible.
456204431Sraj     But at this point some targets need to take over.  */
457204431Sraj  /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
458204431Sraj     but if not possible try to move this hook elsewhere rather than
459204431Sraj     have two hooks.  */
460204431Sraj  length = CGEN_PRINT_INSN (cd, pc, info);
461204431Sraj  if (length > 0)
462204431Sraj    return length;
463204431Sraj  if (length < 0)
464204431Sraj    return -1;
465204431Sraj
466204431Sraj  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
467204431Sraj  return cd->default_insn_bitsize / 8;
468204431Sraj}
469204431Sraj