xref: /openbsd-src/gnu/usr.bin/binutils/gdb/vax-tdep.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
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 
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 = (char *)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]", reg_names[regnum]);
124 	break;
125 
126       case 5:			/* Register */
127 	(*info->fprintf_func) (info->stream, reg_names[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)", reg_names[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)+", reg_names[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, reg_names[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, reg_names[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 + *(long *)p + 5;
248 	    (*info->print_address_func) (info->target, info);
249 	  }
250 	else
251 	  (*info->fprintf_func) (info->stream, "%d(%s)",
252 				 *(long *)p, reg_names[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 }
264