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