1 /* i370-dis.c -- Disassemble Instruction 370 (ESA/390) instructions 2 Copyright (C) 1994-2014 Free Software Foundation, Inc. 3 PowerPC version written by Ian Lance Taylor, Cygnus Support 4 Rewritten for i370 ESA/390 support by Linas Vepstas <linas (at) linas.org> 5 6 This file is part of the GNU opcodes library. 7 8 This library is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3, or (at your option) 11 any later version. 12 13 It is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16 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, 51 Franklin Street - Fifth Floor, Boston, 21 MA 02110-1301, USA. */ 22 23 #include "sysdep.h" 24 #include <stdio.h> 25 #include "dis-asm.h" 26 #include "opcode/i370.h" 27 28 /* This file provides several disassembler functions, all of which use 29 the disassembler interface defined in dis-asm.h. */ 30 31 int 32 print_insn_i370 (bfd_vma memaddr, struct disassemble_info *info) 33 { 34 bfd_byte buffer[8]; 35 int status; 36 i370_insn_t insn; 37 const struct i370_opcode *opcode; 38 const struct i370_opcode *opcode_end; 39 40 status = (*info->read_memory_func) (memaddr, buffer, 6, info); 41 if (status != 0) 42 { 43 (*info->memory_error_func) (status, memaddr, info); 44 return -1; 45 } 46 47 /* Cast the bytes into the insn (in a host-endian indep way). */ 48 insn.i[0] = (buffer[0] << 24) & 0xff000000; 49 insn.i[0] |= (buffer[1] << 16) & 0xff0000; 50 insn.i[0] |= (buffer[2] << 8) & 0xff00; 51 insn.i[0] |= buffer[3] & 0xff; 52 insn.i[1] = (buffer[4] << 24) & 0xff000000; 53 insn.i[1] |= (buffer[5] << 16) & 0xff0000; 54 55 /* Find the first match in the opcode table. We could speed this up 56 a bit by doing a binary search on the major opcode. */ 57 opcode_end = i370_opcodes + i370_num_opcodes; 58 for (opcode = i370_opcodes; opcode < opcode_end; opcode++) 59 { 60 const unsigned char *opindex; 61 const struct i370_operand *operand; 62 i370_insn_t masked; 63 int invalid; 64 65 /* Mask off operands, and look for a match ... */ 66 masked = insn; 67 if (2 == opcode->len) 68 { 69 masked.i[0] >>= 16; 70 masked.i[0] &= 0xffff; 71 } 72 masked.i[0] &= opcode->mask.i[0]; 73 if (masked.i[0] != opcode->opcode.i[0]) 74 continue; 75 76 if (6 == opcode->len) 77 { 78 masked.i[1] &= opcode->mask.i[1]; 79 if (masked.i[1] != opcode->opcode.i[1]) 80 continue; 81 } 82 83 /* Found a match. adjust a tad. */ 84 if (2 == opcode->len) 85 { 86 insn.i[0] >>= 16; 87 insn.i[0] &= 0xffff; 88 } 89 90 /* Make two passes over the operands. First see if any of them 91 have extraction functions, and, if they do, make sure the 92 instruction is valid. */ 93 invalid = 0; 94 for (opindex = opcode->operands; *opindex != 0; opindex++) 95 { 96 operand = i370_operands + *opindex; 97 if (operand->extract) 98 (*operand->extract) (insn, &invalid); 99 } 100 if (invalid) 101 continue; 102 103 /* The instruction is valid. */ 104 (*info->fprintf_func) (info->stream, "%s", opcode->name); 105 if (opcode->operands[0] != 0) 106 (*info->fprintf_func) (info->stream, "\t"); 107 108 /* Now extract and print the operands. */ 109 for (opindex = opcode->operands; *opindex != 0; opindex++) 110 { 111 long value; 112 113 operand = i370_operands + *opindex; 114 115 /* Extract the value from the instruction. */ 116 if (operand->extract) 117 value = (*operand->extract) (insn, (int *) NULL); 118 else 119 value = (insn.i[0] >> operand->shift) & ((1 << operand->bits) - 1); 120 121 /* Print the operand as directed by the flags. */ 122 if ((operand->flags & I370_OPERAND_OPTIONAL) != 0) 123 { 124 if (value) 125 (*info->fprintf_func) (info->stream, "(r%ld)", value); 126 } 127 else if ((operand->flags & I370_OPERAND_SBASE) != 0) 128 { 129 (*info->fprintf_func) (info->stream, "(r%ld)", value); 130 } 131 else if ((operand->flags & I370_OPERAND_INDEX) != 0) 132 { 133 if (value) 134 (*info->fprintf_func) (info->stream, "(r%ld,", value); 135 else 136 (*info->fprintf_func) (info->stream, "(,"); 137 } 138 else if ((operand->flags & I370_OPERAND_LENGTH) != 0) 139 { 140 (*info->fprintf_func) (info->stream, "(%ld,", value); 141 } 142 else if ((operand->flags & I370_OPERAND_BASE) != 0) 143 (*info->fprintf_func) (info->stream, "r%ld)", value); 144 else if ((operand->flags & I370_OPERAND_GPR) != 0) 145 (*info->fprintf_func) (info->stream, "r%ld,", value); 146 else if ((operand->flags & I370_OPERAND_FPR) != 0) 147 (*info->fprintf_func) (info->stream, "f%ld,", value); 148 else if ((operand->flags & I370_OPERAND_RELATIVE) != 0) 149 (*info->fprintf_func) (info->stream, "%ld", value); 150 else 151 (*info->fprintf_func) (info->stream, " %ld, ", value); 152 } 153 154 return opcode->len; 155 } 156 157 /* We could not find a match. */ 158 (*info->fprintf_func) (info->stream, ".short 0x%02x%02x", buffer[0], buffer[1]); 159 160 return 2; 161 } 162