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