1214571Sdim/* Disassembler interface for targets using CGEN. -*- C -*-
2214571Sdim   CGEN: Cpu tools GENerator
3214571Sdim
4214571Sdim   THIS FILE IS MACHINE GENERATED WITH CGEN.
5214571Sdim   - the resultant file is machine generated, cgen-dis.in isn't
6214571Sdim
7214571Sdim   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005
8214571Sdim   Free Software Foundation, Inc.
9214571Sdim
10214571Sdim   This file is part of the GNU Binutils and GDB, the GNU debugger.
11214571Sdim
12214571Sdim   This program is free software; you can redistribute it and/or modify
13214571Sdim   it under the terms of the GNU General Public License as published by
14214571Sdim   the Free Software Foundation; either version 2, or (at your option)
15214571Sdim   any later version.
16214571Sdim
17214571Sdim   This program is distributed in the hope that it will be useful,
18214571Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
19214571Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20214571Sdim   GNU General Public License for more details.
21214571Sdim
22214571Sdim   You should have received a copy of the GNU General Public License
23214571Sdim   along with this program; if not, write to the Free Software Foundation, Inc.,
24214571Sdim   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
25214571Sdim
26214571Sdim/* ??? Eventually more and more of this stuff can go to cpu-independent files.
27214571Sdim   Keep that in mind.  */
28214571Sdim
29214571Sdim#include "sysdep.h"
30214571Sdim#include <stdio.h>
31214571Sdim#include "ansidecl.h"
32214571Sdim#include "dis-asm.h"
33214571Sdim#include "bfd.h"
34214571Sdim#include "symcat.h"
35214571Sdim#include "libiberty.h"
36214571Sdim#include "mep-desc.h"
37214571Sdim#include "mep-opc.h"
38214571Sdim#include "opintl.h"
39214571Sdim
40214571Sdim/* Default text to print if an instruction isn't recognized.  */
41214571Sdim#define UNKNOWN_INSN_MSG _("*unknown*")
42214571Sdim
43214571Sdimstatic void print_normal
44214571Sdim  (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
45214571Sdimstatic void print_address
46214571Sdim  (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
47214571Sdimstatic void print_keyword
48214571Sdim  (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
49214571Sdimstatic void print_insn_normal
50214571Sdim  (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
51214571Sdimstatic int print_insn
52214571Sdim  (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
53214571Sdimstatic int default_print_insn
54214571Sdim  (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
55214571Sdimstatic int read_insn
56214571Sdim  (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
57214571Sdim   unsigned long *);
58214571Sdim
59214571Sdim/* -- disassembler routines inserted here.  */
60214571Sdim
61214571Sdim/* -- dis.c */
62214571Sdim
63214571Sdim#include "elf/mep.h"
64214571Sdim#include "elf-bfd.h"
65214571Sdim
66214571Sdim#define CGEN_VALIDATE_INSN_SUPPORTED
67214571Sdim
68214571Sdimstatic void print_tpreg (CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int);
69214571Sdimstatic void print_spreg (CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned int);
70214571Sdim
71214571Sdimstatic void
72214571Sdimprint_tpreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, PTR dis_info,
73214571Sdim	     CGEN_KEYWORD *table ATTRIBUTE_UNUSED, long val ATTRIBUTE_UNUSED,
74214571Sdim	     unsigned int flags ATTRIBUTE_UNUSED)
75214571Sdim{
76214571Sdim  disassemble_info *info = (disassemble_info *) dis_info;
77214571Sdim
78214571Sdim  (*info->fprintf_func) (info->stream, "$tp");
79214571Sdim}
80214571Sdim
81214571Sdimstatic void
82214571Sdimprint_spreg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, PTR dis_info,
83214571Sdim	     CGEN_KEYWORD *table ATTRIBUTE_UNUSED, long val ATTRIBUTE_UNUSED,
84214571Sdim	     unsigned int flags ATTRIBUTE_UNUSED)
85214571Sdim{
86214571Sdim  disassemble_info *info = (disassemble_info *) dis_info;
87214571Sdim
88214571Sdim  (*info->fprintf_func) (info->stream, "$sp");
89214571Sdim}
90214571Sdim
91214571Sdim/* begin-cop-ip-print-handlers */
92214571Sdimstatic void
93214571Sdimprint_fmax_cr (CGEN_CPU_DESC cd,
94214571Sdim	void *dis_info,
95214571Sdim	CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED,
96214571Sdim	long value,
97214571Sdim	unsigned int attrs)
98214571Sdim{
99214571Sdim  print_keyword (cd, dis_info, & mep_cgen_opval_h_cr_fmax, value, attrs);
100214571Sdim}
101214571Sdimstatic void
102214571Sdimprint_fmax_ccr (CGEN_CPU_DESC cd,
103214571Sdim	void *dis_info,
104214571Sdim	CGEN_KEYWORD *keyword_table ATTRIBUTE_UNUSED,
105214571Sdim	long value,
106214571Sdim	unsigned int attrs)
107214571Sdim{
108214571Sdim  print_keyword (cd, dis_info, & mep_cgen_opval_h_ccr_fmax, value, attrs);
109214571Sdim}
110214571Sdim/* end-cop-ip-print-handlers */
111214571Sdim
112214571Sdim/************************************************************\
113214571Sdim*********************** Experimental *************************
114214571Sdim\************************************************************/
115214571Sdim
116214571Sdim#undef  CGEN_PRINT_INSN
117214571Sdim#define CGEN_PRINT_INSN mep_print_insn
118214571Sdim
119214571Sdimstatic int
120214571Sdimmep_print_vliw_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info,
121214571Sdim		      bfd_byte *buf, int corelength, int copro1length,
122214571Sdim		      int copro2length ATTRIBUTE_UNUSED)
123214571Sdim{
124214571Sdim  int i;
125214571Sdim  int status = 0;
126214571Sdim  /* char insnbuf[CGEN_MAX_INSN_SIZE]; */
127214571Sdim  bfd_byte insnbuf[64];
128214571Sdim
129214571Sdim  /* If corelength > 0 then there is a core insn present. It
130214571Sdim     will be at the beginning of the buffer.  After printing
131214571Sdim     the core insn, we need to print the + on the next line.  */
132214571Sdim  if (corelength > 0)
133214571Sdim    {
134214571Sdim      int my_status = 0;
135214571Sdim
136214571Sdim      for (i = 0; i < corelength; i++ )
137214571Sdim	insnbuf[i] = buf[i];
138214571Sdim      cd->isas = & MEP_CORE_ISA;
139214571Sdim
140214571Sdim      my_status = print_insn (cd, pc, info, insnbuf, corelength);
141214571Sdim      if (my_status != corelength)
142214571Sdim	{
143214571Sdim	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
144214571Sdim	  my_status = corelength;
145214571Sdim	}
146214571Sdim      status += my_status;
147214571Sdim
148214571Sdim      /* Print the + to indicate that the following copro insn is   */
149214571Sdim      /* part of a vliw group.                                      */
150214571Sdim      if (copro1length > 0)
151214571Sdim	(*info->fprintf_func) (info->stream, " + ");
152214571Sdim    }
153214571Sdim
154214571Sdim  /* Now all that is left to be processed is the coprocessor insns
155214571Sdim     In vliw mode, there will always be one.  Its positioning will
156214571Sdim     be from byte corelength to byte corelength+copro1length -1.
157214571Sdim     No need to check for existence.   Also, the first vliw insn,
158214571Sdim     will, as spec'd, always be at least as long as the core insn
159214571Sdim     so we don't need to flush the buffer.  */
160214571Sdim  if (copro1length > 0)
161214571Sdim    {
162214571Sdim      int my_status = 0;
163214571Sdim
164214571Sdim      for (i = corelength; i < corelength + copro1length; i++ )
165214571Sdim	insnbuf[i - corelength] = buf[i];
166214571Sdim
167214571Sdim      switch (copro1length)
168214571Sdim	{
169214571Sdim	case 0:
170214571Sdim	  break;
171214571Sdim	case 2:
172214571Sdim	  cd->isas = & MEP_COP16_ISA;
173214571Sdim	  break;
174214571Sdim	case 4:
175214571Sdim	  cd->isas = & MEP_COP32_ISA;
176214571Sdim	  break;
177214571Sdim	case 6:
178214571Sdim	  cd->isas = & MEP_COP48_ISA;
179214571Sdim	  break;
180214571Sdim	case 8:
181214571Sdim	  cd->isas = & MEP_COP64_ISA;
182214571Sdim	  break;
183214571Sdim	default:
184214571Sdim	  /* Shouldn't be anything but 16,32,48,64.  */
185214571Sdim	  break;
186214571Sdim	}
187214571Sdim
188214571Sdim      my_status = print_insn (cd, pc, info, insnbuf, copro1length);
189214571Sdim
190214571Sdim      if (my_status != copro1length)
191214571Sdim	{
192214571Sdim	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
193214571Sdim	  my_status = copro1length;
194214571Sdim	}
195214571Sdim      status += my_status;
196214571Sdim    }
197214571Sdim
198214571Sdim#if 0
199214571Sdim  /* Now we need to process the second copro insn if it exists. We
200214571Sdim     have no guarantee that the second copro insn will be longer
201214571Sdim     than the first, so we have to flush the buffer if we are have
202214571Sdim     a second copro insn to process.  If present, this insn will
203214571Sdim     be in the position from byte corelength+copro1length to byte
204214571Sdim     corelength+copro1length+copro2length-1 (which better equal 8
205214571Sdim     or else we're in big trouble.  */
206214571Sdim  if (copro2length > 0)
207214571Sdim    {
208214571Sdim      int my_status = 0;
209214571Sdim
210214571Sdim      for (i = 0; i < 64 ; i++)
211214571Sdim	insnbuf[i] = 0;
212214571Sdim
213214571Sdim      for (i = corelength + copro1length; i < 64; i++)
214214571Sdim	insnbuf[i - (corelength + copro1length)] = buf[i];
215214571Sdim
216214571Sdim      switch (copro2length)
217214571Sdim	{
218214571Sdim	case 2:
219214571Sdim	  cd->isas = 1 << ISA_EXT_COP1_16;
220214571Sdim	  break;
221214571Sdim	case 4:
222214571Sdim	  cd->isas = 1 << ISA_EXT_COP1_32;
223214571Sdim	  break;
224214571Sdim	case 6:
225214571Sdim	  cd->isas = 1 << ISA_EXT_COP1_48;
226214571Sdim	  break;
227214571Sdim	case 8:
228214571Sdim	  cd->isas = 1 << ISA_EXT_COP1_64;
229214571Sdim	  break;
230214571Sdim	default:
231214571Sdim	  /* Shouldn't be anything but 16,32,48,64.  */
232214571Sdim	  break;
233214571Sdim	}
234214571Sdim
235214571Sdim      my_status = print_insn (cd, pc, info, insnbuf, copro2length);
236214571Sdim
237214571Sdim      if (my_status != copro2length)
238214571Sdim	{
239214571Sdim	  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
240214571Sdim	  my_status = copro2length;
241214571Sdim	}
242214571Sdim
243214571Sdim      status += my_status;
244214571Sdim    }
245214571Sdim#endif
246214571Sdim
247214571Sdim  /* Status should now be the number of bytes that were printed
248214571Sdim     which should be 4 for VLIW32 mode and 64 for VLIW64 mode.  */
249214571Sdim
250214571Sdim  if ((!MEP_VLIW64 && (status != 4)) || (MEP_VLIW64 && (status != 8)))
251214571Sdim    return -1;
252214571Sdim  else
253214571Sdim    return status;
254214571Sdim}
255214571Sdim
256214571Sdim/* The two functions mep_examine_vliw[32,64]_insns are used find out
257214571Sdim   which vliw combinaion (16 bit core with 48 bit copro, 32 bit core
258214571Sdim   with 32 bit copro, etc.) is present.  Later on, when internally
259214571Sdim   parallel coprocessors are handled, only these functions should
260214571Sdim   need to be changed.
261214571Sdim
262214571Sdim   At this time only the following combinations are supported:
263214571Sdim
264214571Sdim   VLIW32 Mode:
265214571Sdim   16 bit core insn (core) and 16 bit coprocessor insn (cop1)
266214571Sdim   32 bit core insn (core)
267214571Sdim   32 bit coprocessor insn (cop1)
268214571Sdim   Note: As of this time, I do not believe we have enough information
269214571Sdim         to distinguish a 32 bit core insn from a 32 bit cop insn. Also,
270214571Sdim         no 16 bit coprocessor insns have been specified.
271214571Sdim
272214571Sdim   VLIW64 Mode:
273214571Sdim   16 bit core insn (core) and 48 bit coprocessor insn (cop1)
274214571Sdim   32 bit core insn (core) and 32 bit coprocessor insn (cop1)
275214571Sdim   64 bit coprocessor insn (cop1)
276214571Sdim
277214571Sdim   The framework for an internally parallel coprocessor is also
278214571Sdim   present (2nd coprocessor insn is cop2), but at this time it
279214571Sdim   is not used.  This only appears to be valid in VLIW64 mode.  */
280214571Sdim
281214571Sdimstatic int
282214571Sdimmep_examine_vliw32_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
283214571Sdim{
284214571Sdim  int status;
285214571Sdim  int buflength;
286214571Sdim  int corebuflength;
287214571Sdim  int cop1buflength;
288214571Sdim  int cop2buflength;
289214571Sdim  bfd_byte buf[CGEN_MAX_INSN_SIZE];
290214571Sdim  char indicator16[1];
291214571Sdim  char indicatorcop32[2];
292214571Sdim
293214571Sdim  /* At this time we're not supporting internally parallel coprocessors,
294214571Sdim     so cop2buflength will always be 0.  */
295214571Sdim  cop2buflength = 0;
296214571Sdim
297214571Sdim  /* Read in 32 bits.  */
298214571Sdim  buflength = 4; /* VLIW insn spans 4 bytes.  */
299214571Sdim  status = (*info->read_memory_func) (pc, buf, buflength, info);
300214571Sdim
301214571Sdim  if (status != 0)
302214571Sdim    {
303214571Sdim      (*info->memory_error_func) (status, pc, info);
304214571Sdim      return -1;
305214571Sdim    }
306214571Sdim
307214571Sdim  /* Put the big endian representation of the bytes to be examined
308214571Sdim     in the temporary buffers for examination.  */
309214571Sdim
310214571Sdim  if (info->endian == BFD_ENDIAN_BIG)
311214571Sdim    {
312214571Sdim      indicator16[0] = buf[0];
313214571Sdim      indicatorcop32[0] = buf[0];
314214571Sdim      indicatorcop32[1] = buf[1];
315214571Sdim    }
316214571Sdim  else
317214571Sdim    {
318214571Sdim      indicator16[0] = buf[1];
319214571Sdim      indicatorcop32[0] = buf[1];
320214571Sdim      indicatorcop32[1] = buf[0];
321214571Sdim    }
322214571Sdim
323214571Sdim  /* If the two high order bits are 00, 01 or 10, we have a 16 bit
324214571Sdim     core insn and a 48 bit copro insn.  */
325214571Sdim
326214571Sdim  if ((indicator16[0] & 0x80) && (indicator16[0] & 0x40))
327214571Sdim    {
328214571Sdim      if ((indicatorcop32[0] & 0xf0) == 0xf0 && (indicatorcop32[1] & 0x07) == 0x07)
329214571Sdim	{
330214571Sdim          /* We have a 32 bit copro insn.  */
331214571Sdim          corebuflength = 0;
332214571Sdim	  /* All 4 4ytes are one copro insn. */
333214571Sdim          cop1buflength = 4;
334214571Sdim	}
335214571Sdim      else
336214571Sdim	{
337214571Sdim          /* We have a 32 bit core.  */
338214571Sdim          corebuflength = 4;
339214571Sdim          cop1buflength = 0;
340214571Sdim	}
341214571Sdim    }
342214571Sdim  else
343214571Sdim    {
344214571Sdim      /* We have a 16 bit core insn and a 16 bit copro insn.  */
345214571Sdim      corebuflength = 2;
346214571Sdim      cop1buflength = 2;
347214571Sdim    }
348214571Sdim
349214571Sdim  /* Now we have the distrubution set.  Print them out.  */
350214571Sdim  status = mep_print_vliw_insns (cd, pc, info, buf, corebuflength,
351214571Sdim				 cop1buflength, cop2buflength);
352214571Sdim
353214571Sdim  return status;
354214571Sdim}
355214571Sdim
356214571Sdimstatic int
357214571Sdimmep_examine_vliw64_insns (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
358214571Sdim{
359214571Sdim  int status;
360214571Sdim  int buflength;
361214571Sdim  int corebuflength;
362214571Sdim  int cop1buflength;
363214571Sdim  int cop2buflength;
364214571Sdim  bfd_byte buf[CGEN_MAX_INSN_SIZE];
365214571Sdim  char indicator16[1];
366214571Sdim  char indicator64[4];
367214571Sdim
368214571Sdim  /* At this time we're not supporting internally parallel
369214571Sdim     coprocessors, so cop2buflength will always be 0.  */
370214571Sdim  cop2buflength = 0;
371214571Sdim
372214571Sdim  /* Read in 64 bits.  */
373214571Sdim  buflength = 8; /* VLIW insn spans 8 bytes.  */
374214571Sdim  status = (*info->read_memory_func) (pc, buf, buflength, info);
375214571Sdim
376214571Sdim  if (status != 0)
377214571Sdim    {
378214571Sdim      (*info->memory_error_func) (status, pc, info);
379214571Sdim      return -1;
380214571Sdim    }
381214571Sdim
382214571Sdim  /* We have all 64 bits in the buffer now.  We have to figure out
383214571Sdim     what combination of instruction sizes are present.  The two
384214571Sdim     high order bits will indicate whether or not we have a 16 bit
385214571Sdim     core insn or not.  If not, then we have to look at the 7,8th
386214571Sdim     bytes to tell whether we have 64 bit copro insn or a 32 bit
387214571Sdim     core insn with a 32 bit copro insn.  Endianness will make a
388214571Sdim     difference here.  */
389214571Sdim
390214571Sdim  /* Put the big endian representation of the bytes to be examined
391214571Sdim     in the temporary buffers for examination.  */
392214571Sdim
393214571Sdim  /* indicator16[0] = buf[0];  */
394214571Sdim  if (info->endian == BFD_ENDIAN_BIG)
395214571Sdim    {
396214571Sdim      indicator16[0] = buf[0];
397214571Sdim      indicator64[0] = buf[0];
398214571Sdim      indicator64[1] = buf[1];
399214571Sdim      indicator64[2] = buf[2];
400214571Sdim      indicator64[3] = buf[3];
401214571Sdim    }
402214571Sdim  else
403214571Sdim    {
404214571Sdim      indicator16[0] = buf[1];
405214571Sdim      indicator64[0] = buf[1];
406214571Sdim      indicator64[1] = buf[0];
407214571Sdim      indicator64[2] = buf[3];
408214571Sdim      indicator64[3] = buf[2];
409214571Sdim    }
410214571Sdim
411214571Sdim  /* If the two high order bits are 00, 01 or 10, we have a 16 bit
412214571Sdim     core insn and a 48 bit copro insn.  */
413214571Sdim
414214571Sdim  if ((indicator16[0] & 0x80) && (indicator16[0] & 0x40))
415214571Sdim    {
416214571Sdim      if ((indicator64[0] & 0xf0) == 0xf0 && (indicator64[1] & 0x07) == 0x07
417214571Sdim	  && ((indicator64[2] & 0xfe) != 0xf0 || (indicator64[3] & 0xf4) != 0))
418214571Sdim	{
419214571Sdim          /* We have a 64 bit copro insn.  */
420214571Sdim          corebuflength = 0;
421214571Sdim	  /* All 8 bytes are one copro insn.  */
422214571Sdim          cop1buflength = 8;
423214571Sdim	}
424214571Sdim      else
425214571Sdim	{
426214571Sdim          /* We have a 32 bit core insn and a 32 bit copro insn.  */
427214571Sdim          corebuflength = 4;
428214571Sdim          cop1buflength = 4;
429214571Sdim	}
430214571Sdim    }
431214571Sdim  else
432214571Sdim    {
433214571Sdim      /* We have a 16 bit core insn and a 48 bit copro insn.  */
434214571Sdim      corebuflength = 2;
435214571Sdim      cop1buflength = 6;
436214571Sdim    }
437214571Sdim
438214571Sdim  /* Now we have the distrubution set.  Print them out. */
439214571Sdim  status = mep_print_vliw_insns (cd, pc, info, buf, corebuflength,
440214571Sdim				 cop1buflength, cop2buflength);
441214571Sdim
442214571Sdim  return status;
443214571Sdim}
444214571Sdim
445214571Sdimstatic int
446214571Sdimmep_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
447214571Sdim{
448214571Sdim  int status;
449214571Sdim
450214571Sdim  /* Extract and adapt to configuration number, if available. */
451214571Sdim  if (info->section && info->section->owner)
452214571Sdim    {
453214571Sdim      bfd *abfd = info->section->owner;
454214571Sdim      mep_config_index = abfd->tdata.elf_obj_data->elf_header->e_flags & EF_MEP_INDEX_MASK;
455214571Sdim      /* This instantly redefines MEP_CONFIG, MEP_OMASK, .... MEP_VLIW64 */
456214571Sdim    }
457214571Sdim
458214571Sdim  /* Picking the right ISA bitmask for the current context is tricky.  */
459214571Sdim  if (info->section)
460214571Sdim    {
461214571Sdim      if (info->section->flags & SEC_MEP_VLIW)
462214571Sdim	{
463214571Sdim	  /* Are we in 32 or 64 bit vliw mode?  */
464214571Sdim	  if (MEP_VLIW64)
465214571Sdim	    status = mep_examine_vliw64_insns (cd, pc, info);
466214571Sdim	  else
467214571Sdim	    status = mep_examine_vliw32_insns (cd, pc, info);
468214571Sdim	  /* Both the above branches set their own isa bitmasks.  */
469214571Sdim	}
470214571Sdim      else
471214571Sdim	{
472214571Sdim	  cd->isas = & MEP_CORE_ISA;
473214571Sdim	  status = default_print_insn (cd, pc, info);
474214571Sdim	}
475214571Sdim    }
476214571Sdim  else /* sid or gdb */
477214571Sdim    {
478214571Sdim      status = default_print_insn (cd, pc, info);
479214571Sdim    }
480214571Sdim
481214571Sdim  return status;
482214571Sdim}
483214571Sdim
484214571Sdim
485214571Sdim/* -- opc.c */
486214571Sdim
487214571Sdimvoid mep_cgen_print_operand
488214571Sdim  (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
489214571Sdim
490214571Sdim/* Main entry point for printing operands.
491214571Sdim   XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
492214571Sdim   of dis-asm.h on cgen.h.
493214571Sdim
494214571Sdim   This function is basically just a big switch statement.  Earlier versions
495214571Sdim   used tables to look up the function to use, but
496214571Sdim   - if the table contains both assembler and disassembler functions then
497214571Sdim     the disassembler contains much of the assembler and vice-versa,
498214571Sdim   - there's a lot of inlining possibilities as things grow,
499214571Sdim   - using a switch statement avoids the function call overhead.
500214571Sdim
501214571Sdim   This function could be moved into `print_insn_normal', but keeping it
502214571Sdim   separate makes clear the interface between `print_insn_normal' and each of
503214571Sdim   the handlers.  */
504214571Sdim
505214571Sdimvoid
506214571Sdimmep_cgen_print_operand (CGEN_CPU_DESC cd,
507214571Sdim			   int opindex,
508214571Sdim			   void * xinfo,
509214571Sdim			   CGEN_FIELDS *fields,
510214571Sdim			   void const *attrs ATTRIBUTE_UNUSED,
511214571Sdim			   bfd_vma pc,
512214571Sdim			   int length)
513214571Sdim{
514214571Sdim  disassemble_info *info = (disassemble_info *) xinfo;
515214571Sdim
516214571Sdim  switch (opindex)
517214571Sdim    {
518214571Sdim    case MEP_OPERAND_ADDR24A4 :
519214571Sdim      print_normal (cd, info, fields->f_24u8a4n, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
520214571Sdim      break;
521214571Sdim    case MEP_OPERAND_CALLNUM :
522214571Sdim      print_normal (cd, info, fields->f_callnum, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
523214571Sdim      break;
524214571Sdim    case MEP_OPERAND_CCCC :
525214571Sdim      print_normal (cd, info, fields->f_rm, 0, pc, length);
526214571Sdim      break;
527214571Sdim    case MEP_OPERAND_CCRN :
528214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_ccr, fields->f_ccrn, 0|(1<<CGEN_OPERAND_VIRTUAL));
529214571Sdim      break;
530214571Sdim    case MEP_OPERAND_CDISP8 :
531214571Sdim      print_normal (cd, info, fields->f_8s24, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
532214571Sdim      break;
533214571Sdim    case MEP_OPERAND_CDISP8A2 :
534214571Sdim      print_normal (cd, info, fields->f_8s24a2, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
535214571Sdim      break;
536214571Sdim    case MEP_OPERAND_CDISP8A4 :
537214571Sdim      print_normal (cd, info, fields->f_8s24a4, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
538214571Sdim      break;
539214571Sdim    case MEP_OPERAND_CDISP8A8 :
540214571Sdim      print_normal (cd, info, fields->f_8s24a8, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
541214571Sdim      break;
542214571Sdim    case MEP_OPERAND_CIMM4 :
543214571Sdim      print_normal (cd, info, fields->f_rn, 0, pc, length);
544214571Sdim      break;
545214571Sdim    case MEP_OPERAND_CIMM5 :
546214571Sdim      print_normal (cd, info, fields->f_5u24, 0, pc, length);
547214571Sdim      break;
548214571Sdim    case MEP_OPERAND_CODE16 :
549214571Sdim      print_normal (cd, info, fields->f_16u16, 0, pc, length);
550214571Sdim      break;
551214571Sdim    case MEP_OPERAND_CODE24 :
552214571Sdim      print_normal (cd, info, fields->f_24u4n, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
553214571Sdim      break;
554214571Sdim    case MEP_OPERAND_CP_FLAG :
555214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_ccr, 0, 0);
556214571Sdim      break;
557214571Sdim    case MEP_OPERAND_CRN :
558214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_cr, fields->f_crn, 0);
559214571Sdim      break;
560214571Sdim    case MEP_OPERAND_CRN64 :
561214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_cr64, fields->f_crn, 0);
562214571Sdim      break;
563214571Sdim    case MEP_OPERAND_CRNX :
564214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_cr, fields->f_crnx, 0|(1<<CGEN_OPERAND_VIRTUAL));
565214571Sdim      break;
566214571Sdim    case MEP_OPERAND_CRNX64 :
567214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_cr64, fields->f_crnx, 0|(1<<CGEN_OPERAND_VIRTUAL));
568214571Sdim      break;
569214571Sdim    case MEP_OPERAND_CSRN :
570214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, fields->f_csrn, 0|(1<<CGEN_OPERAND_VIRTUAL));
571214571Sdim      break;
572214571Sdim    case MEP_OPERAND_CSRN_IDX :
573214571Sdim      print_normal (cd, info, fields->f_csrn, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
574214571Sdim      break;
575214571Sdim    case MEP_OPERAND_DBG :
576214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
577214571Sdim      break;
578214571Sdim    case MEP_OPERAND_DEPC :
579214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
580214571Sdim      break;
581214571Sdim    case MEP_OPERAND_EPC :
582214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
583214571Sdim      break;
584214571Sdim    case MEP_OPERAND_EXC :
585214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
586214571Sdim      break;
587214571Sdim    case MEP_OPERAND_FMAX_CCRN :
588214571Sdim      print_fmax_ccr (cd, info, & mep_cgen_opval_h_ccr, fields->f_fmax_4_4, 0);
589214571Sdim      break;
590214571Sdim    case MEP_OPERAND_FMAX_FRD :
591214571Sdim      print_fmax_cr (cd, info, & mep_cgen_opval_h_cr, fields->f_fmax_frd, 0|(1<<CGEN_OPERAND_VIRTUAL));
592214571Sdim      break;
593214571Sdim    case MEP_OPERAND_FMAX_FRD_INT :
594214571Sdim      print_fmax_cr (cd, info, & mep_cgen_opval_h_cr, fields->f_fmax_frd, 0|(1<<CGEN_OPERAND_VIRTUAL));
595214571Sdim      break;
596214571Sdim    case MEP_OPERAND_FMAX_FRM :
597214571Sdim      print_fmax_cr (cd, info, & mep_cgen_opval_h_cr, fields->f_fmax_frm, 0|(1<<CGEN_OPERAND_VIRTUAL));
598214571Sdim      break;
599214571Sdim    case MEP_OPERAND_FMAX_FRN :
600214571Sdim      print_fmax_cr (cd, info, & mep_cgen_opval_h_cr, fields->f_fmax_frn, 0|(1<<CGEN_OPERAND_VIRTUAL));
601214571Sdim      break;
602214571Sdim    case MEP_OPERAND_FMAX_FRN_INT :
603214571Sdim      print_fmax_cr (cd, info, & mep_cgen_opval_h_cr, fields->f_fmax_frn, 0|(1<<CGEN_OPERAND_VIRTUAL));
604214571Sdim      break;
605214571Sdim    case MEP_OPERAND_FMAX_RM :
606214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_fmax_rm, 0);
607214571Sdim      break;
608214571Sdim    case MEP_OPERAND_HI :
609214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
610214571Sdim      break;
611214571Sdim    case MEP_OPERAND_LO :
612214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
613214571Sdim      break;
614214571Sdim    case MEP_OPERAND_LP :
615214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
616214571Sdim      break;
617214571Sdim    case MEP_OPERAND_MB0 :
618214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
619214571Sdim      break;
620214571Sdim    case MEP_OPERAND_MB1 :
621214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
622214571Sdim      break;
623214571Sdim    case MEP_OPERAND_ME0 :
624214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
625214571Sdim      break;
626214571Sdim    case MEP_OPERAND_ME1 :
627214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
628214571Sdim      break;
629214571Sdim    case MEP_OPERAND_NPC :
630214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
631214571Sdim      break;
632214571Sdim    case MEP_OPERAND_OPT :
633214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
634214571Sdim      break;
635214571Sdim    case MEP_OPERAND_PCABS24A2 :
636214571Sdim      print_address (cd, info, fields->f_24u5a2n, 0|(1<<CGEN_OPERAND_ABS_ADDR)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
637214571Sdim      break;
638214571Sdim    case MEP_OPERAND_PCREL12A2 :
639214571Sdim      print_address (cd, info, fields->f_12s4a2, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
640214571Sdim      break;
641214571Sdim    case MEP_OPERAND_PCREL17A2 :
642214571Sdim      print_address (cd, info, fields->f_17s16a2, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
643214571Sdim      break;
644214571Sdim    case MEP_OPERAND_PCREL24A2 :
645214571Sdim      print_address (cd, info, fields->f_24s5a2n, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_PCREL_ADDR)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
646214571Sdim      break;
647214571Sdim    case MEP_OPERAND_PCREL8A2 :
648214571Sdim      print_address (cd, info, fields->f_8s8a2, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
649214571Sdim      break;
650214571Sdim    case MEP_OPERAND_PSW :
651214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
652214571Sdim      break;
653214571Sdim    case MEP_OPERAND_R0 :
654214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, 0, 0);
655214571Sdim      break;
656214571Sdim    case MEP_OPERAND_R1 :
657214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, 0, 0);
658214571Sdim      break;
659214571Sdim    case MEP_OPERAND_RL :
660214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rl, 0);
661214571Sdim      break;
662214571Sdim    case MEP_OPERAND_RM :
663214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rm, 0);
664214571Sdim      break;
665214571Sdim    case MEP_OPERAND_RMA :
666214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rm, 0);
667214571Sdim      break;
668214571Sdim    case MEP_OPERAND_RN :
669214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn, 0);
670214571Sdim      break;
671214571Sdim    case MEP_OPERAND_RN3 :
672214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn3, 0);
673214571Sdim      break;
674214571Sdim    case MEP_OPERAND_RN3C :
675214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn3, 0);
676214571Sdim      break;
677214571Sdim    case MEP_OPERAND_RN3L :
678214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn3, 0);
679214571Sdim      break;
680214571Sdim    case MEP_OPERAND_RN3S :
681214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn3, 0);
682214571Sdim      break;
683214571Sdim    case MEP_OPERAND_RN3UC :
684214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn3, 0);
685214571Sdim      break;
686214571Sdim    case MEP_OPERAND_RN3UL :
687214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn3, 0);
688214571Sdim      break;
689214571Sdim    case MEP_OPERAND_RN3US :
690214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn3, 0);
691214571Sdim      break;
692214571Sdim    case MEP_OPERAND_RNC :
693214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn, 0);
694214571Sdim      break;
695214571Sdim    case MEP_OPERAND_RNL :
696214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn, 0);
697214571Sdim      break;
698214571Sdim    case MEP_OPERAND_RNS :
699214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn, 0);
700214571Sdim      break;
701214571Sdim    case MEP_OPERAND_RNUC :
702214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn, 0);
703214571Sdim      break;
704214571Sdim    case MEP_OPERAND_RNUL :
705214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn, 0);
706214571Sdim      break;
707214571Sdim    case MEP_OPERAND_RNUS :
708214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, fields->f_rn, 0);
709214571Sdim      break;
710214571Sdim    case MEP_OPERAND_SAR :
711214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_csr, 0, 0);
712214571Sdim      break;
713214571Sdim    case MEP_OPERAND_SDISP16 :
714214571Sdim      print_normal (cd, info, fields->f_16s16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
715214571Sdim      break;
716214571Sdim    case MEP_OPERAND_SIMM16 :
717214571Sdim      print_normal (cd, info, fields->f_16s16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
718214571Sdim      break;
719214571Sdim    case MEP_OPERAND_SIMM6 :
720214571Sdim      print_normal (cd, info, fields->f_6s8, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
721214571Sdim      break;
722214571Sdim    case MEP_OPERAND_SIMM8 :
723214571Sdim      print_normal (cd, info, fields->f_8s8, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_RELOC_IMPLIES_OVERFLOW), pc, length);
724214571Sdim      break;
725214571Sdim    case MEP_OPERAND_SP :
726214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, 0, 0);
727214571Sdim      break;
728214571Sdim    case MEP_OPERAND_SPR :
729214571Sdim      print_spreg (cd, info, & mep_cgen_opval_h_gpr, 0, 0);
730214571Sdim      break;
731214571Sdim    case MEP_OPERAND_TP :
732214571Sdim      print_keyword (cd, info, & mep_cgen_opval_h_gpr, 0, 0);
733214571Sdim      break;
734214571Sdim    case MEP_OPERAND_TPR :
735214571Sdim      print_tpreg (cd, info, & mep_cgen_opval_h_gpr, 0, 0);
736214571Sdim      break;
737214571Sdim    case MEP_OPERAND_UDISP2 :
738214571Sdim      print_normal (cd, info, fields->f_2u6, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
739214571Sdim      break;
740214571Sdim    case MEP_OPERAND_UDISP7 :
741214571Sdim      print_normal (cd, info, fields->f_7u9, 0, pc, length);
742214571Sdim      break;
743214571Sdim    case MEP_OPERAND_UDISP7A2 :
744214571Sdim      print_normal (cd, info, fields->f_7u9a2, 0, pc, length);
745214571Sdim      break;
746214571Sdim    case MEP_OPERAND_UDISP7A4 :
747214571Sdim      print_normal (cd, info, fields->f_7u9a4, 0, pc, length);
748214571Sdim      break;
749214571Sdim    case MEP_OPERAND_UIMM16 :
750214571Sdim      print_normal (cd, info, fields->f_16u16, 0, pc, length);
751214571Sdim      break;
752214571Sdim    case MEP_OPERAND_UIMM2 :
753214571Sdim      print_normal (cd, info, fields->f_2u10, 0, pc, length);
754214571Sdim      break;
755214571Sdim    case MEP_OPERAND_UIMM24 :
756214571Sdim      print_normal (cd, info, fields->f_24u8n, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
757214571Sdim      break;
758214571Sdim    case MEP_OPERAND_UIMM3 :
759214571Sdim      print_normal (cd, info, fields->f_3u5, 0, pc, length);
760214571Sdim      break;
761214571Sdim    case MEP_OPERAND_UIMM4 :
762214571Sdim      print_normal (cd, info, fields->f_4u8, 0, pc, length);
763214571Sdim      break;
764214571Sdim    case MEP_OPERAND_UIMM5 :
765214571Sdim      print_normal (cd, info, fields->f_5u8, 0, pc, length);
766214571Sdim      break;
767214571Sdim    case MEP_OPERAND_UIMM7A4 :
768214571Sdim      print_normal (cd, info, fields->f_7u9a4, 0, pc, length);
769214571Sdim      break;
770214571Sdim    case MEP_OPERAND_ZERO :
771214571Sdim      print_normal (cd, info, 0, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
772214571Sdim      break;
773214571Sdim
774214571Sdim    default :
775214571Sdim      /* xgettext:c-format */
776214571Sdim      fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
777214571Sdim	       opindex);
778214571Sdim    abort ();
779214571Sdim  }
780214571Sdim}
781214571Sdim
782214571Sdimcgen_print_fn * const mep_cgen_print_handlers[] =
783214571Sdim{
784214571Sdim  print_insn_normal,
785214571Sdim};
786214571Sdim
787214571Sdim
788214571Sdimvoid
789214571Sdimmep_cgen_init_dis (CGEN_CPU_DESC cd)
790214571Sdim{
791214571Sdim  mep_cgen_init_opcode_table (cd);
792214571Sdim  mep_cgen_init_ibld_table (cd);
793214571Sdim  cd->print_handlers = & mep_cgen_print_handlers[0];
794214571Sdim  cd->print_operand = mep_cgen_print_operand;
795214571Sdim}
796214571Sdim
797214571Sdim
798214571Sdim/* Default print handler.  */
799214571Sdim
800214571Sdimstatic void
801214571Sdimprint_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
802214571Sdim	      void *dis_info,
803214571Sdim	      long value,
804214571Sdim	      unsigned int attrs,
805214571Sdim	      bfd_vma pc ATTRIBUTE_UNUSED,
806214571Sdim	      int length ATTRIBUTE_UNUSED)
807214571Sdim{
808214571Sdim  disassemble_info *info = (disassemble_info *) dis_info;
809214571Sdim
810214571Sdim#ifdef CGEN_PRINT_NORMAL
811214571Sdim  CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
812214571Sdim#endif
813214571Sdim
814214571Sdim  /* Print the operand as directed by the attributes.  */
815214571Sdim  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
816214571Sdim    ; /* nothing to do */
817214571Sdim  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
818214571Sdim    (*info->fprintf_func) (info->stream, "%ld", value);
819214571Sdim  else
820214571Sdim    (*info->fprintf_func) (info->stream, "0x%lx", value);
821214571Sdim}
822214571Sdim
823214571Sdim/* Default address handler.  */
824214571Sdim
825214571Sdimstatic void
826214571Sdimprint_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
827214571Sdim	       void *dis_info,
828214571Sdim	       bfd_vma value,
829214571Sdim	       unsigned int attrs,
830214571Sdim	       bfd_vma pc ATTRIBUTE_UNUSED,
831214571Sdim	       int length ATTRIBUTE_UNUSED)
832214571Sdim{
833214571Sdim  disassemble_info *info = (disassemble_info *) dis_info;
834214571Sdim
835214571Sdim#ifdef CGEN_PRINT_ADDRESS
836214571Sdim  CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
837214571Sdim#endif
838214571Sdim
839214571Sdim  /* Print the operand as directed by the attributes.  */
840214571Sdim  if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
841214571Sdim    ; /* Nothing to do.  */
842214571Sdim  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
843214571Sdim    (*info->print_address_func) (value, info);
844214571Sdim  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
845214571Sdim    (*info->print_address_func) (value, info);
846214571Sdim  else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
847214571Sdim    (*info->fprintf_func) (info->stream, "%ld", (long) value);
848214571Sdim  else
849214571Sdim    (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
850214571Sdim}
851214571Sdim
852214571Sdim/* Keyword print handler.  */
853214571Sdim
854214571Sdimstatic void
855214571Sdimprint_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
856214571Sdim	       void *dis_info,
857214571Sdim	       CGEN_KEYWORD *keyword_table,
858214571Sdim	       long value,
859214571Sdim	       unsigned int attrs ATTRIBUTE_UNUSED)
860214571Sdim{
861214571Sdim  disassemble_info *info = (disassemble_info *) dis_info;
862214571Sdim  const CGEN_KEYWORD_ENTRY *ke;
863214571Sdim
864214571Sdim  ke = cgen_keyword_lookup_value (keyword_table, value);
865214571Sdim  if (ke != NULL)
866214571Sdim    (*info->fprintf_func) (info->stream, "%s", ke->name);
867214571Sdim  else
868214571Sdim    (*info->fprintf_func) (info->stream, "???");
869214571Sdim}
870214571Sdim
871214571Sdim/* Default insn printer.
872214571Sdim
873214571Sdim   DIS_INFO is defined as `void *' so the disassembler needn't know anything
874214571Sdim   about disassemble_info.  */
875214571Sdim
876214571Sdimstatic void
877214571Sdimprint_insn_normal (CGEN_CPU_DESC cd,
878214571Sdim		   void *dis_info,
879214571Sdim		   const CGEN_INSN *insn,
880214571Sdim		   CGEN_FIELDS *fields,
881214571Sdim		   bfd_vma pc,
882214571Sdim		   int length)
883214571Sdim{
884214571Sdim  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
885214571Sdim  disassemble_info *info = (disassemble_info *) dis_info;
886214571Sdim  const CGEN_SYNTAX_CHAR_TYPE *syn;
887214571Sdim
888214571Sdim  CGEN_INIT_PRINT (cd);
889214571Sdim
890214571Sdim  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
891214571Sdim    {
892214571Sdim      if (CGEN_SYNTAX_MNEMONIC_P (*syn))
893214571Sdim	{
894214571Sdim	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
895214571Sdim	  continue;
896214571Sdim	}
897214571Sdim      if (CGEN_SYNTAX_CHAR_P (*syn))
898214571Sdim	{
899214571Sdim	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
900214571Sdim	  continue;
901214571Sdim	}
902214571Sdim
903214571Sdim      /* We have an operand.  */
904214571Sdim      mep_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
905214571Sdim				 fields, CGEN_INSN_ATTRS (insn), pc, length);
906214571Sdim    }
907214571Sdim}
908214571Sdim
909214571Sdim/* Subroutine of print_insn. Reads an insn into the given buffers and updates
910214571Sdim   the extract info.
911214571Sdim   Returns 0 if all is well, non-zero otherwise.  */
912214571Sdim
913214571Sdimstatic int
914214571Sdimread_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
915214571Sdim	   bfd_vma pc,
916214571Sdim	   disassemble_info *info,
917214571Sdim	   bfd_byte *buf,
918214571Sdim	   int buflen,
919214571Sdim	   CGEN_EXTRACT_INFO *ex_info,
920214571Sdim	   unsigned long *insn_value)
921214571Sdim{
922214571Sdim  int status = (*info->read_memory_func) (pc, buf, buflen, info);
923214571Sdim
924214571Sdim  if (status != 0)
925214571Sdim    {
926214571Sdim      (*info->memory_error_func) (status, pc, info);
927214571Sdim      return -1;
928214571Sdim    }
929214571Sdim
930214571Sdim  ex_info->dis_info = info;
931214571Sdim  ex_info->valid = (1 << buflen) - 1;
932214571Sdim  ex_info->insn_bytes = buf;
933214571Sdim
934214571Sdim  *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
935214571Sdim  return 0;
936214571Sdim}
937214571Sdim
938214571Sdim/* Utility to print an insn.
939214571Sdim   BUF is the base part of the insn, target byte order, BUFLEN bytes long.
940214571Sdim   The result is the size of the insn in bytes or zero for an unknown insn
941214571Sdim   or -1 if an error occurs fetching data (memory_error_func will have
942214571Sdim   been called).  */
943214571Sdim
944214571Sdimstatic int
945214571Sdimprint_insn (CGEN_CPU_DESC cd,
946214571Sdim	    bfd_vma pc,
947214571Sdim	    disassemble_info *info,
948214571Sdim	    bfd_byte *buf,
949214571Sdim	    unsigned int buflen)
950214571Sdim{
951214571Sdim  CGEN_INSN_INT insn_value;
952214571Sdim  const CGEN_INSN_LIST *insn_list;
953214571Sdim  CGEN_EXTRACT_INFO ex_info;
954214571Sdim  int basesize;
955214571Sdim
956214571Sdim  /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
957214571Sdim  basesize = cd->base_insn_bitsize < buflen * 8 ?
958214571Sdim                                     cd->base_insn_bitsize : buflen * 8;
959214571Sdim  insn_value = cgen_get_insn_value (cd, buf, basesize);
960214571Sdim
961214571Sdim
962214571Sdim  /* Fill in ex_info fields like read_insn would.  Don't actually call
963214571Sdim     read_insn, since the incoming buffer is already read (and possibly
964214571Sdim     modified a la m32r).  */
965214571Sdim  ex_info.valid = (1 << buflen) - 1;
966214571Sdim  ex_info.dis_info = info;
967214571Sdim  ex_info.insn_bytes = buf;
968214571Sdim
969214571Sdim  /* The instructions are stored in hash lists.
970214571Sdim     Pick the first one and keep trying until we find the right one.  */
971214571Sdim
972214571Sdim  insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
973214571Sdim  while (insn_list != NULL)
974214571Sdim    {
975214571Sdim      const CGEN_INSN *insn = insn_list->insn;
976214571Sdim      CGEN_FIELDS fields;
977214571Sdim      int length;
978214571Sdim      unsigned long insn_value_cropped;
979214571Sdim
980214571Sdim#ifdef CGEN_VALIDATE_INSN_SUPPORTED
981214571Sdim      /* Not needed as insn shouldn't be in hash lists if not supported.  */
982214571Sdim      /* Supported by this cpu?  */
983214571Sdim      if (! mep_cgen_insn_supported (cd, insn))
984214571Sdim        {
985214571Sdim          insn_list = CGEN_DIS_NEXT_INSN (insn_list);
986214571Sdim	  continue;
987214571Sdim        }
988214571Sdim#endif
989214571Sdim
990214571Sdim      /* Basic bit mask must be correct.  */
991214571Sdim      /* ??? May wish to allow target to defer this check until the extract
992214571Sdim	 handler.  */
993214571Sdim
994214571Sdim      /* Base size may exceed this instruction's size.  Extract the
995214571Sdim         relevant part from the buffer. */
996214571Sdim      if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
997214571Sdim	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
998214571Sdim	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
999214571Sdim					   info->endian == BFD_ENDIAN_BIG);
1000214571Sdim      else
1001214571Sdim	insn_value_cropped = insn_value;
1002214571Sdim
1003214571Sdim      if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
1004214571Sdim	  == CGEN_INSN_BASE_VALUE (insn))
1005214571Sdim	{
1006214571Sdim	  /* Printing is handled in two passes.  The first pass parses the
1007214571Sdim	     machine insn and extracts the fields.  The second pass prints
1008214571Sdim	     them.  */
1009214571Sdim
1010214571Sdim	  /* Make sure the entire insn is loaded into insn_value, if it
1011214571Sdim	     can fit.  */
1012214571Sdim	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
1013214571Sdim	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
1014214571Sdim	    {
1015214571Sdim	      unsigned long full_insn_value;
1016214571Sdim	      int rc = read_insn (cd, pc, info, buf,
1017214571Sdim				  CGEN_INSN_BITSIZE (insn) / 8,
1018214571Sdim				  & ex_info, & full_insn_value);
1019214571Sdim	      if (rc != 0)
1020214571Sdim		return rc;
1021214571Sdim	      length = CGEN_EXTRACT_FN (cd, insn)
1022214571Sdim		(cd, insn, &ex_info, full_insn_value, &fields, pc);
1023214571Sdim	    }
1024214571Sdim	  else
1025214571Sdim	    length = CGEN_EXTRACT_FN (cd, insn)
1026214571Sdim	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
1027214571Sdim
1028214571Sdim	  /* Length < 0 -> error.  */
1029214571Sdim	  if (length < 0)
1030214571Sdim	    return length;
1031214571Sdim	  if (length > 0)
1032214571Sdim	    {
1033214571Sdim	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
1034214571Sdim	      /* Length is in bits, result is in bytes.  */
1035214571Sdim	      return length / 8;
1036214571Sdim	    }
1037214571Sdim	}
1038214571Sdim
1039214571Sdim      insn_list = CGEN_DIS_NEXT_INSN (insn_list);
1040214571Sdim    }
1041214571Sdim
1042214571Sdim  return 0;
1043214571Sdim}
1044214571Sdim
1045214571Sdim/* Default value for CGEN_PRINT_INSN.
1046214571Sdim   The result is the size of the insn in bytes or zero for an unknown insn
1047214571Sdim   or -1 if an error occured fetching bytes.  */
1048214571Sdim
1049214571Sdim#ifndef CGEN_PRINT_INSN
1050214571Sdim#define CGEN_PRINT_INSN default_print_insn
1051214571Sdim#endif
1052214571Sdim
1053214571Sdimstatic int
1054214571Sdimdefault_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
1055214571Sdim{
1056214571Sdim  bfd_byte buf[CGEN_MAX_INSN_SIZE];
1057214571Sdim  int buflen;
1058214571Sdim  int status;
1059214571Sdim
1060214571Sdim  /* Attempt to read the base part of the insn.  */
1061214571Sdim  buflen = cd->base_insn_bitsize / 8;
1062214571Sdim  status = (*info->read_memory_func) (pc, buf, buflen, info);
1063214571Sdim
1064214571Sdim  /* Try again with the minimum part, if min < base.  */
1065214571Sdim  if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
1066214571Sdim    {
1067214571Sdim      buflen = cd->min_insn_bitsize / 8;
1068214571Sdim      status = (*info->read_memory_func) (pc, buf, buflen, info);
1069214571Sdim    }
1070214571Sdim
1071214571Sdim  if (status != 0)
1072214571Sdim    {
1073214571Sdim      (*info->memory_error_func) (status, pc, info);
1074214571Sdim      return -1;
1075214571Sdim    }
1076214571Sdim
1077214571Sdim  return print_insn (cd, pc, info, buf, buflen);
1078214571Sdim}
1079214571Sdim
1080214571Sdim/* Main entry point.
1081214571Sdim   Print one instruction from PC on INFO->STREAM.
1082214571Sdim   Return the size of the instruction (in bytes).  */
1083214571Sdim
1084214571Sdimtypedef struct cpu_desc_list
1085214571Sdim{
1086214571Sdim  struct cpu_desc_list *next;
1087214571Sdim  CGEN_BITSET *isa;
1088214571Sdim  int mach;
1089214571Sdim  int endian;
1090214571Sdim  CGEN_CPU_DESC cd;
1091214571Sdim} cpu_desc_list;
1092214571Sdim
1093214571Sdimint
1094214571Sdimprint_insn_mep (bfd_vma pc, disassemble_info *info)
1095214571Sdim{
1096214571Sdim  static cpu_desc_list *cd_list = 0;
1097214571Sdim  cpu_desc_list *cl = 0;
1098214571Sdim  static CGEN_CPU_DESC cd = 0;
1099214571Sdim  static CGEN_BITSET *prev_isa;
1100214571Sdim  static int prev_mach;
1101214571Sdim  static int prev_endian;
1102214571Sdim  int length;
1103214571Sdim  CGEN_BITSET *isa;
1104214571Sdim  int mach;
1105214571Sdim  int endian = (info->endian == BFD_ENDIAN_BIG
1106214571Sdim		? CGEN_ENDIAN_BIG
1107214571Sdim		: CGEN_ENDIAN_LITTLE);
1108214571Sdim  enum bfd_architecture arch;
1109214571Sdim
1110214571Sdim  /* ??? gdb will set mach but leave the architecture as "unknown" */
1111214571Sdim#ifndef CGEN_BFD_ARCH
1112214571Sdim#define CGEN_BFD_ARCH bfd_arch_mep
1113214571Sdim#endif
1114214571Sdim  arch = info->arch;
1115214571Sdim  if (arch == bfd_arch_unknown)
1116214571Sdim    arch = CGEN_BFD_ARCH;
1117214571Sdim
1118214571Sdim  /* There's no standard way to compute the machine or isa number
1119214571Sdim     so we leave it to the target.  */
1120214571Sdim#ifdef CGEN_COMPUTE_MACH
1121214571Sdim  mach = CGEN_COMPUTE_MACH (info);
1122214571Sdim#else
1123214571Sdim  mach = info->mach;
1124214571Sdim#endif
1125214571Sdim
1126214571Sdim#ifdef CGEN_COMPUTE_ISA
1127214571Sdim  {
1128214571Sdim    static CGEN_BITSET *permanent_isa;
1129214571Sdim
1130214571Sdim    if (!permanent_isa)
1131214571Sdim      permanent_isa = cgen_bitset_create (MAX_ISAS);
1132214571Sdim    isa = permanent_isa;
1133214571Sdim    cgen_bitset_clear (isa);
1134214571Sdim    cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
1135214571Sdim  }
1136214571Sdim#else
1137214571Sdim  isa = info->insn_sets;
1138214571Sdim#endif
1139214571Sdim
1140214571Sdim  /* If we've switched cpu's, try to find a handle we've used before */
1141214571Sdim  if (cd
1142214571Sdim      && (cgen_bitset_compare (isa, prev_isa) != 0
1143214571Sdim	  || mach != prev_mach
1144214571Sdim	  || endian != prev_endian))
1145214571Sdim    {
1146214571Sdim      cd = 0;
1147214571Sdim      for (cl = cd_list; cl; cl = cl->next)
1148214571Sdim	{
1149214571Sdim	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
1150214571Sdim	      cl->mach == mach &&
1151214571Sdim	      cl->endian == endian)
1152214571Sdim	    {
1153214571Sdim	      cd = cl->cd;
1154214571Sdim 	      prev_isa = cd->isas;
1155214571Sdim	      break;
1156214571Sdim	    }
1157214571Sdim	}
1158214571Sdim    }
1159214571Sdim
1160214571Sdim  /* If we haven't initialized yet, initialize the opcode table.  */
1161214571Sdim  if (! cd)
1162214571Sdim    {
1163214571Sdim      const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
1164214571Sdim      const char *mach_name;
1165214571Sdim
1166214571Sdim      if (!arch_type)
1167214571Sdim	abort ();
1168214571Sdim      mach_name = arch_type->printable_name;
1169214571Sdim
1170214571Sdim      prev_isa = cgen_bitset_copy (isa);
1171214571Sdim      prev_mach = mach;
1172214571Sdim      prev_endian = endian;
1173214571Sdim      cd = mep_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
1174214571Sdim				 CGEN_CPU_OPEN_BFDMACH, mach_name,
1175214571Sdim				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
1176214571Sdim				 CGEN_CPU_OPEN_END);
1177214571Sdim      if (!cd)
1178214571Sdim	abort ();
1179214571Sdim
1180214571Sdim      /* Save this away for future reference.  */
1181214571Sdim      cl = xmalloc (sizeof (struct cpu_desc_list));
1182214571Sdim      cl->cd = cd;
1183214571Sdim      cl->isa = prev_isa;
1184214571Sdim      cl->mach = mach;
1185214571Sdim      cl->endian = endian;
1186214571Sdim      cl->next = cd_list;
1187214571Sdim      cd_list = cl;
1188214571Sdim
1189214571Sdim      mep_cgen_init_dis (cd);
1190214571Sdim    }
1191214571Sdim
1192214571Sdim  /* We try to have as much common code as possible.
1193214571Sdim     But at this point some targets need to take over.  */
1194214571Sdim  /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
1195214571Sdim     but if not possible try to move this hook elsewhere rather than
1196214571Sdim     have two hooks.  */
1197214571Sdim  length = CGEN_PRINT_INSN (cd, pc, info);
1198214571Sdim  if (length > 0)
1199214571Sdim    return length;
1200214571Sdim  if (length < 0)
1201214571Sdim    return -1;
1202214571Sdim
1203214571Sdim  (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
1204214571Sdim  return cd->default_insn_bitsize / 8;
1205214571Sdim}
1206