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