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