This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / gdb / vax-tdep.c
1 /* Print VAX instructions for GDB, the GNU debugger.
2    Copyright 1986, 1989, 1991, 1992, 1996 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include "defs.h"
21 #include "symtab.h"
22 #include "opcode/vax.h"
23
24 /* Vax instructions are never longer than this.  */
25 #define MAXLEN 62
26
27 /* Number of elements in the opcode table.  */
28 #define NOPCODES (sizeof votstrs / sizeof votstrs[0])
29
30 static unsigned char *print_insn_arg ();
31 \f
32 /* Print the vax instruction at address MEMADDR in debugged memory,
33    from disassembler info INFO.
34    Returns length of the instruction, in bytes.  */
35
36 static int
37 vax_print_insn (memaddr, info)
38      CORE_ADDR memaddr;
39      disassemble_info *info;
40 {
41   unsigned char buffer[MAXLEN];
42   register int i;
43   register unsigned char *p;
44   register char *d;
45
46   int status = (*info->read_memory_func) (memaddr, buffer, MAXLEN, info);
47   if (status != 0)
48     {
49       (*info->memory_error_func) (status, memaddr, info);
50       return -1;
51     }
52
53   for (i = 0; i < NOPCODES; i++)
54     if (votstrs[i].detail.code == buffer[0]
55         || votstrs[i].detail.code == *(unsigned short *)buffer)
56       break;
57
58   /* Handle undefined instructions.  */
59   if (i == NOPCODES)
60     {
61       (*info->fprintf_func) (info->stream, "0%o", buffer[0]);
62       return 1;
63     }
64
65   (*info->fprintf_func) (info->stream, "%s", votstrs[i].name);
66
67   /* Point at first byte of argument data,
68      and at descriptor for first argument.  */
69   p = buffer + 1 + (votstrs[i].detail.code >= 0x100);
70   d = votstrs[i].detail.args;
71
72   if (*d)
73     (*info->fprintf_func) (info->stream, " ");
74
75   while (*d)
76     {
77       p = print_insn_arg (d, p, memaddr + (p - buffer), info);
78       d += 2;
79       if (*d)
80         (*info->fprintf_func) (info->stream, ",");
81     }
82   return p - buffer;
83 }
84
85 static unsigned char *
86 print_insn_arg (d, p, addr, info)
87      char *d;
88      register char *p;
89      CORE_ADDR addr;
90      disassemble_info *info;
91 {
92   register int regnum = *p & 0xf;
93   float floatlitbuf;
94
95   if (*d == 'b')
96     {
97       if (d[1] == 'b')
98         (*info->fprintf_func) (info->stream, "0x%x", addr + *p++ + 1);
99       else
100         {
101           (*info->fprintf_func) (info->stream, "0x%x", addr + *(short *)p + 2);
102           p += 2;
103         }
104     }
105   else
106     switch ((*p++ >> 4) & 0xf)
107       {
108       case 0:
109       case 1:
110       case 2:
111       case 3:                   /* Literal mode */
112         if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
113           {
114             *(int *)&floatlitbuf = 0x4000 + ((p[-1] & 0x3f) << 4);
115             (*info->fprintf_func) (info->stream, "$%f", floatlitbuf);
116           }
117         else
118           (*info->fprintf_func) (info->stream, "$%d", p[-1] & 0x3f);
119         break;
120
121       case 4:                   /* Indexed */
122         p = (char *) print_insn_arg (d, p, addr + 1, info);
123         (*info->fprintf_func) (info->stream, "[%s]", REGISTER_NAME (regnum));
124         break;
125
126       case 5:                   /* Register */
127         (*info->fprintf_func) (info->stream, REGISTER_NAME (regnum));
128         break;
129
130       case 7:                   /* Autodecrement */
131         (*info->fprintf_func) (info->stream, "-");
132       case 6:                   /* Register deferred */
133         (*info->fprintf_func) (info->stream, "(%s)", REGISTER_NAME (regnum));
134         break;
135
136       case 9:                   /* Autoincrement deferred */
137         (*info->fprintf_func) (info->stream, "@");
138         if (regnum == PC_REGNUM)
139           {
140             (*info->fprintf_func) (info->stream, "#");
141             info->target = *(long *)p;
142             (*info->print_address_func) (info->target, info);
143             p += 4;
144             break;
145           }
146       case 8:                   /* Autoincrement */
147         if (regnum == PC_REGNUM)
148           {
149             (*info->fprintf_func) (info->stream, "#");
150             switch (d[1])
151               {
152               case 'b':
153                 (*info->fprintf_func) (info->stream, "%d", *p++);
154                 break;
155
156               case 'w':
157                 (*info->fprintf_func) (info->stream, "%d", *(short *)p);
158                 p += 2;
159                 break;
160
161               case 'l':
162                 (*info->fprintf_func) (info->stream, "%d", *(long *)p);
163                 p += 4;
164                 break;
165
166               case 'q':
167                 (*info->fprintf_func) (info->stream, "0x%x%08x",
168                                        ((long *)p)[1], ((long *)p)[0]);
169                 p += 8;
170                 break;
171
172               case 'o':
173                 (*info->fprintf_func) (info->stream, "0x%x%08x%08x%08x",
174                                        ((long *)p)[3], ((long *)p)[2],
175                                        ((long *)p)[1], ((long *)p)[0]);
176                 p += 16;
177                 break;
178
179               case 'f':
180                 if (INVALID_FLOAT (p, 4))
181                   (*info->fprintf_func) (info->stream,
182                                          "<<invalid float 0x%x>>",
183                                          *(int *) p);
184                 else
185                   (*info->fprintf_func) (info->stream, "%f", *(float *) p);
186                 p += 4;
187                 break;
188
189               case 'd':
190                 if (INVALID_FLOAT (p, 8))
191                   (*info->fprintf_func) (info->stream,
192                                          "<<invalid float 0x%x%08x>>",
193                                          ((long *)p)[1], ((long *)p)[0]);
194                 else
195                   (*info->fprintf_func) (info->stream, "%f", *(double *) p);
196                 p += 8;
197                 break;
198
199               case 'g':
200                 (*info->fprintf_func) (info->stream, "g-float");
201                 p += 8;
202                 break;
203
204               case 'h':
205                 (*info->fprintf_func) (info->stream, "h-float");
206                 p += 16;
207                 break;
208
209               }
210           }
211         else
212           (*info->fprintf_func) (info->stream, "(%s)+", REGISTER_NAME (regnum));
213         break;
214
215       case 11:                  /* Byte displacement deferred */
216         (*info->fprintf_func) (info->stream, "@");
217       case 10:                  /* Byte displacement */
218         if (regnum == PC_REGNUM)
219           {
220             info->target = addr + *p + 2;
221             (*info->print_address_func) (info->target, info);
222           }
223         else
224           (*info->fprintf_func) (info->stream, "%d(%s)", *p, REGISTER_NAME (regnum));
225         p += 1;
226         break;
227
228       case 13:                  /* Word displacement deferred */
229         (*info->fprintf_func) (info->stream, "@");
230       case 12:                  /* Word displacement */
231         if (regnum == PC_REGNUM)
232           {
233             info->target = addr + *(short *)p + 3;
234             (*info->print_address_func) (info->target, info);
235           }
236         else
237           (*info->fprintf_func) (info->stream, "%d(%s)",
238                                  *(short *)p, REGISTER_NAME (regnum));
239         p += 2;
240         break;
241
242       case 15:                  /* Long displacement deferred */
243         (*info->fprintf_func) (info->stream, "@");
244       case 14:                  /* Long displacement */
245         if (regnum == PC_REGNUM)
246           {
247             info->target = addr + *(short *)p + 5;
248             (*info->print_address_func) (info->target, info);
249           }
250         else
251           (*info->fprintf_func) (info->stream, "%d(%s)",
252                                  *(long *)p, REGISTER_NAME (regnum));
253         p += 4;
254       }
255
256   return (unsigned char *) p;
257 }
258
259 void
260 _initialize_vax_tdep ()
261 {
262   tm_print_insn = vax_print_insn;
263 }