This commit was generated by cvs2svn to track changes on a CVS vendor
[platform/upstream/binutils.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 }