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