source: branches/libc-0.6/src/binutils/opcodes/d10v-dis.c

Last change on this file was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

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