]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/v850-dis.c
2012-10-04 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
[thirdparty/binutils-gdb.git] / opcodes / v850-dis.c
CommitLineData
252b5132 1/* Disassemble V850 instructions.
df7b86aa
NC
2 Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005, 2007, 2010,
3 2012 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
8ad30312 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
8ad30312
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
47b0e7ad
NC
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
252b5132
RH
21
22
0d8dfecf 23#include "sysdep.h"
df7b86aa 24#include <stdio.h>
47b0e7ad 25#include "opcode/v850.h"
252b5132
RH
26#include "dis-asm.h"
27#include "opintl.h"
28
29static const char *const v850_reg_names[] =
1cd986c5
NC
30{
31 "r0", "r1", "r2", "sp", "gp", "r5", "r6", "r7",
47b0e7ad
NC
32 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
33 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
1cd986c5
NC
34 "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp"
35};
252b5132
RH
36
37static const char *const v850_sreg_names[] =
1cd986c5
NC
38{
39 "eipc/vip/mpm", "eipsw/mpc", "fepc/tid", "fepsw/ppa", "ecr/vmecr", "psw/vmtid",
40 "sr6/fpsr/vmadr/dcc", "sr7/fpepc/dc0",
41 "sr8/fpst/vpecr/dcv1", "sr9/fpcc/vptid", "sr10/fpcfg/vpadr/spal", "sr11/spau",
42 "sr12/vdecr/ipa0l", "eiic/vdtid/ipa0u", "feic/ipa1l", "dbic/ipa1u",
43 "ctpc/ipa2l", "ctpsw/ipa2u", "dbpc/ipa3l", "dbpsw/ipa3u", "ctbp/dpa0l",
44 "dir/dpa0u", "bpc/dpa0u", "asid/dpa1l",
45 "bpav/dpa1u", "bpam/dpa2l", "bpdv/dpa2u", "bpdm/dpa3l", "eiwr/dpa3u",
46 "fewr", "dbwr", "bsel"
47};
252b5132
RH
48
49static const char *const v850_cc_names[] =
1cd986c5
NC
50{
51 "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
52 "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt"
53};
252b5132 54
1cd986c5 55static const char *const v850_float_cc_names[] =
252b5132 56{
1cd986c5
NC
57 "f/t", "un/or", "eq/neq", "ueq/ogl", "olt/uge", "ult/oge", "ole/ugt", "ule/ogt",
58 "sf/st", "ngle/gle", "seq/sne", "ngl/gl", "lt/nlt", "nge/ge", "le/nle", "ngt/gt"
59};
47b0e7ad 60
47b0e7ad 61
1cd986c5
NC
62static void
63print_value (int flags, bfd_vma memaddr, struct disassemble_info *info, long value)
64{
65 if (flags & V850_PCREL)
66 {
67 bfd_vma addr = value + memaddr;
68 info->print_address_func (addr, info);
69 }
70 else if (flags & V850_OPERAND_DISP)
71 {
72 if (flags & V850_OPERAND_SIGNED)
73 {
74 info->fprintf_func (info->stream, "%ld", value);
75 }
76 else
77 {
78 info->fprintf_func (info->stream, "%lu", value);
79 }
80 }
81 else if (flags & V850E_IMMEDIATE32)
82 {
83 info->fprintf_func (info->stream, "0x%lx", value);
84 }
85 else
86 {
87 if (flags & V850_OPERAND_SIGNED)
88 {
89 info->fprintf_func (info->stream, "%ld", value);
90 }
91 else
92 {
93 info->fprintf_func (info->stream, "%lu", value);
94 }
95 }
96}
47b0e7ad 97
1cd986c5
NC
98static long
99get_operand_value (const struct v850_operand *operand,
100 unsigned long insn,
101 int bytes_read,
102 bfd_vma memaddr,
103 struct disassemble_info * info,
104 bfd_boolean noerror,
105 int *invalid)
106{
107 long value;
108 bfd_byte buffer[4];
109
110 if ((operand->flags & V850E_IMMEDIATE16)
111 || (operand->flags & V850E_IMMEDIATE16HI))
112 {
113 int status = info->read_memory_func (memaddr + bytes_read, buffer, 2, info);
114
115 if (status == 0)
116 {
117 value = bfd_getl16 (buffer);
118
119 if (operand->flags & V850E_IMMEDIATE16HI)
120 value <<= 16;
121
122 return value;
123 }
124
125 if (!noerror)
126 info->memory_error_func (status, memaddr + bytes_read, info);
127
128 return 0;
129 }
130
131 if (operand->flags & V850E_IMMEDIATE23)
132 {
133 int status = info->read_memory_func (memaddr + 2, buffer, 4, info);
134
135 if (status == 0)
136 {
137 value = bfd_getl32 (buffer);
138
139 value = (operand->extract) (value, invalid);
140
141 return value;
142 }
143
144 if (!noerror)
145 info->memory_error_func (status, memaddr + bytes_read, info);
146
147 return 0;
148 }
149
150 if (operand->flags & V850E_IMMEDIATE32)
151 {
152 int status = info->read_memory_func (memaddr + bytes_read, buffer, 4, info);
153
154 if (status == 0)
155 {
156 bytes_read += 4;
157 value = bfd_getl32 (buffer);
158
159 return value;
160 }
161
162 if (!noerror)
163 info->memory_error_func (status, memaddr + bytes_read, info);
164
165 return 0;
166 }
167
168 if (operand->extract)
169 value = (operand->extract) (insn, invalid);
170 else
171 {
172 if (operand->bits == -1)
173 value = (insn & operand->shift);
174 else
175 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
176
177 if (operand->flags & V850_OPERAND_SIGNED)
178 value = ((long)(value << (sizeof (long)*8 - operand->bits))
179 >> (sizeof (long)*8 - operand->bits));
180 }
181
182 return value;
183}
184
185
186static int
187disassemble (bfd_vma memaddr, struct disassemble_info *info, int bytes_read, unsigned long insn)
188{
189 struct v850_opcode *op = (struct v850_opcode *)v850_opcodes;
190 const struct v850_operand *operand;
191 int match = 0;
192 int target_processor;
252b5132
RH
193
194 switch (info->mach)
195 {
196 case 0:
197 default:
198 target_processor = PROCESSOR_V850;
199 break;
200
201 case bfd_mach_v850e:
202 target_processor = PROCESSOR_V850E;
203 break;
8ad30312
NC
204
205 case bfd_mach_v850e1:
1cd986c5
NC
206 target_processor = PROCESSOR_V850E;
207 break;
208
209 case bfd_mach_v850e2:
210 target_processor = PROCESSOR_V850E2;
211 break;
212
213 case bfd_mach_v850e2v3:
214 target_processor = PROCESSOR_V850E2V3;
8ad30312 215 break;
252b5132 216 }
47b0e7ad 217
1cd986c5
NC
218 /* If this is a two byte insn, then mask off the high bits. */
219 if (bytes_read == 2)
220 insn &= 0xffff;
221
252b5132
RH
222 /* Find the opcode. */
223 while (op->name)
224 {
225 if ((op->mask & insn) == op->opcode
1cd986c5
NC
226 && (op->processors & target_processor)
227 && !(op->processors & PROCESSOR_OPTION_ALIAS))
252b5132 228 {
1cd986c5 229 /* Code check start. */
b34976b6
AM
230 const unsigned char *opindex_ptr;
231 unsigned int opnum;
232 unsigned int memop;
252b5132 233
1cd986c5
NC
234 for (opindex_ptr = op->operands, opnum = 1;
235 *opindex_ptr != 0;
236 opindex_ptr++, opnum++)
237 {
238 int invalid = 0;
239 long value;
240
241 operand = &v850_operands[*opindex_ptr];
242
243 value = get_operand_value (operand, insn, bytes_read, memaddr, info, 1, &invalid);
244
245 if (invalid)
246 goto next_opcode;
247
248 if ((operand->flags & V850_NOT_R0) && value == 0 && (op->memop) <=2)
249 goto next_opcode;
250
251 if ((operand->flags & V850_NOT_SA) && value == 0xd)
252 goto next_opcode;
253
254 if ((operand->flags & V850_NOT_IMM0) && value == 0)
255 goto next_opcode;
256 }
257
258 /* Code check end. */
259
252b5132
RH
260 match = 1;
261 (*info->fprintf_func) (info->stream, "%s\t", op->name);
1cd986c5
NC
262#if 0
263 fprintf (stderr, "match: insn: %lx, mask: %lx, opcode: %lx, name: %s\n",
264 insn, op->mask, op->opcode, op->name );
265#endif
252b5132
RH
266
267 memop = op->memop;
268 /* Now print the operands.
269
270 MEMOP is the operand number at which a memory
271 address specification starts, or zero if this
272 instruction has no memory addresses.
273
274 A memory address is always two arguments.
275
276 This information allows us to determine when to
277 insert commas into the output stream as well as
278 when to insert disp[reg] expressions onto the
279 output stream. */
47b0e7ad 280
252b5132
RH
281 for (opindex_ptr = op->operands, opnum = 1;
282 *opindex_ptr != 0;
283 opindex_ptr++, opnum++)
284 {
7d063384 285 bfd_boolean square = FALSE;
b34976b6
AM
286 long value;
287 int flag;
1cd986c5 288 char *prefix;
47b0e7ad 289
252b5132 290 operand = &v850_operands[*opindex_ptr];
47b0e7ad 291
1cd986c5 292 value = get_operand_value (operand, insn, bytes_read, memaddr, info, 0, 0);
252b5132
RH
293
294 /* The first operand is always output without any
295 special handling.
296
297 For the following arguments:
298
299 If memop && opnum == memop + 1, then we need '[' since
300 we're about to output the register used in a memory
301 reference.
302
303 If memop && opnum == memop + 2, then we need ']' since
304 we just finished the register in a memory reference. We
305 also need a ',' before this operand.
306
307 Else we just need a comma.
308
309 We may need to output a trailing ']' if the last operand
47b0e7ad 310 in an instruction is the register for a memory address.
252b5132
RH
311
312 The exception (and there's always an exception) is the
313 "jmp" insn which needs square brackets around it's only
314 register argument. */
1cd986c5
NC
315 prefix = "";
316 if (operand->flags & V850_OPERAND_BANG)
317 {
318 prefix = "!";
319 }
320 else if (operand->flags & V850_OPERAND_PERCENT)
321 {
322 prefix = "%";
323 }
252b5132 324
1cd986c5 325 if (opnum == 1 && opnum == memop)
7d063384
NC
326 {
327 info->fprintf_func (info->stream, "%s[", prefix);
328 square = TRUE;
329 }
1cd986c5
NC
330 else if (opnum > 1
331 && (v850_operands[*(opindex_ptr - 1)].flags & V850_OPERAND_DISP) != 0
332 && opnum == memop)
7d063384
NC
333 {
334 info->fprintf_func (info->stream, "%s[", prefix);
335 square = TRUE;
336 }
1cd986c5
NC
337 else if (opnum > 1)
338 info->fprintf_func (info->stream, ", %s", prefix);
339
340 /* Extract the flags, ignoring ones which do not effect disassembly output. */
341 flag = operand->flags & (V850_OPERAND_REG
342 | V850_REG_EVEN
343 | V850_OPERAND_EP
344 | V850_OPERAND_SRG
345 | V850E_OPERAND_REG_LIST
346 | V850_OPERAND_CC
347 | V850_OPERAND_FLOAT_CC);
47b0e7ad 348
252b5132
RH
349 switch (flag)
350 {
1cd986c5
NC
351 case V850_OPERAND_REG: info->fprintf_func (info->stream, "%s", v850_reg_names[value]); break;
352 case (V850_OPERAND_REG|V850_REG_EVEN): info->fprintf_func (info->stream, "%s", v850_reg_names[value*2]); break;
353 case V850_OPERAND_EP: info->fprintf_func (info->stream, "ep"); break;
354 case V850_OPERAND_SRG: info->fprintf_func (info->stream, "%s", v850_sreg_names[value]); break;
47b0e7ad 355
1cd986c5 356 case V850E_OPERAND_REG_LIST:
252b5132 357 {
1cd986c5
NC
358 static int list12_regs[32] = { 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
359 0, 0, 0, 0, 0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
b34976b6
AM
360 int *regs;
361 int i;
252b5132 362 unsigned long int mask = 0;
b34976b6 363 int pc = 0;
1cd986c5 364
47b0e7ad 365
252b5132
RH
366 switch (operand->shift)
367 {
368 case 0xffe00001: regs = list12_regs; break;
252b5132
RH
369 default:
370 /* xgettext:c-format */
1cd986c5 371 fprintf (stderr, _("unknown operand shift: %x\n"), operand->shift );
47b0e7ad 372 abort ();
252b5132
RH
373 }
374
375 for (i = 0; i < 32; i++)
376 {
377 if (value & (1 << i))
378 {
379 switch (regs[ i ])
380 {
381 default: mask |= (1 << regs[ i ]); break;
382 /* xgettext:c-format */
1cd986c5 383 case 0: fprintf (stderr, _("unknown reg: %d\n"), i ); abort ();
b34976b6 384 case -1: pc = 1; break;
252b5132
RH
385 }
386 }
387 }
388
389 info->fprintf_func (info->stream, "{");
47b0e7ad 390
1cd986c5 391 if (mask || pc)
252b5132
RH
392 {
393 if (mask)
394 {
395 unsigned int bit;
b34976b6 396 int shown_one = 0;
47b0e7ad 397
252b5132
RH
398 for (bit = 0; bit < 32; bit++)
399 if (mask & (1 << bit))
400 {
401 unsigned long int first = bit;
402 unsigned long int last;
403
404 if (shown_one)
405 info->fprintf_func (info->stream, ", ");
406 else
b34976b6 407 shown_one = 1;
47b0e7ad 408
48891606 409 info->fprintf_func (info->stream, "%s", v850_reg_names[first]);
47b0e7ad 410
252b5132
RH
411 for (bit++; bit < 32; bit++)
412 if ((mask & (1 << bit)) == 0)
413 break;
414
415 last = bit;
416
417 if (last > first + 1)
1cd986c5
NC
418 {
419 info->fprintf_func (info->stream, " - %s", v850_reg_names[ last - 1 ]);
420 }
252b5132
RH
421 }
422 }
47b0e7ad 423
252b5132
RH
424 if (pc)
425 info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
252b5132 426 }
47b0e7ad 427
252b5132
RH
428 info->fprintf_func (info->stream, "}");
429 }
252b5132 430 break;
47b0e7ad 431
1cd986c5
NC
432 case V850_OPERAND_CC: info->fprintf_func (info->stream, "%s", v850_cc_names[value]); break;
433 case V850_OPERAND_FLOAT_CC: info->fprintf_func (info->stream, "%s", v850_float_cc_names[value]); break;
434
435 default:
436 print_value (operand->flags, memaddr, info, value);
252b5132 437 break;
47b0e7ad 438 }
252b5132 439
7d063384 440 if (square)
252b5132
RH
441 (*info->fprintf_func) (info->stream, "]");
442 }
443
252b5132
RH
444 /* All done. */
445 break;
446 }
1cd986c5 447 next_opcode:
252b5132
RH
448 op++;
449 }
450
1cd986c5 451 return match;
252b5132
RH
452}
453
47b0e7ad
NC
454int
455print_insn_v850 (bfd_vma memaddr, struct disassemble_info * info)
252b5132 456{
1cd986c5
NC
457 int status, status2, match;
458 bfd_byte buffer[8];
459 int length = 0, code_length = 0;
460 unsigned long insn = 0, insn2 = 0;
461 int target_processor;
462
463 switch (info->mach)
464 {
465 case 0:
466 default:
467 target_processor = PROCESSOR_V850;
468 break;
469
470 case bfd_mach_v850e:
471 target_processor = PROCESSOR_V850E;
472 break;
473
474 case bfd_mach_v850e1:
475 target_processor = PROCESSOR_V850E;
476 break;
477
478 case bfd_mach_v850e2:
479 target_processor = PROCESSOR_V850E2;
480 break;
481
482 case bfd_mach_v850e2v3:
483 target_processor = PROCESSOR_V850E2V3;
484 break;
485 }
252b5132 486
252b5132 487 status = info->read_memory_func (memaddr, buffer, 2, info);
1cd986c5
NC
488
489 if (status)
490 {
491 info->memory_error_func (status, memaddr, info);
492 return -1;
493 }
494
495 insn = bfd_getl16 (buffer);
496
497 status2 = info->read_memory_func (memaddr+2, buffer, 2 , info);
498
499 if (!status2)
252b5132 500 {
1cd986c5
NC
501 insn2 = bfd_getl16 (buffer);
502 /* fprintf (stderr, "insn2 0x%08lx\n", insn2); */
503 }
47b0e7ad 504
1cd986c5
NC
505 /* Special case. */
506 if (length == 0
507 && (target_processor == PROCESSOR_V850E2
508 || target_processor == PROCESSOR_V850E2V3))
509 {
510 if ((insn & 0xffff) == 0x02e0 /* jr 32bit */
511 && !status2 && (insn2 & 0x1) == 0)
512 {
513 length = 2;
514 code_length = 6;
515 }
516 else if ((insn & 0xffe0) == 0x02e0 /* jarl 32bit */
517 && !status2 && (insn2 & 0x1) == 0)
518 {
519 length = 2;
520 code_length = 6;
521 }
522 else if ((insn & 0xffe0) == 0x06e0 /* jmp 32bit */
523 && !status2 && (insn2 & 0x1) == 0)
252b5132 524 {
1cd986c5
NC
525 length = 2;
526 code_length = 6;
527 }
528 }
252b5132 529
1cd986c5
NC
530 if (length == 0
531 && target_processor == PROCESSOR_V850E2V3)
532 {
533 if (((insn & 0xffe0) == 0x0780 /* ld.b 23bit */
534 && !status2 && (insn2 & 0x000f) == 0x0005)
535 || ((insn & 0xffe0) == 0x07a0 /* ld.bu 23bit */
536 && !status2 && (insn2 & 0x000f) == 0x0005)
537 || ((insn & 0xffe0) == 0x0780 /* ld.h 23bit */
538 && !status2 && (insn2 & 0x000f) == 0x0007)
539 || ((insn & 0xffe0) == 0x07a0 /* ld.hu 23bit */
540 && !status2 && (insn2 & 0x000f) == 0x0007)
541 || ((insn & 0xffe0) == 0x0780 /* ld.w 23bit */
542 && !status2 && (insn2 & 0x000f) == 0x0009))
543 {
544 length = 4;
545 code_length = 6;
546 }
547 else if (((insn & 0xffe0) == 0x0780 /* st.b 23bit */
548 && !status2 && (insn2 & 0x000f) == 0x000d)
549 || ((insn & 0xffe0) == 0x07a0 /* st.h 23bit */
550 && !status2 && (insn2 & 0x000f) == 0x000d)
551 || ((insn & 0xffe0) == 0x0780 /* st.w 23bit */
552 && !status2 && (insn2 & 0x000f) == 0x000f))
553 {
554 length = 4;
555 code_length = 6;
252b5132
RH
556 }
557 }
47b0e7ad 558
1cd986c5
NC
559 if (length == 0
560 && target_processor != PROCESSOR_V850)
252b5132 561 {
1cd986c5
NC
562 if ((insn & 0xffe0) == 0x0620) /* 32 bit MOV */
563 {
564 length = 2;
565 code_length = 6;
566 }
567 else if ((insn & 0xffc0) == 0x0780 /* prepare {list}, imm5, imm16<<16 */
568 && !status2 && (insn2 & 0x001f) == 0x0013)
569 {
570 length = 4;
571 code_length = 6;
572 }
573 else if ((insn & 0xffc0) == 0x0780 /* prepare {list}, imm5, imm16 */
574 && !status2 && (insn2 & 0x001f) == 0x000b)
575 {
576 length = 4;
577 code_length = 6;
578 }
579 else if ((insn & 0xffc0) == 0x0780 /* prepare {list}, imm5, imm32 */
580 && !status2 && (insn2 & 0x001f) == 0x001b)
581 {
582 length = 4;
583 code_length = 8;
584 }
585 }
586
587 if (length == 4
588 || (length == 0
589 && (insn & 0x0600) == 0x0600))
590 {
591 /* This is a 4 byte insn. */
592 status = info->read_memory_func (memaddr, buffer, 4, info);
593 if (!status)
594 {
595 insn = bfd_getl32 (buffer);
596
597 if (!length)
598 length = code_length = 4;
599 }
600 }
601
602 if (code_length > length)
603 {
604 status = info->read_memory_func (memaddr + length, buffer, code_length - length, info);
605 if (status)
606 length = 0;
607 }
608
609 if (length == 0 && !status)
610 length = code_length = 2;
611
612 if (length == 2)
613 insn &= 0xffff;
614
615 match = disassemble (memaddr, info, length, insn);
616
617 if (!match)
618 {
619 int l = 0;
620
621 status = info->read_memory_func (memaddr, buffer, code_length, info);
622
623 while (l < code_length)
624 {
625 if (code_length - l == 2)
626 {
627 insn = bfd_getl16 (buffer + l) & 0xffff;
628 info->fprintf_func (info->stream, ".short\t0x%04lx", insn);
629 l += 2;
630 }
631 else
632 {
633 insn = bfd_getl32 (buffer + l);
634 info->fprintf_func (info->stream, ".long\t0x%08lx", insn);
635 l += 4;
636 }
637 }
252b5132
RH
638 }
639
1cd986c5 640 return code_length;
252b5132 641}