1 /* Disassemble D30V instructions.
2 Copyright (C) 1997, 1998 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19 #include "opcode/d30v.h"
23 #define PC_MASK 0xFFFFFFFF
25 static int lookup_opcode
PARAMS (( struct d30v_insn
*insn
, long num
, int is_long
));
26 static void print_insn
PARAMS (( struct disassemble_info
*info
, bfd_vma memaddr
, long long num
,
27 struct d30v_insn
*insn
, int is_long
, int show_ext
));
28 static int extract_value
PARAMS (( long long num
, struct d30v_operand
*oper
, int is_long
));
31 print_insn_d30v (memaddr
, info
)
33 struct disassemble_info
*info
;
37 unsigned long in1
,in2
;
38 struct d30v_insn insn
;
41 insn
.form
= (struct d30v_format
*)NULL
;
43 info
->bytes_per_line
= 8;
44 info
->bytes_per_chunk
= 4;
45 info
->display_endian
= BFD_ENDIAN_BIG
;
47 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 4, info
);
50 (*info
->memory_error_func
) (status
, memaddr
, info
);
53 in1
= bfd_getb32 (buffer
);
55 status
= (*info
->read_memory_func
) (memaddr
+4, buffer
, 4, info
);
58 info
->bytes_per_line
= 8;
59 if (!(result
= lookup_opcode(&insn
, in1
, 0)))
60 (*info
->fprintf_func
) (info
->stream
, ".long\t0x%x",in1
);
62 print_insn(info
, memaddr
, (long long) in1
, &insn
, 0, result
);
65 in2
= bfd_getb32 (buffer
);
69 /* LONG instruction */
70 if (!(result
= lookup_opcode(&insn
, in1
, 1)))
72 (*info
->fprintf_func
) (info
->stream
, ".long\t0x%x,0x%x",in1
,in2
);
75 num
= (long long)in1
<< 32 | in2
;
76 print_insn(info
, memaddr
, num
, &insn
, 1, result
);
81 if (!(result
= lookup_opcode(&insn
, in1
, 0)))
82 (*info
->fprintf_func
) (info
->stream
, ".long\t0x%x",in1
);
84 print_insn(info
, memaddr
, num
, &insn
, 0, result
);
86 switch ( ((in1
>>31)<<1) | (in2
>>31) )
89 (*info
->fprintf_func
) (info
->stream
, "\t||\t");
92 (*info
->fprintf_func
) (info
->stream
, "\t->\t");
95 (*info
->fprintf_func
) (info
->stream
, "\t<-\t");
100 insn
.form
= (struct d30v_format
*)NULL
;
102 if (!(result
= lookup_opcode(&insn
, in2
, 0)))
103 (*info
->fprintf_func
) (info
->stream
, ".long\t0x%x",in2
);
105 print_insn(info
, memaddr
, num
, &insn
, 0, result
);
112 /* returns 0 if lookup fails */
113 /* 1 if found and only one form */
114 /* 2 if found and there are short and long forms */
116 lookup_opcode (insn
, num
, is_long
)
117 struct d30v_insn
*insn
;
122 struct d30v_format
*f
;
123 struct d30v_opcode
*op
= (struct d30v_opcode
*)d30v_opcode_table
;
124 int op1
= (num
>> 25) & 0x7;
125 int op2
= (num
>> 20) & 0x1f;
126 int mod
= (num
>> 18) & 0x3;
128 /* find the opcode */
130 if ((op
->op1
== op1
) && (op
->op2
== op2
))
135 if (!op
|| !op
->name
)
138 while (op
->op1
== op1
&& op
->op2
== op2
)
140 /* scan through all the formats for the opcode */
141 index
= op
->format
[i
++];
144 f
= (struct d30v_format
*)&d30v_format_table
[index
];
145 while (f
->form
== index
)
147 if ((!is_long
|| f
->form
>= LONG
) && (f
->modifier
== mod
))
156 } while ((index
= op
->format
[i
++]) != 0);
162 if (insn
->form
== NULL
)
166 insn
->ecc
= (num
>> 28) & 0x7;
175 print_insn ( info
, memaddr
, num
, insn
, is_long
, show_ext
)
176 struct disassemble_info
*info
;
179 struct d30v_insn
*insn
;
183 int val
, opnum
, need_comma
=0;
184 struct d30v_operand
*oper
;
185 int i
, match
, opind
=0, need_paren
=0, found_control
=0;
187 (*info
->fprintf_func
) (info
->stream
, "%s",insn
->op
->name
);
189 /* check for CMP or CMPU */
190 if (d30v_operand_table
[insn
->form
->operands
[0]].flags
& OPERAND_NAME
)
193 val
= extract_value(num
,(struct d30v_operand
*)&d30v_operand_table
[insn
->form
->operands
[0]],is_long
);
194 (*info
->fprintf_func
) (info
->stream
, "%s",d30v_cc_names
[val
]);
197 /* add in ".s" or ".l" */
201 (*info
->fprintf_func
) (info
->stream
, ".l");
203 (*info
->fprintf_func
) (info
->stream
, ".s");
207 (*info
->fprintf_func
) (info
->stream
, "/%s",d30v_ecc_names
[insn
->ecc
]);
209 (*info
->fprintf_func
) (info
->stream
, "\t");
211 while ((opnum
= insn
->form
->operands
[opind
++]) != 0)
214 oper
= (struct d30v_operand
*)&d30v_operand_table
[opnum
];
216 if (oper
->flags
& OPERAND_SHIFT
)
219 if (need_comma
&& oper
->flags
!= OPERAND_PLUS
&& oper
->flags
!= OPERAND_MINUS
)
222 (*info
->fprintf_func
) (info
->stream
, ", ");
225 if (oper
->flags
== OPERAND_ATMINUS
)
227 (*info
->fprintf_func
) (info
->stream
, "@-");
230 if (oper
->flags
== OPERAND_MINUS
)
232 (*info
->fprintf_func
) (info
->stream
, "-");
235 if (oper
->flags
== OPERAND_PLUS
)
237 (*info
->fprintf_func
) (info
->stream
, "+");
240 if (oper
->flags
== OPERAND_ATSIGN
)
242 (*info
->fprintf_func
) (info
->stream
, "@");
245 if (oper
->flags
== OPERAND_ATPAR
)
247 (*info
->fprintf_func
) (info
->stream
, "@(");
252 if (oper
->flags
== OPERAND_SPECIAL
)
255 val
= extract_value(num
, oper
, is_long
);
257 if (oper
->flags
& OPERAND_REG
)
260 if (oper
->flags
& OPERAND_CONTROL
)
262 struct d30v_operand
*oper3
=
263 (struct d30v_operand
*)&d30v_operand_table
[insn
->form
->operands
[2]];
264 int id
= extract_value (num
, oper3
, is_long
);
269 val
|= OPERAND_CONTROL
;
273 val
= OPERAND_CONTROL
+ MAX_CONTROL_REG
+ id
;
279 fprintf(stderr
,"illegal id (%d)\n",id
);
282 else if (oper
->flags
& OPERAND_ACC
)
284 else if (oper
->flags
& OPERAND_FLAG
)
286 for (i
=0;i
<reg_name_cnt();i
++)
288 if (val
== pre_defined_registers
[i
].value
)
290 if (pre_defined_registers
[i
].pname
)
291 (*info
->fprintf_func
)
292 (info
->stream
, "%s",pre_defined_registers
[i
].pname
);
294 (*info
->fprintf_func
)
295 (info
->stream
, "%s",pre_defined_registers
[i
].name
);
302 /* this would only get executed if a register was not in the
304 (*info
->fprintf_func
)
305 (info
->stream
, _("<unknown register %d>"), val
& 0x3F);
308 else if (insn
->op
->reloc_flag
== RELOC_PCREL
||
309 (opind
== 1 && (insn
->form
->form
== SHORT_D2
|| insn
->form
->form
== LONG_D
)))
313 max
= (1 << (bits
- 1));
319 val
= -val
& ((1 << bits
)-1);
322 if (opind
== 1 && (insn
->form
->form
== SHORT_D2
|| insn
->form
->form
== LONG_D
))
324 (*info
->fprintf_func
) (info
->stream
, "%x",val
);
329 (*info
->fprintf_func
) (info
->stream
, "-%x\t(",val
);
330 (*info
->print_address_func
) ((memaddr
- val
) & PC_MASK
, info
);
331 (*info
->fprintf_func
) (info
->stream
, ")");
335 (*info
->fprintf_func
) (info
->stream
, "%x\t(",val
);
336 (*info
->print_address_func
) ((memaddr
+ val
) & PC_MASK
, info
);
337 (*info
->fprintf_func
) (info
->stream
, ")");
341 else if (insn
->op
->reloc_flag
== RELOC_ABS
)
343 (*info
->print_address_func
) (val
, info
);
347 if (oper
->flags
& OPERAND_SIGNED
)
349 int max
= (1 << (bits
- 1));
354 val
&= ((1 << bits
) - 1);
355 (*info
->fprintf_func
) (info
->stream
, "-");
358 (*info
->fprintf_func
) (info
->stream
, "0x%x",val
);
360 /* if there is another operand, then write a comma and space */
361 if (insn
->form
->operands
[opind
] && !(found_control
&& opind
== 2))
365 (*info
->fprintf_func
) (info
->stream
, ")");
371 extract_value (num
, oper
, is_long
)
373 struct d30v_operand
*oper
;
377 int shift
= 12 - oper
->position
;
378 int mask
= (0xFFFFFFFF >> (32 - oper
->bits
));
382 if (oper
->bits
== 32)
384 /* piece together 32-bit constant */
385 val
= ((num
& 0x3FFFF)
386 | ((num
& 0xFF00000) >> 2)
387 | ((num
& 0x3F00000000LL
) >> 6));
390 val
= (num
>> (32 + shift
)) & mask
;
393 val
= (num
>> shift
) & mask
;
395 if (oper
->flags
& OPERAND_SHIFT
)