Allow both signed and unsigned fields in PowerPC cmpli insn
[deliverable/binutils-gdb.git] / opcodes / s390-dis.c
1 /* s390-dis.c -- Disassemble S390 instructions
2 Copyright (C) 2000-2014 Free Software Foundation, Inc.
3 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
4
5 This file is part of the GNU opcodes library.
6
7 This library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 It is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this file; see the file COPYING. If not, write to the
19 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
21
22 #include "sysdep.h"
23 #include <stdio.h>
24 #include "ansidecl.h"
25 #include "dis-asm.h"
26 #include "opintl.h"
27 #include "opcode/s390.h"
28
29 static int init_flag = 0;
30 static int opc_index[256];
31 static int current_arch_mask = 0;
32
33 /* Set up index table for first opcode byte. */
34
35 static void
36 init_disasm (struct disassemble_info *info)
37 {
38 const struct s390_opcode *opcode;
39 const struct s390_opcode *opcode_end;
40 const char *p;
41
42 memset (opc_index, 0, sizeof (opc_index));
43 opcode_end = s390_opcodes + s390_num_opcodes;
44 for (opcode = s390_opcodes; opcode < opcode_end; opcode++)
45 {
46 opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes;
47 while ((opcode < opcode_end) &&
48 (opcode[1].opcode[0] == opcode->opcode[0]))
49 opcode++;
50 }
51
52 for (p = info->disassembler_options; p != NULL; )
53 {
54 if (CONST_STRNEQ (p, "esa"))
55 current_arch_mask = 1 << S390_OPCODE_ESA;
56 else if (CONST_STRNEQ (p, "zarch"))
57 current_arch_mask = 1 << S390_OPCODE_ZARCH;
58 else
59 fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
60
61 p = strchr (p, ',');
62 if (p != NULL)
63 p++;
64 }
65
66 if (!current_arch_mask)
67 current_arch_mask = 1 << S390_OPCODE_ZARCH;
68
69 init_flag = 1;
70 }
71
72 /* Extracts an operand value from an instruction. */
73 /* We do not perform the shift operation for larl-type address
74 operands here since that would lead to an overflow of the 32 bit
75 integer value. Instead the shift operation is done when printing
76 the operand in print_insn_s390. */
77
78 static inline unsigned int
79 s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
80 {
81 unsigned int val;
82 int bits;
83
84 /* Extract fragments of the operand byte for byte. */
85 insn += operand->shift / 8;
86 bits = (operand->shift & 7) + operand->bits;
87 val = 0;
88 do
89 {
90 val <<= 8;
91 val |= (unsigned int) *insn++;
92 bits -= 8;
93 }
94 while (bits > 0);
95 val >>= -bits;
96 val &= ((1U << (operand->bits - 1)) << 1) - 1;
97
98 /* Check for special long displacement case. */
99 if (operand->bits == 20 && operand->shift == 20)
100 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
101
102 /* Sign extend value if the operand is signed or pc relative. */
103 if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
104 && (val & (1U << (operand->bits - 1))))
105 val |= (-1U << (operand->bits - 1)) << 1;
106
107 /* Length x in an instructions has real length x + 1. */
108 if (operand->flags & S390_OPERAND_LENGTH)
109 val++;
110 return val;
111 }
112
113 /* Print a S390 instruction. */
114
115 int
116 print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
117 {
118 bfd_byte buffer[6];
119 const struct s390_opcode *opcode;
120 const struct s390_opcode *opcode_end;
121 unsigned int value;
122 int status, opsize, bufsize;
123 char separator;
124
125 if (init_flag == 0)
126 init_disasm (info);
127
128 /* The output looks better if we put 6 bytes on a line. */
129 info->bytes_per_line = 6;
130
131 /* Every S390 instruction is max 6 bytes long. */
132 memset (buffer, 0, 6);
133 status = (*info->read_memory_func) (memaddr, buffer, 6, info);
134 if (status != 0)
135 {
136 for (bufsize = 0; bufsize < 6; bufsize++)
137 if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0)
138 break;
139 if (bufsize <= 0)
140 {
141 (*info->memory_error_func) (status, memaddr, info);
142 return -1;
143 }
144 /* Opsize calculation looks strange but it works
145 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes,
146 11xxxxxx -> 6 bytes. */
147 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
148 status = opsize > bufsize;
149 }
150 else
151 {
152 bufsize = 6;
153 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
154 }
155
156 if (status == 0)
157 {
158 const struct s390_opcode *op;
159
160 /* Find the first match in the opcode table. */
161 opcode_end = s390_opcodes + s390_num_opcodes;
162 for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
163 (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]);
164 opcode++)
165 {
166 const struct s390_operand *operand;
167 const unsigned char *opindex;
168
169 /* Check architecture. */
170 if (!(opcode->modes & current_arch_mask))
171 continue;
172
173 /* Check signature of the opcode. */
174 if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
175 || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
176 || (buffer[3] & opcode->mask[3]) != opcode->opcode[3]
177 || (buffer[4] & opcode->mask[4]) != opcode->opcode[4]
178 || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
179 continue;
180
181 /* Advance to an opcode with a more specific mask. */
182 for (op = opcode + 1; op < opcode_end; op++)
183 {
184 if ((buffer[0] & op->mask[0]) != op->opcode[0])
185 break;
186
187 if ((buffer[1] & op->mask[1]) != op->opcode[1]
188 || (buffer[2] & op->mask[2]) != op->opcode[2]
189 || (buffer[3] & op->mask[3]) != op->opcode[3]
190 || (buffer[4] & op->mask[4]) != op->opcode[4]
191 || (buffer[5] & op->mask[5]) != op->opcode[5])
192 continue;
193
194 if (((int)opcode->mask[0] + opcode->mask[1] +
195 opcode->mask[2] + opcode->mask[3] +
196 opcode->mask[4] + opcode->mask[5]) <
197 ((int)op->mask[0] + op->mask[1] +
198 op->mask[2] + op->mask[3] +
199 op->mask[4] + op->mask[5]))
200 opcode = op;
201 }
202
203 /* The instruction is valid. */
204 if (opcode->operands[0] != 0)
205 (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
206 else
207 (*info->fprintf_func) (info->stream, "%s", opcode->name);
208
209 /* Extract the operands. */
210 separator = 0;
211 for (opindex = opcode->operands; *opindex != 0; opindex++)
212 {
213 operand = s390_operands + *opindex;
214 value = s390_extract_operand (buffer, operand);
215
216 if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
217 continue;
218 if ((operand->flags & S390_OPERAND_BASE) &&
219 value == 0 && separator == '(')
220 {
221 separator = ',';
222 continue;
223 }
224
225 if (separator)
226 (*info->fprintf_func) (info->stream, "%c", separator);
227
228 if (operand->flags & S390_OPERAND_GPR)
229 (*info->fprintf_func) (info->stream, "%%r%i", value);
230 else if (operand->flags & S390_OPERAND_FPR)
231 (*info->fprintf_func) (info->stream, "%%f%i", value);
232 else if (operand->flags & S390_OPERAND_AR)
233 (*info->fprintf_func) (info->stream, "%%a%i", value);
234 else if (operand->flags & S390_OPERAND_CR)
235 (*info->fprintf_func) (info->stream, "%%c%i", value);
236 else if (operand->flags & S390_OPERAND_PCREL)
237 (*info->print_address_func) (memaddr + (int)value + (int)value,
238 info);
239 else if (operand->flags & S390_OPERAND_SIGNED)
240 (*info->fprintf_func) (info->stream, "%i", (int) value);
241 else
242 (*info->fprintf_func) (info->stream, "%u", value);
243
244 if (operand->flags & S390_OPERAND_DISP)
245 {
246 separator = '(';
247 }
248 else if (operand->flags & S390_OPERAND_BASE)
249 {
250 (*info->fprintf_func) (info->stream, ")");
251 separator = ',';
252 }
253 else
254 separator = ',';
255 }
256
257 /* Found instruction, printed it, return its size. */
258 return opsize;
259 }
260 /* No matching instruction found, fall through to hex print. */
261 }
262
263 if (bufsize >= 4)
264 {
265 value = (unsigned int) buffer[0];
266 value = (value << 8) + (unsigned int) buffer[1];
267 value = (value << 8) + (unsigned int) buffer[2];
268 value = (value << 8) + (unsigned int) buffer[3];
269 (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
270 return 4;
271 }
272 else if (bufsize >= 2)
273 {
274 value = (unsigned int) buffer[0];
275 value = (value << 8) + (unsigned int) buffer[1];
276 (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
277 return 2;
278 }
279 else
280 {
281 value = (unsigned int) buffer[0];
282 (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
283 return 1;
284 }
285 }
286
287 void
288 print_s390_disassembler_options (FILE *stream)
289 {
290 fprintf (stream, _("\n\
291 The following S/390 specific disassembler options are supported for use\n\
292 with the -M switch (multiple options should be separated by commas):\n"));
293
294 fprintf (stream, _(" esa Disassemble in ESA architecture mode\n"));
295 fprintf (stream, _(" zarch Disassemble in z/Architecture mode\n"));
296 }
This page took 0.036088 seconds and 4 git commands to generate.