Back to index

cell-binutils  2.17cvs20070401
i370-dis.c
Go to the documentation of this file.
00001 /* i370-dis.c -- Disassemble Instruction 370 (ESA/390) instructions
00002    Copyright 1994, 2000, 2003, 2005 Free Software Foundation, Inc.
00003    PowerPC version written by Ian Lance Taylor, Cygnus Support
00004    Rewritten for i370 ESA/390 support by Linas Vepstas <linas@linas.org>
00005 
00006    This file is part of GDB, GAS, and the GNU binutils.
00007 
00008    GDB, GAS, and the GNU binutils are free software; you can redistribute
00009    them and/or modify them under the terms of the GNU General Public
00010    License as published by the Free Software Foundation; either version
00011    2, or (at your option) any later version.
00012 
00013    GDB, GAS, and the GNU binutils are distributed in the hope that they
00014    will be useful, but WITHOUT ANY WARRANTY; without even the implied
00015    warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
00016    the GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this file; see the file COPYING.  If not, write to the Free
00020    Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
00021    MA 02110-1301, USA.  */
00022 
00023 #include <stdio.h>
00024 #include "sysdep.h"
00025 #include "dis-asm.h"
00026 #include "opcode/i370.h"
00027 
00028 /* This file provides several disassembler functions, all of which use
00029    the disassembler interface defined in dis-asm.h.  */
00030 
00031 int
00032 print_insn_i370 (bfd_vma memaddr, struct disassemble_info *info)
00033 {
00034   bfd_byte buffer[8];
00035   int status;
00036   i370_insn_t insn;
00037   const struct i370_opcode *opcode;
00038   const struct i370_opcode *opcode_end;
00039 
00040   status = (*info->read_memory_func) (memaddr, buffer, 6, info);
00041   if (status != 0)
00042     {
00043       (*info->memory_error_func) (status, memaddr, info);
00044       return -1;
00045     }
00046 
00047   /* Cast the bytes into the insn (in a host-endian indep way).  */
00048   insn.i[0] = (buffer[0] << 24) & 0xff000000;
00049   insn.i[0] |= (buffer[1] << 16) & 0xff0000;
00050   insn.i[0] |= (buffer[2] << 8) & 0xff00;
00051   insn.i[0] |= buffer[3]  & 0xff;
00052   insn.i[1] = (buffer[4] << 24) & 0xff000000;
00053   insn.i[1] |= (buffer[5] << 16) & 0xff0000;
00054 
00055   /* Find the first match in the opcode table.  We could speed this up
00056      a bit by doing a binary search on the major opcode.  */
00057   opcode_end = i370_opcodes + i370_num_opcodes;
00058   for (opcode = i370_opcodes; opcode < opcode_end; opcode++)
00059     {
00060       const unsigned char *opindex;
00061       const struct i370_operand *operand;
00062       i370_insn_t masked;
00063       int invalid;
00064 
00065       /* Mask off operands, and look for a match ... */
00066       masked = insn;
00067       if (2 == opcode->len)
00068         {
00069           masked.i[0] >>= 16;
00070           masked.i[0] &= 0xffff;
00071         }
00072       masked.i[0] &= opcode->mask.i[0];
00073       if (masked.i[0] != opcode->opcode.i[0])
00074        continue;
00075 
00076       if (6 == opcode->len)
00077         {
00078           masked.i[1] &= opcode->mask.i[1];
00079           if (masked.i[1] != opcode->opcode.i[1])
00080            continue;
00081         }
00082 
00083       /* Found a match.  adjust a tad.  */
00084       if (2 == opcode->len)
00085         {
00086           insn.i[0] >>= 16;
00087           insn.i[0] &= 0xffff;
00088         }
00089 
00090       /* Make two passes over the operands.  First see if any of them
00091          have extraction functions, and, if they do, make sure the
00092          instruction is valid.  */
00093       invalid = 0;
00094       for (opindex = opcode->operands; *opindex != 0; opindex++)
00095         {
00096           operand = i370_operands + *opindex;
00097           if (operand->extract)
00098             (*operand->extract) (insn, &invalid);
00099         }
00100       if (invalid)
00101        continue;
00102 
00103       /* The instruction is valid.  */
00104       (*info->fprintf_func) (info->stream, "%s", opcode->name);
00105       if (opcode->operands[0] != 0)
00106         (*info->fprintf_func) (info->stream, "\t");
00107 
00108       /* Now extract and print the operands.  */
00109       for (opindex = opcode->operands; *opindex != 0; opindex++)
00110         {
00111           long value;
00112 
00113           operand = i370_operands + *opindex;
00114 
00115           /* Extract the value from the instruction.  */
00116           if (operand->extract)
00117             value = (*operand->extract) (insn, (int *) NULL);
00118           else
00119            value = (insn.i[0] >> operand->shift) & ((1 << operand->bits) - 1);
00120 
00121           /* Print the operand as directed by the flags.  */
00122           if ((operand->flags & I370_OPERAND_OPTIONAL) != 0)
00123             {
00124               if (value)
00125                 (*info->fprintf_func) (info->stream, "(r%ld)", value);
00126             }
00127           else if ((operand->flags & I370_OPERAND_SBASE) != 0)
00128             {
00129               (*info->fprintf_func) (info->stream, "(r%ld)", value);
00130             }
00131           else if ((operand->flags & I370_OPERAND_INDEX) != 0)
00132             {
00133               if (value)
00134                 (*info->fprintf_func) (info->stream, "(r%ld,", value);
00135               else
00136                 (*info->fprintf_func) (info->stream, "(,");
00137             }
00138           else if ((operand->flags & I370_OPERAND_LENGTH) != 0)
00139             {
00140               (*info->fprintf_func) (info->stream, "(%ld,", value);
00141             }
00142           else if ((operand->flags & I370_OPERAND_BASE) != 0)
00143             (*info->fprintf_func) (info->stream, "r%ld)", value);
00144           else if ((operand->flags & I370_OPERAND_GPR) != 0)
00145             (*info->fprintf_func) (info->stream, "r%ld,", value);
00146           else if ((operand->flags & I370_OPERAND_FPR) != 0)
00147             (*info->fprintf_func) (info->stream, "f%ld,", value);
00148           else if ((operand->flags & I370_OPERAND_RELATIVE) != 0)
00149             (*info->fprintf_func) (info->stream, "%ld", value);
00150           else
00151             (*info->fprintf_func) (info->stream, " %ld, ", value);
00152         }
00153 
00154       return opcode->len;
00155     }
00156 
00157   /* We could not find a match.  */
00158   (*info->fprintf_func) (info->stream, ".short 0x%02x%02x", buffer[0], buffer[1]);
00159 
00160   return 2;
00161 }