]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - opcodes/openrisc-dis.c
Update copyright years
[thirdparty/binutils-gdb.git] / opcodes / openrisc-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 (C) 1996-2014 Free Software Foundation, Inc.
8
9 This file is part of libopcodes.
10
11 This library is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3, or (at your option)
14 any later version.
15
16 It is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
19 License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
24
25 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
26 Keep that in mind. */
27
28 #include "sysdep.h"
29 #include <stdio.h>
30 #include "ansidecl.h"
31 #include "dis-asm.h"
32 #include "bfd.h"
33 #include "symcat.h"
34 #include "libiberty.h"
35 #include "openrisc-desc.h"
36 #include "openrisc-opc.h"
37 #include "opintl.h"
38
39 /* Default text to print if an instruction isn't recognized. */
40 #define UNKNOWN_INSN_MSG _("*unknown*")
41
42 static void print_normal
43 (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
44 static void print_address
45 (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
46 static void print_keyword
47 (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
48 static void print_insn_normal
49 (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
50 static int print_insn
51 (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, unsigned);
52 static int default_print_insn
53 (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
54 static int read_insn
55 (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
56 unsigned long *);
57 \f
58 /* -- disassembler routines inserted here. */
59
60
61 void openrisc_cgen_print_operand
62 (CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *, void const *, bfd_vma, int);
63
64 /* Main entry point for printing operands.
65 XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
66 of dis-asm.h on cgen.h.
67
68 This function is basically just a big switch statement. Earlier versions
69 used tables to look up the function to use, but
70 - if the table contains both assembler and disassembler functions then
71 the disassembler contains much of the assembler and vice-versa,
72 - there's a lot of inlining possibilities as things grow,
73 - using a switch statement avoids the function call overhead.
74
75 This function could be moved into `print_insn_normal', but keeping it
76 separate makes clear the interface between `print_insn_normal' and each of
77 the handlers. */
78
79 void
80 openrisc_cgen_print_operand (CGEN_CPU_DESC cd,
81 int opindex,
82 void * xinfo,
83 CGEN_FIELDS *fields,
84 void const *attrs ATTRIBUTE_UNUSED,
85 bfd_vma pc,
86 int length)
87 {
88 disassemble_info *info = (disassemble_info *) xinfo;
89
90 switch (opindex)
91 {
92 case OPENRISC_OPERAND_ABS_26 :
93 print_address (cd, info, fields->f_abs26, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
94 break;
95 case OPENRISC_OPERAND_DISP_26 :
96 print_address (cd, info, fields->f_disp26, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
97 break;
98 case OPENRISC_OPERAND_HI16 :
99 print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
100 break;
101 case OPENRISC_OPERAND_LO16 :
102 print_normal (cd, info, fields->f_lo16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
103 break;
104 case OPENRISC_OPERAND_OP_F_23 :
105 print_normal (cd, info, fields->f_op4, 0, pc, length);
106 break;
107 case OPENRISC_OPERAND_OP_F_3 :
108 print_normal (cd, info, fields->f_op5, 0, pc, length);
109 break;
110 case OPENRISC_OPERAND_RA :
111 print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r2, 0);
112 break;
113 case OPENRISC_OPERAND_RB :
114 print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r3, 0);
115 break;
116 case OPENRISC_OPERAND_RD :
117 print_keyword (cd, info, & openrisc_cgen_opval_h_gr, fields->f_r1, 0);
118 break;
119 case OPENRISC_OPERAND_SIMM_16 :
120 print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
121 break;
122 case OPENRISC_OPERAND_UI16NC :
123 print_normal (cd, info, fields->f_i16nc, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
124 break;
125 case OPENRISC_OPERAND_UIMM_16 :
126 print_normal (cd, info, fields->f_uimm16, 0, pc, length);
127 break;
128 case OPENRISC_OPERAND_UIMM_5 :
129 print_normal (cd, info, fields->f_uimm5, 0, pc, length);
130 break;
131
132 default :
133 /* xgettext:c-format */
134 fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
135 opindex);
136 abort ();
137 }
138 }
139
140 cgen_print_fn * const openrisc_cgen_print_handlers[] =
141 {
142 print_insn_normal,
143 };
144
145
146 void
147 openrisc_cgen_init_dis (CGEN_CPU_DESC cd)
148 {
149 openrisc_cgen_init_opcode_table (cd);
150 openrisc_cgen_init_ibld_table (cd);
151 cd->print_handlers = & openrisc_cgen_print_handlers[0];
152 cd->print_operand = openrisc_cgen_print_operand;
153 }
154
155 \f
156 /* Default print handler. */
157
158 static void
159 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
160 void *dis_info,
161 long value,
162 unsigned int attrs,
163 bfd_vma pc ATTRIBUTE_UNUSED,
164 int length ATTRIBUTE_UNUSED)
165 {
166 disassemble_info *info = (disassemble_info *) dis_info;
167
168 /* Print the operand as directed by the attributes. */
169 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
170 ; /* nothing to do */
171 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
172 (*info->fprintf_func) (info->stream, "%ld", value);
173 else
174 (*info->fprintf_func) (info->stream, "0x%lx", value);
175 }
176
177 /* Default address handler. */
178
179 static void
180 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
181 void *dis_info,
182 bfd_vma value,
183 unsigned int attrs,
184 bfd_vma pc ATTRIBUTE_UNUSED,
185 int length ATTRIBUTE_UNUSED)
186 {
187 disassemble_info *info = (disassemble_info *) dis_info;
188
189 /* Print the operand as directed by the attributes. */
190 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
191 ; /* Nothing to do. */
192 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
193 (*info->print_address_func) (value, info);
194 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
195 (*info->print_address_func) (value, info);
196 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
197 (*info->fprintf_func) (info->stream, "%ld", (long) value);
198 else
199 (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
200 }
201
202 /* Keyword print handler. */
203
204 static void
205 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
206 void *dis_info,
207 CGEN_KEYWORD *keyword_table,
208 long value,
209 unsigned int attrs ATTRIBUTE_UNUSED)
210 {
211 disassemble_info *info = (disassemble_info *) dis_info;
212 const CGEN_KEYWORD_ENTRY *ke;
213
214 ke = cgen_keyword_lookup_value (keyword_table, value);
215 if (ke != NULL)
216 (*info->fprintf_func) (info->stream, "%s", ke->name);
217 else
218 (*info->fprintf_func) (info->stream, "???");
219 }
220 \f
221 /* Default insn printer.
222
223 DIS_INFO is defined as `void *' so the disassembler needn't know anything
224 about disassemble_info. */
225
226 static void
227 print_insn_normal (CGEN_CPU_DESC cd,
228 void *dis_info,
229 const CGEN_INSN *insn,
230 CGEN_FIELDS *fields,
231 bfd_vma pc,
232 int length)
233 {
234 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
235 disassemble_info *info = (disassemble_info *) dis_info;
236 const CGEN_SYNTAX_CHAR_TYPE *syn;
237
238 CGEN_INIT_PRINT (cd);
239
240 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
241 {
242 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
243 {
244 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
245 continue;
246 }
247 if (CGEN_SYNTAX_CHAR_P (*syn))
248 {
249 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
250 continue;
251 }
252
253 /* We have an operand. */
254 openrisc_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
255 fields, CGEN_INSN_ATTRS (insn), pc, length);
256 }
257 }
258 \f
259 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
260 the extract info.
261 Returns 0 if all is well, non-zero otherwise. */
262
263 static int
264 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
265 bfd_vma pc,
266 disassemble_info *info,
267 bfd_byte *buf,
268 int buflen,
269 CGEN_EXTRACT_INFO *ex_info,
270 unsigned long *insn_value)
271 {
272 int status = (*info->read_memory_func) (pc, buf, buflen, info);
273
274 if (status != 0)
275 {
276 (*info->memory_error_func) (status, pc, info);
277 return -1;
278 }
279
280 ex_info->dis_info = info;
281 ex_info->valid = (1 << buflen) - 1;
282 ex_info->insn_bytes = buf;
283
284 *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
285 return 0;
286 }
287
288 /* Utility to print an insn.
289 BUF is the base part of the insn, target byte order, BUFLEN bytes long.
290 The result is the size of the insn in bytes or zero for an unknown insn
291 or -1 if an error occurs fetching data (memory_error_func will have
292 been called). */
293
294 static int
295 print_insn (CGEN_CPU_DESC cd,
296 bfd_vma pc,
297 disassemble_info *info,
298 bfd_byte *buf,
299 unsigned int buflen)
300 {
301 CGEN_INSN_INT insn_value;
302 const CGEN_INSN_LIST *insn_list;
303 CGEN_EXTRACT_INFO ex_info;
304 int basesize;
305
306 /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
307 basesize = cd->base_insn_bitsize < buflen * 8 ?
308 cd->base_insn_bitsize : buflen * 8;
309 insn_value = cgen_get_insn_value (cd, buf, basesize);
310
311
312 /* Fill in ex_info fields like read_insn would. Don't actually call
313 read_insn, since the incoming buffer is already read (and possibly
314 modified a la m32r). */
315 ex_info.valid = (1 << buflen) - 1;
316 ex_info.dis_info = info;
317 ex_info.insn_bytes = buf;
318
319 /* The instructions are stored in hash lists.
320 Pick the first one and keep trying until we find the right one. */
321
322 insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
323 while (insn_list != NULL)
324 {
325 const CGEN_INSN *insn = insn_list->insn;
326 CGEN_FIELDS fields;
327 int length;
328 unsigned long insn_value_cropped;
329
330 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
331 /* Not needed as insn shouldn't be in hash lists if not supported. */
332 /* Supported by this cpu? */
333 if (! openrisc_cgen_insn_supported (cd, insn))
334 {
335 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
336 continue;
337 }
338 #endif
339
340 /* Basic bit mask must be correct. */
341 /* ??? May wish to allow target to defer this check until the extract
342 handler. */
343
344 /* Base size may exceed this instruction's size. Extract the
345 relevant part from the buffer. */
346 if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
347 (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
348 insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
349 info->endian == BFD_ENDIAN_BIG);
350 else
351 insn_value_cropped = insn_value;
352
353 if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
354 == CGEN_INSN_BASE_VALUE (insn))
355 {
356 /* Printing is handled in two passes. The first pass parses the
357 machine insn and extracts the fields. The second pass prints
358 them. */
359
360 /* Make sure the entire insn is loaded into insn_value, if it
361 can fit. */
362 if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
363 (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
364 {
365 unsigned long full_insn_value;
366 int rc = read_insn (cd, pc, info, buf,
367 CGEN_INSN_BITSIZE (insn) / 8,
368 & ex_info, & full_insn_value);
369 if (rc != 0)
370 return rc;
371 length = CGEN_EXTRACT_FN (cd, insn)
372 (cd, insn, &ex_info, full_insn_value, &fields, pc);
373 }
374 else
375 length = CGEN_EXTRACT_FN (cd, insn)
376 (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
377
378 /* Length < 0 -> error. */
379 if (length < 0)
380 return length;
381 if (length > 0)
382 {
383 CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
384 /* Length is in bits, result is in bytes. */
385 return length / 8;
386 }
387 }
388
389 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
390 }
391
392 return 0;
393 }
394
395 /* Default value for CGEN_PRINT_INSN.
396 The result is the size of the insn in bytes or zero for an unknown insn
397 or -1 if an error occured fetching bytes. */
398
399 #ifndef CGEN_PRINT_INSN
400 #define CGEN_PRINT_INSN default_print_insn
401 #endif
402
403 static int
404 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
405 {
406 bfd_byte buf[CGEN_MAX_INSN_SIZE];
407 int buflen;
408 int status;
409
410 /* Attempt to read the base part of the insn. */
411 buflen = cd->base_insn_bitsize / 8;
412 status = (*info->read_memory_func) (pc, buf, buflen, info);
413
414 /* Try again with the minimum part, if min < base. */
415 if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
416 {
417 buflen = cd->min_insn_bitsize / 8;
418 status = (*info->read_memory_func) (pc, buf, buflen, info);
419 }
420
421 if (status != 0)
422 {
423 (*info->memory_error_func) (status, pc, info);
424 return -1;
425 }
426
427 return print_insn (cd, pc, info, buf, buflen);
428 }
429
430 /* Main entry point.
431 Print one instruction from PC on INFO->STREAM.
432 Return the size of the instruction (in bytes). */
433
434 typedef struct cpu_desc_list
435 {
436 struct cpu_desc_list *next;
437 CGEN_BITSET *isa;
438 int mach;
439 int endian;
440 CGEN_CPU_DESC cd;
441 } cpu_desc_list;
442
443 int
444 print_insn_openrisc (bfd_vma pc, disassemble_info *info)
445 {
446 static cpu_desc_list *cd_list = 0;
447 cpu_desc_list *cl = 0;
448 static CGEN_CPU_DESC cd = 0;
449 static CGEN_BITSET *prev_isa;
450 static int prev_mach;
451 static int prev_endian;
452 int length;
453 CGEN_BITSET *isa;
454 int mach;
455 int endian = (info->endian == BFD_ENDIAN_BIG
456 ? CGEN_ENDIAN_BIG
457 : CGEN_ENDIAN_LITTLE);
458 enum bfd_architecture arch;
459
460 /* ??? gdb will set mach but leave the architecture as "unknown" */
461 #ifndef CGEN_BFD_ARCH
462 #define CGEN_BFD_ARCH bfd_arch_openrisc
463 #endif
464 arch = info->arch;
465 if (arch == bfd_arch_unknown)
466 arch = CGEN_BFD_ARCH;
467
468 /* There's no standard way to compute the machine or isa number
469 so we leave it to the target. */
470 #ifdef CGEN_COMPUTE_MACH
471 mach = CGEN_COMPUTE_MACH (info);
472 #else
473 mach = info->mach;
474 #endif
475
476 #ifdef CGEN_COMPUTE_ISA
477 {
478 static CGEN_BITSET *permanent_isa;
479
480 if (!permanent_isa)
481 permanent_isa = cgen_bitset_create (MAX_ISAS);
482 isa = permanent_isa;
483 cgen_bitset_clear (isa);
484 cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
485 }
486 #else
487 isa = info->insn_sets;
488 #endif
489
490 /* If we've switched cpu's, try to find a handle we've used before */
491 if (cd
492 && (cgen_bitset_compare (isa, prev_isa) != 0
493 || mach != prev_mach
494 || endian != prev_endian))
495 {
496 cd = 0;
497 for (cl = cd_list; cl; cl = cl->next)
498 {
499 if (cgen_bitset_compare (cl->isa, isa) == 0 &&
500 cl->mach == mach &&
501 cl->endian == endian)
502 {
503 cd = cl->cd;
504 prev_isa = cd->isas;
505 break;
506 }
507 }
508 }
509
510 /* If we haven't initialized yet, initialize the opcode table. */
511 if (! cd)
512 {
513 const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
514 const char *mach_name;
515
516 if (!arch_type)
517 abort ();
518 mach_name = arch_type->printable_name;
519
520 prev_isa = cgen_bitset_copy (isa);
521 prev_mach = mach;
522 prev_endian = endian;
523 cd = openrisc_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
524 CGEN_CPU_OPEN_BFDMACH, mach_name,
525 CGEN_CPU_OPEN_ENDIAN, prev_endian,
526 CGEN_CPU_OPEN_END);
527 if (!cd)
528 abort ();
529
530 /* Save this away for future reference. */
531 cl = xmalloc (sizeof (struct cpu_desc_list));
532 cl->cd = cd;
533 cl->isa = prev_isa;
534 cl->mach = mach;
535 cl->endian = endian;
536 cl->next = cd_list;
537 cd_list = cl;
538
539 openrisc_cgen_init_dis (cd);
540 }
541
542 /* We try to have as much common code as possible.
543 But at this point some targets need to take over. */
544 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
545 but if not possible try to move this hook elsewhere rather than
546 have two hooks. */
547 length = CGEN_PRINT_INSN (cd, pc, info);
548 if (length > 0)
549 return length;
550 if (length < 0)
551 return -1;
552
553 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
554 return cd->default_insn_bitsize / 8;
555 }