]> Git Repo - binutils.git/blob - gdb/rs6000-pinsn.c
* target.h: Put remote_debug declaration back here. Add baud_rate.
[binutils.git] / gdb / rs6000-pinsn.c
1 /* Print IBM RS/6000 instructions for GNU software.
2    Copyright 1991 Free Software Foundation, Inc.
3    Contributed by IBM Corporation.
4
5 This file is part of GDB and the GNU binutils.
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 "opcode/rs6k.h"
23
24 /* Print the rs6k instruction at address MEMADDR in debugged memory,
25    on STREAM.  Returns length of the instruction, in bytes.  */
26
27 int
28 print_insn (memaddr, stream)
29   CORE_ADDR memaddr;
30   FILE *stream;
31 {
32         int  pop, eop, probable_eop;    /* primary and extended opcodes */
33         int  min, max;
34         int  best = -1;                 /* found best opcode index      */
35         int  oldbest = -1;
36         unsigned int the_insn;
37
38         read_memory (memaddr, &the_insn, sizeof (the_insn));
39         pop = (unsigned)(the_insn >> 26);
40         min = 0, max = NOPCODES-1;
41
42         while (min < max) {
43           best = (min + max) / 2;
44
45           /* see if we are running in loops */
46           if (best == oldbest)
47             goto not_found;
48           oldbest = best;
49
50           if (pop < rs6k_ops [best].p_opcode)
51             max = best;
52
53           else if (pop > rs6k_ops [best].p_opcode)
54             min = best;
55
56           else {
57             /* Opcode matched, check extended opcode. */
58
59             if (rs6k_ops [best].e_opcode == -1) {
60               /* there is no valid extended opcode, what we've got is
61                  just fine. */
62               goto insn_found;
63             }
64
65             /* Largest possible value of extended opcode. */
66             probable_eop = ((the_insn) >> 1) & 0x3ff;
67
68             eop = probable_eop & eopMask [rs6k_ops [best].format];
69
70             if (eop < rs6k_ops [best].e_opcode) {
71
72               while (pop == rs6k_ops [best].p_opcode) {
73                 if (eop == rs6k_ops [best].e_opcode)    /* found it! */
74                   goto insn_found;
75                 --best;
76                 eop = probable_eop & eopMask [rs6k_ops [best].format];
77               }
78               goto not_found;
79             }
80
81             else if (eop > rs6k_ops [best].e_opcode) {
82
83               while (pop == rs6k_ops [best].p_opcode) {
84                 if (eop == rs6k_ops [best].e_opcode)    /* found it! */
85                   goto insn_found;
86                 ++best;
87                 eop = probable_eop & eopMask [rs6k_ops [best].format];
88               }
89               goto not_found;
90             }
91
92             else /*  eop == rs6k_ops [best].e_opcode */
93               goto insn_found;
94           }
95         }       
96
97         best = min;
98         if (pop == rs6k_ops [best].p_opcode &&
99            (rs6k_ops [best].e_opcode == -1 || rs6k_ops [best].e_opcode == eop))
100             goto insn_found;
101
102         else
103           goto not_found;
104
105
106 insn_found:
107         print_operator (stream, memaddr, the_insn, best);
108         return 4;
109
110 not_found:
111         fprintf (stream, "0x%08x", the_insn);
112         return 4;
113 }
114
115
116
117 /* condition code names */
118 static char *cond_code [] = {
119   "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", "nl", "ng", "z", "nz" };
120
121
122 print_operator (stream, memaddr, insn_word, insn_no)
123 FILE    *stream;
124 long    memaddr;
125 long    insn_word;
126 int     insn_no;
127 {
128   char buf [20];
129   char *qq = buf;
130   char *pp = rs6k_ops[insn_no].opr_ext;
131   int tmp;
132   int nocomma = 0;                      /* true if no comma needed */
133
134   if (pp) {
135     while (*pp) {
136
137       switch ( *pp ) {
138         case '.':
139           if (insn_word & 0x1)
140             *qq++ = '.';
141           break;
142
143         case 'l':
144           if (insn_word & 0x1)
145            *qq++ = 'l';
146           break;
147
148         case 't':
149           if ((insn_word & 0x03e00000) == 0x01800000)
150            *qq++ = 't';
151           break;
152
153         case 'f':
154           if ((insn_word & 0x03e00000) == 0x00800000)
155            *qq++ = 'f';
156           break;
157
158         case 'a':
159           if (insn_word & 0x2)
160            *qq++ = 'a';
161           break;
162
163         case 'o':
164           if (insn_word & 0x4000)
165            *qq++ = 'o';
166           break;
167
168         case '1':               /* exception #1 for bb/bc ambiguity */
169           tmp = (insn_word >> 21) & 0x1f;       /* extract BO   */
170           if (tmp != 0xc && tmp != 0x4) {
171             /* you can't use `bb' now. switch to `bc' */
172             *(qq-1) = 'c';
173             ++insn_no;
174             pp = rs6k_ops[insn_no].opr_ext;
175             continue;
176           }
177           break;
178
179         default:
180           abort ();
181       }
182       ++pp;
183     }
184   }
185   *qq = '\0';
186
187   fprintf (stream, "%s%s\t", rs6k_ops[insn_no].operator, buf);
188
189   /* parse the operand now. */
190   pp = rs6k_ops[insn_no].oprnd_format;
191
192   while (*pp != 0) {
193     switch (*pp) {
194       case TO   :
195         fprintf (stream, "%d", (insn_word >> 21) & 0x1f);
196         break;
197
198       case RT   :
199       case RS   :
200         fprintf (stream, "r%d", (insn_word >> 21) & 0x1f);
201         break;
202
203       case LI   :
204         tmp  = (insn_word >> 16) & 0x1f;
205 #if 0
206         /* This is wrong, wrong, wrong.  The condition code only goes
207            from 0 to 3 (for the instructions which can use extended
208            mnemonics of this type), and the XX (lt, gt, eq etc.) goes
209            into the mnemonic, not as an operand.
210
211            Probably the best way to get this right in both assembler
212            and disassembler is to switch to a match/lose style opcode
213            table like the sparc.  */
214         if (tmp > 11) {
215           fprintf (stream, "{unknown cond code: 0x%x}", insn_word);
216           tmp = 0;
217         }
218         fprintf (stream, "%s", cond_code [tmp]);
219 #else
220         /* So for just always use the "bbf/bbt" form.  This is perfectly
221            correct, just not necessarily as legible.
222
223            If tmp is not in the range 0-3, we can't use an XX form anyway.  */
224         fprintf (stream, "%d", tmp);
225 #endif
226         break;
227
228       case A2   :
229       case TA14 :
230         tmp = (insn_word & 0xfffc);
231         if (tmp & 0x8000)               /* fix sign extension   */
232           tmp -= 0x10000;
233
234         if ((insn_word & 0x2) == 0)     /* if AA not set        */
235           tmp += memaddr;
236
237         print_address (tmp, stream);
238         break;
239
240       case TA24 :
241         tmp = insn_word & 0x03fffffc;
242         if (tmp & 0x2000000)
243           tmp -= 0x4000000;
244         
245         if ((insn_word & 0x2) == 0)             /* if no AA bit set */
246           tmp += memaddr;
247
248         print_address (tmp, stream);
249         break;
250
251       case LEV  :                       /* for svc only */
252         if (insn_word & 0x2) {          /* SA is set    */
253           nocomma = 1;
254         }
255         else
256           fprintf (stream, "%d", (insn_word >> 5) & 0x7f);
257         break;
258
259       case FL1  :                       /* for svc only */
260         if (insn_word & 0x2) {          /* SA is set    */
261           nocomma = 1;
262         }
263         else
264           fprintf (stream, "%d", (insn_word >> 12) & 0xf);
265         break;
266
267       case FL2  :                       /* for svc only */
268         nocomma = 0;
269         if (insn_word & 0x2)            /* SA is set    */
270           fprintf (stream, "%d", (insn_word >> 2) & 0x3fff);
271         else
272           fprintf (stream, "%d", (insn_word >> 2) & 0x7);
273         break;
274
275       case RA   :
276         if (nocomma) {
277           fprintf (stream, "r%d)", (insn_word >> 16) & 0x1f);
278           nocomma = 0;
279         }
280         else
281           fprintf (stream, "r%d", (insn_word >> 16) & 0x1f);
282         break;
283
284       case RB   :
285         fprintf (stream, "r%d", (insn_word >> 11) & 0x1f);
286         break;
287
288       case SI   :
289         tmp = insn_word & 0xffff;
290         if (tmp & 0x8000)
291           tmp -= 0x10000;
292         fprintf (stream, "%d", tmp);
293         break;
294
295       case UI   :
296         fprintf (stream, "%d", insn_word & 0xffff);
297         break;
298
299       case BF   :
300         fprintf (stream, "%d", (insn_word >> 23) & 0x7);
301         break;
302
303       case BFA  :
304         fprintf (stream, "%d", (insn_word >> 18) & 0x7);
305         break;
306
307       case BT   :
308         fprintf (stream, "%d", (insn_word >> 21) & 0x1f);
309         break;
310
311       case BA   :
312         fprintf (stream, "%d", (insn_word >> 16) & 0x1f);
313         break;
314
315       case BB   :
316         fprintf (stream, "%d", (insn_word >> 11) & 0x1f);
317         break;
318
319       case BO   :
320         fprintf (stream, "%d", (insn_word >> 21) & 0x1f);
321         break;
322
323       case BI   :
324         fprintf (stream, "%d", (insn_word >> 16) & 0x1f);
325         break;
326
327       case SH   :
328         fprintf (stream, "%d", (insn_word >> 11) & 0x1f);
329         break;
330
331       case MB   :
332         fprintf (stream, "0x%x", (insn_word >> 6) & 0x1f);
333         break;
334
335       case ME   :
336         fprintf (stream, "0x%x", (insn_word >> 1) & 0x1f);
337         break;
338
339       case SPR  :
340         fprintf (stream, "%d", (insn_word >> 16) & 0x1f);
341         break;
342
343       case DIS  :
344         nocomma = 1;
345         tmp = insn_word & 0xffff;
346         if (tmp & 0x8000)
347           tmp -= 0x10000;
348         fprintf (stream, "%d(", tmp);
349         break;
350
351       case FXM  :
352         fprintf (stream, "0x%x", (insn_word >> 12) & 0xff);
353         break;
354
355       case FRT  :
356       case FRS  :
357         fprintf (stream, "f%d", (insn_word >> 21) & 0x1f);
358         break;
359
360       case FRA  :
361         fprintf (stream, "f%d", (insn_word >> 16) & 0x1f);
362         break;
363
364       case FRB  :
365         fprintf (stream, "f%d", (insn_word >> 11) & 0x1f);
366         break;
367
368       case FRC  :
369         fprintf (stream, "f%d", (insn_word >> 6) & 0x1f);
370         break;
371
372       case FLM  :
373         fprintf (stream, "0x%x", (insn_word >> 17) & 0xff);
374         break;
375
376       case NB   :
377         fprintf (stream, "%d", (insn_word >> 11) & 0x1f);
378         break;
379
380       case I    :
381         fprintf (stream, "%d", (insn_word >> 12) & 0xf);
382         break;
383
384       default   :
385         fprintf (stream,
386                  "{Internal error: Unknown operand format identifier %d}",
387                  *pp);
388     }
389     ++pp;
390
391     if (*pp != '\0' && !nocomma)
392       fputc(',', stream);
393   }
394 }
This page took 0.045038 seconds and 4 git commands to generate.