1 /* Disassemble D30V instructions.
2 Copyright (C) 1997-2019 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. */
23 #include "opcode/d30v.h"
24 #include "disassemble.h"
26 #include "libiberty.h"
28 #define PC_MASK 0xFFFFFFFF
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. */
35 lookup_opcode (struct d30v_insn
*insn
, long num
, int is_long
)
38 struct d30v_format
*f
;
39 struct d30v_opcode
*op
= (struct d30v_opcode
*) d30v_opcode_table
;
40 int op1
= (num
>> 25) & 0x7;
41 int op2
= (num
>> 20) & 0x1f;
42 int mod
= (num
>> 18) & 0x3;
44 /* Find the opcode. */
47 if ((op
->op1
== op1
) && (op
->op2
== op2
))
56 while (op
->op1
== op1
&& op
->op2
== op2
)
58 /* Scan through all the formats for the opcode. */
59 op_index
= op
->format
[i
++];
62 f
= (struct d30v_format
*) &d30v_format_table
[op_index
];
63 while (f
->form
== op_index
)
65 if ((!is_long
|| f
->form
>= LONG
) && (f
->modifier
== mod
))
75 while ((op_index
= op
->format
[i
++]) != 0);
81 if (insn
->form
== NULL
)
85 insn
->ecc
= (num
>> 28) & 0x7;
93 extract_value (long long num
, struct d30v_operand
*oper
, int is_long
)
96 int shift
= 12 - oper
->position
;
97 int mask
= (0xFFFFFFFF >> (32 - oper
->bits
));
101 if (oper
->bits
== 32)
102 /* Piece together 32-bit constant. */
103 val
= ((num
& 0x3FFFF)
104 | ((num
& 0xFF00000) >> 2)
105 | ((num
& 0x3F00000000LL
) >> 6));
107 val
= (num
>> (32 + shift
)) & mask
;
110 val
= (num
>> shift
) & mask
;
112 if (oper
->flags
& OPERAND_SHIFT
)
119 print_insn (struct disassemble_info
*info
,
122 struct d30v_insn
*insn
,
126 int val
, opnum
, need_comma
= 0;
127 struct d30v_operand
*oper
;
128 int i
, match
, opind
= 0, need_paren
= 0, found_control
= 0;
130 (*info
->fprintf_func
) (info
->stream
, "%s", insn
->op
->name
);
132 /* Check for CMP or CMPU. */
133 if (d30v_operand_table
[insn
->form
->operands
[0]].flags
& OPERAND_NAME
)
138 (struct d30v_operand
*) &d30v_operand_table
[insn
->form
->operands
[0]],
140 (*info
->fprintf_func
) (info
->stream
, "%s", d30v_cc_names
[val
]);
143 /* Add in ".s" or ".l". */
147 (*info
->fprintf_func
) (info
->stream
, ".l");
149 (*info
->fprintf_func
) (info
->stream
, ".s");
153 (*info
->fprintf_func
) (info
->stream
, "/%s", d30v_ecc_names
[insn
->ecc
]);
155 (*info
->fprintf_func
) (info
->stream
, "\t");
157 while ((opnum
= insn
->form
->operands
[opind
++]) != 0)
161 oper
= (struct d30v_operand
*) &d30v_operand_table
[opnum
];
163 if (oper
->flags
& OPERAND_SHIFT
)
167 && oper
->flags
!= OPERAND_PLUS
168 && oper
->flags
!= OPERAND_MINUS
)
171 (*info
->fprintf_func
) (info
->stream
, ", ");
174 if (oper
->flags
== OPERAND_ATMINUS
)
176 (*info
->fprintf_func
) (info
->stream
, "@-");
179 if (oper
->flags
== OPERAND_MINUS
)
181 (*info
->fprintf_func
) (info
->stream
, "-");
184 if (oper
->flags
== OPERAND_PLUS
)
186 (*info
->fprintf_func
) (info
->stream
, "+");
189 if (oper
->flags
== OPERAND_ATSIGN
)
191 (*info
->fprintf_func
) (info
->stream
, "@");
194 if (oper
->flags
== OPERAND_ATPAR
)
196 (*info
->fprintf_func
) (info
->stream
, "@(");
201 if (oper
->flags
== OPERAND_SPECIAL
)
204 val
= extract_value (num
, oper
, is_long
);
206 if (oper
->flags
& OPERAND_REG
)
209 if (oper
->flags
& OPERAND_CONTROL
)
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
);
219 val
|= OPERAND_CONTROL
;
223 val
= OPERAND_CONTROL
+ MAX_CONTROL_REG
+ id
;
229 /* xgettext: c-format */
230 opcodes_error_handler (_("illegal id (%d)"), id
);
234 else if (oper
->flags
& OPERAND_ACC
)
236 else if (oper
->flags
& OPERAND_FLAG
)
238 for (i
= 0; i
< reg_name_cnt (); i
++)
240 if (val
== pre_defined_registers
[i
].value
)
242 if (pre_defined_registers
[i
].pname
)
243 (*info
->fprintf_func
)
244 (info
->stream
, "%s", pre_defined_registers
[i
].pname
);
246 (*info
->fprintf_func
)
247 (info
->stream
, "%s", pre_defined_registers
[i
].name
);
254 /* This would only get executed if a register was not in
255 the register table. */
256 (*info
->fprintf_func
)
257 (info
->stream
, _("<unknown register %d>"), val
& 0x3F);
260 /* repeati has a relocation, but its first argument is a plain
261 immediate. OTOH instructions like djsri have a pc-relative
262 delay target, but an absolute jump target. Therefore, a test
263 of insn->op->reloc_flag is not specific enough; we must test
264 if the actual operand we are handling now is pc-relative. */
265 else if (oper
->flags
& OPERAND_PCREL
)
269 /* IMM6S3 is unsigned. */
270 if (oper
->flags
& OPERAND_SIGNED
|| bits
== 32)
273 max
= (1 << (bits
- 1));
279 val
= -val
& ((1 << bits
) - 1);
285 (*info
->fprintf_func
) (info
->stream
, "-%x\t(", val
);
286 (*info
->print_address_func
) ((memaddr
- val
) & PC_MASK
, info
);
287 (*info
->fprintf_func
) (info
->stream
, ")");
291 (*info
->fprintf_func
) (info
->stream
, "%x\t(", val
);
292 (*info
->print_address_func
) ((memaddr
+ val
) & PC_MASK
, info
);
293 (*info
->fprintf_func
) (info
->stream
, ")");
296 else if (insn
->op
->reloc_flag
== RELOC_ABS
)
298 (*info
->print_address_func
) (val
, info
);
302 if (oper
->flags
& OPERAND_SIGNED
)
304 int max
= (1 << (bits
- 1));
310 val
&= ((1 << bits
) - 1);
311 (*info
->fprintf_func
) (info
->stream
, "-");
314 (*info
->fprintf_func
) (info
->stream
, "0x%x", val
);
316 /* If there is another operand, then write a comma and space. */
317 if (opind
< (int) ARRAY_SIZE (insn
->form
->operands
)
318 && insn
->form
->operands
[opind
]
319 && !(found_control
&& opind
== 2))
323 (*info
->fprintf_func
) (info
->stream
, ")");
327 print_insn_d30v (bfd_vma memaddr
, struct disassemble_info
*info
)
331 unsigned long in1
, in2
;
332 struct d30v_insn insn
;
337 info
->bytes_per_line
= 8;
338 info
->bytes_per_chunk
= 4;
339 info
->display_endian
= BFD_ENDIAN_BIG
;
341 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 4, info
);
344 (*info
->memory_error_func
) (status
, memaddr
, info
);
347 in1
= bfd_getb32 (buffer
);
349 status
= (*info
->read_memory_func
) (memaddr
+ 4, buffer
, 4, info
);
352 info
->bytes_per_line
= 8;
353 if (!(result
= lookup_opcode (&insn
, in1
, 0)))
354 (*info
->fprintf_func
) (info
->stream
, ".long\t0x%lx", in1
);
356 print_insn (info
, memaddr
, (long long) in1
, &insn
, 0, result
);
359 in2
= bfd_getb32 (buffer
);
361 if (in1
& in2
& FM01
)
363 /* LONG instruction. */
364 if (!(result
= lookup_opcode (&insn
, in1
, 1)))
366 (*info
->fprintf_func
) (info
->stream
, ".long\t0x%lx,0x%lx", in1
, in2
);
369 num
= (long long) in1
<< 32 | in2
;
370 print_insn (info
, memaddr
, num
, &insn
, 1, result
);
375 if (!(result
= lookup_opcode (&insn
, in1
, 0)))
376 (*info
->fprintf_func
) (info
->stream
, ".long\t0x%lx", in1
);
378 print_insn (info
, memaddr
, num
, &insn
, 0, result
);
380 switch (((in1
>> 31) << 1) | (in2
>> 31))
383 (*info
->fprintf_func
) (info
->stream
, "\t||\t");
386 (*info
->fprintf_func
) (info
->stream
, "\t->\t");
389 (*info
->fprintf_func
) (info
->stream
, "\t<-\t");
396 if (!(result
= lookup_opcode (&insn
, in2
, 0)))
397 (*info
->fprintf_func
) (info
->stream
, ".long\t0x%lx", in2
);
399 print_insn (info
, memaddr
, num
, &insn
, 0, result
);
This page took 0.037889 seconds and 4 git commands to generate.