1 /* alpha-dis.c -- Disassemble Alpha AXP instructions 2 Copyright 1996, 1999 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 { 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 { 46 "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", 47 "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", 48 "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", 49 "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ", 50 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", 51 "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", 52 "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", 53 "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ" 54 }; 55 56 /* Disassemble Alpha instructions. */ 57 58 int 59 print_insn_alpha (memaddr, info) 60 bfd_vma memaddr; 61 struct disassemble_info *info; 62 { 63 static const struct alpha_opcode *opcode_index[AXP_NOPS+1]; 64 const char * const * regnames; 65 const struct alpha_opcode *opcode, *opcode_end; 66 const unsigned char *opindex; 67 unsigned insn, op, isa_mask; 68 int need_comma; 69 70 /* Initialize the majorop table the first time through */ 71 if (!opcode_index[0]) 72 { 73 opcode = alpha_opcodes; 74 opcode_end = opcode + alpha_num_opcodes; 75 76 for (op = 0; op < AXP_NOPS; ++op) 77 { 78 opcode_index[op] = opcode; 79 while (opcode < opcode_end && op == AXP_OP (opcode->opcode)) 80 ++opcode; 81 } 82 opcode_index[op] = opcode; 83 } 84 85 if (info->flavour == bfd_target_evax_flavour) 86 regnames = vms_regnames; 87 else 88 regnames = osf_regnames; 89 90 isa_mask = AXP_OPCODE_NOPAL; 91 switch (info->mach) 92 { 93 case bfd_mach_alpha_ev4: 94 isa_mask |= AXP_OPCODE_EV4; 95 break; 96 case bfd_mach_alpha_ev5: 97 isa_mask |= AXP_OPCODE_EV5; 98 break; 99 case bfd_mach_alpha_ev6: 100 isa_mask |= AXP_OPCODE_EV6; 101 break; 102 } 103 104 /* Read the insn into a host word */ 105 { 106 bfd_byte buffer[4]; 107 int status = (*info->read_memory_func) (memaddr, buffer, 4, info); 108 if (status != 0) 109 { 110 (*info->memory_error_func) (status, memaddr, info); 111 return -1; 112 } 113 insn = bfd_getl32 (buffer); 114 } 115 116 /* Get the major opcode of the instruction. */ 117 op = AXP_OP (insn); 118 119 /* Find the first match in the opcode table. */ 120 opcode_end = opcode_index[op+1]; 121 for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode) 122 { 123 if ((insn & opcode->mask) != opcode->opcode) 124 continue; 125 126 if (!(opcode->flags & isa_mask)) 127 continue; 128 129 /* Make two passes over the operands. First see if any of them 130 have extraction functions, and, if they do, make sure the 131 instruction is valid. */ 132 { 133 int invalid = 0; 134 for (opindex = opcode->operands; *opindex != 0; opindex++) 135 { 136 const struct alpha_operand *operand = alpha_operands + *opindex; 137 if (operand->extract) 138 (*operand->extract) (insn, &invalid); 139 } 140 if (invalid) 141 continue; 142 } 143 144 /* The instruction is valid. */ 145 goto found; 146 } 147 148 /* No instruction found */ 149 (*info->fprintf_func) (info->stream, ".long %#08x", insn); 150 151 return 4; 152 153 found: 154 (*info->fprintf_func) (info->stream, "%s", opcode->name); 155 if (opcode->operands[0] != 0) 156 (*info->fprintf_func) (info->stream, "\t"); 157 158 /* Now extract and print the operands. */ 159 need_comma = 0; 160 for (opindex = opcode->operands; *opindex != 0; opindex++) 161 { 162 const struct alpha_operand *operand = alpha_operands + *opindex; 163 int value; 164 165 /* Operands that are marked FAKE are simply ignored. We 166 already made sure that the extract function considered 167 the instruction to be valid. */ 168 if ((operand->flags & AXP_OPERAND_FAKE) != 0) 169 continue; 170 171 /* Extract the value from the instruction. */ 172 if (operand->extract) 173 value = (*operand->extract) (insn, (int *) NULL); 174 else 175 { 176 value = (insn >> operand->shift) & ((1 << operand->bits) - 1); 177 if (operand->flags & AXP_OPERAND_SIGNED) 178 { 179 int signbit = 1 << (operand->bits - 1); 180 value = (value ^ signbit) - signbit; 181 } 182 } 183 184 if (need_comma && 185 ((operand->flags & (AXP_OPERAND_PARENS|AXP_OPERAND_COMMA)) 186 != AXP_OPERAND_PARENS)) 187 { 188 (*info->fprintf_func) (info->stream, ","); 189 } 190 if (operand->flags & AXP_OPERAND_PARENS) 191 (*info->fprintf_func) (info->stream, "("); 192 193 /* Print the operand as directed by the flags. */ 194 if (operand->flags & AXP_OPERAND_IR) 195 (*info->fprintf_func) (info->stream, "%s", regnames[value]); 196 else if (operand->flags & AXP_OPERAND_FPR) 197 (*info->fprintf_func) (info->stream, "%s", regnames[value+32]); 198 else if (operand->flags & AXP_OPERAND_RELATIVE) 199 (*info->print_address_func) (memaddr + 4 + value, info); 200 else if (operand->flags & AXP_OPERAND_SIGNED) 201 (*info->fprintf_func) (info->stream, "%d", value); 202 else 203 (*info->fprintf_func) (info->stream, "%#x", value); 204 205 if (operand->flags & AXP_OPERAND_PARENS) 206 (*info->fprintf_func) (info->stream, ")"); 207 need_comma = 1; 208 } 209 210 return 4; 211 } 212