2ebfdb6d3686f49874377e09459e9dea1757876e
[platform/upstream/binutils.git] / opcodes / sh-dis.c
1 /* Disassemble SH instructions.
2    Copyright (C) 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #include <stdio.h>
19 #define STATIC_TABLE
20 #define DEFINE_TABLE
21
22 #include "sh-opc.h"
23 #include "dis-asm.h"
24
25 #define LITTLE_BIT 2
26
27 static int 
28 print_insn_shx (memaddr, info)
29      bfd_vma memaddr;
30      struct disassemble_info *info;
31 {
32   fprintf_ftype fprintf_fn = info->fprintf_func;
33   void *stream = info->stream;
34   unsigned char insn[2];
35   unsigned char nibs[4];
36   int status;
37   bfd_vma relmask = ~ (bfd_vma) 0;
38   sh_opcode_info *op;
39
40   status = info->read_memory_func (memaddr, insn, 2, info);
41
42   if (status != 0) 
43     {
44       info->memory_error_func (status, memaddr, info);
45       return -1;
46     }
47
48   if (info->flags & LITTLE_BIT) 
49     {
50       nibs[0] = (insn[1] >> 4) & 0xf;
51       nibs[1] = insn[1] & 0xf;
52
53       nibs[2] = (insn[0] >> 4) & 0xf;
54       nibs[3] = insn[0] & 0xf;
55     }
56   else 
57     {
58       nibs[0] = (insn[0] >> 4) & 0xf;
59       nibs[1] = insn[0] & 0xf;
60
61       nibs[2] = (insn[1] >> 4) & 0xf;
62       nibs[3] = insn[1] & 0xf;
63     }
64
65   for (op = sh_table; op->name; op++) 
66     {
67       int n;
68       int imm = 0;
69       int rn = 0;
70       int rm = 0;
71       int rb = 0;
72       int disp_pc;
73       bfd_vma disp_pc_addr = 0;
74
75       for (n = 0; n < 4; n++)
76         {
77           int i = op->nibbles[n];
78
79           if (i < 16) 
80             {
81               if (nibs[n] == i)
82                 continue;
83               goto fail;
84             }
85           switch (i)
86             {
87             case BRANCH_8:
88               imm = (nibs[2] << 4) | (nibs[3]);   
89               if (imm & 0x80)
90                 imm |= ~0xff;
91               imm = ((char)imm) * 2 + 4 ;
92               goto ok;
93             case BRANCH_12:
94               imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]);
95               if (imm & 0x800)
96                 imm |= ~0xfff;
97               imm = imm * 2 + 4;
98               goto ok;
99             case IMM_4:
100               imm = nibs[3];
101               goto ok;
102             case IMM_4BY2:
103               imm = nibs[3] <<1;
104               goto ok;
105             case IMM_4BY4:
106               imm = nibs[3] <<2;
107               goto ok;
108             case IMM_8:
109               imm = (nibs[2] << 4) | nibs[3];
110               goto ok;
111             case PCRELIMM_8BY2:
112               imm = ((nibs[2] << 4) | nibs[3]) <<1;
113               relmask = ~ (bfd_vma) 1;
114               goto ok;
115             case PCRELIMM_8BY4:
116               imm = ((nibs[2] << 4) | nibs[3]) <<2;
117               relmask = ~ (bfd_vma) 3;
118               goto ok;
119             case IMM_8BY2:
120               imm = ((nibs[2] << 4) | nibs[3]) <<1;
121               goto ok;
122             case IMM_8BY4:
123               imm = ((nibs[2] << 4) | nibs[3]) <<2;
124               goto ok;
125             case DISP_8:
126               imm = (nibs[2] << 4) | (nibs[3]);   
127               goto ok;
128             case DISP_4:
129               imm = nibs[3];
130               goto ok;
131             case REG_N:
132               rn = nibs[n];
133               break;
134             case REG_M:
135               rm = nibs[n];
136               break;
137             case REG_NM:
138               rn = (nibs[n] & 0xc) >> 2;
139               rm = (nibs[n] & 0x3);
140               break;
141             case REG_B:
142               rb = nibs[n] & 0x07;
143               break;    
144             default:
145               abort();
146             }
147         }
148
149     ok:
150       fprintf_fn (stream,"%s\t", op->name);
151       disp_pc = 0;
152       for (n = 0; n < 3 && op->arg[n] != A_END; n++) 
153         {
154           if (n && op->arg[1] != A_END)
155             fprintf_fn (stream, ",");
156           switch (op->arg[n]) 
157             {
158             case A_IMM:
159               fprintf_fn (stream, "#%d", (char)(imm));
160               break;
161             case A_R0:
162               fprintf_fn (stream, "r0");
163               break;
164             case A_REG_N:
165               fprintf_fn (stream, "r%d", rn);
166               break;
167             case A_INC_N:
168               fprintf_fn (stream, "@r%d+", rn); 
169               break;
170             case A_DEC_N:
171               fprintf_fn (stream, "@-r%d", rn); 
172               break;
173             case A_IND_N:
174               fprintf_fn (stream, "@r%d", rn);  
175               break;
176             case A_DISP_REG_N:
177               fprintf_fn (stream, "@(%d,r%d)", imm, rn);        
178               break;
179             case A_REG_M:
180               fprintf_fn (stream, "r%d", rm);
181               break;
182             case A_INC_M:
183               fprintf_fn (stream, "@r%d+", rm); 
184               break;
185             case A_DEC_M:
186               fprintf_fn (stream, "@-r%d", rm); 
187               break;
188             case A_IND_M:
189               fprintf_fn (stream, "@r%d", rm);  
190               break;
191             case A_DISP_REG_M:
192               fprintf_fn (stream, "@(%d,r%d)", imm, rm);        
193               break;
194             case A_REG_B:
195               fprintf_fn (stream, "r%d_bank", rb);
196               break;
197             case A_DISP_PC:
198               disp_pc = 1;
199               disp_pc_addr = imm + 4 + (memaddr & relmask);
200               (*info->print_address_func) (disp_pc_addr, info);
201               break;
202             case A_IND_R0_REG_N:
203               fprintf_fn (stream, "@(r0,r%d)", rn);
204               break; 
205             case A_IND_R0_REG_M:
206               fprintf_fn (stream, "@(r0,r%d)", rm);
207               break; 
208             case A_DISP_GBR:
209               fprintf_fn (stream, "@(%d,gbr)",imm);
210               break;
211             case A_R0_GBR:
212               fprintf_fn (stream, "@(r0,gbr)");
213               break;
214             case A_BDISP12:
215             case A_BDISP8:
216               (*info->print_address_func) (imm + memaddr, info);
217               break;
218             case A_SR:
219               fprintf_fn (stream, "sr");
220               break;
221             case A_GBR:
222               fprintf_fn (stream, "gbr");
223               break;
224             case A_VBR:
225               fprintf_fn (stream, "vbr");
226               break;
227             case A_SSR:
228               fprintf_fn (stream, "ssr");
229               break;
230             case A_SPC:
231               fprintf_fn (stream, "spc");
232               break;
233             case A_MACH:
234               fprintf_fn (stream, "mach");
235               break;
236             case A_MACL:
237               fprintf_fn (stream ,"macl");
238               break;
239             case A_PR:
240               fprintf_fn (stream, "pr");
241               break;
242             case A_SGR:
243               fprintf_fn (stream, "sgr");
244               break;
245             case A_DBR:
246               fprintf_fn (stream, "dbr");
247               break;
248             case FD_REG_N:
249               if (0)
250                 goto d_reg_n;
251             case F_REG_N:
252               fprintf_fn (stream, "fr%d", rn);
253               break;
254             case F_REG_M:
255               fprintf_fn (stream, "fr%d", rm);
256               break;
257             case DX_REG_N:
258               if (rn & 1)
259                 {
260                   fprintf_fn (stream, "xd%d", rn & ~1);
261                   break;
262                 }
263             d_reg_n:
264             case D_REG_N:
265               fprintf_fn (stream, "dr%d", rn);
266               break;
267             case DX_REG_M:
268               if (rm & 1)
269                 {
270                   fprintf_fn (stream, "xd%d", rm & ~1);
271                   break;
272                 }
273             case D_REG_M:
274               fprintf_fn (stream, "dr%d", rm);
275               break;
276             case FPSCR_M:
277             case FPSCR_N:
278               fprintf_fn (stream, "fpscr");
279               break;
280             case FPUL_M:
281             case FPUL_N:
282               fprintf_fn (stream, "fpul");
283               break;
284             case F_FR0:
285               fprintf_fn (stream, "fr0");
286               break;
287             case V_REG_N:
288               fprintf_fn (stream, "fv%d", rn*4);
289               break;
290             case V_REG_M:
291               fprintf_fn (stream, "fv%d", rm*4);
292               break;
293             case XMTRX_M4:
294               fprintf_fn (stream, "xmtrx");
295               break;
296             default:
297               abort();
298             }
299         }
300
301 #if 0
302       /* This code prints instructions in delay slots on the same line
303          as the instruction which needs the delay slots.  This can be
304          confusing, since other disassembler don't work this way, and
305          it means that the instructions are not all in a line.  So I
306          disabled it.  Ian.  */
307       if (!(info->flags & 1)
308           && (op->name[0] == 'j'
309               || (op->name[0] == 'b'
310                   && (op->name[1] == 'r' 
311                       || op->name[1] == 's'))
312               || (op->name[0] == 'r' && op->name[1] == 't')
313               || (op->name[0] == 'b' && op->name[2] == '.')))
314         {
315           info->flags |= 1;
316           fprintf_fn (stream, "\t(slot ");
317           print_insn_shx (memaddr + 2, info);
318           info->flags &= ~1;
319           fprintf_fn (stream, ")");
320           return 4;
321         }
322 #endif
323
324       if (disp_pc && strcmp (op->name, "mova") != 0)
325         {
326           int size;
327           bfd_byte bytes[4];
328
329           if (relmask == ~ (bfd_vma) 1)
330             size = 2;
331           else
332             size = 4;
333           status = info->read_memory_func (disp_pc_addr, bytes, size, info);
334           if (status == 0)
335             {
336               unsigned int val;
337
338               if (size == 2)
339                 {
340                   if ((info->flags & LITTLE_BIT) != 0)
341                     val = bfd_getl16 (bytes);
342                   else
343                     val = bfd_getb16 (bytes);
344                 }
345               else
346                 {
347                   if ((info->flags & LITTLE_BIT) != 0)
348                     val = bfd_getl32 (bytes);
349                   else
350                     val = bfd_getb32 (bytes);
351                 }
352               fprintf_fn (stream, "\t! 0x%x", val);
353             }
354         }
355
356       return 2;
357     fail:
358       ;
359
360     }
361   fprintf_fn (stream, ".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]);
362   return 2;
363 }
364
365 int 
366 print_insn_shl (memaddr, info)
367      bfd_vma memaddr;
368      struct disassemble_info *info;
369 {
370   int r;
371
372   info->flags = LITTLE_BIT;
373   r = print_insn_shx (memaddr, info);
374   return r;
375 }
376
377 int 
378 print_insn_sh (memaddr, info)
379      bfd_vma memaddr;
380      struct disassemble_info *info;
381 {
382   int r;
383
384   info->flags = 0;
385   r = print_insn_shx (memaddr, info);
386   return r;
387 }