1 /* Disassemble D30V instructions.
2 Copyright (C) 1997 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"
22 #define PC_MASK 0xFFFFFFFF
24 static int lookup_opcode PARAMS (( struct d30v_insn *insn, long num, int is_long ));
25 static void print_insn PARAMS (( struct disassemble_info *info, bfd_vma memaddr, long long num,
26 struct d30v_insn *insn, int is_long ));
27 static int extract_value PARAMS (( long long num, struct d30v_operand *oper, int is_long ));
30 print_insn_d30v (memaddr, info)
32 struct disassemble_info *info;
36 unsigned long in1,in2;
37 struct d30v_insn insn;
40 insn.form = (struct d30v_format *)NULL;
42 status = (*info->read_memory_func) (memaddr, buffer, 8, info);
45 (*info->memory_error_func) (status, memaddr, info);
48 info->bytes_per_line = 8;
49 info->bytes_per_chunk = 4;
50 info->display_endian = BFD_ENDIAN_BIG;
51 in1 = bfd_getb32 (buffer);
52 in2 = bfd_getb32 (buffer+4);
56 /* LONG instruction */
57 if (!lookup_opcode(&insn, in1, 1))
59 (*info->fprintf_func) (info->stream, ".long\t0x%x,0x%x",in1,in2);
62 num = (long long)in1 << 32 | in2;
63 print_insn(info, memaddr, num, &insn, 1);
68 if (!lookup_opcode(&insn, in1, 0))
69 (*info->fprintf_func) (info->stream, ".long\t0x%x",in1);
71 print_insn(info, memaddr, num, &insn, 0);
73 switch ( ((in1>>31)<<1) | (in2>>31) )
76 (*info->fprintf_func) (info->stream, "\t||\t");
79 (*info->fprintf_func) (info->stream, "\t->\t");
82 (*info->fprintf_func) (info->stream, "\t<-\t");
87 insn.form = (struct d30v_format *)NULL;
89 if (!lookup_opcode(&insn, in2, 0))
90 (*info->fprintf_func) (info->stream, ".long\t0x%x",in2);
92 print_insn(info, memaddr, num, &insn, 0);
100 lookup_opcode (insn, num, is_long)
101 struct d30v_insn *insn;
106 struct d30v_format *f;
107 struct d30v_opcode *op = (struct d30v_opcode *)d30v_opcode_table;
108 int op1 = (num >> 25) & 0x7;
109 int op2 = (num >> 20) & 0x1f;
110 int mod = (num >> 18) & 0x3;
112 /* find the opcode */
114 if ((op->op1 == op1) && (op->op2 == op2))
119 if (!op || !op->name)
122 while (op->op1 == op1 && op->op2 == op2)
124 /* scan through all the formats for the opcode */
125 while (index = op->format[i++])
127 f = (struct d30v_format *)&d30v_format_table[index];
128 while (f->form == index)
130 if ((!is_long || f->form >= LONG) && (f->modifier == mod))
145 if (insn->form == NULL)
149 insn->ecc = (num >> 28) & 0x7;
155 print_insn ( info, memaddr, num, insn, is_long )
156 struct disassemble_info *info;
159 struct d30v_insn *insn;
163 int val, opnum, need_comma=0;
164 struct d30v_operand *oper;
165 int i, match, opind=0, need_paren=0, found_control=0;
167 (*info->fprintf_func) (info->stream, "%s",insn->op->name);
169 /* check for CMP or CMPU */
170 if (d30v_operand_table[insn->form->operands[0]].flags & OPERAND_NAME)
173 val = extract_value(num,(struct d30v_operand *)&d30v_operand_table[insn->form->operands[0]],is_long);
174 (*info->fprintf_func) (info->stream, "%s",d30v_cc_names[val]);
178 (*info->fprintf_func) (info->stream, "/%s",d30v_ecc_names[insn->ecc]);
180 (*info->fprintf_func) (info->stream, "\t");
182 while (opnum = insn->form->operands[opind++])
184 oper = (struct d30v_operand *)&d30v_operand_table[opnum];
186 if (need_comma && oper->flags != OPERAND_PLUS && oper->flags != OPERAND_MINUS)
189 (*info->fprintf_func) (info->stream, ", ");
192 if (oper->flags == OPERAND_ATMINUS)
194 (*info->fprintf_func) (info->stream, "@-");
197 if (oper->flags == OPERAND_MINUS)
199 (*info->fprintf_func) (info->stream, "-");
202 if (oper->flags == OPERAND_PLUS)
204 (*info->fprintf_func) (info->stream, "+");
207 if (oper->flags == OPERAND_ATSIGN)
209 (*info->fprintf_func) (info->stream, "@");
212 if (oper->flags == OPERAND_ATPAR)
214 (*info->fprintf_func) (info->stream, "@(");
219 if (oper->flags == OPERAND_SPECIAL)
222 val = extract_value(num, oper, is_long);
224 if (oper->flags & OPERAND_REG)
227 if (oper->flags & OPERAND_CONTROL)
229 struct d30v_operand *oper3 =
230 (struct d30v_operand *)&d30v_operand_table[insn->form->operands[2]];
231 int id = extract_value (num, oper3, is_long );
236 val |= OPERAND_CONTROL;
240 val = OPERAND_CONTROL + MAX_CONTROL_REG + id;
246 fprintf(stderr,"illegal id (%d)\n",id);
249 else if (oper->flags & OPERAND_ACC)
251 else if (oper->flags & OPERAND_FLAG)
253 for (i=0;i<reg_name_cnt();i++)
255 if (val == pre_defined_registers[i].value)
257 if (pre_defined_registers[i].pname)
258 (*info->fprintf_func) (info->stream, "%s",pre_defined_registers[i].pname);
260 (*info->fprintf_func) (info->stream, "%s",pre_defined_registers[i].name);
267 /* this would only get executed if a register was not in the
269 (*info->fprintf_func) (info->stream, "<unknown register %d>",val & 0x3F);
272 else if (insn->op->reloc_flag == RELOC_PCREL)
276 max = (1 << (oper->bits - 1));
279 if (oper->bits == 32)
282 val = -val & ((1 << oper->bits)-1);
286 (*info->print_address_func) ((memaddr - val) & PC_MASK, info);
288 (*info->print_address_func) ((memaddr + val) & PC_MASK, info);
290 else if (insn->op->reloc_flag == RELOC_ABS)
292 (*info->print_address_func) (val, info);
296 if (oper->flags & OPERAND_SIGNED)
298 int max = (1 << (oper->bits - 1));
301 val = -val & ((1 << oper->bits) - 1);
302 (*info->fprintf_func) (info->stream, "-");
305 (*info->fprintf_func) (info->stream, "0x%x",val);
307 /* if there is another operand, then write a comma and space */
308 if (insn->form->operands[opind] && !(found_control && opind == 2))
312 (*info->fprintf_func) (info->stream, ")");
318 extract_value (num, oper, is_long)
320 struct d30v_operand *oper;
324 int shift = 12 - oper->position;
325 int mask = (0xFFFFFFFF >> (32 - oper->bits));
329 if (oper->bits == 32)
331 /* piece together 32-bit constant */
332 val = num & 0x3FFFF | (num & 0xFF00000) >> 2 |
333 (num & 0x3F00000000LL) >> 6;
336 val = (num >> (32 + shift)) & mask;
339 val = (num >> shift) & mask;
341 if (oper->flags & OPERAND_SHIFT)