cris-dis.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 1,405 行 · 第 1/3 页
C
1,405 行
/* Disassembler code for CRIS. Copyright 2000 Free Software Foundation, Inc. Contributed by Axis Communications AB, Lund, Sweden. Written by Hans-Peter Nilsson.This file is part of the GNU binutils and GDB, the GNU debugger.This program is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the FreeSoftware Foundation; either version 2 of the License, or (at your option)any later version.This program is distributed in the hope that it will be useful, but WITHOUTANY WARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License formore details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "dis-asm.h"#include "sysdep.h"#include "opcode/cris.h"#include "libiberty.h"/* No instruction will be disassembled longer than this. In theory, and in silicon, address prefixes can be cascaded. In practice, cascading is not used by GCC, and not supported by the assembler. */#ifndef MAX_BYTES_PER_CRIS_INSN#define MAX_BYTES_PER_CRIS_INSN 8#endif/* Whether or not to decode prefixes, folding it into the following instruction. FIXME: Make this optional later. */#ifndef PARSE_PREFIX#define PARSE_PREFIX 1#endif/* Sometimes we prefix all registers with this character. */#define REGISTER_PREFIX_CHAR '$'/* Whether or not to trace the following sequence: sub* X,r%d bound* Y,r%d adds.w [pc+r%d.w],pc This is the assembly form of a switch-statement in C. The "sub is optional. If there is none, then X will be zero. X is the value of the first case, Y is the number of cases (including default). This results in case offsets printed on the form: case N: -> case_address where N is an estimation on the corresponding 'case' operand in C, and case_address is where execution of that case continues after the sequence presented above. The old style of output was to print the offsets as instructions, which made it hard to follow "case"-constructs in the disassembly, and caused a lot of annoying warnings about undefined instructions. FIXME: Make this optional later. */#ifndef TRACE_CASE#define TRACE_CASE 1#endif/* Value of first element in switch. */static long case_offset = 0;/* How many more case-offsets to print. */static long case_offset_counter = 0;/* Number of case offsets. */static long no_of_case_offsets = 0;/* Candidate for next case_offset. */static long last_immediate = 0;static int number_of_bits PARAMS ((unsigned int));static char *format_hex PARAMS ((unsigned long, char *));static char *format_dec PARAMS ((long, char *, int));static char *format_reg PARAMS ((int, char *, boolean));static int cris_constraint PARAMS ((const char *, unsigned int, unsigned int));static unsigned bytes_to_skip PARAMS ((unsigned int, const struct cris_opcode *));static char *print_flags PARAMS ((unsigned int, char *));static void print_with_operands PARAMS ((const struct cris_opcode *, unsigned int, unsigned char *, bfd_vma, disassemble_info *, const struct cris_opcode *, unsigned int, unsigned char *, boolean));static const struct cris_spec_reg *spec_reg_info PARAMS ((unsigned int));static int print_insn_cris_generic PARAMS ((bfd_vma, disassemble_info *, boolean));static int print_insn_cris_with_register_prefix PARAMS ((bfd_vma, disassemble_info *));static int print_insn_cris_without_register_prefix PARAMS ((bfd_vma, disassemble_info *));/* Return the descriptor of a special register. FIXME: Depend on a CPU-version specific argument when all machinery is in place. */static const struct cris_spec_reg *spec_reg_info (sreg) unsigned int sreg;{ int i; for (i = 0; cris_spec_regs[i].name != NULL; i++) { if (cris_spec_regs[i].number == sreg) return &cris_spec_regs[i]; } return NULL;}/* Return the number of bits in the argument. */static intnumber_of_bits (val) unsigned int val;{ int bits; for (bits = 0; val != 0; val &= val-1) bits++; return bits;}/* Get an entry in the opcode-table. */static const struct cris_opcode *get_opcode_entry (insn, prefix_insn) unsigned int insn; unsigned int prefix_insn;{ /* For non-prefixed insns, we keep a table of pointers, indexed by the insn code. Each entry is initialized when found to be NULL. */ static const struct cris_opcode **opc_table = NULL; const struct cris_opcode *max_matchedp = NULL; const struct cris_opcode **prefix_opc_table = NULL; /* We hold a table for each prefix that need to be handled differently. */ static const struct cris_opcode **dip_prefixes = NULL; static const struct cris_opcode **bdapq_m1_prefixes = NULL; static const struct cris_opcode **bdapq_m2_prefixes = NULL; static const struct cris_opcode **bdapq_m4_prefixes = NULL; static const struct cris_opcode **rest_prefixes = NULL; /* Allocate and clear the opcode-table. */ if (opc_table == NULL) { opc_table = xmalloc (65536 * sizeof (opc_table[0])); memset (opc_table, 0, 65536 * sizeof (const struct cris_opcode *)); dip_prefixes = xmalloc (65536 * sizeof (const struct cris_opcode **)); memset (dip_prefixes, 0, 65536 * sizeof (dip_prefixes[0])); bdapq_m1_prefixes = xmalloc (65536 * sizeof (const struct cris_opcode **)); memset (bdapq_m1_prefixes, 0, 65536 * sizeof (bdapq_m1_prefixes[0])); bdapq_m2_prefixes = xmalloc (65536 * sizeof (const struct cris_opcode **)); memset (bdapq_m2_prefixes, 0, 65536 * sizeof (bdapq_m2_prefixes[0])); bdapq_m4_prefixes = xmalloc (65536 * sizeof (const struct cris_opcode **)); memset (bdapq_m4_prefixes, 0, 65536 * sizeof (bdapq_m4_prefixes[0])); rest_prefixes = xmalloc (65536 * sizeof (const struct cris_opcode **)); memset (rest_prefixes, 0, 65536 * sizeof (rest_prefixes[0])); } /* Get the right table if this is a prefix. This code is connected to cris_constraints in that it knows what prefixes play a role in recognition of patterns; the necessary state is reflected by which table is used. If constraints involving match or non-match of prefix insns are changed, then this probably needs changing too. */ if (prefix_insn != NO_CRIS_PREFIX) { const struct cris_opcode *popcodep = (opc_table[prefix_insn] != NULL ? opc_table[prefix_insn] : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX)); if (popcodep == NULL) return NULL; if (popcodep->match == BDAP_QUICK_OPCODE) { /* Since some offsets are recognized with "push" macros, we have to have different tables for them. */ int offset = (prefix_insn & 255); if (offset > 127) offset -= 256; switch (offset) { case -4: prefix_opc_table = bdapq_m4_prefixes; break; case -2: prefix_opc_table = bdapq_m2_prefixes; break; case -1: prefix_opc_table = bdapq_m1_prefixes; break; default: prefix_opc_table = rest_prefixes; break; } } else if (popcodep->match == DIP_OPCODE) /* We don't allow postincrement when the prefix is DIP, so use a different table for DIP. */ prefix_opc_table = dip_prefixes; else prefix_opc_table = rest_prefixes; } if (prefix_insn != NO_CRIS_PREFIX && prefix_opc_table[insn] != NULL) max_matchedp = prefix_opc_table[insn]; else if (prefix_insn == NO_CRIS_PREFIX && opc_table[insn] != NULL) max_matchedp = opc_table[insn]; else { const struct cris_opcode *opcodep; int max_level_of_match = -1; for (opcodep = cris_opcodes; opcodep->name != NULL; opcodep++) { int level_of_match; /* We give a double lead for bits matching the template in cris_opcodes. Not even, because then "move p8,r10" would be given 2 bits lead over "clear.d r10". When there's a tie, the first entry in the table wins. This is deliberate, to avoid a more complicated recognition formula. */ if ((opcodep->match & insn) == opcodep->match && (opcodep->lose & insn) == 0 && ((level_of_match = cris_constraint (opcodep->args, insn, prefix_insn)) >= 0) && ((level_of_match += 2 * number_of_bits (opcodep->match | opcodep->lose)) > max_level_of_match)) { max_matchedp = opcodep; max_level_of_match = level_of_match; /* If there was a full match, never mind looking further. */ if (level_of_match >= 2 * 16) break; } } /* Fill in the new entry. If there are changes to the opcode-table involving prefixes, and disassembly then does not work correctly, try removing the else-clause below that fills in the prefix-table. If that helps, you need to change the prefix_opc_table setting above, or something related. */ if (prefix_insn == NO_CRIS_PREFIX) opc_table[insn] = max_matchedp; else prefix_opc_table[insn] = max_matchedp; } return max_matchedp;}/* Format number as hex with a leading "0x" into outbuffer. */static char *format_hex (number, outbuffer) unsigned long number; char *outbuffer;{ /* Obfuscate to avoid warning on 32-bit host, but properly truncate negative numbers on >32-bit hosts. */ if (sizeof (number) > 4) number &= (1 << (sizeof (number) > 4 ? 32 : 1)) - 1; sprintf (outbuffer, "0x%lx", number); /* Save this value for the "case" support. */ if (TRACE_CASE) last_immediate = number; return outbuffer + strlen (outbuffer);}/* Format number as decimal into outbuffer. Parameter signedp says whether the number should be formatted as signed (!= 0) or unsigned (== 0). */static char *format_dec (number, outbuffer, signedp) long number; char *outbuffer; int signedp;{ last_immediate = number; sprintf (outbuffer, signedp ? "%ld" : "%lu", number); return outbuffer + strlen (outbuffer);}/* Format the name of the general register regno into outbuffer. */static char *format_reg (regno, outbuffer_start, with_reg_prefix) int regno; char *outbuffer_start; boolean with_reg_prefix;{ char *outbuffer = outbuffer_start; if (with_reg_prefix) *outbuffer++ = REGISTER_PREFIX_CHAR; switch (regno) { case 15: strcpy (outbuffer, "pc"); break; case 14: strcpy (outbuffer, "sp"); break; default: sprintf (outbuffer, "r%d", regno); break; } return outbuffer_start + strlen (outbuffer_start);}/* Return -1 if the constraints of a bitwise-matched instruction say that there is no match. Otherwise return a nonnegative number indicating the confidence in the match (higher is better). */static intcris_constraint (cs, insn, prefix_insn) const char *cs; unsigned int insn; unsigned int prefix_insn;{ int retval = 0; int tmp; int prefix_ok = 0; const char *s; for (s = cs; *s; s++) switch (*s) { case '!': /* Do not recognize "pop" if there's a prefix. */ if (prefix_insn != NO_CRIS_PREFIX) return -1; break; case 'M': /* Size modifier for "clear", i.e. special register 0, 4 or 8. Check that it is one of them. Only special register 12 could be mismatched, but checking for matches is more logical than checking for mismatches when there are only a few cases. */ tmp = ((insn >> 12) & 0xf); if (tmp != 0 && tmp != 4 && tmp != 8) return -1; break; case 'm': if ((insn & 0x30) == 0x30) return -1; break; case 'S': /* A prefix operand without side-effect. */ if (prefix_insn != NO_CRIS_PREFIX && (insn & 0x400) == 0) { prefix_ok = 1; break; } else return -1; case 's': case 'y': /* If this is a prefixed insn with postincrement (side-effect), the prefix must not be DIP. */ if (prefix_insn != NO_CRIS_PREFIX) { if (insn & 0x400) { const struct cris_opcode *prefix_opcodep = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX); if (prefix_opcodep->match == DIP_OPCODE) return -1; } prefix_ok = 1; } break; case 'B': /* If we don't fall through, then the prefix is ok. */ prefix_ok = 1; /* A "push" prefix. Check for valid "push" size. In case of special register, it may be != 4. */ if (prefix_insn != NO_CRIS_PREFIX) { /* Match the prefix insn to BDAPQ. */ const struct cris_opcode *prefix_opcodep = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX); if (prefix_opcodep->match == BDAP_QUICK_OPCODE) { int pushsize = (prefix_insn & 255); if (pushsize > 127) pushsize -= 256; if (s[1] == 'P') { unsigned int spec_reg = (insn >> 12) & 15; const struct cris_spec_reg *sregp = spec_reg_info (spec_reg); /* For a special-register, the "prefix size" must match the size of the register. */ if (sregp && sregp->reg_size == (unsigned int) -pushsize) break; } else if (s[1] == 'R') { if ((insn & 0x30) == 0x20 && pushsize == -4) break; } /* FIXME: Should abort here; next constraint letter *must* be 'P' or 'R'. */ } } return -1; case 'D':
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?