/* The function nios2_print_insn_arg uses the character pointed to by ARGPTR to determine how it print the next token or separator character in the arguments to an instruction. */ static int nios2_print_insn_arg (const char *argptr, unsigned long opcode, bfd_vma address, disassemble_info *info, const struct nios2_opcode *op) { unsigned long i = 0; struct nios2_reg *reg_base; switch (*argptr) { case ',': case '(': case ')': (*info->fprintf_func) (info->stream, "%c", *argptr); break; case 'c': /* Control register index. */ switch (op->format) { case iw_r_type: i = GET_IW_R_IMM5 (opcode); break; case iw_F3X6L5_type: i = GET_IW_F3X6L5_IMM5 (opcode); break; default: bad_opcode (op); } reg_base = nios2_control_regs (); (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); break; case 'd': reg_base = nios2_regs; switch (op->format) { case iw_r_type: i = GET_IW_R_C (opcode); break; case iw_custom_type: i = GET_IW_CUSTOM_C (opcode); if (GET_IW_CUSTOM_READC (opcode) == 0) reg_base = nios2_coprocessor_regs (); break; case iw_F3X6L5_type: case iw_F3X6_type: i = GET_IW_F3X6L5_C (opcode); break; case iw_F3X8_type: i = GET_IW_F3X8_C (opcode); if (GET_IW_F3X8_READC (opcode) == 0) reg_base = nios2_coprocessor_regs (); break; case iw_F2_type: i = GET_IW_F2_B (opcode); break; default: bad_opcode (op); } if (i < NUMREGNAMES) (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); else (*info->fprintf_func) (info->stream, "unknown"); break; case 's': reg_base = nios2_regs; switch (op->format) { case iw_r_type: i = GET_IW_R_A (opcode); break; case iw_i_type: i = GET_IW_I_A (opcode); break; case iw_custom_type: i = GET_IW_CUSTOM_A (opcode); if (GET_IW_CUSTOM_READA (opcode) == 0) reg_base = nios2_coprocessor_regs (); break; case iw_F2I16_type: i = GET_IW_F2I16_A (opcode); break; case iw_F2X4I12_type: i = GET_IW_F2X4I12_A (opcode); break; case iw_F1X4I12_type: i = GET_IW_F1X4I12_A (opcode); break; case iw_F1X4L17_type: i = GET_IW_F1X4L17_A (opcode); break; case iw_F3X6L5_type: case iw_F3X6_type: i = GET_IW_F3X6L5_A (opcode); break; case iw_F2X6L10_type: i = GET_IW_F2X6L10_A (opcode); break; case iw_F3X8_type: i = GET_IW_F3X8_A (opcode); if (GET_IW_F3X8_READA (opcode) == 0) reg_base = nios2_coprocessor_regs (); break; case iw_F1X1_type: i = GET_IW_F1X1_A (opcode); break; case iw_F1I5_type: i = 27; /* Implicit stack pointer reference. */ break; case iw_F2_type: i = GET_IW_F2_A (opcode); break; default: bad_opcode (op); } if (i < NUMREGNAMES) (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); else (*info->fprintf_func) (info->stream, "unknown"); break; case 't': reg_base = nios2_regs; switch (op->format) { case iw_r_type: i = GET_IW_R_B (opcode); break; case iw_i_type: i = GET_IW_I_B (opcode); break; case iw_custom_type: i = GET_IW_CUSTOM_B (opcode); if (GET_IW_CUSTOM_READB (opcode) == 0) reg_base = nios2_coprocessor_regs (); break; case iw_F2I16_type: i = GET_IW_F2I16_B (opcode); break; case iw_F2X4I12_type: i = GET_IW_F2X4I12_B (opcode); break; case iw_F3X6L5_type: case iw_F3X6_type: i = GET_IW_F3X6L5_B (opcode); break; case iw_F2X6L10_type: i = GET_IW_F2X6L10_B (opcode); break; case iw_F3X8_type: i = GET_IW_F3X8_B (opcode); if (GET_IW_F3X8_READB (opcode) == 0) reg_base = nios2_coprocessor_regs (); break; case iw_F1I5_type: i = GET_IW_F1I5_B (opcode); break; case iw_F2_type: i = GET_IW_F2_B (opcode); break; case iw_T1X1I6_type: i = 0; break; default: bad_opcode (op); } if (i < NUMREGNAMES) (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); else (*info->fprintf_func) (info->stream, "unknown"); break; case 'D': switch (op->format) { case iw_T1I7_type: i = GET_IW_T1I7_A3 (opcode); break; case iw_T2X1L3_type: i = GET_IW_T2X1L3_B3 (opcode); break; case iw_T2X1I3_type: i = GET_IW_T2X1I3_B3 (opcode); break; case iw_T3X1_type: i = GET_IW_T3X1_C3 (opcode); break; case iw_T2X3_type: if (op->num_args == 3) i = GET_IW_T2X3_A3 (opcode); else i = GET_IW_T2X3_B3 (opcode); break; default: bad_opcode (op); } i = nios2_r2_reg3_mappings[i]; (*info->fprintf_func) (info->stream, "%s", nios2_regs[i].name); break; case 'M': /* 6-bit unsigned immediate with no shift. */ switch (op->format) { case iw_T1X1I6_type: i = GET_IW_T1X1I6_IMM6 (opcode); break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'N': /* 6-bit unsigned immediate with 2-bit shift. */ switch (op->format) { case iw_T1X1I6_type: i = GET_IW_T1X1I6_IMM6 (opcode) << 2; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'S': switch (op->format) { case iw_T1I7_type: i = GET_IW_T1I7_A3 (opcode); break; case iw_T2I4_type: i = GET_IW_T2I4_A3 (opcode); break; case iw_T2X1L3_type: i = GET_IW_T2X1L3_A3 (opcode); break; case iw_T2X1I3_type: i = GET_IW_T2X1I3_A3 (opcode); break; case iw_T3X1_type: i = GET_IW_T3X1_A3 (opcode); break; case iw_T2X3_type: i = GET_IW_T2X3_A3 (opcode); break; case iw_T1X1I6_type: i = GET_IW_T1X1I6_A3 (opcode); break; default: bad_opcode (op); } i = nios2_r2_reg3_mappings[i]; (*info->fprintf_func) (info->stream, "%s", nios2_regs[i].name); break; case 'T': switch (op->format) { case iw_T2I4_type: i = GET_IW_T2I4_B3 (opcode); break; case iw_T3X1_type: i = GET_IW_T3X1_B3 (opcode); break; case iw_T2X3_type: i = GET_IW_T2X3_B3 (opcode); break; default: bad_opcode (op); } i = nios2_r2_reg3_mappings[i]; (*info->fprintf_func) (info->stream, "%s", nios2_regs[i].name); break; case 'i': /* 16-bit signed immediate. */ switch (op->format) { case iw_i_type: i = (signed) (GET_IW_I_IMM16 (opcode) << 16) >> 16; break; case iw_F2I16_type: i = (signed) (GET_IW_F2I16_IMM16 (opcode) << 16) >> 16; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'I': /* 12-bit signed immediate. */ switch (op->format) { case iw_F2X4I12_type: i = (signed) (GET_IW_F2X4I12_IMM12 (opcode) << 20) >> 20; break; case iw_F1X4I12_type: i = (signed) (GET_IW_F1X4I12_IMM12 (opcode) << 20) >> 20; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'u': /* 16-bit unsigned immediate. */ switch (op->format) { case iw_i_type: i = GET_IW_I_IMM16 (opcode); break; case iw_F2I16_type: i = GET_IW_F2I16_IMM16 (opcode); break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'U': /* 7-bit unsigned immediate with 2-bit shift. */ switch (op->format) { case iw_T1I7_type: i = GET_IW_T1I7_IMM7 (opcode) << 2; break; case iw_X1I7_type: i = GET_IW_X1I7_IMM7 (opcode) << 2; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'V': /* 5-bit unsigned immediate with 2-bit shift. */ switch (op->format) { case iw_F1I5_type: i = GET_IW_F1I5_IMM5 (opcode) << 2; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'W': /* 4-bit unsigned immediate with 2-bit shift. */ switch (op->format) { case iw_T2I4_type: i = GET_IW_T2I4_IMM4 (opcode) << 2; break; case iw_L5I4X1_type: i = GET_IW_L5I4X1_IMM4 (opcode) << 2; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'X': /* 4-bit unsigned immediate with 1-bit shift. */ switch (op->format) { case iw_T2I4_type: i = GET_IW_T2I4_IMM4 (opcode) << 1; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'Y': /* 4-bit unsigned immediate without shift. */ switch (op->format) { case iw_T2I4_type: i = GET_IW_T2I4_IMM4 (opcode); break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'o': /* 16-bit signed immediate address offset. */ switch (op->format) { case iw_i_type: i = (signed) (GET_IW_I_IMM16 (opcode) << 16) >> 16; break; case iw_F2I16_type: i = (signed) (GET_IW_F2I16_IMM16 (opcode) << 16) >> 16; break; default: bad_opcode (op); } address = address + 4 + i; (*info->print_address_func) (address, info); break; case 'O': /* 10-bit signed address offset with 1-bit shift. */ switch (op->format) { case iw_I10_type: i = (signed) (GET_IW_I10_IMM10 (opcode) << 22) >> 21; break; default: bad_opcode (op); } address = address + 2 + i; (*info->print_address_func) (address, info); break; case 'P': /* 7-bit signed address offset with 1-bit shift. */ switch (op->format) { case iw_T1I7_type: i = (signed) (GET_IW_T1I7_IMM7 (opcode) << 25) >> 24; break; default: bad_opcode (op); } address = address + 2 + i; (*info->print_address_func) (address, info); break; case 'j': /* 5-bit unsigned immediate. */ switch (op->format) { case iw_r_type: i = GET_IW_R_IMM5 (opcode); break; case iw_F3X6L5_type: i = GET_IW_F3X6L5_IMM5 (opcode); break; case iw_F2X6L10_type: i = GET_IW_F2X6L10_MSB (opcode); break; case iw_X2L5_type: i = GET_IW_X2L5_IMM5 (opcode); break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'k': /* Second 5-bit unsigned immediate field. */ switch (op->format) { case iw_F2X6L10_type: i = GET_IW_F2X6L10_LSB (opcode); break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'l': /* 8-bit unsigned immediate. */ switch (op->format) { case iw_custom_type: i = GET_IW_CUSTOM_N (opcode); break; case iw_F3X8_type: i = GET_IW_F3X8_N (opcode); break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%lu", i); break; case 'm': /* 26-bit unsigned immediate. */ switch (op->format) { case iw_j_type: i = GET_IW_J_IMM26 (opcode); break; case iw_L26_type: i = GET_IW_L26_IMM26 (opcode); break; default: bad_opcode (op); } /* This translates to an address because it's only used in call instructions. */ address = (address & 0xf0000000) | (i << 2); (*info->print_address_func) (address, info); break; case 'e': /* Encoded enumeration for addi.n/subi.n. */ switch (op->format) { case iw_T2X1I3_type: i = nios2_r2_asi_n_mappings[GET_IW_T2X1I3_IMM3 (opcode)]; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%lu", i); break; case 'f': /* Encoded enumeration for slli.n/srli.n. */ switch (op->format) { case iw_T2X1L3_type: i = nios2_r2_shi_n_mappings[GET_IW_T2X1I3_IMM3 (opcode)]; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%lu", i); break; case 'g': /* Encoded enumeration for andi.n. */ switch (op->format) { case iw_T2I4_type: i = nios2_r2_andi_n_mappings[GET_IW_T2I4_IMM4 (opcode)]; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%lu", i); break; case 'h': /* Encoded enumeration for movi.n. */ switch (op->format) { case iw_T1I7_type: i = GET_IW_T1I7_IMM7 (opcode); if (i == 125) i = 0xff; else if (i == 126) i = -2; else if (i == 127) i = -1; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'R': { unsigned long reglist = 0; int dir = 1; int k, t; switch (op->format) { case iw_F1X4L17_type: /* Encoding for ldwm/stwm. */ i = GET_IW_F1X4L17_REGMASK (opcode); if (GET_IW_F1X4L17_RS (opcode)) { reglist = ((i << 14) & 0x00ffc000); if (i & (1 << 10)) reglist |= (1 << 28); if (i & (1 << 11)) reglist |= (1 << 31); } else reglist = i << 2; dir = GET_IW_F1X4L17_REGMASK (opcode) ? 1 : -1; break; case iw_L5I4X1_type: /* Encoding for push.n/pop.n. */ reglist |= (1 << 31); if (GET_IW_L5I4X1_FP (opcode)) reglist |= (1 << 28); if (GET_IW_L5I4X1_CS (opcode)) { int val = GET_IW_L5I4X1_REGRANGE (opcode); reglist |= nios2_r2_reg_range_mappings[val]; } dir = (op->match == MATCH_R2_POP_N ? 1 : -1); break; default: bad_opcode (op); } t = 0; (*info->fprintf_func) (info->stream, "{"); for (k = (dir == 1 ? 0 : 31); (dir == 1 && k < 32) || (dir == -1 && k >= 0); k += dir) if (reglist & (1 << k)) { if (t) (*info->fprintf_func) (info->stream, ","); else t++; (*info->fprintf_func) (info->stream, "%s", nios2_regs[k].name); } (*info->fprintf_func) (info->stream, "}"); break; } case 'B': /* Base register and options for ldwm/stwm. */ switch (op->format) { case iw_F1X4L17_type: if (GET_IW_F1X4L17_ID (opcode) == 0) (*info->fprintf_func) (info->stream, "--"); i = GET_IW_F1X4I12_A (opcode); (*info->fprintf_func) (info->stream, "(%s)", nios2_builtin_regs[i].name); if (GET_IW_F1X4L17_ID (opcode)) (*info->fprintf_func) (info->stream, "++"); if (GET_IW_F1X4L17_WB (opcode)) (*info->fprintf_func) (info->stream, ",writeback"); if (GET_IW_F1X4L17_PC (opcode)) (*info->fprintf_func) (info->stream, ",ret"); break; default: bad_opcode (op); } break; default: (*info->fprintf_func) (info->stream, "unknown"); break; } return 0; }
static CORE_ADDR nios2_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR start_pc, const CORE_ADDR current_pc, struct nios2_unwind_cache *cache, struct frame_info *this_frame) { /* Maximum lines of prologue to check. Note that this number should not be too large, else we can potentially end up iterating through unmapped memory. */ CORE_ADDR limit_pc = start_pc + 200; int regno; enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); /* Does the frame set up the FP register? */ int base_reg = 0; struct reg_value *value = cache->reg_value; struct reg_value temp_value[NIOS2_NUM_REGS]; int i; /* Save the starting PC so we can correct the pc after running through the prolog, using symbol info. */ CORE_ADDR pc = start_pc; /* Is this an exception handler? */ int exception_handler = 0; /* What was the original value of SP (or fake original value for functions which switch stacks? */ CORE_ADDR frame_high; /* Is this the end of the prologue? */ int within_prologue = 1; CORE_ADDR prologue_end; /* Is this the innermost function? */ int innermost = (this_frame ? (frame_relative_level (this_frame) == 0) : 1); if (nios2_debug) fprintf_unfiltered (gdb_stdlog, "{ nios2_analyze_prologue start=%s, current=%s ", paddress (gdbarch, start_pc), paddress (gdbarch, current_pc)); /* Set up the default values of the registers. */ nios2_setup_default (cache); prologue_end = start_pc; /* Find the prologue instructions. */ while (pc < limit_pc && within_prologue) { /* Present instruction. */ uint32_t insn; int prologue_insn = 0; if (pc == current_pc) { /* When we reach the current PC we must save the current register state (for the backtrace) but keep analysing because there might be more to find out (eg. is this an exception handler). */ memcpy (temp_value, value, sizeof (temp_value)); value = temp_value; if (nios2_debug) fprintf_unfiltered (gdb_stdlog, "*"); } insn = read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE, byte_order); pc += NIOS2_OPCODE_SIZE; if (nios2_debug) fprintf_unfiltered (gdb_stdlog, "[%08X]", insn); /* The following instructions can appear in the prologue. */ if ((insn & MASK_R1_ADD) == MATCH_R1_ADD) { /* ADD rc, ra, rb (also used for MOV) */ int ra = GET_IW_R_A (insn); int rb = GET_IW_R_B (insn); int rc = GET_IW_R_C (insn); if (rc == NIOS2_SP_REGNUM && rb == 0 && value[ra].reg == cache->reg_saved[NIOS2_SP_REGNUM].basereg) { /* If the previous value of SP is available somewhere near the new stack pointer value then this is a stack switch. */ /* If any registers were saved on the stack before then we can't backtrace into them now. */ for (i = 0 ; i < NIOS2_NUM_REGS ; i++) { if (cache->reg_saved[i].basereg == NIOS2_SP_REGNUM) cache->reg_saved[i].basereg = -1; if (value[i].reg == NIOS2_SP_REGNUM) value[i].reg = -1; } /* Create a fake "high water mark" 4 bytes above where SP was stored and fake up the registers to be consistent with that. */ value[NIOS2_SP_REGNUM].reg = NIOS2_SP_REGNUM; value[NIOS2_SP_REGNUM].offset = (value[ra].offset - cache->reg_saved[NIOS2_SP_REGNUM].addr - 4); cache->reg_saved[NIOS2_SP_REGNUM].basereg = NIOS2_SP_REGNUM; cache->reg_saved[NIOS2_SP_REGNUM].addr = -4; } else if (rc != 0) { if (value[rb].reg == 0) value[rc].reg = value[ra].reg; else if (value[ra].reg == 0) value[rc].reg = value[rb].reg; else value[rc].reg = -1; value[rc].offset = value[ra].offset + value[rb].offset; } prologue_insn = 1; } else if ((insn & MASK_R1_SUB) == MATCH_R1_SUB) { /* SUB rc, ra, rb */ int ra = GET_IW_R_A (insn); int rb = GET_IW_R_B (insn); int rc = GET_IW_R_C (insn); if (rc != 0) { if (value[rb].reg == 0) value[rc].reg = value[ra].reg; else value[rc].reg = -1; value[rc].offset = value[ra].offset - value[rb].offset; } } else if ((insn & MASK_R1_ADDI) == MATCH_R1_ADDI) { /* ADDI rb, ra, immed (also used for MOVI) */ short immed = GET_IW_I_IMM16 (insn); int ra = GET_IW_I_A (insn); int rb = GET_IW_I_B (insn); /* The first stack adjustment is part of the prologue. Any subsequent stack adjustments are either down to alloca or the epilogue so stop analysing when we hit them. */ if (rb == NIOS2_SP_REGNUM && (value[rb].offset != 0 || value[ra].reg != NIOS2_SP_REGNUM)) break; if (rb != 0) { value[rb].reg = value[ra].reg; value[rb].offset = value[ra].offset + immed; } prologue_insn = 1; } else if ((insn & MASK_R1_ORHI) == MATCH_R1_ORHI) { /* ORHI rb, ra, immed (also used for MOVHI) */ unsigned int immed = GET_IW_I_IMM16 (insn); int ra = GET_IW_I_A (insn); int rb = GET_IW_I_B (insn); if (rb != 0) { value[rb].reg = (value[ra].reg == 0) ? 0 : -1; value[rb].offset = value[ra].offset | (immed << 16); } } else if ((insn & MASK_R1_STW) == MATCH_R1_STW || (insn & MASK_R1_STWIO) == MATCH_R1_STWIO) { /* STW rb, immediate(ra) */ short immed16 = GET_IW_I_IMM16 (insn); int ra = GET_IW_I_A (insn); int rb = GET_IW_I_B (insn); /* Are we storing the original value of a register? For exception handlers the value of EA-4 (return address from interrupts etc) is sometimes stored. */ int orig = value[rb].reg; if (orig > 0 && (value[rb].offset == 0 || (orig == NIOS2_EA_REGNUM && value[rb].offset == -4))) { /* We are most interested in stores to the stack, but also take note of stores to other places as they might be useful later. */ if ((value[ra].reg == NIOS2_SP_REGNUM && cache->reg_saved[orig].basereg != NIOS2_SP_REGNUM) || cache->reg_saved[orig].basereg == -1) { if (pc < current_pc) { /* Save off callee saved registers. */ cache->reg_saved[orig].basereg = value[ra].reg; cache->reg_saved[orig].addr = value[ra].offset + immed16; } prologue_insn = 1; if (orig == NIOS2_EA_REGNUM || orig == NIOS2_ESTATUS_REGNUM) exception_handler = 1; } } else /* Non-stack memory writes are not part of the prologue. */ within_prologue = 0; } else if ((insn & MASK_R1_RDCTL) == MATCH_R1_RDCTL) { /* RDCTL rC, ctlN */ int rc = GET_IW_R_C (insn); int n = GET_IW_R_A (insn); if (rc != 0) { value[rc].reg = NIOS2_STATUS_REGNUM + n; value[rc].offset = 0; } prologue_insn = 1; } else if ((insn & MASK_R1_CALL) == MATCH_R1_CALL && value[8].reg == NIOS2_RA_REGNUM && value[8].offset == 0 && value[NIOS2_SP_REGNUM].reg == NIOS2_SP_REGNUM && value[NIOS2_SP_REGNUM].offset == 0) { /* A CALL instruction. This is treated as a call to mcount if ra has been stored into r8 beforehand and if it's before the stack adjust. Note mcount corrupts r2-r3, r9-r15 & ra. */ for (i = 2 ; i <= 3 ; i++) value[i].reg = -1; for (i = 9 ; i <= 15 ; i++) value[i].reg = -1; value[NIOS2_RA_REGNUM].reg = -1; prologue_insn = 1; } else if ((insn & 0xf83fffff) == 0xd800012e) { /* BGEU sp, rx, +8 BREAK 3 This instruction sequence is used in stack checking; we can ignore it. */ unsigned int next_insn = read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE, byte_order); if (next_insn != 0x003da0fa) within_prologue = 0; else pc += NIOS2_OPCODE_SIZE; } else if ((insn & 0xf800003f) == 0xd8000036) { /* BLTU sp, rx, .Lstackoverflow If the location branched to holds a BREAK 3 instruction then this is also stack overflow detection. We can ignore it. */ CORE_ADDR target_pc = pc + ((insn & 0x3fffc0) >> 6); unsigned int target_insn = read_memory_unsigned_integer (target_pc, NIOS2_OPCODE_SIZE, byte_order); if (target_insn != 0x003da0fa) within_prologue = 0; } /* Any other instructions are allowed to be moved up into the prologue. If we reach a branch, call or return then the prologue is considered over. We also consider a second stack adjustment as terminating the prologue (see above). */ else { switch (GET_IW_R1_OP (insn))
/* The function nios2_print_insn_arg uses the character pointed to by ARGPTR to determine how it print the next token or separator character in the arguments to an instruction. */ static int nios2_print_insn_arg (const char *argptr, unsigned long opcode, bfd_vma address, disassemble_info *info, const struct nios2_opcode *op) { unsigned long i = 0; struct nios2_reg *reg_base; switch (*argptr) { case ',': case '(': case ')': (*info->fprintf_func) (info->stream, "%c", *argptr); break; case 'd': switch (op->format) { case iw_r_type: i = GET_IW_R_C (opcode); reg_base = nios2_regs; break; case iw_custom_type: i = GET_IW_CUSTOM_C (opcode); if (GET_IW_CUSTOM_READC (opcode) == 0) reg_base = nios2_coprocessor_regs (); else reg_base = nios2_regs; break; default: bad_opcode (op); } if (i < NUMREGNAMES) (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); else (*info->fprintf_func) (info->stream, "unknown"); break; case 's': switch (op->format) { case iw_r_type: i = GET_IW_R_A (opcode); reg_base = nios2_regs; break; case iw_i_type: i = GET_IW_I_A (opcode); reg_base = nios2_regs; break; case iw_custom_type: i = GET_IW_CUSTOM_A (opcode); if (GET_IW_CUSTOM_READA (opcode) == 0) reg_base = nios2_coprocessor_regs (); else reg_base = nios2_regs; break; default: bad_opcode (op); } if (i < NUMREGNAMES) (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); else (*info->fprintf_func) (info->stream, "unknown"); break; case 't': switch (op->format) { case iw_r_type: i = GET_IW_R_B (opcode); reg_base = nios2_regs; break; case iw_i_type: i = GET_IW_I_B (opcode); reg_base = nios2_regs; break; case iw_custom_type: i = GET_IW_CUSTOM_B (opcode); if (GET_IW_CUSTOM_READB (opcode) == 0) reg_base = nios2_coprocessor_regs (); else reg_base = nios2_regs; break; default: bad_opcode (op); } if (i < NUMREGNAMES) (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); else (*info->fprintf_func) (info->stream, "unknown"); break; case 'i': /* 16-bit signed immediate. */ switch (op->format) { case iw_i_type: i = (signed) (GET_IW_I_IMM16 (opcode) << 16) >> 16; break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'u': /* 16-bit unsigned immediate. */ switch (op->format) { case iw_i_type: i = GET_IW_I_IMM16 (opcode); break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'o': /* 16-bit signed immediate address offset. */ switch (op->format) { case iw_i_type: i = (signed) (GET_IW_I_IMM16 (opcode) << 16) >> 16; break; default: bad_opcode (op); } address = address + 4 + i; (*info->print_address_func) (address, info); break; case 'j': /* 5-bit unsigned immediate. */ switch (op->format) { case iw_r_type: i = GET_IW_R_IMM5 (opcode); break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%ld", i); break; case 'l': /* 8-bit unsigned immediate. */ switch (op->format) { case iw_custom_type: i = GET_IW_CUSTOM_N (opcode); break; default: bad_opcode (op); } (*info->fprintf_func) (info->stream, "%lu", i); break; case 'm': /* 26-bit unsigned immediate. */ switch (op->format) { case iw_j_type: i = GET_IW_J_IMM26 (opcode); break; default: bad_opcode (op); } /* This translates to an address because it's only used in call instructions. */ address = (address & 0xf0000000) | (i << 2); (*info->print_address_func) (address, info); break; case 'c': /* Control register index. */ switch (op->format) { case iw_r_type: i = GET_IW_R_IMM5 (opcode); break; default: bad_opcode (op); } reg_base = nios2_control_regs (); (*info->fprintf_func) (info->stream, "%s", reg_base[i].name); break; default: (*info->fprintf_func) (info->stream, "unknown"); break; } return 0; }