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