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