OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [opcodes/] [s390-dis.c] - Blame information for rev 287

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.