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