]> Git Repo - binutils.git/blob - gdb/am29k-pinsn.c
Use new i386aout when i386-aout seen
[binutils.git] / gdb / am29k-pinsn.c
1 /* Instruction printing code for the AMD 29000
2    Copyright (C) 1990 Free Software Foundation, Inc.
3    Contributed by Cygnus Support.  Written by Jim Kingdon.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 #include <stdio.h>
22
23 #include "defs.h"
24 #include "target.h"
25 #include "am29k-opcode.h"
26
27 /* Print a symbolic representation of a general-purpose
28    register number NUM on STREAM.
29    NUM is a number as found in the instruction, not as found in
30    debugging symbols; it must be in the range 0-255.  */
31 static void
32 print_general (num, stream)
33      int num;
34      FILE *stream;
35 {
36   if (num < 128)
37     fprintf_filtered (stream, "gr%d", num);
38   else
39     fprintf_filtered (stream, "lr%d", num - 128);
40 }
41
42 /* Like print_general but a special-purpose register.
43    
44    The mnemonics used by the AMD assembler are not quite the same
45    as the ones in the User's Manual.  We use the ones that the
46    assembler uses.  */
47 static void
48 print_special (num, stream)
49      int num;
50      FILE *stream;
51 {
52   /* Register names of registers 0-SPEC0_NUM-1.  */
53   static char *spec0_names[] = {
54     "vab", "ops", "cps", "cfg", "cha", "chd", "chc", "rbp", "tmc", "tmr",
55     "pc0", "pc1", "pc2", "mmu", "lru"
56     };
57 #define SPEC0_NUM ((sizeof spec0_names) / (sizeof spec0_names[0]))
58
59   /* Register names of registers 128-128+SPEC128_NUM-1.  */
60   static char *spec128_names[] = {
61     "ipc", "ipa", "ipb", "q", "alu", "bp", "fc", "cr"
62     };
63 #define SPEC128_NUM ((sizeof spec128_names) / (sizeof spec128_names[0]))
64
65   /* Register names of registers 160-160+SPEC160_NUM-1.  */
66   static char *spec160_names[] = {
67     "fpe", "inte", "fps", "sr163", "exop"
68     };
69 #define SPEC160_NUM ((sizeof spec160_names) / (sizeof spec160_names[0]))
70
71   if (num < SPEC0_NUM)
72     fprintf_filtered (stream, spec0_names[num]);
73   else if (num >= 128 && num < 128 + SPEC128_NUM)
74     fprintf_filtered (stream, spec128_names[num-128]);
75   else if (num >= 160 && num < 160 + SPEC160_NUM)
76     fprintf_filtered (stream, spec160_names[num-160]);
77   else
78     fprintf_filtered (stream, "sr%d", num);
79 }
80
81 /* Is an instruction with OPCODE a delayed branch?  */
82 static int
83 is_delayed_branch (opcode)
84      int opcode;
85 {
86   return (opcode == 0xa8 || opcode == 0xa9 || opcode == 0xa0 || opcode == 0xa1
87           || opcode == 0xa4 || opcode == 0xa5
88           || opcode == 0xb4 || opcode == 0xb5
89           || opcode == 0xc4 || opcode == 0xc0
90           || opcode == 0xac || opcode == 0xad
91           || opcode == 0xcc);
92 }
93
94 /* Now find the four bytes of INSN and put them in *INSN{0,8,16,24}.
95    Note that the amd can be set up as either
96    big or little-endian (the tm file says which) and we can't assume
97    the host machine is the same.  */
98 static void
99 find_bytes (insn, insn0, insn8, insn16, insn24)
100      char *insn;
101      unsigned char *insn0;
102      unsigned char *insn8;
103      unsigned char *insn16;
104      unsigned char *insn24;
105 {
106 #if TARGET_BYTE_ORDER == BIG_ENDIAN
107   *insn24 = insn[0];
108   *insn16 = insn[1];
109   *insn8  = insn[2];
110   *insn0  = insn[3];
111 #else /* Little-endian.  */
112   *insn24 = insn[3];
113   *insn16 = insn[2];
114   *insn8 = insn[1];
115   *insn0 = insn[0];
116 #endif /* Little-endian.  */
117 }
118
119 /* Print one instruction from MEMADDR on STREAM.
120    Return the size of the instruction (always 4 on am29k).  */
121 int
122 print_insn (memaddr, stream)
123      CORE_ADDR memaddr;
124      FILE *stream;
125 {
126   /* The raw instruction.  */
127   char insn[4];
128
129   /* The four bytes of the instruction.  */
130   unsigned char insn24, insn16, insn8, insn0;
131
132   struct am29k_opcode *opcode;
133
134   read_memory (memaddr, &insn[0], 4);
135
136   find_bytes (insn, &insn0, &insn8, &insn16, &insn24);
137
138   /* Handle the nop (aseq 0x40,gr1,gr1) specially */
139   if ((insn24==0x70) && (insn16==0x40) && (insn8==0x01) && (insn0==0x01)) {
140     fprintf_filtered (stream,"nop");
141     return 4;
142   }
143
144   /* The opcode is always in insn24.  */
145   for (opcode = &am29k_opcodes[0];
146        opcode < &am29k_opcodes[NUM_OPCODES];
147        ++opcode)
148     {
149       if (insn24 == opcode->opcode)
150         {
151           char *s;
152           
153           fprintf_filtered (stream, "%s ", opcode->name);
154           for (s = opcode->args; *s != '\0'; ++s)
155             {
156               switch (*s)
157                 {
158                 case 'a':
159                   print_general (insn8, stream);
160                   break;
161                   
162                 case 'b':
163                   print_general (insn0, stream);
164                   break;
165
166                 case 'c':
167                   print_general (insn16, stream);
168                   break;
169
170                 case 'i':
171                   fprintf_filtered (stream, "%d", insn0);
172                   break;
173
174                 case 'x':
175                   fprintf_filtered (stream, "%d", (insn16 << 8) + insn0);
176                   break;
177
178                 case 'h':
179                   fprintf_filtered (stream, "0x%x",
180                                     (insn16 << 24) + (insn0 << 16));
181                   break;
182
183                 case 'X':
184                   fprintf_filtered (stream, "%d",
185                                     ((insn16 << 8) + insn0) | 0xffff0000);
186                   break;
187
188                 case 'P':
189                   /* This output looks just like absolute addressing, but
190                      maybe that's OK (it's what the GDB 68k and EBMON
191                      29k disassemblers do).  */
192                   /* All the shifting is to sign-extend it.  p*/
193                   print_address
194                     (memaddr +
195                      (((int)((insn16 << 10) + (insn0 << 2)) << 14) >> 14),
196                      stream);
197                   break;
198
199                 case 'A':
200                   print_address ((insn16 << 10) + (insn0 << 2), stream);
201                   break;
202
203                 case 'e':
204                   fprintf_filtered (stream, "%d", insn16 >> 7);
205                   break;
206
207                 case 'n':
208                   fprintf_filtered (stream, "0x%x", insn16 & 0x7f);
209                   break;
210
211                 case 'v':
212                   fprintf_filtered (stream, "0x%x", insn16);
213                   break;
214
215                 case 's':
216                   print_special (insn8, stream);
217                   break;
218
219                 case 'u':
220                   fprintf_filtered (stream, "%d", insn0 >> 7);
221                   break;
222
223                 case 'r':
224                   fprintf_filtered (stream, "%d", (insn0 >> 4) & 7);
225                   break;
226
227                 case 'd':
228                   fprintf_filtered (stream, "%d", (insn0 >> 2) & 3);
229                   break;
230
231                 case 'f':
232                   fprintf_filtered (stream, "%d", insn0 & 3);
233                   break;
234
235                 case 'F':
236                   fprintf_filtered (stream, "%d", (insn0 >> 18) & 15);
237                   break;
238
239                 case 'C':
240                   fprintf_filtered (stream, "%d", (insn0 >> 16) & 3);
241                   break;
242
243                 default:
244                   fprintf_filtered (stream, "%c", *s);
245                 }
246             }
247
248           /* Now we look for a const,consth pair of instructions,
249              in which case we try to print the symbolic address.  */
250           if (insn24 == 2)  /* consth */
251             {
252               int errcode;
253               char prev_insn[4];
254               unsigned char prev_insn0, prev_insn8, prev_insn16, prev_insn24;
255               
256               errcode = target_read_memory (memaddr - 4,
257                                             &prev_insn[0],
258                                             4);
259               if (errcode == 0)
260                 {
261                   /* If it is a delayed branch, we need to look at the
262                      instruction before the delayed brach to handle
263                      things like
264                      
265                      const _foo
266                      call _printf
267                      consth _foo
268                      */
269                   find_bytes (prev_insn, &prev_insn0, &prev_insn8,
270                               &prev_insn16, &prev_insn24);
271                   if (is_delayed_branch (prev_insn24))
272                     {
273                       errcode = target_read_memory
274                         (memaddr - 8, &prev_insn[0], 4);
275                       find_bytes (prev_insn, &prev_insn0, &prev_insn8,
276                                   &prev_insn16, &prev_insn24);
277                     }
278                 }
279                   
280               /* If there was a problem reading memory, then assume
281                  the previous instruction was not const.  */
282               if (errcode == 0)
283                 {
284                   /* Is it const to the same register?  */
285                   if (prev_insn24 == 3
286                       && prev_insn8 == insn8)
287                     {
288                       fprintf_filtered (stream, "\t; ");
289                       print_address (((insn16 << 24) + (insn0 << 16)
290                                       + (prev_insn16 << 8) + (prev_insn0)),
291                                      stream);
292                     }
293                 }
294             }
295
296           return 4;
297         }
298     }
299   fprintf_filtered (stream, ".word 0x%8x",
300                     (insn24 << 24) + (insn16 << 16) + (insn8 << 8) + insn0);
301   return 4;
302 }
This page took 0.042281 seconds and 4 git commands to generate.