* thread.c: cull duplicate prototypes. Move prototypes to top.
[deliverable/binutils-gdb.git] / opcodes / d30v-dis.c
1 /* Disassemble D30V instructions.
2 Copyright (C) 1997 Free Software Foundation, Inc.
3
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.
8
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.
13
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. */
17
18 #include <stdio.h>
19 #include "opcode/d30v.h"
20 #include "dis-asm.h"
21
22 #define PC_MASK 0xFFFFFFFF
23
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 ));
28
29 int
30 print_insn_d30v (memaddr, info)
31 bfd_vma memaddr;
32 struct disassemble_info *info;
33 {
34 int status, i;
35 bfd_byte buffer[12];
36 unsigned long in1,in2;
37 struct d30v_insn insn;
38 long long num;
39
40 insn.form = (struct d30v_format *)NULL;
41
42 status = (*info->read_memory_func) (memaddr, buffer, 8, info);
43 if (status != 0)
44 {
45 (*info->memory_error_func) (status, memaddr, info);
46 return -1;
47 }
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);
53
54 if (in1 & in2 & FM01)
55 {
56 /* LONG instruction */
57 if (!lookup_opcode(&insn, in1, 1))
58 {
59 (*info->fprintf_func) (info->stream, ".long\t0x%x,0x%x",in1,in2);
60 return 8;
61 }
62 num = (long long)in1 << 32 | in2;
63 print_insn(info, memaddr, num, &insn, 1);
64 }
65 else
66 {
67 num = in1;
68 if (!lookup_opcode(&insn, in1, 0))
69 (*info->fprintf_func) (info->stream, ".long\t0x%x",in1);
70 else
71 print_insn(info, memaddr, num, &insn, 0);
72
73 switch ( ((in1>>31)<<1) | (in2>>31) )
74 {
75 case 0:
76 (*info->fprintf_func) (info->stream, "\t||\t");
77 break;
78 case 1:
79 (*info->fprintf_func) (info->stream, "\t->\t");
80 break;
81 case 2:
82 (*info->fprintf_func) (info->stream, "\t<-\t");
83 default:
84 break;
85 }
86
87 insn.form = (struct d30v_format *)NULL;
88 num = in2;
89 if (!lookup_opcode(&insn, in2, 0))
90 (*info->fprintf_func) (info->stream, ".long\t0x%x",in2);
91 else
92 print_insn(info, memaddr, num, &insn, 0);
93
94 }
95 return 8;
96 }
97
98
99 static int
100 lookup_opcode (insn, num, is_long)
101 struct d30v_insn *insn;
102 long num;
103 int is_long;
104 {
105 int i=0, index;
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;
111
112 /* find the opcode */
113 do {
114 if ((op->op1 == op1) && (op->op2 == op2))
115 break;
116 op++;
117 } while (op->name);
118
119 if (!op || !op->name)
120 return 0;
121
122 while (op->op1 == op1 && op->op2 == op2)
123 {
124 /* scan through all the formats for the opcode */
125 while (index = op->format[i++])
126 {
127 f = (struct d30v_format *)&d30v_format_table[index];
128 while (f->form == index)
129 {
130 if ((!is_long || f->form >= LONG) && (f->modifier == mod))
131 {
132 insn->form = f;
133 break;
134 }
135 f++;
136 }
137 if (insn->form)
138 break;
139 }
140 if (insn->form)
141 break;
142 op++;
143 i=0;
144 }
145 if (insn->form == NULL)
146 return 0;
147
148 insn->op = op;
149 insn->ecc = (num >> 28) & 0x7;
150 return 1;
151 }
152
153
154 static void
155 print_insn ( info, memaddr, num, insn, is_long )
156 struct disassemble_info *info;
157 bfd_vma memaddr;
158 long long num;
159 struct d30v_insn *insn;
160 int is_long;
161 {
162 char buffer[128];
163 int val, opnum, need_comma=0;
164 struct d30v_operand *oper;
165 int i, match, opind=0, need_paren=0, found_control=0;
166
167 (*info->fprintf_func) (info->stream, "%s",insn->op->name);
168
169 /* check for CMP or CMPU */
170 if (d30v_operand_table[insn->form->operands[0]].flags & OPERAND_NAME)
171 {
172 opind++;
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]);
175 }
176
177 if (insn->ecc)
178 (*info->fprintf_func) (info->stream, "/%s",d30v_ecc_names[insn->ecc]);
179
180 (*info->fprintf_func) (info->stream, "\t");
181
182 while (opnum = insn->form->operands[opind++])
183 {
184 oper = (struct d30v_operand *)&d30v_operand_table[opnum];
185
186 if (need_comma && oper->flags != OPERAND_PLUS && oper->flags != OPERAND_MINUS)
187 {
188 need_comma=0;
189 (*info->fprintf_func) (info->stream, ", ");
190 }
191
192 if (oper->flags == OPERAND_ATMINUS)
193 {
194 (*info->fprintf_func) (info->stream, "@-");
195 continue;
196 }
197 if (oper->flags == OPERAND_MINUS)
198 {
199 (*info->fprintf_func) (info->stream, "-");
200 continue;
201 }
202 if (oper->flags == OPERAND_PLUS)
203 {
204 (*info->fprintf_func) (info->stream, "+");
205 continue;
206 }
207 if (oper->flags == OPERAND_ATSIGN)
208 {
209 (*info->fprintf_func) (info->stream, "@");
210 continue;
211 }
212 if (oper->flags == OPERAND_ATPAR)
213 {
214 (*info->fprintf_func) (info->stream, "@(");
215 need_paren = 1;
216 continue;
217 }
218
219 if (oper->flags == OPERAND_SPECIAL)
220 continue;
221
222 val = extract_value(num, oper, is_long);
223
224 if (oper->flags & OPERAND_REG)
225 {
226 match = 0;
227 if (oper->flags & OPERAND_CONTROL)
228 {
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 );
232 found_control = 1;
233 switch ( id )
234 {
235 case 0:
236 val |= OPERAND_CONTROL;
237 break;
238 case 1:
239 case 2:
240 val = OPERAND_CONTROL + MAX_CONTROL_REG + id;
241 break;
242 case 3:
243 val |= OPERAND_FLAG;
244 break;
245 default:
246 fprintf(stderr,"illegal id (%d)\n",id);
247 }
248 }
249 else if (oper->flags & OPERAND_ACC)
250 val |= OPERAND_ACC;
251 else if (oper->flags & OPERAND_FLAG)
252 val |= OPERAND_FLAG;
253 for (i=0;i<reg_name_cnt();i++)
254 {
255 if (val == pre_defined_registers[i].value)
256 {
257 if (pre_defined_registers[i].pname)
258 (*info->fprintf_func) (info->stream, "%s",pre_defined_registers[i].pname);
259 else
260 (*info->fprintf_func) (info->stream, "%s",pre_defined_registers[i].name);
261 match=1;
262 break;
263 }
264 }
265 if (match==0)
266 {
267 /* this would only get executed if a register was not in the
268 register table */
269 (*info->fprintf_func) (info->stream, "<unknown register %d>",val & 0x3F);
270 }
271 }
272 else if (insn->op->reloc_flag == RELOC_PCREL)
273 {
274 long max;
275 int neg=0;
276 max = (1 << (oper->bits - 1));
277 if (val & max)
278 {
279 if (oper->bits == 32)
280 val = -val;
281 else
282 val = -val & ((1 << oper->bits)-1);
283 neg = 1;
284 }
285 if (neg)
286 (*info->print_address_func) ((memaddr - val) & PC_MASK, info);
287 else
288 (*info->print_address_func) ((memaddr + val) & PC_MASK, info);
289 }
290 else if (insn->op->reloc_flag == RELOC_ABS)
291 {
292 (*info->print_address_func) (val, info);
293 }
294 else
295 {
296 if (oper->flags & OPERAND_SIGNED)
297 {
298 int max = (1 << (oper->bits - 1));
299 if (val & max)
300 {
301 val = -val & ((1 << oper->bits) - 1);
302 (*info->fprintf_func) (info->stream, "-");
303 }
304 }
305 (*info->fprintf_func) (info->stream, "0x%x",val);
306 }
307 /* if there is another operand, then write a comma and space */
308 if (insn->form->operands[opind] && !(found_control && opind == 2))
309 need_comma = 1;
310 }
311 if (need_paren)
312 (*info->fprintf_func) (info->stream, ")");
313 }
314
315
316
317 static int
318 extract_value (num, oper, is_long)
319 long long num;
320 struct d30v_operand *oper;
321 int is_long;
322 {
323 int val;
324 int shift = 12 - oper->position;
325 int mask = (0xFFFFFFFF >> (32 - oper->bits));
326
327 if (is_long)
328 {
329 if (oper->bits == 32)
330 {
331 /* piece together 32-bit constant */
332 val = num & 0x3FFFF | (num & 0xFF00000) >> 2 |
333 (num & 0x3F00000000LL) >> 6;
334 }
335 else
336 val = (num >> (32 + shift)) & mask;
337 }
338 else
339 val = (num >> shift) & mask;
340
341 if (oper->flags & OPERAND_SHIFT)
342 val <<= 3;
343
344 return val;
345 }
This page took 0.038812 seconds and 4 git commands to generate.