* cgen-dis.in (print_normal): CGEN_OPERAND_FAKE renamed to
[deliverable/binutils-gdb.git] / opcodes / cgen-dis.in
1 /* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
3
4 THIS FILE IS USED TO GENERATE @prefix@-dis.c.
5
6 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
7
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation, Inc.,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23
24 #include "sysdep.h"
25 #include <stdio.h>
26 #include "ansidecl.h"
27 #include "dis-asm.h"
28 #include "bfd.h"
29 #include "symcat.h"
30 #include "@prefix@-opc.h"
31 #include "opintl.h"
32
33 #undef INLINE
34 #ifdef __GNUC__
35 #define INLINE __inline__
36 #else
37 #define INLINE
38 #endif
39
40 /* Default text to print if an instruction isn't recognized. */
41 #define UNKNOWN_INSN_MSG _("*unknown*")
42
43 static int extract_normal
44 PARAMS ((CGEN_OPCODE_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_BYTES,
45 unsigned int, int, int, int, long *));
46 static void print_normal
47 PARAMS ((CGEN_OPCODE_DESC, PTR, long, unsigned int, bfd_vma, int));
48 static void print_address
49 PARAMS ((CGEN_OPCODE_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
50 static void print_keyword
51 PARAMS ((CGEN_OPCODE_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
52 static int extract_insn_normal
53 PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
54 unsigned long, CGEN_FIELDS *, bfd_vma));
55 static void print_insn_normal
56 PARAMS ((CGEN_OPCODE_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
57 bfd_vma, int));
58 static int print_insn PARAMS ((CGEN_OPCODE_DESC, bfd_vma,
59 disassemble_info *, char *, int));
60 static int default_print_insn
61 PARAMS ((CGEN_OPCODE_DESC, bfd_vma, disassemble_info *));
62 \f
63 /* -- disassembler routines inserted here */
64 \f
65 #if ! CGEN_INT_INSN_P
66
67 /* Subroutine of extract_normal. */
68
69 static INLINE long
70 extract_1 (od, ex_info, start, length, word_length, bufp)
71 CGEN_OPCODE_DESC od;
72 CGEN_EXTRACT_INFO *info;
73 int start,length,word_length;
74 unsigned char *bufp;
75 {
76 unsigned long x,mask;
77 int shift;
78 int big_p = CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG;
79
80 /* FIXME: Need to use ex_info to ensure bytes have been fetched. */
81
82 switch (word_length)
83 {
84 case 8:
85 x = *bufp;
86 break;
87 case 16:
88 if (big_p)
89 x = bfd_getb16 (bufp);
90 else
91 x = bfd_getl16 (bufp);
92 break;
93 case 24:
94 /* ??? This may need reworking as these cases don't necessarily
95 want the first byte and the last two bytes handled like this. */
96 if (big_p)
97 x = (bfd_getb8 (bufp) << 16) | bfd_getb16 (bufp + 1);
98 else
99 x = bfd_getl16 (bufp) | (bfd_getb8 (bufp + 2) << 16);
100 break;
101 case 32:
102 if (big_p)
103 x = bfd_getb32 (bufp);
104 else
105 x = bfd_getl32 (bufp);
106 break;
107 default :
108 abort ();
109 }
110
111 /* Written this way to avoid undefined behaviour. */
112 mask = (((1L << (length - 1)) - 1) << 1) | 1;
113 if (CGEN_INSN_LSB0_P)
114 shift = start;
115 else
116 shift = (word_length - (start + length));
117 return (x >> shift) & mask;
118 }
119
120 #endif /* ! CGEN_INT_INSN_P */
121
122 /* Default extraction routine.
123
124 ATTRS is a mask of the boolean attributes. We only need `unsigned',
125 but for generality we take a bitmask of all of them. */
126
127 /* ??? This doesn't handle bfd_vma's. Create another function when
128 necessary. */
129
130 static int
131 extract_normal (od, ex_info, insn_value, attrs, start, length, total_length, valuep)
132 CGEN_OPCODE_DESC od;
133 CGEN_EXTRACT_INFO *ex_info;
134 CGEN_INSN_BYTES insn_value;
135 unsigned int attrs;
136 int start, length, total_length;
137 long *valuep;
138 {
139 unsigned long value;
140
141 /* If LENGTH is zero, this operand doesn't contribute to the value
142 so give it a standard value of zero. */
143 if (length == 0)
144 {
145 *valuep = 0;
146 return 1;
147 }
148
149 #if CGEN_INT_INSN_P
150
151 {
152 /* Written this way to avoid undefined behaviour. */
153 unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
154
155 if (CGEN_INSN_LSB0_P)
156 value = insn_value >> start;
157 else
158 value = insn_value >> (total_length - (start + length));
159 value &= mask;
160 /* sign extend? */
161 if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
162 && (value & (1L << (length - 1))))
163 value |= ~mask;
164 }
165
166 #else
167
168 /* The hard case is probably too slow for the normal cases.
169 It's certainly more difficult to understand than the normal case.
170 Thus this is split into two. Keep it that way. The hard case is defined
171 to be when a field straddles a (loosely defined) word boundary
172 (??? which may require target specific help to determine). */
173
174 #if 0 /*wip*/
175
176 #define HARD_CASE_P 0 /* FIXME:wip */
177
178 if (HARD_CASE_P)
179 {
180 }
181 #endif
182 else
183 {
184 unsigned char *bufp = (unsigned char *) insn_value;
185
186 if (length > 32)
187 abort ();
188
189 /* Adjust start,total_length,bufp to point to the pseudo-word that holds
190 the value. For example in a 48 bit insn where the value to insert
191 (say an immediate value) is the last 16 bits then word_length here
192 would be 16. To handle a 24 bit insn with an 18 bit immediate,
193 extract_1 handles 24 bits (using a combination of bfd_get8,16). */
194
195 if (total_length > 32)
196 {
197 int needed_width = start % 8 + length;
198 int fetch_length = (needed_width <= 8 ? 8
199 : needed_width <= 16 ? 16
200 : 32);
201
202 if (CGEN_INSN_LSB0_P)
203 {
204 if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
205 {
206 abort (); /* wip */
207 }
208 else
209 {
210 int offset = start & ~7;
211
212 bufp += offset / 8;
213 start -= offset;
214 total_length -= offset;
215 }
216 }
217 else
218 {
219 if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
220 {
221 int offset = start & ~7;
222
223 bufp += offset / 8;
224 start -= offset;
225 total_length -= offset;
226 }
227 else
228 {
229 abort (); /* wip */
230 }
231 }
232 }
233
234 /* FIXME: which bytes are being extracted have been lost. */
235 value = extract_1 (od, ex_info, start, length, total_length, bufp);
236 }
237
238 #endif /* ! CGEN_INT_INSN_P */
239
240 *valuep = value;
241
242 /* FIXME: for now */
243 return 1;
244 }
245
246 /* Default print handler. */
247
248 static void
249 print_normal (od, dis_info, value, attrs, pc, length)
250 CGEN_OPCODE_DESC od;
251 PTR dis_info;
252 long value;
253 unsigned int attrs;
254 bfd_vma pc;
255 int length;
256 {
257 disassemble_info *info = (disassemble_info *) dis_info;
258
259 #ifdef CGEN_PRINT_NORMAL
260 CGEN_PRINT_NORMAL (od, info, value, attrs, pc, length);
261 #endif
262
263 /* Print the operand as directed by the attributes. */
264 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
265 ; /* nothing to do */
266 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
267 (*info->fprintf_func) (info->stream, "0x%lx", value);
268 else
269 (*info->fprintf_func) (info->stream, "%ld", value);
270 }
271
272 /* Default address handler. */
273
274 static void
275 print_address (od, dis_info, value, attrs, pc, length)
276 CGEN_OPCODE_DESC od;
277 PTR dis_info;
278 bfd_vma value;
279 unsigned int attrs;
280 bfd_vma pc;
281 int length;
282 {
283 disassemble_info *info = (disassemble_info *) dis_info;
284
285 #ifdef CGEN_PRINT_ADDRESS
286 CGEN_PRINT_ADDRESS (od, info, value, attrs, pc, length);
287 #endif
288
289 /* Print the operand as directed by the attributes. */
290 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
291 ; /* nothing to do */
292 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
293 (*info->print_address_func) (value, info);
294 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
295 (*info->print_address_func) (value, info);
296 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
297 (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
298 else
299 (*info->fprintf_func) (info->stream, "%ld", (long) value);
300 }
301
302 /* Keyword print handler. */
303
304 static void
305 print_keyword (od, dis_info, keyword_table, value, attrs)
306 CGEN_OPCODE_DESC od;
307 PTR dis_info;
308 CGEN_KEYWORD *keyword_table;
309 long value;
310 unsigned int attrs;
311 {
312 disassemble_info *info = (disassemble_info *) dis_info;
313 const CGEN_KEYWORD_ENTRY *ke;
314
315 ke = cgen_keyword_lookup_value (keyword_table, value);
316 if (ke != NULL)
317 (*info->fprintf_func) (info->stream, "%s", ke->name);
318 else
319 (*info->fprintf_func) (info->stream, "???");
320 }
321 \f
322 /* Default insn extractor.
323
324 INSN_VALUE is the first CGEN_BASE_INSN_SIZE bytes, translated to host order.
325 The extracted fields are stored in FIELDS.
326 EX_INFO is used to handle reading variable length insns.
327 Return the length of the insn in bits, or 0 if no match,
328 or -1 if an error occurs fetching data (memory_error_func will have
329 been called). */
330
331 static int
332 extract_insn_normal (od, insn, ex_info, insn_value, fields, pc)
333 CGEN_OPCODE_DESC od;
334 const CGEN_INSN *insn;
335 CGEN_EXTRACT_INFO *ex_info;
336 unsigned long insn_value;
337 CGEN_FIELDS *fields;
338 bfd_vma pc;
339 {
340 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
341 const unsigned char *syn;
342
343 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
344
345 CGEN_INIT_EXTRACT (od);
346
347 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
348 {
349 int length;
350
351 if (CGEN_SYNTAX_CHAR_P (*syn))
352 continue;
353
354 length = @arch@_cgen_extract_operand (od, CGEN_SYNTAX_FIELD (*syn),
355 ex_info, insn_value, fields, pc);
356 if (length <= 0)
357 return length;
358 }
359
360 /* We recognized and successfully extracted this insn. */
361 return CGEN_INSN_BITSIZE (insn);
362 }
363
364 /* Default insn printer.
365
366 DIS_INFO is defined as `PTR' so the disassembler needn't know anything
367 about disassemble_info. */
368
369 static void
370 print_insn_normal (od, dis_info, insn, fields, pc, length)
371 CGEN_OPCODE_DESC od;
372 PTR dis_info;
373 const CGEN_INSN *insn;
374 CGEN_FIELDS *fields;
375 bfd_vma pc;
376 int length;
377 {
378 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
379 disassemble_info *info = (disassemble_info *) dis_info;
380 const unsigned char *syn;
381
382 CGEN_INIT_PRINT (od);
383
384 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
385 {
386 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
387 {
388 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
389 continue;
390 }
391 if (CGEN_SYNTAX_CHAR_P (*syn))
392 {
393 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
394 continue;
395 }
396
397 /* We have an operand. */
398 @arch@_cgen_print_operand (od, CGEN_SYNTAX_FIELD (*syn), info,
399 fields, CGEN_INSN_ATTRS (insn), pc, length);
400 }
401 }
402 \f
403 /* Utility to print an insn.
404 BUF is the base part of the insn, target byte order, BUFLEN bytes long.
405 The result is the size of the insn in bytes or zero for an unknown insn
406 or -1 if an error occurs fetching data (memory_error_func will have
407 been called). */
408
409 static int
410 print_insn (od, pc, info, buf, buflen)
411 CGEN_OPCODE_DESC od;
412 bfd_vma pc;
413 disassemble_info *info;
414 char *buf;
415 int buflen;
416 {
417 unsigned long insn_value;
418 const CGEN_INSN_LIST *insn_list;
419 CGEN_EXTRACT_INFO ex_info;
420
421 ex_info.dis_info = info;
422 ex_info.valid = (1 << CGEN_BASE_INSN_SIZE) - 1;
423 ex_info.bytes = buf;
424
425 switch (buflen)
426 {
427 case 1:
428 insn_value = buf[0];
429 break;
430 case 2:
431 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
432 break;
433 case 4:
434 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
435 break;
436 default:
437 abort ();
438 }
439
440 /* The instructions are stored in hash lists.
441 Pick the first one and keep trying until we find the right one. */
442
443 insn_list = CGEN_DIS_LOOKUP_INSN (od, buf, insn_value);
444 while (insn_list != NULL)
445 {
446 const CGEN_INSN *insn = insn_list->insn;
447 CGEN_FIELDS fields;
448 int length;
449
450 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
451 /* Supported by this cpu? */
452 if (! @arch@_cgen_insn_supported (od, insn))
453 continue;
454 #endif
455
456 /* Basic bit mask must be correct. */
457 /* ??? May wish to allow target to defer this check until the extract
458 handler. */
459 if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
460 {
461 /* Printing is handled in two passes. The first pass parses the
462 machine insn and extracts the fields. The second pass prints
463 them. */
464
465 length = (*CGEN_EXTRACT_FN (insn)) (od, insn, &ex_info, insn_value,
466 &fields, pc);
467 /* length < 0 -> error */
468 if (length < 0)
469 return length;
470 if (length > 0)
471 {
472 (*CGEN_PRINT_FN (insn)) (od, info, insn, &fields, pc, length);
473 /* length is in bits, result is in bytes */
474 return length / 8;
475 }
476 }
477
478 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
479 }
480
481 return 0;
482 }
483
484 /* Default value for CGEN_PRINT_INSN.
485 The result is the size of the insn in bytes or zero for an unknown insn
486 or -1 if an error occured fetching bytes. */
487
488 #ifndef CGEN_PRINT_INSN
489 #define CGEN_PRINT_INSN default_print_insn
490 #endif
491
492 static int
493 default_print_insn (od, pc, info)
494 CGEN_OPCODE_DESC od;
495 bfd_vma pc;
496 disassemble_info *info;
497 {
498 char buf[CGEN_MAX_INSN_SIZE];
499 int status;
500
501 /* Read the base part of the insn. */
502
503 status = (*info->read_memory_func) (pc, buf, CGEN_BASE_INSN_SIZE, info);
504 if (status != 0)
505 {
506 (*info->memory_error_func) (status, pc, info);
507 return -1;
508 }
509
510 return print_insn (od, pc, info, buf, CGEN_BASE_INSN_SIZE);
511 }
512
513 /* Main entry point.
514 Print one instruction from PC on INFO->STREAM.
515 Return the size of the instruction (in bytes). */
516
517 int
518 print_insn_@arch@ (pc, info)
519 bfd_vma pc;
520 disassemble_info *info;
521 {
522 int length;
523 static CGEN_OPCODE_DESC od = 0;
524 int mach = info->mach;
525 int big_p = info->endian == BFD_ENDIAN_BIG;
526
527 /* If we haven't initialized yet, initialize the opcode table. */
528 if (! od)
529 {
530 od = @arch@_cgen_opcode_open (mach,
531 big_p ?
532 CGEN_ENDIAN_BIG
533 : CGEN_ENDIAN_LITTLE);
534 @arch@_cgen_init_dis (od);
535 }
536 /* If we've switched cpu's, re-initialize. */
537 /* ??? Perhaps we should use BFD_ENDIAN. */
538 else if (mach != CGEN_OPCODE_MACH (od)
539 || (CGEN_OPCODE_ENDIAN (od)
540 != (big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE)))
541 {
542 cgen_set_cpu (od, mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
543 }
544
545 /* We try to have as much common code as possible.
546 But at this point some targets need to take over. */
547 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
548 but if not possible try to move this hook elsewhere rather than
549 have two hooks. */
550 length = CGEN_PRINT_INSN (od, pc, info);
551 if (length > 0)
552 return length;
553 if (length < 0)
554 return -1;
555
556 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
557 return CGEN_DEFAULT_INSN_SIZE;
558 }
This page took 0.041583 seconds and 5 git commands to generate.