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