sync changelog with gcc, plus commit the following patch:
[deliverable/binutils-gdb.git] / opcodes / d10v-dis.c
CommitLineData
252b5132 1/* Disassemble D10V instructions.
9b201bb5
NC
2 Copyright 1996, 1997, 1998, 2000, 2001, 2005, 2007
3 Free Software Foundation, Inc.
252b5132 4
9b201bb5
NC
5 This file is part of the GNU opcodes library.
6
7 This library is free software; you can redistribute it and/or modify
47b0e7ad 8 it under the terms of the GNU General Public License as published by
9b201bb5
NC
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
252b5132 11
9b201bb5
NC
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.
252b5132 16
47b0e7ad
NC
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
252b5132 21
252b5132
RH
22#include <stdio.h>
23
0d8dfecf 24#include "sysdep.h"
2dcee538 25#include "opcode/d10v.h"
252b5132
RH
26#include "dis-asm.h"
27
2dcee538
KH
28/* The PC wraps at 18 bits, except for the segment number,
29 so use this mask to keep the parts we want. */
252b5132
RH
30#define PC_MASK 0x0303FFFF
31
252b5132 32static void
47b0e7ad
NC
33print_operand (struct d10v_operand *oper,
34 unsigned long insn,
35 struct d10v_opcode *op,
36 bfd_vma memaddr,
37 struct disassemble_info *info)
252b5132
RH
38{
39 int num, shift;
40
41 if (oper->flags == OPERAND_ATMINUS)
42 {
2dcee538 43 (*info->fprintf_func) (info->stream, "@-");
252b5132
RH
44 return;
45 }
46 if (oper->flags == OPERAND_MINUS)
47 {
2dcee538 48 (*info->fprintf_func) (info->stream, "-");
252b5132
RH
49 return;
50 }
51 if (oper->flags == OPERAND_PLUS)
52 {
2dcee538 53 (*info->fprintf_func) (info->stream, "+");
252b5132
RH
54 return;
55 }
56 if (oper->flags == OPERAND_ATSIGN)
57 {
2dcee538 58 (*info->fprintf_func) (info->stream, "@");
252b5132
RH
59 return;
60 }
61 if (oper->flags == OPERAND_ATPAR)
62 {
2dcee538 63 (*info->fprintf_func) (info->stream, "@(");
252b5132
RH
64 return;
65 }
66
67 shift = oper->shift;
68
2dcee538 69 /* The LONG_L format shifts registers over by 15. */
252b5132
RH
70 if (op->format == LONG_L && (oper->flags & OPERAND_REG))
71 shift += 15;
72
73 num = (insn >> shift) & (0x7FFFFFFF >> (31 - oper->bits));
74
75 if (oper->flags & OPERAND_REG)
76 {
77 int i;
2dcee538 78 int match = 0;
47b0e7ad 79
252b5132 80 num += (oper->flags
2dcee538
KH
81 & (OPERAND_GPR | OPERAND_FFLAG | OPERAND_CFLAG | OPERAND_CONTROL));
82 if (oper->flags & (OPERAND_ACC0 | OPERAND_ACC1))
252b5132 83 num += num ? OPERAND_ACC1 : OPERAND_ACC0;
2dcee538 84 for (i = 0; i < d10v_reg_name_cnt (); i++)
252b5132 85 {
d1267250 86 if (num == (d10v_predefined_registers[i].value & ~ OPERAND_SP))
252b5132
RH
87 {
88 if (d10v_predefined_registers[i].pname)
2dcee538
KH
89 (*info->fprintf_func) (info->stream, "%s",
90 d10v_predefined_registers[i].pname);
252b5132 91 else
2dcee538
KH
92 (*info->fprintf_func) (info->stream, "%s",
93 d10v_predefined_registers[i].name);
94 match = 1;
252b5132
RH
95 break;
96 }
97 }
98 if (match == 0)
99 {
2dcee538
KH
100 /* This would only get executed if a register was not in the
101 register table. */
102 if (oper->flags & (OPERAND_ACC0 | OPERAND_ACC1))
252b5132
RH
103 (*info->fprintf_func) (info->stream, "a");
104 else if (oper->flags & OPERAND_CONTROL)
105 (*info->fprintf_func) (info->stream, "cr");
2dcee538 106 else if (oper->flags & OPERAND_REG)
252b5132 107 (*info->fprintf_func) (info->stream, "r");
373efcb3 108 (*info->fprintf_func) (info->stream, "%d", num & REGISTER_MASK);
252b5132
RH
109 }
110 }
111 else
112 {
2dcee538 113 /* Addresses are right-shifted by 2. */
252b5132
RH
114 if (oper->flags & OPERAND_ADDR)
115 {
116 long max;
2dcee538 117 int neg = 0;
47b0e7ad 118
252b5132
RH
119 max = (1 << (oper->bits - 1));
120 if (num & max)
121 {
2dcee538 122 num = -num & ((1 << oper->bits) - 1);
252b5132
RH
123 neg = 1;
124 }
2dcee538 125 num = num << 2;
252b5132
RH
126 if (info->flags & INSN_HAS_RELOC)
127 (*info->print_address_func) (num & PC_MASK, info);
128 else
129 {
130 if (neg)
131 (*info->print_address_func) ((memaddr - num) & PC_MASK, info);
132 else
133 (*info->print_address_func) ((memaddr + num) & PC_MASK, info);
134 }
135 }
136 else
137 {
138 if (oper->flags & OPERAND_SIGNED)
139 {
140 int max = (1 << (oper->bits - 1));
141 if (num & max)
142 {
2dcee538 143 num = -num & ((1 << oper->bits) - 1);
252b5132
RH
144 (*info->fprintf_func) (info->stream, "-");
145 }
146 }
2dcee538 147 (*info->fprintf_func) (info->stream, "0x%x", num);
252b5132
RH
148 }
149 }
150}
151
252b5132 152static void
47b0e7ad
NC
153dis_long (unsigned long insn,
154 bfd_vma memaddr,
155 struct disassemble_info *info)
252b5132
RH
156{
157 int i;
2dcee538 158 struct d10v_opcode *op = (struct d10v_opcode *) d10v_opcodes;
252b5132
RH
159 struct d10v_operand *oper;
160 int need_paren = 0;
161 int match = 0;
162
163 while (op->name)
164 {
47b0e7ad
NC
165 if ((op->format & LONG_OPCODE)
166 && ((op->mask & insn) == (unsigned long) op->opcode))
252b5132
RH
167 {
168 match = 1;
2dcee538 169 (*info->fprintf_func) (info->stream, "%s\t", op->name);
47b0e7ad 170
2dcee538 171 for (i = 0; op->operands[i]; i++)
252b5132 172 {
2dcee538 173 oper = (struct d10v_operand *) &d10v_operands[op->operands[i]];
252b5132
RH
174 if (oper->flags == OPERAND_ATPAR)
175 need_paren = 1;
176 print_operand (oper, insn, op, memaddr, info);
2dcee538
KH
177 if (op->operands[i + 1] && oper->bits
178 && d10v_operands[op->operands[i + 1]].flags != OPERAND_PLUS
179 && d10v_operands[op->operands[i + 1]].flags != OPERAND_MINUS)
180 (*info->fprintf_func) (info->stream, ", ");
252b5132
RH
181 }
182 break;
183 }
184 op++;
185 }
186
187 if (!match)
0fd3a477 188 (*info->fprintf_func) (info->stream, ".long\t0x%08lx", insn);
252b5132
RH
189
190 if (need_paren)
2dcee538 191 (*info->fprintf_func) (info->stream, ")");
252b5132
RH
192}
193
194static void
47b0e7ad
NC
195dis_2_short (unsigned long insn,
196 bfd_vma memaddr,
197 struct disassemble_info *info,
198 int order)
252b5132 199{
2dcee538 200 int i, j;
252b5132
RH
201 unsigned int ins[2];
202 struct d10v_opcode *op;
2dcee538 203 int match, num_match = 0;
252b5132
RH
204 struct d10v_operand *oper;
205 int need_paren = 0;
206
207 ins[0] = (insn & 0x3FFFFFFF) >> 15;
208 ins[1] = insn & 0x00007FFF;
209
2dcee538 210 for (j = 0; j < 2; j++)
252b5132 211 {
2dcee538
KH
212 op = (struct d10v_opcode *) d10v_opcodes;
213 match = 0;
252b5132
RH
214 while (op->name)
215 {
2dcee538 216 if ((op->format & SHORT_OPCODE)
920a34a7
L
217 && ((((unsigned int) op->mask) & ins[j])
218 == (unsigned int) op->opcode))
252b5132 219 {
2dcee538
KH
220 (*info->fprintf_func) (info->stream, "%s\t", op->name);
221 for (i = 0; op->operands[i]; i++)
252b5132 222 {
2dcee538 223 oper = (struct d10v_operand *) &d10v_operands[op->operands[i]];
252b5132
RH
224 if (oper->flags == OPERAND_ATPAR)
225 need_paren = 1;
226 print_operand (oper, ins[j], op, memaddr, info);
2dcee538
KH
227 if (op->operands[i + 1] && oper->bits
228 && d10v_operands[op->operands[i + 1]].flags != OPERAND_PLUS
229 && d10v_operands[op->operands[i + 1]].flags != OPERAND_MINUS)
230 (*info->fprintf_func) (info->stream, ", ");
252b5132
RH
231 }
232 match = 1;
233 num_match++;
234 break;
235 }
236 op++;
237 }
238 if (!match)
2dcee538 239 (*info->fprintf_func) (info->stream, "unknown");
252b5132
RH
240
241 switch (order)
242 {
243 case 0:
2dcee538 244 (*info->fprintf_func) (info->stream, "\t->\t");
252b5132
RH
245 order = -1;
246 break;
247 case 1:
2dcee538 248 (*info->fprintf_func) (info->stream, "\t<-\t");
252b5132
RH
249 order = -1;
250 break;
251 case 2:
2dcee538 252 (*info->fprintf_func) (info->stream, "\t||\t");
252b5132
RH
253 order = -1;
254 break;
255 default:
256 break;
257 }
258 }
259
260 if (num_match == 0)
0fd3a477 261 (*info->fprintf_func) (info->stream, ".long\t0x%08lx", insn);
252b5132
RH
262
263 if (need_paren)
2dcee538 264 (*info->fprintf_func) (info->stream, ")");
252b5132 265}
47b0e7ad
NC
266
267int
268print_insn_d10v (bfd_vma memaddr, struct disassemble_info *info)
269{
270 int status;
271 bfd_byte buffer[4];
272 unsigned long insn;
273
274 status = (*info->read_memory_func) (memaddr, buffer, 4, info);
275 if (status != 0)
276 {
277 (*info->memory_error_func) (status, memaddr, info);
278 return -1;
279 }
280 insn = bfd_getb32 (buffer);
281
282 status = insn & FM11;
283 switch (status)
284 {
285 case 0:
286 dis_2_short (insn, memaddr, info, 2);
287 break;
288 case FM01:
289 dis_2_short (insn, memaddr, info, 0);
290 break;
291 case FM10:
292 dis_2_short (insn, memaddr, info, 1);
293 break;
294 case FM11:
295 dis_long (insn, memaddr, info);
296 break;
297 }
298 return 4;
299}
This page took 0.67701 seconds and 4 git commands to generate.