Initial revision
[binutils.git] / opcodes / sh-dis.c
blob2ebfdb6d3686f49874377e09459e9dea1757876e
1 /* Disassemble SH instructions.
2 Copyright (C) 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
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.
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.
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. */
18 #include <stdio.h>
19 #define STATIC_TABLE
20 #define DEFINE_TABLE
22 #include "sh-opc.h"
23 #include "dis-asm.h"
25 #define LITTLE_BIT 2
27 static int
28 print_insn_shx (memaddr, info)
29 bfd_vma memaddr;
30 struct disassemble_info *info;
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;
40 status = info->read_memory_func (memaddr, insn, 2, info);
42 if (status != 0)
44 info->memory_error_func (status, memaddr, info);
45 return -1;
48 if (info->flags & LITTLE_BIT)
50 nibs[0] = (insn[1] >> 4) & 0xf;
51 nibs[1] = insn[1] & 0xf;
53 nibs[2] = (insn[0] >> 4) & 0xf;
54 nibs[3] = insn[0] & 0xf;
56 else
58 nibs[0] = (insn[0] >> 4) & 0xf;
59 nibs[1] = insn[0] & 0xf;
61 nibs[2] = (insn[1] >> 4) & 0xf;
62 nibs[3] = insn[1] & 0xf;
65 for (op = sh_table; op->name; op++)
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;
75 for (n = 0; n < 4; n++)
77 int i = op->nibbles[n];
79 if (i < 16)
81 if (nibs[n] == i)
82 continue;
83 goto fail;
85 switch (i)
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();
150 fprintf_fn (stream,"%s\t", op->name);
151 disp_pc = 0;
152 for (n = 0; n < 3 && op->arg[n] != A_END; n++)
154 if (n && op->arg[1] != A_END)
155 fprintf_fn (stream, ",");
156 switch (op->arg[n])
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)
260 fprintf_fn (stream, "xd%d", rn & ~1);
261 break;
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)
270 fprintf_fn (stream, "xd%d", rm & ~1);
271 break;
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();
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] == '.')))
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;
322 #endif
324 if (disp_pc && strcmp (op->name, "mova") != 0)
326 int size;
327 bfd_byte bytes[4];
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)
336 unsigned int val;
338 if (size == 2)
340 if ((info->flags & LITTLE_BIT) != 0)
341 val = bfd_getl16 (bytes);
342 else
343 val = bfd_getb16 (bytes);
345 else
347 if ((info->flags & LITTLE_BIT) != 0)
348 val = bfd_getl32 (bytes);
349 else
350 val = bfd_getb32 (bytes);
352 fprintf_fn (stream, "\t! 0x%x", val);
356 return 2;
357 fail:
361 fprintf_fn (stream, ".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]);
362 return 2;
365 int
366 print_insn_shl (memaddr, info)
367 bfd_vma memaddr;
368 struct disassemble_info *info;
370 int r;
372 info->flags = LITTLE_BIT;
373 r = print_insn_shx (memaddr, info);
374 return r;
377 int
378 print_insn_sh (memaddr, info)
379 bfd_vma memaddr;
380 struct disassemble_info *info;
382 int r;
384 info->flags = 0;
385 r = print_insn_shx (memaddr, info);
386 return r;