cris-dis.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 1,405 行 · 第 1/3 页
C
1,405 行
retval = (((insn >> 12) & 15) == (insn & 15)); if (!retval) return -1; else retval += 4; break; case 'P': { const struct cris_spec_reg *sregp = spec_reg_info ((insn >> 12) & 15); /* Since we match four bits, we will give a value of 4-1 = 3 in a match. If there is a corresponding exact match of a special register in another pattern, it will get a value of 4, which will be higher. This should be correct in that an exact pattern would match better than a general pattern. Note that there is a reason for not returning zero; the pattern for "clear" is partly matched in the bit-pattern (the two lower bits must be zero), while the bit-pattern for a move from a special register is matched in the register constraint. */ if (sregp != NULL) { retval += 3; break; } else return -1; } } if (prefix_insn != NO_CRIS_PREFIX && ! prefix_ok) return -1; return retval;}/* Return the length of an instruction. */static unsignedbytes_to_skip (insn, matchedp) unsigned int insn; const struct cris_opcode *matchedp;{ /* Each insn is a word plus "immediate" operands. */ unsigned to_skip = 2; const char *template = matchedp->args; const char *s; for (s = template; *s; s++) if (*s == 's' && (insn & 0x400) && (insn & 15) == 15) { /* Immediate via [pc+], so we have to check the size of the operand. */ int mode_size = 1 << ((insn >> 4) & (*template == 'z' ? 1 : 3)); if (matchedp->imm_oprnd_size == SIZE_FIX_32) to_skip += 4; else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG) { const struct cris_spec_reg *sregp = spec_reg_info ((insn >> 12) & 15); /* FIXME: Improve error handling; should have been caught earlier. */ if (sregp == NULL) return 2; /* PC is incremented by two, not one, for a byte. */ to_skip += (sregp->reg_size + 1) & ~1; } else to_skip += (mode_size + 1) & ~1; } else if (*s == 'b') to_skip += 2; return to_skip;}/* Print condition code flags. */static char *print_flags (insn, cp) unsigned int insn; char *cp;{ /* Use the v8 (Etrax 100) flag definitions for disassembly. The differences with v0 (Etrax 1..4) vs. Svinto are: v0 'd' <=> v8 'm' v0 'e' <=> v8 'b'. */ static const char fnames[] = "cvznxibm"; unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15)); int i; for (i = 0; i < 8; i++) if (flagbits & (1 << i)) *cp++ = fnames[i]; return cp;}/* Print out an insn with its operands, and update the info->insn_type fields. The prefix_opcodep and the rest hold a prefix insn that is supposed to be output as an address mode. */static voidprint_with_operands (opcodep, insn, buffer, addr, info, prefix_opcodep, prefix_insn, prefix_buffer, with_reg_prefix) const struct cris_opcode *opcodep; unsigned int insn; unsigned char *buffer; bfd_vma addr; disassemble_info *info; /* If a prefix insn was before this insn (and is supposed to be output as an address), here is a description of it. */ const struct cris_opcode *prefix_opcodep; unsigned int prefix_insn; unsigned char *prefix_buffer; boolean with_reg_prefix;{ /* Get a buffer of somewhat reasonable size where we store intermediate parts of the insn. */ char temp[sizeof (".d [$r13=$r12-2147483648],$r10") * 2]; char *tp = temp; static const char mode_char[] = "bwd?"; const char *s; const char *cs; /* Print out the name first thing we do. */ (*info->fprintf_func) (info->stream, "%s", opcodep->name); cs = opcodep->args; s = cs; /* Ignore any prefix indicator. */ if (*s == 'p') s++; if (*s == 'm' || *s == 'M' || *s == 'z') { *tp++ = '.'; /* Get the size-letter. */ *tp++ = *s == 'M' ? (insn & 0x8000 ? 'd' : insn & 0x4000 ? 'w' : 'b') : mode_char[(insn >> 4) & (*s == 'z' ? 1 : 3)]; /* Ignore the size and the space character that follows. */ s += 2; } /* Add a space if this isn't a long-branch, because for those will add the condition part of the name later. */ if (opcodep->match != (BRANCH_PC_LOW + BRANCH_INCR_HIGH * 256)) *tp++ = ' '; /* Fill in the insn-type if deducible from the name (and there's no better way). */ if (opcodep->name[0] == 'j') { if (strncmp (opcodep->name, "jsr", 3) == 0) /* It's "jsr" or "jsrc". */ info->insn_type = dis_jsr; else /* Any other jump-type insn is considered a branch. */ info->insn_type = dis_branch; } /* We might know some more fields right now. */ info->branch_delay_insns = opcodep->delayed; /* Handle operands. */ for (; *s; s++) { switch (*s) { case ',': *tp++ = *s; break; case '!': /* Ignore at this point; used at earlier stages to avoid recognition if there's a prefixes at something that in other ways looks like a "pop". */ break; case 'B': /* This was the prefix that made this a "push". We've already handled it by recognizing it, so signal that the prefix is handled by setting it to NULL. */ prefix_opcodep = NULL; break; case 'D': case 'r': tp = format_reg (insn & 15, tp, with_reg_prefix); break; case 'R': tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix); break; case 'y': case 'S': case 's': /* Any "normal" memory operand. */ if ((insn & 0x400) && (insn & 15) == 15) { /* We're looking at [pc+], i.e. we need to output an immediate number, where the size can depend on different things. */ long number; int signedp = ((*cs == 'z' && (insn & 0x20)) || opcodep->match == BDAP_QUICK_OPCODE); int nbytes; if (opcodep->imm_oprnd_size == SIZE_FIX_32) nbytes = 4; else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) { const struct cris_spec_reg *sregp = spec_reg_info ((insn >> 12) & 15); /* A NULL return should have been as a non-match earlier, so catch it as an internal error in the error-case below. */ if (sregp == NULL) /* Whatever non-valid size. */ nbytes = 42; else /* PC is always incremented by a multiple of two. */ nbytes = (sregp->reg_size + 1) & ~1; } else { int mode_size = 1 << ((insn >> 4) & (*cs == 'z' ? 1 : 3)); if (mode_size == 1) nbytes = 2; else nbytes = mode_size; } switch (nbytes) { case 1: number = buffer[2]; if (signedp && number > 127) number -= 256; break; case 2: number = buffer[2] + buffer[3] * 256; if (signedp && number > 32767) number -= 65536; break; case 4: number = buffer[2] + buffer[3] * 256 + buffer[4] * 65536 + buffer[5] * 0x1000000; break; default: strcpy (tp, "bug"); tp += 3; number = 42; } if ((*cs == 'z' && (insn & 0x20)) || (opcodep->match == BDAP_QUICK_OPCODE && (nbytes <= 2 || buffer[1 + nbytes] == 0))) tp = format_dec (number, tp, signedp); else { unsigned int highbyte = (number >> 24) & 0xff; /* Either output this as an address or as a number. If it's a dword with the same high-byte as the address of the insn, assume it's an address, and also if it's a non-zero non-0xff high-byte. If this is a jsr or a jump, then it's definitely an address. */ if (nbytes == 4 && (highbyte == ((addr >> 24) & 0xff) || (highbyte != 0 && highbyte != 0xff) || info->insn_type == dis_branch || info->insn_type == dis_jsr)) { /* Finish off and output previous formatted bytes. */ *tp = 0; tp = temp; if (temp[0]) (*info->fprintf_func) (info->stream, "%s", temp); (*info->print_address_func) ((bfd_vma) number, info); info->target = number; } else tp = format_hex (number, tp); } } else { /* Not an immediate number. Then this is a (possibly prefixed) memory operand. */ if (info->insn_type != dis_nonbranch) { int mode_size = 1 << ((insn >> 4) & (opcodep->args[0] == 'z' ? 1 : 3)); int size; info->insn_type = dis_dref; info->flags |= CRIS_DIS_FLAG_MEMREF; if (opcodep->imm_oprnd_size == SIZE_FIX_32) size = 4; else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG) { const struct cris_spec_reg *sregp = spec_reg_info ((insn >> 12) & 15); /* FIXME: Improve error handling; should have been caught earlier. */ if (sregp == NULL) size = 4; else size = sregp->reg_size; } else size = mode_size; info->data_size = size; } *tp++ = '['; if (prefix_opcodep /* We don't match dip with a postincremented field as a side-effect address mode. */ && ((insn & 0x400) == 0 || prefix_opcodep->match != DIP_OPCODE)) { if (insn & 0x400) { tp = format_reg (insn & 15, tp, with_reg_prefix); *tp++ = '='; } /* We mainly ignore the prefix format string when the address-mode syntax is output. */ switch (prefix_opcodep->match) { case DIP_OPCODE: /* It's [r], [r+] or [pc+]. */ if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15) { /* It's [pc+]. This cannot possibly be anything but an address. */ unsigned long number = prefix_buffer[2] + prefix_buffer[3] * 256 + prefix_buffer[4] * 65536 + prefix_buffer[5] * 0x1000000; info->target = (bfd_vma) number; /* Finish off and output previous formatted data. */ *tp = 0; tp = temp; if (temp[0]) (*info->fprintf_func) (info->stream, "%s", temp); (*info->print_address_func) ((bfd_vma) number, info); } else { /* For a memref in an address, we use target2. In this case, target is zero. */ info->flags |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG | CRIS_DIS_FLAG_MEM_TARGET2_MEM); info->target2 = prefix_insn & 15; *tp++ = '['; tp = format_reg (prefix_insn & 15, tp, with_reg_prefix); if (prefix_insn & 0x400) *tp++ = '+'; *tp++ = ']'; } break; case BDAP_QUICK_OPCODE: { int number; number = prefix_buffer[0]; if (number > 127) number -= 256; /* Output "reg+num" or, if num < 0, "reg-num". */ tp = format_reg ((prefix_insn >> 12) & 15, tp, with_reg_prefix); if (number >= 0) *tp++ = '+'; tp = format_dec (number, tp, 1); info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG; info->target = (prefix_insn >> 12) & 15; info->target2 = (bfd_vma) number; break; } case BIAP_OPCODE: /* Output "r+R.m". */ tp = format_reg (prefix_insn & 15, tp, with_reg_prefix); *tp++ = '+'; tp = format_reg ((prefix_insn >> 12) & 15, tp, with_reg_prefix); *tp++ = '.'; *tp++ = mode_char[(prefix_insn >> 4) & 3]; info->flags |= (CRIS_DIS_FLAG_MEM_TARGET2_IS_REG | CRIS_DIS_FLAG_MEM_TARGET_IS_REG | ((prefix_insn & 0x8000) ? CRIS_DIS_FLAG_MEM_TARGET2_MULT4 : ((prefix_insn & 0x8000) ? CRIS_DIS_FLAG_MEM_TARGET2_MULT2 : 0))); /* Is it the casejump? It's a "adds.w [pc+r%d.w],pc". */ if (insn == 0xf83f && (prefix_insn & ~0xf000) == 0x55f) /* Then start interpreting data as offsets. */ case_offset_counter = no_of_case_offsets; break; case BDAP_INDIR_OPCODE: /* Output "r+s.m", or, if "s" is [pc+], "r+s" or "r-s". */ tp = format_reg ((prefix_insn >> 12) & 15, tp, with_reg_prefix); if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15) { long number; unsigned int nbytes; /* It's a value. Get its size. */ int mode_size = 1 << ((prefix_insn >> 4) & 3); if (mode_size == 1) nbytes = 2; else nbytes = mode_size; switch (nbytes) { case 1:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?