From Brad Lucier <lucier@math.purdue.edu>:
[binutils.git] / opcodes / d30v-dis.c
blob9358b7532358fd50f845657414934522bb6468f5
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. */
18 #include <stdio.h>
19 #include "opcode/d30v.h"
20 #include "dis-asm.h"
21 #include "opintl.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 ));
30 int
31 print_insn_d30v (memaddr, info)
32 bfd_vma memaddr;
33 struct disassemble_info *info;
35 int status, result;
36 bfd_byte buffer[12];
37 unsigned long in1,in2;
38 struct d30v_insn insn;
39 long long num;
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);
48 if (status != 0)
50 (*info->memory_error_func) (status, memaddr, info);
51 return -1;
53 in1 = bfd_getb32 (buffer);
55 status = (*info->read_memory_func) (memaddr+4, buffer, 4, info);
56 if (status != 0)
58 info->bytes_per_line = 8;
59 if (!(result = lookup_opcode(&insn, in1, 0)))
60 (*info->fprintf_func) (info->stream, ".long\t0x%x",in1);
61 else
62 print_insn(info, memaddr, (long long) in1, &insn, 0, result);
63 return 4;
65 in2 = bfd_getb32 (buffer);
67 if (in1 & in2 & FM01)
69 /* LONG instruction */
70 if (!(result = lookup_opcode(&insn, in1, 1)))
72 (*info->fprintf_func) (info->stream, ".long\t0x%x,0x%x",in1,in2);
73 return 8;
75 num = (long long)in1 << 32 | in2;
76 print_insn(info, memaddr, num, &insn, 1, result);
78 else
80 num = in1;
81 if (!(result = lookup_opcode(&insn, in1, 0)))
82 (*info->fprintf_func) (info->stream, ".long\t0x%x",in1);
83 else
84 print_insn(info, memaddr, num, &insn, 0, result);
86 switch ( ((in1>>31)<<1) | (in2>>31) )
88 case 0:
89 (*info->fprintf_func) (info->stream, "\t||\t");
90 break;
91 case 1:
92 (*info->fprintf_func) (info->stream, "\t->\t");
93 break;
94 case 2:
95 (*info->fprintf_func) (info->stream, "\t<-\t");
96 default:
97 break;
100 insn.form = (struct d30v_format *)NULL;
101 num = in2;
102 if (!(result = lookup_opcode(&insn, in2, 0)))
103 (*info->fprintf_func) (info->stream, ".long\t0x%x",in2);
104 else
105 print_insn(info, memaddr, num, &insn, 0, result);
108 return 8;
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 */
115 static int
116 lookup_opcode (insn, num, is_long)
117 struct d30v_insn *insn;
118 long num;
119 int is_long;
121 int i=0, index;
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 */
129 do {
130 if ((op->op1 == op1) && (op->op2 == op2))
131 break;
132 op++;
133 } while (op->name);
135 if (!op || !op->name)
136 return 0;
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))
149 insn->form = f;
150 break;
152 f++;
154 if (insn->form)
155 break;
156 } while ((index = op->format[i++]) != 0);
157 if (insn->form)
158 break;
159 op++;
160 i=0;
162 if (insn->form == NULL)
163 return 0;
165 insn->op = op;
166 insn->ecc = (num >> 28) & 0x7;
167 if (op->format[1])
168 return 2;
169 else
170 return 1;
174 static void
175 print_insn ( info, memaddr, num, insn, is_long, show_ext )
176 struct disassemble_info *info;
177 bfd_vma memaddr;
178 long long num;
179 struct d30v_insn *insn;
180 int is_long;
181 int show_ext;
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)
192 opind++;
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" */
198 if (show_ext == 2)
200 if (is_long)
201 (*info->fprintf_func) (info->stream, ".l");
202 else
203 (*info->fprintf_func) (info->stream, ".s");
206 if (insn->ecc)
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)
213 int bits;
214 oper = (struct d30v_operand *)&d30v_operand_table[opnum];
215 bits = oper->bits;
216 if (oper->flags & OPERAND_SHIFT)
217 bits += 3;
219 if (need_comma && oper->flags != OPERAND_PLUS && oper->flags != OPERAND_MINUS)
221 need_comma=0;
222 (*info->fprintf_func) (info->stream, ", ");
225 if (oper->flags == OPERAND_ATMINUS)
227 (*info->fprintf_func) (info->stream, "@-");
228 continue;
230 if (oper->flags == OPERAND_MINUS)
232 (*info->fprintf_func) (info->stream, "-");
233 continue;
235 if (oper->flags == OPERAND_PLUS)
237 (*info->fprintf_func) (info->stream, "+");
238 continue;
240 if (oper->flags == OPERAND_ATSIGN)
242 (*info->fprintf_func) (info->stream, "@");
243 continue;
245 if (oper->flags == OPERAND_ATPAR)
247 (*info->fprintf_func) (info->stream, "@(");
248 need_paren = 1;
249 continue;
252 if (oper->flags == OPERAND_SPECIAL)
253 continue;
255 val = extract_value(num, oper, is_long);
257 if (oper->flags & OPERAND_REG)
259 match = 0;
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 );
265 found_control = 1;
266 switch ( id )
268 case 0:
269 val |= OPERAND_CONTROL;
270 break;
271 case 1:
272 case 2:
273 val = OPERAND_CONTROL + MAX_CONTROL_REG + id;
274 break;
275 case 3:
276 val |= OPERAND_FLAG;
277 break;
278 default:
279 fprintf(stderr,"illegal id (%d)\n",id);
282 else if (oper->flags & OPERAND_ACC)
283 val |= OPERAND_ACC;
284 else if (oper->flags & OPERAND_FLAG)
285 val |= 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);
293 else
294 (*info->fprintf_func)
295 (info->stream, "%s",pre_defined_registers[i].name);
296 match=1;
297 break;
300 if (match==0)
302 /* this would only get executed if a register was not in the
303 register table */
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)))
311 long max;
312 int neg=0;
313 max = (1 << (bits - 1));
314 if (val & max)
316 if (bits == 32)
317 val = -val;
318 else
319 val = -val & ((1 << bits)-1);
320 neg = 1;
322 if (opind == 1 && (insn->form->form == SHORT_D2 || insn->form->form == LONG_D))
324 (*info->fprintf_func) (info->stream, "%x",val);
326 else {
327 if (neg)
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, ")");
333 else
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);
345 else
347 if (oper->flags & OPERAND_SIGNED)
349 int max = (1 << (bits - 1));
350 if (val & max)
352 val = -val;
353 if (bits < 32)
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))
362 need_comma = 1;
364 if (need_paren)
365 (*info->fprintf_func) (info->stream, ")");
370 static int
371 extract_value (num, oper, is_long)
372 long long num;
373 struct d30v_operand *oper;
374 int is_long;
376 int val;
377 int shift = 12 - oper->position;
378 int mask = (0xFFFFFFFF >> (32 - oper->bits));
380 if (is_long)
382 if (oper->bits == 32)
384 /* piece together 32-bit constant */
385 val = ((num & 0x3FFFF)
386 | ((num & 0xFF00000) >> 2)
387 | ((num & 0x3F00000000LL) >> 6));
389 else
390 val = (num >> (32 + shift)) & mask;
392 else
393 val = (num >> shift) & mask;
395 if (oper->flags & OPERAND_SHIFT)
396 val <<= 3;
398 return val;