1 /* Disassemble V850 instructions.
2 Copyright (C) 1996-2024 Free Software Foundation, Inc.
4 This file is part of the GNU opcodes library.
6 This library is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 It is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
25 #include "opcode/v850.h"
26 #include "disassemble.h"
28 #include "libiberty.h"
30 static const int v850_cacheop_codes
[] =
32 0x00, 0x20, 0x40, 0x60, 0x61, 0x04, 0x06,
33 0x07, 0x24, 0x26, 0x27, 0x44, 0x64, 0x65, -1
36 static const int v850_prefop_codes
[] =
40 print_value (int flags
,
42 struct disassemble_info
*info
,
45 if (flags
& V850_PCREL
)
47 bfd_vma addr
= value
+ memaddr
;
49 if (flags
& V850_INVERSE_PCREL
)
50 addr
= memaddr
- value
;
51 info
->print_address_func (addr
, info
);
53 else if (flags
& V850_OPERAND_DISP
)
55 if (flags
& V850_OPERAND_SIGNED
)
57 info
->fprintf_func (info
->stream
, "%ld", value
);
61 info
->fprintf_func (info
->stream
, "%lu", value
);
64 else if ((flags
& V850E_IMMEDIATE32
)
65 || (flags
& V850E_IMMEDIATE16HI
))
67 info
->fprintf_func (info
->stream
, "0x%lx", value
);
71 if (flags
& V850_OPERAND_SIGNED
)
73 info
->fprintf_func (info
->stream
, "%ld", value
);
77 info
->fprintf_func (info
->stream
, "%lu", value
);
83 get_operand_value (const struct v850_operand
*operand
,
87 struct disassemble_info
* info
,
94 if ((operand
->flags
& V850E_IMMEDIATE16
)
95 || (operand
->flags
& V850E_IMMEDIATE16HI
))
97 int status
= info
->read_memory_func (memaddr
+ bytes_read
, buffer
, 2, info
);
101 value
= bfd_getl16 (buffer
);
103 if (operand
->flags
& V850E_IMMEDIATE16HI
)
105 else if (value
& 0x8000)
106 value
|= (-1UL << 16);
112 info
->memory_error_func (status
, memaddr
+ bytes_read
, info
);
117 if (operand
->flags
& V850E_IMMEDIATE23
)
119 int status
= info
->read_memory_func (memaddr
+ 2, buffer
, 4, info
);
123 value
= bfd_getl32 (buffer
);
125 value
= (operand
->extract
) (value
, invalid
);
131 info
->memory_error_func (status
, memaddr
+ bytes_read
, info
);
136 if (operand
->flags
& V850E_IMMEDIATE32
)
138 int status
= info
->read_memory_func (memaddr
+ bytes_read
, buffer
, 4, info
);
143 value
= bfd_getl32 (buffer
);
149 info
->memory_error_func (status
, memaddr
+ bytes_read
, info
);
154 if (operand
->extract
)
155 value
= (operand
->extract
) (insn
, invalid
);
158 if (operand
->bits
== -1)
159 value
= (insn
& operand
->shift
);
161 value
= (insn
>> operand
->shift
) & ((1ul << operand
->bits
) - 1);
163 if (operand
->flags
& V850_OPERAND_SIGNED
)
165 unsigned long sign
= 1ul << (operand
->bits
- 1);
166 value
= (value
^ sign
) - sign
;
174 get_v850_sreg_name (unsigned int reg
)
176 static const char *const v850_sreg_names
[] =
178 "eipc/vip/mpm", "eipsw/mpc", "fepc/tid", "fepsw/ppa", "ecr/vmecr", "psw/vmtid",
179 "sr6/fpsr/vmadr/dcc", "sr7/fpepc/dc0",
180 "sr8/fpst/vpecr/dcv1", "sr9/fpcc/vptid", "sr10/fpcfg/vpadr/spal", "sr11/spau",
181 "sr12/vdecr/ipa0l", "eiic/vdtid/ipa0u", "feic/ipa1l", "dbic/ipa1u",
182 "ctpc/ipa2l", "ctpsw/ipa2u", "dbpc/ipa3l", "dbpsw/ipa3u", "ctbp/dpa0l",
183 "dir/dpa0u", "bpc/dpa0u", "asid/dpa1l",
184 "bpav/dpa1u", "bpam/dpa2l", "bpdv/dpa2u", "bpdm/dpa3l", "eiwr/dpa3u",
185 "fewr", "dbwr", "bsel"
188 if (reg
< ARRAY_SIZE (v850_sreg_names
))
189 return v850_sreg_names
[reg
];
190 return _("<invalid s-reg number>");
194 get_v850_reg_name (unsigned int reg
)
196 static const char *const v850_reg_names
[] =
198 "r0", "r1", "r2", "sp", "gp", "r5", "r6", "r7",
199 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
200 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
201 "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp"
204 if (reg
< ARRAY_SIZE (v850_reg_names
))
205 return v850_reg_names
[reg
];
206 return _("<invalid reg number>");
210 get_v850_vreg_name (unsigned int reg
)
212 static const char *const v850_vreg_names
[] =
214 "vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7", "vr8", "vr9",
215 "vr10", "vr11", "vr12", "vr13", "vr14", "vr15", "vr16", "vr17", "vr18",
216 "vr19", "vr20", "vr21", "vr22", "vr23", "vr24", "vr25", "vr26", "vr27",
217 "vr28", "vr29", "vr30", "vr31"
220 if (reg
< ARRAY_SIZE (v850_vreg_names
))
221 return v850_vreg_names
[reg
];
222 return _("<invalid v-reg number>");
226 get_v850_cc_name (unsigned int reg
)
228 static const char *const v850_cc_names
[] =
230 "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
231 "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt"
234 if (reg
< ARRAY_SIZE (v850_cc_names
))
235 return v850_cc_names
[reg
];
236 return _("<invalid CC-reg number>");
240 get_v850_float_cc_name (unsigned int reg
)
242 static const char *const v850_float_cc_names
[] =
244 "f/t", "un/or", "eq/neq", "ueq/ogl", "olt/uge", "ult/oge", "ole/ugt", "ule/ogt",
245 "sf/st", "ngle/gle", "seq/sne", "ngl/gl", "lt/nlt", "nge/ge", "le/nle", "ngt/gt"
248 if (reg
< ARRAY_SIZE (v850_float_cc_names
))
249 return v850_float_cc_names
[reg
];
250 return _("<invalid float-CC-reg number>");
254 get_v850_cacheop_name (unsigned int reg
)
256 static const char *const v850_cacheop_names
[] =
258 "chbii", "cibii", "cfali", "cisti", "cildi", "chbid", "chbiwbd",
259 "chbwbd", "cibid", "cibiwbd", "cibwbd", "cfald", "cistd", "cildd"
262 if (reg
< ARRAY_SIZE (v850_cacheop_names
))
263 return v850_cacheop_names
[reg
];
264 return _("<invalid cacheop number>");
268 get_v850_prefop_name (unsigned int reg
)
270 static const char *const v850_prefop_names
[] =
271 { "prefi", "prefd" };
273 if (reg
< ARRAY_SIZE (v850_prefop_names
))
274 return v850_prefop_names
[reg
];
275 return _("<invalid prefop number>");
279 disassemble (bfd_vma memaddr
,
280 struct disassemble_info
*info
,
284 struct v850_opcode
*op
= (struct v850_opcode
*) v850_opcodes
;
285 const struct v850_operand
*operand
;
287 int target_processor
;
293 target_processor
= PROCESSOR_V850
;
297 target_processor
= PROCESSOR_V850E
;
300 case bfd_mach_v850e1
:
301 target_processor
= PROCESSOR_V850E
;
304 case bfd_mach_v850e2
:
305 target_processor
= PROCESSOR_V850E2
;
308 case bfd_mach_v850e2v3
:
309 target_processor
= PROCESSOR_V850E2V3
;
312 case bfd_mach_v850e3v5
:
313 target_processor
= PROCESSOR_V850E3V5
;
317 /* If this is a two byte insn, then mask off the high bits. */
321 /* Find the opcode. */
324 if ((op
->mask
& insn
) == op
->opcode
325 && (op
->processors
& target_processor
)
326 && !(op
->processors
& PROCESSOR_OPTION_ALIAS
))
328 /* Code check start. */
329 const unsigned char *opindex_ptr
;
333 for (opindex_ptr
= op
->operands
, opnum
= 1;
335 opindex_ptr
++, opnum
++)
340 operand
= &v850_operands
[*opindex_ptr
];
342 value
= get_operand_value (operand
, insn
, bytes_read
, memaddr
,
348 if ((operand
->flags
& V850_NOT_R0
) && value
== 0 && (op
->memop
) <=2)
351 if ((operand
->flags
& V850_NOT_SA
) && value
== 0xd)
354 if ((operand
->flags
& V850_NOT_IMM0
) && value
== 0)
358 /* Code check end. */
361 (*info
->fprintf_func
) (info
->stream
, "%s\t", op
->name
);
363 fprintf (stderr
, "match: insn: %lx, mask: %lx, opcode: %lx, name: %s\n",
364 insn
, op
->mask
, op
->opcode
, op
->name
);
368 /* Now print the operands.
370 MEMOP is the operand number at which a memory
371 address specification starts, or zero if this
372 instruction has no memory addresses.
374 A memory address is always two arguments.
376 This information allows us to determine when to
377 insert commas into the output stream as well as
378 when to insert disp[reg] expressions onto the
381 for (opindex_ptr
= op
->operands
, opnum
= 1;
383 opindex_ptr
++, opnum
++)
390 operand
= &v850_operands
[*opindex_ptr
];
392 value
= get_operand_value (operand
, insn
, bytes_read
, memaddr
,
395 /* The first operand is always output without any
398 For the following arguments:
400 If memop && opnum == memop + 1, then we need '[' since
401 we're about to output the register used in a memory
404 If memop && opnum == memop + 2, then we need ']' since
405 we just finished the register in a memory reference. We
406 also need a ',' before this operand.
408 Else we just need a comma.
410 We may need to output a trailing ']' if the last operand
411 in an instruction is the register for a memory address.
413 The exception (and there's always an exception) are the
414 "jmp" insn which needs square brackets around it's only
415 register argument, and the clr1/not1/set1/tst1 insns
416 which [...] around their second register argument. */
419 if (operand
->flags
& V850_OPERAND_BANG
)
423 else if (operand
->flags
& V850_OPERAND_PERCENT
)
428 if (opnum
== 1 && opnum
== memop
)
430 info
->fprintf_func (info
->stream
, "%s[", prefix
);
433 else if ( (strcmp ("stc.w", op
->name
) == 0
434 || strcmp ("cache", op
->name
) == 0
435 || strcmp ("pref", op
->name
) == 0)
436 && opnum
== 2 && opnum
== memop
)
438 info
->fprintf_func (info
->stream
, ", [");
441 else if ( (strcmp (op
->name
, "pushsp") == 0
442 || strcmp (op
->name
, "popsp") == 0
443 || strcmp (op
->name
, "dbpush" ) == 0)
446 info
->fprintf_func (info
->stream
, "-");
449 && (v850_operands
[*(opindex_ptr
- 1)].flags
450 & V850_OPERAND_DISP
) != 0
453 info
->fprintf_func (info
->stream
, "%s[", prefix
);
457 && ( op
->opcode
== 0x00e407e0 /* clr1 */
458 || op
->opcode
== 0x00e207e0 /* not1 */
459 || op
->opcode
== 0x00e007e0 /* set1 */
460 || op
->opcode
== 0x00e607e0 /* tst1 */
463 info
->fprintf_func (info
->stream
, ", %s[", prefix
);
467 info
->fprintf_func (info
->stream
, ", %s", prefix
);
469 /* Extract the flags, ignoring ones which do not
470 effect disassembly output. */
471 flag
= operand
->flags
& (V850_OPERAND_REG
475 | V850E_OPERAND_REG_LIST
478 | V850_OPERAND_CACHEOP
479 | V850_OPERAND_PREFOP
480 | V850_OPERAND_FLOAT_CC
);
484 case V850_OPERAND_REG
:
485 info
->fprintf_func (info
->stream
, "%s", get_v850_reg_name (value
));
487 case (V850_OPERAND_REG
|V850_REG_EVEN
):
488 info
->fprintf_func (info
->stream
, "%s", get_v850_reg_name (value
* 2));
490 case V850_OPERAND_EP
:
491 info
->fprintf_func (info
->stream
, "ep");
493 case V850_OPERAND_SRG
:
494 info
->fprintf_func (info
->stream
, "%s", get_v850_sreg_name (value
));
496 case V850E_OPERAND_REG_LIST
:
498 static int list12_regs
[32] = { 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
499 0, 0, 0, 0, 0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
502 unsigned int mask
= 0;
505 switch (operand
->shift
)
507 case 0xffe00001: regs
= list12_regs
; break;
509 /* xgettext:c-format */
510 opcodes_error_handler (_("unknown operand shift: %x"),
515 for (i
= 0; i
< 32; i
++)
517 if (value
& (1u << i
))
522 mask
|= (1u << regs
[ i
]);
525 /* xgettext:c-format */
526 opcodes_error_handler (_("unknown reg: %d"), i
);
536 info
->fprintf_func (info
->stream
, "{");
545 for (bit
= 0; bit
< 32; bit
++)
546 if (mask
& (1u << bit
))
548 unsigned int first
= bit
;
552 info
->fprintf_func (info
->stream
, ", ");
556 info
->fprintf_func (info
->stream
, "%s", get_v850_reg_name (first
));
558 for (bit
++; bit
< 32; bit
++)
559 if ((mask
& (1u << bit
)) == 0)
564 if (last
> first
+ 1)
566 info
->fprintf_func (info
->stream
, " - %s", get_v850_reg_name (last
- 1));
572 info
->fprintf_func (info
->stream
, "%sPC", mask
? ", " : "");
575 info
->fprintf_func (info
->stream
, "}");
579 case V850_OPERAND_CC
:
580 info
->fprintf_func (info
->stream
, "%s", get_v850_cc_name (value
));
583 case V850_OPERAND_FLOAT_CC
:
584 info
->fprintf_func (info
->stream
, "%s", get_v850_float_cc_name (value
));
587 case V850_OPERAND_CACHEOP
:
591 for (idx
= 0; v850_cacheop_codes
[idx
] != -1; idx
++)
593 if (value
== v850_cacheop_codes
[idx
])
595 info
->fprintf_func (info
->stream
, "%s",
596 get_v850_cacheop_name (idx
));
597 goto MATCH_CACHEOP_CODE
;
600 info
->fprintf_func (info
->stream
, "%d", (int) value
);
605 case V850_OPERAND_PREFOP
:
609 for (idx
= 0; v850_prefop_codes
[idx
] != -1; idx
++)
611 if (value
== v850_prefop_codes
[idx
])
613 info
->fprintf_func (info
->stream
, "%s",
614 get_v850_prefop_name (idx
));
615 goto MATCH_PREFOP_CODE
;
618 info
->fprintf_func (info
->stream
, "%d", (int) value
);
623 case V850_OPERAND_VREG
:
624 info
->fprintf_func (info
->stream
, "%s", get_v850_vreg_name (value
));
628 print_value (operand
->flags
, memaddr
, info
, value
);
633 (*info
->fprintf_func
) (info
->stream
, "]");
647 print_insn_v850 (bfd_vma memaddr
, struct disassemble_info
* info
)
649 int status
, status2
, match
;
651 int length
= 0, code_length
= 0;
652 unsigned long insn
= 0, insn2
= 0;
653 int target_processor
;
659 target_processor
= PROCESSOR_V850
;
663 target_processor
= PROCESSOR_V850E
;
666 case bfd_mach_v850e1
:
667 target_processor
= PROCESSOR_V850E
;
670 case bfd_mach_v850e2
:
671 target_processor
= PROCESSOR_V850E2
;
674 case bfd_mach_v850e2v3
:
675 target_processor
= PROCESSOR_V850E2V3
;
678 case bfd_mach_v850e3v5
:
679 target_processor
= PROCESSOR_V850E3V5
;
683 status
= info
->read_memory_func (memaddr
, buffer
, 2, info
);
687 info
->memory_error_func (status
, memaddr
, info
);
691 insn
= bfd_getl16 (buffer
);
693 status2
= info
->read_memory_func (memaddr
+2, buffer
, 2 , info
);
697 insn2
= bfd_getl16 (buffer
);
698 /* fprintf (stderr, "insn2 0x%08lx\n", insn2); */
703 && ((target_processor
& PROCESSOR_V850E2_UP
) != 0))
705 if ((insn
& 0xffff) == 0x02e0 /* jr 32bit */
706 && !status2
&& (insn2
& 0x1) == 0)
711 else if ((insn
& 0xffe0) == 0x02e0 /* jarl 32bit */
712 && !status2
&& (insn2
& 0x1) == 0)
717 else if ((insn
& 0xffe0) == 0x06e0 /* jmp 32bit */
718 && !status2
&& (insn2
& 0x1) == 0)
726 && ((target_processor
& PROCESSOR_V850E3V5_UP
) != 0))
728 if ( ((insn
& 0xffe0) == 0x07a0 /* ld.dw 23bit (v850e3v5) */
729 && !status2
&& (insn2
& 0x000f) == 0x0009)
730 || ((insn
& 0xffe0) == 0x07a0 /* st.dw 23bit (v850e3v5) */
731 && !status2
&& (insn2
& 0x000f) == 0x000f))
739 && ((target_processor
& PROCESSOR_V850E2V3_UP
) != 0))
741 if (((insn
& 0xffe0) == 0x0780 /* ld.b 23bit */
742 && !status2
&& (insn2
& 0x000f) == 0x0005)
743 || ((insn
& 0xffe0) == 0x07a0 /* ld.bu 23bit */
744 && !status2
&& (insn2
& 0x000f) == 0x0005)
745 || ((insn
& 0xffe0) == 0x0780 /* ld.h 23bit */
746 && !status2
&& (insn2
& 0x000f) == 0x0007)
747 || ((insn
& 0xffe0) == 0x07a0 /* ld.hu 23bit */
748 && !status2
&& (insn2
& 0x000f) == 0x0007)
749 || ((insn
& 0xffe0) == 0x0780 /* ld.w 23bit */
750 && !status2
&& (insn2
& 0x000f) == 0x0009))
755 else if (((insn
& 0xffe0) == 0x0780 /* st.b 23bit */
756 && !status2
&& (insn2
& 0x000f) == 0x000d)
757 || ((insn
& 0xffe0) == 0x07a0 /* st.h 23bit */
758 && !status2
&& (insn2
& 0x000f) == 0x000d)
759 || ((insn
& 0xffe0) == 0x0780 /* st.w 23bit */
760 && !status2
&& (insn2
& 0x000f) == 0x000f))
768 && target_processor
!= PROCESSOR_V850
)
770 if ((insn
& 0xffe0) == 0x0620) /* 32 bit MOV */
775 else if ((insn
& 0xffc0) == 0x0780 /* prepare {list}, imm5, imm16<<16 */
776 && !status2
&& (insn2
& 0x001f) == 0x0013)
781 else if ((insn
& 0xffc0) == 0x0780 /* prepare {list}, imm5, imm16 */
782 && !status2
&& (insn2
& 0x001f) == 0x000b)
787 else if ((insn
& 0xffc0) == 0x0780 /* prepare {list}, imm5, imm32 */
788 && !status2
&& (insn2
& 0x001f) == 0x001b)
797 && (insn
& 0x0600) == 0x0600))
799 /* This is a 4 byte insn. */
800 status
= info
->read_memory_func (memaddr
, buffer
, 4, info
);
803 insn
= bfd_getl32 (buffer
);
806 length
= code_length
= 4;
810 if (code_length
> length
)
812 status
= info
->read_memory_func (memaddr
+ length
, buffer
, code_length
- length
, info
);
817 if (length
== 0 && !status
)
818 length
= code_length
= 2;
823 /* when the last 2 bytes of section is 0xffff, length will be 0 and cause infinitive loop */
827 match
= disassemble (memaddr
, info
, length
, insn
);
833 status
= info
->read_memory_func (memaddr
, buffer
, code_length
, info
);
835 while (l
< code_length
)
837 if (code_length
- l
== 2)
839 insn
= bfd_getl16 (buffer
+ l
) & 0xffff;
840 info
->fprintf_func (info
->stream
, ".short\t0x%04lx", insn
);
845 insn
= bfd_getl32 (buffer
+ l
);
846 info
->fprintf_func (info
->stream
, ".long\t0x%08lx", insn
);