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