source: branches/libc-0.6/src/binutils/opcodes/d30v-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: 9.9 KB
Line 
1/* Disassemble D30V instructions.
2 Copyright 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#include "sysdep.h"
20#include "opcode/d30v.h"
21#include "dis-asm.h"
22#include "opintl.h"
23
24#define PC_MASK 0xFFFFFFFF
25
26static int lookup_opcode PARAMS ((struct d30v_insn *insn, long num, int is_long));
27static void print_insn PARAMS ((struct disassemble_info *info, bfd_vma memaddr, long long num,
28 struct d30v_insn *insn, int is_long, int show_ext));
29static int extract_value PARAMS ((long long num, struct d30v_operand *oper, int is_long));
30
31int
32print_insn_d30v (memaddr, info)
33 bfd_vma memaddr;
34 struct disassemble_info *info;
35{
36 int status, result;
37 bfd_byte buffer[12];
38 unsigned long in1, in2;
39 struct d30v_insn insn;
40 long long num;
41
42 insn.form = (struct d30v_format *) NULL;
43
44 info->bytes_per_line = 8;
45 info->bytes_per_chunk = 4;
46 info->display_endian = BFD_ENDIAN_BIG;
47
48 status = (*info->read_memory_func) (memaddr, buffer, 4, info);
49 if (status != 0)
50 {
51 (*info->memory_error_func) (status, memaddr, info);
52 return -1;
53 }
54 in1 = bfd_getb32 (buffer);
55
56 status = (*info->read_memory_func) (memaddr + 4, buffer, 4, info);
57 if (status != 0)
58 {
59 info->bytes_per_line = 8;
60 if (!(result = lookup_opcode (&insn, in1, 0)))
61 (*info->fprintf_func) (info->stream, ".long\t0x%x", in1);
62 else
63 print_insn (info, memaddr, (long long) in1, &insn, 0, result);
64 return 4;
65 }
66 in2 = bfd_getb32 (buffer);
67
68 if (in1 & in2 & FM01)
69 {
70 /* LONG instruction. */
71 if (!(result = lookup_opcode (&insn, in1, 1)))
72 {
73 (*info->fprintf_func) (info->stream, ".long\t0x%x,0x%x", in1, in2);
74 return 8;
75 }
76 num = (long long) in1 << 32 | in2;
77 print_insn (info, memaddr, num, &insn, 1, result);
78 }
79 else
80 {
81 num = in1;
82 if (!(result = lookup_opcode (&insn, in1, 0)))
83 (*info->fprintf_func) (info->stream, ".long\t0x%x", in1);
84 else
85 print_insn (info, memaddr, num, &insn, 0, result);
86
87 switch (((in1 >> 31) << 1) | (in2 >> 31))
88 {
89 case 0:
90 (*info->fprintf_func) (info->stream, "\t||\t");
91 break;
92 case 1:
93 (*info->fprintf_func) (info->stream, "\t->\t");
94 break;
95 case 2:
96 (*info->fprintf_func) (info->stream, "\t<-\t");
97 default:
98 break;
99 }
100
101 insn.form = (struct d30v_format *) NULL;
102 num = in2;
103 if (!(result = lookup_opcode (&insn, in2, 0)))
104 (*info->fprintf_func) (info->stream, ".long\t0x%x", in2);
105 else
106 print_insn (info, memaddr, num, &insn, 0, result);
107 }
108 return 8;
109}
110
111/* Return 0 if lookup fails,
112 1 if found and only one form,
113 2 if found and there are short and long forms. */
114
115static int
116lookup_opcode (insn, num, is_long)
117 struct d30v_insn *insn;
118 long num;
119 int is_long;
120{
121 int i = 0, index;
122 struct d30v_format *f;
123 struct d30v_opcode *op = (struct d30v_opcode *) d30v_opcode_table;
124 int op1 = (num >> 25) & 0x7;
125 int op2 = (num >> 20) & 0x1f;
126 int mod = (num >> 18) & 0x3;
127
128 /* Find the opcode. */
129 do
130 {
131 if ((op->op1 == op1) && (op->op2 == op2))
132 break;
133 op++;
134 }
135 while (op->name);
136
137 if (!op || !op->name)
138 return 0;
139
140 while (op->op1 == op1 && op->op2 == op2)
141 {
142 /* Scan through all the formats for the opcode. */
143 index = op->format[i++];
144 do
145 {
146 f = (struct d30v_format *) &d30v_format_table[index];
147 while (f->form == index)
148 {
149 if ((!is_long || f->form >= LONG) && (f->modifier == mod))
150 {
151 insn->form = f;
152 break;
153 }
154 f++;
155 }
156 if (insn->form)
157 break;
158 }
159 while ((index = op->format[i++]) != 0);
160 if (insn->form)
161 break;
162 op++;
163 i = 0;
164 }
165 if (insn->form == NULL)
166 return 0;
167
168 insn->op = op;
169 insn->ecc = (num >> 28) & 0x7;
170 if (op->format[1])
171 return 2;
172 else
173 return 1;
174}
175
176static void
177print_insn (info, memaddr, num, insn, is_long, show_ext)
178 struct disassemble_info *info;
179 bfd_vma memaddr;
180 long long num;
181 struct d30v_insn *insn;
182 int is_long;
183 int show_ext;
184{
185 int val, opnum, need_comma = 0;
186 struct d30v_operand *oper;
187 int i, match, opind = 0, need_paren = 0, found_control = 0;
188
189 (*info->fprintf_func) (info->stream, "%s", insn->op->name);
190
191 /* Check for CMP or CMPU. */
192 if (d30v_operand_table[insn->form->operands[0]].flags & OPERAND_NAME)
193 {
194 opind++;
195 val =
196 extract_value (num,
197 (struct d30v_operand *) &d30v_operand_table[insn->form->operands[0]],
198 is_long);
199 (*info->fprintf_func) (info->stream, "%s", d30v_cc_names[val]);
200 }
201
202 /* Add in ".s" or ".l". */
203 if (show_ext == 2)
204 {
205 if (is_long)
206 (*info->fprintf_func) (info->stream, ".l");
207 else
208 (*info->fprintf_func) (info->stream, ".s");
209 }
210
211 if (insn->ecc)
212 (*info->fprintf_func) (info->stream, "/%s", d30v_ecc_names[insn->ecc]);
213
214 (*info->fprintf_func) (info->stream, "\t");
215
216 while ((opnum = insn->form->operands[opind++]) != 0)
217 {
218 int bits;
219 oper = (struct d30v_operand *) &d30v_operand_table[opnum];
220 bits = oper->bits;
221 if (oper->flags & OPERAND_SHIFT)
222 bits += 3;
223
224 if (need_comma
225 && oper->flags != OPERAND_PLUS
226 && oper->flags != OPERAND_MINUS)
227 {
228 need_comma = 0;
229 (*info->fprintf_func) (info->stream, ", ");
230 }
231
232 if (oper->flags == OPERAND_ATMINUS)
233 {
234 (*info->fprintf_func) (info->stream, "@-");
235 continue;
236 }
237 if (oper->flags == OPERAND_MINUS)
238 {
239 (*info->fprintf_func) (info->stream, "-");
240 continue;
241 }
242 if (oper->flags == OPERAND_PLUS)
243 {
244 (*info->fprintf_func) (info->stream, "+");
245 continue;
246 }
247 if (oper->flags == OPERAND_ATSIGN)
248 {
249 (*info->fprintf_func) (info->stream, "@");
250 continue;
251 }
252 if (oper->flags == OPERAND_ATPAR)
253 {
254 (*info->fprintf_func) (info->stream, "@(");
255 need_paren = 1;
256 continue;
257 }
258
259 if (oper->flags == OPERAND_SPECIAL)
260 continue;
261
262 val = extract_value (num, oper, is_long);
263
264 if (oper->flags & OPERAND_REG)
265 {
266 match = 0;
267 if (oper->flags & OPERAND_CONTROL)
268 {
269 struct d30v_operand *oper3 =
270 (struct d30v_operand *) &d30v_operand_table[insn->form->operands[2]];
271 int id = extract_value (num, oper3, is_long);
272 found_control = 1;
273 switch (id)
274 {
275 case 0:
276 val |= OPERAND_CONTROL;
277 break;
278 case 1:
279 case 2:
280 val = OPERAND_CONTROL + MAX_CONTROL_REG + id;
281 break;
282 case 3:
283 val |= OPERAND_FLAG;
284 break;
285 default:
286 fprintf (stderr, "illegal id (%d)\n", id);
287 }
288 }
289 else if (oper->flags & OPERAND_ACC)
290 val |= OPERAND_ACC;
291 else if (oper->flags & OPERAND_FLAG)
292 val |= OPERAND_FLAG;
293 for (i = 0; i < reg_name_cnt (); i++)
294 {
295 if (val == pre_defined_registers[i].value)
296 {
297 if (pre_defined_registers[i].pname)
298 (*info->fprintf_func)
299 (info->stream, "%s", pre_defined_registers[i].pname);
300 else
301 (*info->fprintf_func)
302 (info->stream, "%s", pre_defined_registers[i].name);
303 match = 1;
304 break;
305 }
306 }
307 if (match == 0)
308 {
309 /* This would only get executed if a register was not in
310 the register table. */
311 (*info->fprintf_func)
312 (info->stream, _("<unknown register %d>"), val & 0x3F);
313 }
314 }
315 /* repeati has a relocation, but its first argument is a plain
316 immediate. OTOH instructions like djsri have a pc-relative
317 delay target, but an absolute jump target. Therefore, a test
318 of insn->op->reloc_flag is not specific enough; we must test
319 if the actual operand we are handling now is pc-relative. */
320 else if (oper->flags & OPERAND_PCREL)
321 {
322 int neg = 0;
323
324 /* IMM6S3 is unsigned. */
325 if (oper->flags & OPERAND_SIGNED || bits == 32)
326 {
327 long max;
328 max = (1 << (bits - 1));
329 if (val & max)
330 {
331 if (bits == 32)
332 val = -val;
333 else
334 val = -val & ((1 << bits) - 1);
335 neg = 1;
336 }
337 }
338 if (neg)
339 {
340 (*info->fprintf_func) (info->stream, "-%x\t(", val);
341 (*info->print_address_func) ((memaddr - val) & PC_MASK, info);
342 (*info->fprintf_func) (info->stream, ")");
343 }
344 else
345 {
346 (*info->fprintf_func) (info->stream, "%x\t(", val);
347 (*info->print_address_func) ((memaddr + val) & PC_MASK, info);
348 (*info->fprintf_func) (info->stream, ")");
349 }
350 }
351 else if (insn->op->reloc_flag == RELOC_ABS)
352 {
353 (*info->print_address_func) (val, info);
354 }
355 else
356 {
357 if (oper->flags & OPERAND_SIGNED)
358 {
359 int max = (1 << (bits - 1));
360 if (val & max)
361 {
362 val = -val;
363 if (bits < 32)
364 val &= ((1 << bits) - 1);
365 (*info->fprintf_func) (info->stream, "-");
366 }
367 }
368 (*info->fprintf_func) (info->stream, "0x%x", val);
369 }
370 /* If there is another operand, then write a comma and space. */
371 if (insn->form->operands[opind] && !(found_control && opind == 2))
372 need_comma = 1;
373 }
374 if (need_paren)
375 (*info->fprintf_func) (info->stream, ")");
376}
377
378static int
379extract_value (num, oper, is_long)
380 long long num;
381 struct d30v_operand *oper;
382 int is_long;
383{
384 int val;
385 int shift = 12 - oper->position;
386 int mask = (0xFFFFFFFF >> (32 - oper->bits));
387
388 if (is_long)
389 {
390 if (oper->bits == 32)
391 {
392 /* Piece together 32-bit constant. */
393 val = ((num & 0x3FFFF)
394 | ((num & 0xFF00000) >> 2)
395 | ((num & 0x3F00000000LL) >> 6));
396 }
397 else
398 val = (num >> (32 + shift)) & mask;
399 }
400 else
401 val = (num >> shift) & mask;
402
403 if (oper->flags & OPERAND_SHIFT)
404 val <<= 3;
405
406 return val;
407}
Note: See TracBrowser for help on using the repository browser.