* tic80-opc.c (tic80_opcodes): Expand comment to note that the
[platform/upstream/binutils.git] / opcodes / d10v-dis.c
1 /* Disassemble D10V instructions.
2    Copyright (C) 1996 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
19 #include <stdio.h>
20
21 #include "opcode/d10v.h" 
22 #include "dis-asm.h"
23
24 static void dis_2_short PARAMS ((unsigned long insn, bfd_vma memaddr, 
25                                  struct disassemble_info *info, int order));
26 static void dis_long PARAMS ((unsigned long insn, bfd_vma memaddr, 
27                               struct disassemble_info *info));
28
29 int 
30 print_insn_d10v (memaddr, info)
31      bfd_vma memaddr;
32      struct disassemble_info *info;
33 {
34   int status;
35   bfd_byte buffer[4];
36   unsigned long insn;
37
38   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
39   if (status != 0)
40     {
41       (*info->memory_error_func) (status, memaddr, info);
42       return -1;
43     }
44   insn = bfd_getb32 (buffer);
45
46   status = insn & FM11;
47   switch (status) {
48   case 0:
49     dis_2_short (insn, memaddr, info, 2);
50     break;
51   case FM01:
52     dis_2_short (insn, memaddr, info, 0);
53     break;
54   case FM10:
55     dis_2_short (insn, memaddr, info, 1);
56     break;
57   case FM11:
58     dis_long (insn, memaddr, info);
59     break;
60   }
61   return 4;
62 }
63
64 static void
65 print_operand (oper, insn, op, memaddr, info)
66      struct d10v_operand *oper;
67      unsigned long insn;
68      struct d10v_opcode *op;
69      bfd_vma memaddr;
70      struct disassemble_info *info;
71 {
72   int num, shift;
73
74   if (oper->flags == OPERAND_ATMINUS)
75     {
76       (*info->fprintf_func) (info->stream, "@-");   
77       return;
78     }
79   if (oper->flags == OPERAND_MINUS)
80     {
81       (*info->fprintf_func) (info->stream, "-");   
82       return;
83     }
84   if (oper->flags == OPERAND_PLUS)
85     {
86       (*info->fprintf_func) (info->stream, "+");   
87       return;
88     }
89   if (oper->flags == OPERAND_ATSIGN)
90     {
91       (*info->fprintf_func) (info->stream, "@");   
92       return;
93     }
94   if (oper->flags == OPERAND_ATPAR)
95     {
96       (*info->fprintf_func) (info->stream, "@(");   
97       return;
98     }
99
100   shift = oper->shift;
101
102   /* the LONG_L format shifts registers over by 15 */
103   if (op->format == LONG_L && (oper->flags & OPERAND_REG))
104     shift += 15;
105
106   num = (insn >> shift) & (0x7FFFFFFF >> (31 - oper->bits));
107
108   if (oper->flags & OPERAND_REG)
109     {
110       int i;
111       int match=0;
112       num += oper->flags & (OPERAND_ACC|OPERAND_FLAG|OPERAND_CONTROL);
113       for (i=0;i<reg_name_cnt();i++)
114         {
115           if (num == pre_defined_registers[i].value)
116             {
117               if (pre_defined_registers[i].pname)
118                 (*info->fprintf_func) (info->stream, "%s",pre_defined_registers[i].pname);
119               else
120                 (*info->fprintf_func) (info->stream, "%s",pre_defined_registers[i].name);
121               match=1;
122               break;
123             }
124         }
125       if (match==0)
126         {
127           /* this would only get executed if a register was not in the 
128              register table */
129           if (oper->flags & OPERAND_ACC)
130             (*info->fprintf_func) (info->stream, "a");
131           else if (oper->flags & OPERAND_CONTROL)
132             (*info->fprintf_func) (info->stream, "cr");
133           else if(oper->flags & OPERAND_REG)
134             (*info->fprintf_func) (info->stream, "r");
135           (*info->fprintf_func) (info->stream, "%d",num);
136         }
137     }
138   else
139     {
140       /* addresses are right-shifted by 2 */
141       if (oper->flags & OPERAND_ADDR)
142         {
143           long max;
144           int neg=0;
145           max = (1 << (oper->bits - 1));
146           if (num & max)
147             {
148               num = -num & (max-1);
149               neg = 1;
150             }
151           num = num<<2;
152           if (neg)
153             (*info->print_address_func) (memaddr - num, info); 
154           else
155             (*info->print_address_func) (memaddr + num, info); 
156         }
157       else
158         {
159           if (oper->flags & OPERAND_SIGNED)
160             {
161               int max = (1 << (oper->bits - 1));
162               if (num & max)
163                 {
164                   num = -num;
165                   num &= (max-1);
166                   (*info->fprintf_func) (info->stream, "-");
167                 }
168             }
169           (*info->fprintf_func) (info->stream, "0x%x",num);
170         }
171     }
172 }
173
174
175 static void
176 dis_long (insn, memaddr, info)
177      unsigned long insn;
178      bfd_vma memaddr;
179      struct disassemble_info *info;
180 {
181   int i;
182   char buf[32];
183   struct d10v_opcode *op = (struct d10v_opcode *)d10v_opcodes;
184   struct d10v_operand *oper;
185   int need_paren = 0;
186
187   while (op->name)
188     {
189       if ((op->format & LONG_OPCODE) && ((op->mask & insn) == op->opcode))
190         {
191           (*info->fprintf_func) (info->stream, "%s\t", op->name);   
192           for ( i=0; op->operands[i]; i++)
193             {
194               oper = (struct d10v_operand *)&d10v_operands[op->operands[i]];
195               if (oper->flags == OPERAND_ATPAR)
196                 need_paren = 1;
197               print_operand (oper, insn, op, memaddr, info);
198               if (op->operands[i+1] && oper->bits &&
199                   d10v_operands[op->operands[i+1]].flags != OPERAND_PLUS &&
200                   d10v_operands[op->operands[i+1]].flags != OPERAND_MINUS)
201                 (*info->fprintf_func) (info->stream, ", ");   
202             }
203           break;
204         }
205       op++;
206     }
207   if (need_paren)
208     (*info->fprintf_func) (info->stream, ")");   
209 }
210
211 static void
212 dis_2_short (insn, memaddr, info, order)
213      unsigned long insn;
214      bfd_vma memaddr;
215      struct disassemble_info *info;
216      int order;
217 {
218   int i,j;
219   char astr[2][32];
220   unsigned int ins[2];
221   struct d10v_opcode *op;
222   char buf[32];
223   int match, num_match=0;
224   struct d10v_operand *oper;
225   int need_paren = 0;
226
227   ins[0] = (insn & 0x3FFFFFFF) >> 15;
228   ins[1] = insn & 0x00007FFF;
229
230   for(j=0;j<2;j++)
231     {
232       op = (struct d10v_opcode *)d10v_opcodes;
233       match=0;
234       while (op->name)
235         {
236           if ((op->format & SHORT_OPCODE) && ((op->mask & ins[j]) == op->opcode))
237             {
238               (*info->fprintf_func) (info->stream, "%s\t",op->name);   
239               for (i=0; op->operands[i]; i++)
240                 {
241                   oper = (struct d10v_operand *)&d10v_operands[op->operands[i]];
242                   if (oper->flags == OPERAND_ATPAR)
243                     need_paren = 1;
244                   print_operand (oper, ins[j], op, memaddr, info);
245                   if (op->operands[i+1] && oper->bits && 
246                   d10v_operands[op->operands[i+1]].flags != OPERAND_PLUS &&
247                   d10v_operands[op->operands[i+1]].flags != OPERAND_MINUS)
248                     (*info->fprintf_func) (info->stream, ", ");   
249                 }
250               match = 1;
251               num_match++;
252               break;
253             }
254           op++;
255         }
256       if (!match)
257         (*info->fprintf_func) (info->stream, "unknown");   
258
259       switch (order)
260         {
261         case 0:
262           (*info->fprintf_func) (info->stream, "\t->\t");   
263           order = -1;
264           break;
265         case 1:
266           (*info->fprintf_func) (info->stream, "\t<-\t");   
267           order = -1;
268           break;
269         case 2:
270           (*info->fprintf_func) (info->stream, "\t||\t");   
271           order = -1;
272           break;
273         default:
274           break;
275         }
276     }
277
278   if (num_match == 0)
279     (*info->fprintf_func) (info->stream, ".long\t0x%08x",insn);   
280
281   if (need_paren)
282     (*info->fprintf_func) (info->stream, ")");   
283 }