1/* Disassembler interface for targets using CGEN. -*- C -*-
2   CGEN: Cpu tools GENerator
3
4   THIS FILE IS MACHINE GENERATED WITH CGEN.
5   - the resultant file is machine generated, cgen-dis.in isn't
6
7   Copyright (C) 1996-2017 Free Software Foundation, Inc.
8
9   This file is part of libopcodes.
10
11   This library is free software; you can redistribute it and/or modify
12   it under the terms of the GNU General Public License as published by
13   the Free Software Foundation; either version 3, or (at your option)
14   any later version.
15
16   It is distributed in the hope that it will be useful, but WITHOUT
17   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
19   License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with this program; if not, write to the Free Software Foundation, Inc.,
23   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
24
25/* ??? Eventually more and more of this stuff can go to cpu-independent files.
26   Keep that in mind.  */
27
28#include "sysdep.h"
29#include <stdio.h>
30#include "ansidecl.h"
31#include "dis-asm.h"
32#include "bfd.h"
33#include "symcat.h"
34#include "libiberty.h"
35#include "epiphany-desc.h"
36#include "epiphany-opc.h"
37#include "opintl.h"
38
39/* Default text to print if an instruction isn't recognized.  */
40#define UNKNOWN_INSN_MSG _("*unknown*")
41
42static void print_normal
43  (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
44static void print_address
45  (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
46static void print_keyword
47  (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
48static void print_insn_normal
49  (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
50static int print_insn
51  (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
52static int default_print_insn
53  (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
54static int read_insn
55  (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
56   unsigned long *);
57
58/* -- disassembler routines inserted here.  */
59
60/* -- dis.c */
61
62#define CGEN_PRINT_INSN epiphany_print_insn
63
64static int
65epiphany_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
66{
67  bfd_byte buf[CGEN_MAX_INSN_SIZE];
68  int buflen;
69  int status;
70
71  info->bytes_per_chunk = 2;
72  info->bytes_per_line = 4;
73
74  /* Attempt to read the base part of the insn.  */
75  buflen = cd->base_insn_bitsize / 8;
76  status = (*info->read_memory_func) (pc, buf, buflen, info);
77
78  /* Try again with the minimum part, if min < base.  */
79  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
80    {
81      buflen = cd->min_insn_bitsize / 8;
82      status = (*info->read_memory_func) (pc, buf, buflen, info);
83    }
84
85  if (status != 0)
86    {
87      (*info->memory_error_func) (status, pc, info);
88      return -1;
89    }
90
91  return print_insn (cd, pc, info, buf, buflen);
92}
93
94
95static void
96print_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
97		 void * dis_info,
98		 long value,
99		 unsigned int attrs ATTRIBUTE_UNUSED,
100		 bfd_vma pc ATTRIBUTE_UNUSED,
101		 int length ATTRIBUTE_UNUSED)
102{
103  disassemble_info *info = (disassemble_info *) dis_info;
104  (*info->fprintf_func) (info->stream, value ? "-" : "+");
105}
106
107static void
108print_simm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
109		    void * dis_info,
110		    long value,
111		    unsigned int attrs ATTRIBUTE_UNUSED,
112		    bfd_vma pc ATTRIBUTE_UNUSED,
113		    int length ATTRIBUTE_UNUSED)
114{
115  print_address (cd, dis_info, value, attrs, pc, length);
116}
117
118static void
119print_uimm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
120		    void * dis_info,
121		    unsigned long value,
122		    unsigned int attrs ATTRIBUTE_UNUSED,
123		    bfd_vma pc ATTRIBUTE_UNUSED,
124		    int length ATTRIBUTE_UNUSED)
125{
126  disassemble_info *info = (disassemble_info *)dis_info;
127
128  if (value & 0x800)
129    (*info->fprintf_func) (info->stream, "-");
130
131  value &= 0x7ff;
132  print_address (cd, dis_info, value, attrs, pc, length);
133}
134
135
136/* -- */
137
138void epiphany_cgen_print_operand
139  (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
140
141/* Main entry point for printing operands.
142   XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
143   of dis-asm.h on cgen.h.
144
145   This function is basically just a big switch statement.  Earlier versions
146   used tables to look up the function to use, but
147   - if the table contains both assembler and disassembler functions then
148     the disassembler contains much of the assembler and vice-versa,
149   - there's a lot of inlining possibilities as things grow,
150   - using a switch statement avoids the function call overhead.
151
152   This function could be moved into `print_insn_normal', but keeping it
153   separate makes clear the interface between `print_insn_normal' and each of
154   the handlers.  */
155
156void
157epiphany_cgen_print_operand (CGEN_CPU_DESC cd,
158			   int opindex,
159			   void * xinfo,
160			   CGEN_FIELDS *fields,
161			   void const *attrs ATTRIBUTE_UNUSED,
162			   bfd_vma pc,
163			   int length)
164{
165  disassemble_info *info = (disassemble_info *) xinfo;
166
167  switch (opindex)
168    {
169    case EPIPHANY_OPERAND_DIRECTION :
170      print_postindex (cd, info, fields->f_addsubx, 0, pc, length);
171      break;
172    case EPIPHANY_OPERAND_DISP11 :
173      print_uimm_not_reg (cd, info, fields->f_disp11, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
174      break;
175    case EPIPHANY_OPERAND_DISP3 :
176      print_normal (cd, info, fields->f_disp3, 0, pc, length);
177      break;
178    case EPIPHANY_OPERAND_DPMI :
179      print_postindex (cd, info, fields->f_subd, 0, pc, length);
180      break;
181    case EPIPHANY_OPERAND_FRD :
182      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd, 0);
183      break;
184    case EPIPHANY_OPERAND_FRD6 :
185      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
186      break;
187    case EPIPHANY_OPERAND_FRM :
188      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm, 0);
189      break;
190    case EPIPHANY_OPERAND_FRM6 :
191      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm6, 0|(1<<CGEN_OPERAND_VIRTUAL));
192      break;
193    case EPIPHANY_OPERAND_FRN :
194      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn, 0);
195      break;
196    case EPIPHANY_OPERAND_FRN6 :
197      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
198      break;
199    case EPIPHANY_OPERAND_IMM16 :
200      print_address (cd, info, fields->f_imm16, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
201      break;
202    case EPIPHANY_OPERAND_IMM8 :
203      print_address (cd, info, fields->f_imm8, 0|(1<<CGEN_OPERAND_RELAX), pc, length);
204      break;
205    case EPIPHANY_OPERAND_RD :
206      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd, 0);
207      break;
208    case EPIPHANY_OPERAND_RD6 :
209      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
210      break;
211    case EPIPHANY_OPERAND_RM :
212      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm, 0);
213      break;
214    case EPIPHANY_OPERAND_RM6 :
215      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rm6, 0|(1<<CGEN_OPERAND_VIRTUAL));
216      break;
217    case EPIPHANY_OPERAND_RN :
218      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn, 0);
219      break;
220    case EPIPHANY_OPERAND_RN6 :
221      print_keyword (cd, info, & epiphany_cgen_opval_gr_names, fields->f_rn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
222      break;
223    case EPIPHANY_OPERAND_SD :
224      print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sd, 0);
225      break;
226    case EPIPHANY_OPERAND_SD6 :
227      print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
228      break;
229    case EPIPHANY_OPERAND_SDDMA :
230      print_keyword (cd, info, & epiphany_cgen_opval_crdma_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
231      break;
232    case EPIPHANY_OPERAND_SDMEM :
233      print_keyword (cd, info, & epiphany_cgen_opval_crmem_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
234      break;
235    case EPIPHANY_OPERAND_SDMESH :
236      print_keyword (cd, info, & epiphany_cgen_opval_crmesh_names, fields->f_sd6, 0|(1<<CGEN_OPERAND_VIRTUAL));
237      break;
238    case EPIPHANY_OPERAND_SHIFT :
239      print_normal (cd, info, fields->f_shift, 0, pc, length);
240      break;
241    case EPIPHANY_OPERAND_SIMM11 :
242      print_simm_not_reg (cd, info, fields->f_sdisp11, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
243      break;
244    case EPIPHANY_OPERAND_SIMM24 :
245      print_address (cd, info, fields->f_simm24, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
246      break;
247    case EPIPHANY_OPERAND_SIMM3 :
248      print_simm_not_reg (cd, info, fields->f_sdisp3, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELAX), pc, length);
249      break;
250    case EPIPHANY_OPERAND_SIMM8 :
251      print_address (cd, info, fields->f_simm8, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
252      break;
253    case EPIPHANY_OPERAND_SN :
254      print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sn, 0);
255      break;
256    case EPIPHANY_OPERAND_SN6 :
257      print_keyword (cd, info, & epiphany_cgen_opval_cr_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
258      break;
259    case EPIPHANY_OPERAND_SNDMA :
260      print_keyword (cd, info, & epiphany_cgen_opval_crdma_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
261      break;
262    case EPIPHANY_OPERAND_SNMEM :
263      print_keyword (cd, info, & epiphany_cgen_opval_crmem_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
264      break;
265    case EPIPHANY_OPERAND_SNMESH :
266      print_keyword (cd, info, & epiphany_cgen_opval_crmesh_names, fields->f_sn6, 0|(1<<CGEN_OPERAND_VIRTUAL));
267      break;
268    case EPIPHANY_OPERAND_SWI_NUM :
269      print_uimm_not_reg (cd, info, fields->f_trap_num, 0, pc, length);
270      break;
271    case EPIPHANY_OPERAND_TRAPNUM6 :
272      print_normal (cd, info, fields->f_trap_num, 0, pc, length);
273      break;
274
275    default :
276      /* xgettext:c-format */
277      fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
278	       opindex);
279    abort ();
280  }
281}
282
283cgen_print_fn * const epiphany_cgen_print_handlers[] =
284{
285  print_insn_normal,
286};
287
288
289void
290epiphany_cgen_init_dis (CGEN_CPU_DESC cd)
291{
292  epiphany_cgen_init_opcode_table (cd);
293  epiphany_cgen_init_ibld_table (cd);
294  cd->print_handlers = & epiphany_cgen_print_handlers[0];
295  cd->print_operand = epiphany_cgen_print_operand;
296}
297
298
299/* Default print handler.  */
300
301static void
302print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
303	      void *dis_info,
304	      long value,
305	      unsigned int attrs,
306	      bfd_vma pc ATTRIBUTE_UNUSED,
307	      int length ATTRIBUTE_UNUSED)
308{
309  disassemble_info *info = (disassemble_info *) dis_info;
310
311  /* Print the operand as directed by the attributes.  */
312  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
313    ; /* nothing to do */
314  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
315    (*info->fprintf_func) (info->stream, "%ld", value);
316  else
317    (*info->fprintf_func) (info->stream, "0x%lx", value);
318}
319
320/* Default address handler.  */
321
322static void
323print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
324	       void *dis_info,
325	       bfd_vma value,
326	       unsigned int attrs,
327	       bfd_vma pc ATTRIBUTE_UNUSED,
328	       int length ATTRIBUTE_UNUSED)
329{
330  disassemble_info *info = (disassemble_info *) dis_info;
331
332  /* Print the operand as directed by the attributes.  */
333  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
334    ; /* Nothing to do.  */
335  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
336    (*info->print_address_func) (value, info);
337  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
338    (*info->print_address_func) (value, info);
339  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
340    (*info->fprintf_func) (info->stream, "%ld", (long) value);
341  else
342    (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
343}
344
345/* Keyword print handler.  */
346
347static void
348print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
349	       void *dis_info,
350	       CGEN_KEYWORD *keyword_table,
351	       long value,
352	       unsigned int attrs ATTRIBUTE_UNUSED)
353{
354  disassemble_info *info = (disassemble_info *) dis_info;
355  const CGEN_KEYWORD_ENTRY *ke;
356
357  ke = cgen_keyword_lookup_value (keyword_table, value);
358  if (ke != NULL)
359    (*info->fprintf_func) (info->stream, "%s", ke->name);
360  else
361    (*info->fprintf_func) (info->stream, "???");
362}
363
364/* Default insn printer.
365
366   DIS_INFO is defined as `void *' so the disassembler needn't know anything
367   about disassemble_info.  */
368
369static void
370print_insn_normal (CGEN_CPU_DESC cd,
371		   void *dis_info,
372		   const CGEN_INSN *insn,
373		   CGEN_FIELDS *fields,
374		   bfd_vma pc,
375		   int length)
376{
377  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
378  disassemble_info *info = (disassemble_info *) dis_info;
379  const CGEN_SYNTAX_CHAR_TYPE *syn;
380
381  CGEN_INIT_PRINT (cd);
382
383  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
384    {
385      if (CGEN_SYNTAX_MNEMONIC_P (*syn))
386	{
387	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
388	  continue;
389	}
390      if (CGEN_SYNTAX_CHAR_P (*syn))
391	{
392	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
393	  continue;
394	}
395
396      /* We have an operand.  */
397      epiphany_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
398				 fields, CGEN_INSN_ATTRS (insn), pc, length);
399    }
400}
401
402/* Subroutine of print_insn. Reads an insn into the given buffers and updates
403   the extract info.
404   Returns 0 if all is well, non-zero otherwise.  */
405
406static int
407read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
408	   bfd_vma pc,
409	   disassemble_info *info,
410	   bfd_byte *buf,
411	   int buflen,
412	   CGEN_EXTRACT_INFO *ex_info,
413	   unsigned long *insn_value)
414{
415  int status = (*info->read_memory_func) (pc, buf, buflen, info);
416
417  if (status != 0)
418    {
419      (*info->memory_error_func) (status, pc, info);
420      return -1;
421    }
422
423  ex_info->dis_info = info;
424  ex_info->valid = (1 << buflen) - 1;
425  ex_info->insn_bytes = buf;
426
427  *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
428  return 0;
429}
430
431/* Utility to print an insn.
432   BUF is the base part of the insn, target byte order, BUFLEN bytes long.
433   The result is the size of the insn in bytes or zero for an unknown insn
434   or -1 if an error occurs fetching data (memory_error_func will have
435   been called).  */
436
437static int
438print_insn (CGEN_CPU_DESC cd,
439	    bfd_vma pc,
440	    disassemble_info *info,
441	    bfd_byte *buf,
442	    unsigned int buflen)
443{
444  CGEN_INSN_INT insn_value;
445  const CGEN_INSN_LIST *insn_list;
446  CGEN_EXTRACT_INFO ex_info;
447  int basesize;
448
449  /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
450  basesize = cd->base_insn_bitsize < buflen * 8 ?
451                                     cd->base_insn_bitsize : buflen * 8;
452  insn_value = cgen_get_insn_value (cd, buf, basesize);
453
454
455  /* Fill in ex_info fields like read_insn would.  Don't actually call
456     read_insn, since the incoming buffer is already read (and possibly
457     modified a la m32r).  */
458  ex_info.valid = (1 << buflen) - 1;
459  ex_info.dis_info = info;
460  ex_info.insn_bytes = buf;
461
462  /* The instructions are stored in hash lists.
463     Pick the first one and keep trying until we find the right one.  */
464
465  insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
466  while (insn_list != NULL)
467    {
468      const CGEN_INSN *insn = insn_list->insn;
469      CGEN_FIELDS fields;
470      int length;
471      unsigned long insn_value_cropped;
472
473#ifdef CGEN_VALIDATE_INSN_SUPPORTED
474      /* Not needed as insn shouldn't be in hash lists if not supported.  */
475      /* Supported by this cpu?  */
476      if (! epiphany_cgen_insn_supported (cd, insn))
477        {
478          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
479	  continue;
480        }
481#endif
482
483      /* Basic bit mask must be correct.  */
484      /* ??? May wish to allow target to defer this check until the extract
485	 handler.  */
486
487      /* Base size may exceed this instruction's size.  Extract the
488         relevant part from the buffer. */
489      if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
490	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
491	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
492					   info->endian == BFD_ENDIAN_BIG);
493      else
494	insn_value_cropped = insn_value;
495
496      if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
497	  == CGEN_INSN_BASE_VALUE (insn))
498	{
499	  /* Printing is handled in two passes.  The first pass parses the
500	     machine insn and extracts the fields.  The second pass prints
501	     them.  */
502
503	  /* Make sure the entire insn is loaded into insn_value, if it
504	     can fit.  */
505	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
506	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
507	    {
508	      unsigned long full_insn_value;
509	      int rc = read_insn (cd, pc, info, buf,
510				  CGEN_INSN_BITSIZE (insn) / 8,
511				  & ex_info, & full_insn_value);
512	      if (rc != 0)
513		return rc;
514	      length = CGEN_EXTRACT_FN (cd, insn)
515		(cd, insn, &ex_info, full_insn_value, &fields, pc);
516	    }
517	  else
518	    length = CGEN_EXTRACT_FN (cd, insn)
519	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
520
521	  /* Length < 0 -> error.  */
522	  if (length < 0)
523	    return length;
524	  if (length > 0)
525	    {
526	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
527	      /* Length is in bits, result is in bytes.  */
528	      return length / 8;
529	    }
530	}
531
532      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
533    }
534
535  return 0;
536}
537
538/* Default value for CGEN_PRINT_INSN.
539   The result is the size of the insn in bytes or zero for an unknown insn
540   or -1 if an error occured fetching bytes.  */
541
542#ifndef CGEN_PRINT_INSN
543#define CGEN_PRINT_INSN default_print_insn
544#endif
545
546static int
547default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
548{
549  bfd_byte buf[CGEN_MAX_INSN_SIZE];
550  int buflen;
551  int status;
552
553  /* Attempt to read the base part of the insn.  */
554  buflen = cd->base_insn_bitsize / 8;
555  status = (*info->read_memory_func) (pc, buf, buflen, info);
556
557  /* Try again with the minimum part, if min < base.  */
558  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
559    {
560      buflen = cd->min_insn_bitsize / 8;
561      status = (*info->read_memory_func) (pc, buf, buflen, info);
562    }
563
564  if (status != 0)
565    {
566      (*info->memory_error_func) (status, pc, info);
567      return -1;
568    }
569
570  return print_insn (cd, pc, info, buf, buflen);
571}
572
573/* Main entry point.
574   Print one instruction from PC on INFO->STREAM.
575   Return the size of the instruction (in bytes).  */
576
577typedef struct cpu_desc_list
578{
579  struct cpu_desc_list *next;
580  CGEN_BITSET *isa;
581  int mach;
582  int endian;
583  CGEN_CPU_DESC cd;
584} cpu_desc_list;
585
586int
587print_insn_epiphany (bfd_vma pc, disassemble_info *info)
588{
589  static cpu_desc_list *cd_list = 0;
590  cpu_desc_list *cl = 0;
591  static CGEN_CPU_DESC cd = 0;
592  static CGEN_BITSET *prev_isa;
593  static int prev_mach;
594  static int prev_endian;
595  int length;
596  CGEN_BITSET *isa;
597  int mach;
598  int endian = (info->endian == BFD_ENDIAN_BIG
599		? CGEN_ENDIAN_BIG
600		: CGEN_ENDIAN_LITTLE);
601  enum bfd_architecture arch;
602
603  /* ??? gdb will set mach but leave the architecture as "unknown" */
604#ifndef CGEN_BFD_ARCH
605#define CGEN_BFD_ARCH bfd_arch_epiphany
606#endif
607  arch = info->arch;
608  if (arch == bfd_arch_unknown)
609    arch = CGEN_BFD_ARCH;
610
611  /* There's no standard way to compute the machine or isa number
612     so we leave it to the target.  */
613#ifdef CGEN_COMPUTE_MACH
614  mach = CGEN_COMPUTE_MACH (info);
615#else
616  mach = info->mach;
617#endif
618
619#ifdef CGEN_COMPUTE_ISA
620  {
621    static CGEN_BITSET *permanent_isa;
622
623    if (!permanent_isa)
624      permanent_isa = cgen_bitset_create (MAX_ISAS);
625    isa = permanent_isa;
626    cgen_bitset_clear (isa);
627    cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
628  }
629#else
630  isa = info->insn_sets;
631#endif
632
633  /* If we've switched cpu's, try to find a handle we've used before */
634  if (cd
635      && (cgen_bitset_compare (isa, prev_isa) != 0
636	  || mach != prev_mach
637	  || endian != prev_endian))
638    {
639      cd = 0;
640      for (cl = cd_list; cl; cl = cl->next)
641	{
642	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
643	      cl->mach == mach &&
644	      cl->endian == endian)
645	    {
646	      cd = cl->cd;
647 	      prev_isa = cd->isas;
648	      break;
649	    }
650	}
651    }
652
653  /* If we haven't initialized yet, initialize the opcode table.  */
654  if (! cd)
655    {
656      const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
657      const char *mach_name;
658
659      if (!arch_type)
660	abort ();
661      mach_name = arch_type->printable_name;
662
663      prev_isa = cgen_bitset_copy (isa);
664      prev_mach = mach;
665      prev_endian = endian;
666      cd = epiphany_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
667				 CGEN_CPU_OPEN_BFDMACH, mach_name,
668				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
669				 CGEN_CPU_OPEN_END);
670      if (!cd)
671	abort ();
672
673      /* Save this away for future reference.  */
674      cl = xmalloc (sizeof (struct cpu_desc_list));
675      cl->cd = cd;
676      cl->isa = prev_isa;
677      cl->mach = mach;
678      cl->endian = endian;
679      cl->next = cd_list;
680      cd_list = cl;
681
682      epiphany_cgen_init_dis (cd);
683    }
684
685  /* We try to have as much common code as possible.
686     But at this point some targets need to take over.  */
687  /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
688     but if not possible try to move this hook elsewhere rather than
689     have two hooks.  */
690  length = CGEN_PRINT_INSN (cd, pc, info);
691  if (length > 0)
692    return length;
693  if (length < 0)
694    return -1;
695
696  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
697  return cd->default_insn_bitsize / 8;
698}
699