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