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