1 /* alpha-dis.c -- Disassemble Alpha AXP instructions 2 Copyright 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. 3 Contributed by Richard Henderson <rth@tamu.edu>, 4 patterned after the PPC opcode handling written by Ian Lance Taylor. 5 6 This file is part of GDB, GAS, and the GNU binutils. 7 8 GDB, GAS, and the GNU binutils are free software; you can redistribute 9 them and/or modify them under the terms of the GNU General Public 10 License as published by the Free Software Foundation; either version 11 2, or (at your option) any later version. 12 13 GDB, GAS, and the GNU binutils are distributed in the hope that they 14 will be useful, but WITHOUT ANY WARRANTY; without even the implied 15 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 16 the GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this file; see the file COPYING. If not, write to the Free 20 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 21 02111-1307, USA. */ 22 23 #include <stdio.h> 24 #include "sysdep.h" 25 #include "dis-asm.h" 26 #include "opcode/alpha.h" 27 28 /* OSF register names. */ 29 30 static const char * const osf_regnames[64] = { 31 "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", 32 "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", 33 "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", 34 "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", 35 "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", 36 "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", 37 "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", 38 "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31" 39 }; 40 41 /* VMS register names. */ 42 43 static const char * const vms_regnames[64] = { 44 "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", 45 "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", 46 "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", 47 "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ", 48 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", 49 "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", 50 "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", 51 "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ" 52 }; 53 54 /* Disassemble Alpha instructions. */ 55 56 int 57 print_insn_alpha (memaddr, info) 58 bfd_vma memaddr; 59 struct disassemble_info *info; 60 { 61 static const struct alpha_opcode *opcode_index[AXP_NOPS+1]; 62 const char * const * regnames; 63 const struct alpha_opcode *opcode, *opcode_end; 64 const unsigned char *opindex; 65 unsigned insn, op, isa_mask; 66 int need_comma; 67 68 /* Initialize the majorop table the first time through */ 69 if (!opcode_index[0]) 70 { 71 opcode = alpha_opcodes; 72 opcode_end = opcode + alpha_num_opcodes; 73 74 for (op = 0; op < AXP_NOPS; ++op) 75 { 76 opcode_index[op] = opcode; 77 while (opcode < opcode_end && op == AXP_OP (opcode->opcode)) 78 ++opcode; 79 } 80 opcode_index[op] = opcode; 81 } 82 83 if (info->flavour == bfd_target_evax_flavour) 84 regnames = vms_regnames; 85 else 86 regnames = osf_regnames; 87 88 isa_mask = AXP_OPCODE_NOPAL; 89 switch (info->mach) 90 { 91 case bfd_mach_alpha_ev4: 92 isa_mask |= AXP_OPCODE_EV4; 93 break; 94 case bfd_mach_alpha_ev5: 95 isa_mask |= AXP_OPCODE_EV5; 96 break; 97 case bfd_mach_alpha_ev6: 98 isa_mask |= AXP_OPCODE_EV6; 99 break; 100 } 101 102 /* Read the insn into a host word */ 103 { 104 bfd_byte buffer[4]; 105 int status = (*info->read_memory_func) (memaddr, buffer, 4, info); 106 if (status != 0) 107 { 108 (*info->memory_error_func) (status, memaddr, info); 109 return -1; 110 } 111 insn = bfd_getl32 (buffer); 112 } 113 114 /* Get the major opcode of the instruction. */ 115 op = AXP_OP (insn); 116 117 /* Find the first match in the opcode table. */ 118 opcode_end = opcode_index[op + 1]; 119 for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode) 120 { 121 if ((insn ^ opcode->opcode) & opcode->mask) 122 continue; 123 124 if (!(opcode->flags & isa_mask)) 125 continue; 126 127 /* Make two passes over the operands. First see if any of them 128 have extraction functions, and, if they do, make sure the 129 instruction is valid. */ 130 { 131 int invalid = 0; 132 for (opindex = opcode->operands; *opindex != 0; opindex++) 133 { 134 const struct alpha_operand *operand = alpha_operands + *opindex; 135 if (operand->extract) 136 (*operand->extract) (insn, &invalid); 137 } 138 if (invalid) 139 continue; 140 } 141 142 /* The instruction is valid. */ 143 goto found; 144 } 145 146 /* No instruction found */ 147 (*info->fprintf_func) (info->stream, ".long %#08x", insn); 148 149 return 4; 150 151 found: 152 (*info->fprintf_func) (info->stream, "%s", opcode->name); 153 if (opcode->operands[0] != 0) 154 (*info->fprintf_func) (info->stream, "\t"); 155 156 /* Now extract and print the operands. */ 157 need_comma = 0; 158 for (opindex = opcode->operands; *opindex != 0; opindex++) 159 { 160 const struct alpha_operand *operand = alpha_operands + *opindex; 161 int value; 162 163 /* Operands that are marked FAKE are simply ignored. We 164 already made sure that the extract function considered 165 the instruction to be valid. */ 166 if ((operand->flags & AXP_OPERAND_FAKE) != 0) 167 continue; 168 169 /* Extract the value from the instruction. */ 170 if (operand->extract) 171 value = (*operand->extract) (insn, (int *) NULL); 172 else 173 { 174 value = (insn >> operand->shift) & ((1 << operand->bits) - 1); 175 if (operand->flags & AXP_OPERAND_SIGNED) 176 { 177 int signbit = 1 << (operand->bits - 1); 178 value = (value ^ signbit) - signbit; 179 } 180 } 181 182 if (need_comma && 183 ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA)) 184 != AXP_OPERAND_PARENS)) 185 { 186 (*info->fprintf_func) (info->stream, ","); 187 } 188 if (operand->flags & AXP_OPERAND_PARENS) 189 (*info->fprintf_func) (info->stream, "("); 190 191 /* Print the operand as directed by the flags. */ 192 if (operand->flags & AXP_OPERAND_IR) 193 (*info->fprintf_func) (info->stream, "%s", regnames[value]); 194 else if (operand->flags & AXP_OPERAND_FPR) 195 (*info->fprintf_func) (info->stream, "%s", regnames[value + 32]); 196 else if (operand->flags & AXP_OPERAND_RELATIVE) 197 (*info->print_address_func) (memaddr + 4 + value, info); 198 else if (operand->flags & AXP_OPERAND_SIGNED) 199 (*info->fprintf_func) (info->stream, "%d", value); 200 else 201 (*info->fprintf_func) (info->stream, "%#x", value); 202 203 if (operand->flags & AXP_OPERAND_PARENS) 204 (*info->fprintf_func) (info->stream, ")"); 205 need_comma = 1; 206 } 207 208 return 4; 209 } 210