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