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