12159047fSniklas /* Disassemble SH instructions.
2c074d1c9Sdrahn Copyright 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003
3b55d4692Sfgsch Free Software Foundation, Inc.
42159047fSniklas
52159047fSniklas This program is free software; you can redistribute it and/or modify
62159047fSniklas it under the terms of the GNU General Public License as published by
72159047fSniklas the Free Software Foundation; either version 2 of the License, or
82159047fSniklas (at your option) any later version.
92159047fSniklas
102159047fSniklas This program is distributed in the hope that it will be useful,
112159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
122159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
132159047fSniklas GNU General Public License for more details.
142159047fSniklas
152159047fSniklas You should have received a copy of the GNU General Public License
162159047fSniklas along with this program; if not, write to the Free Software
172159047fSniklas Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
182159047fSniklas
192159047fSniklas #include <stdio.h>
20b55d4692Sfgsch #include "sysdep.h"
212159047fSniklas #define STATIC_TABLE
222159047fSniklas #define DEFINE_TABLE
232159047fSniklas
242159047fSniklas #include "sh-opc.h"
252159047fSniklas #include "dis-asm.h"
262159047fSniklas
27c074d1c9Sdrahn #ifdef ARCH_all
28c074d1c9Sdrahn #define INCLUDE_SHMEDIA
29c074d1c9Sdrahn #endif
30c074d1c9Sdrahn
31c074d1c9Sdrahn static void print_movxy
32c074d1c9Sdrahn PARAMS ((const sh_opcode_info *, int, int, fprintf_ftype, void *));
33c074d1c9Sdrahn static void print_insn_ddt PARAMS ((int, struct disassemble_info *));
34c074d1c9Sdrahn static void print_dsp_reg PARAMS ((int, fprintf_ftype, void *));
35c074d1c9Sdrahn static void print_insn_ppi PARAMS ((int, struct disassemble_info *));
362159047fSniklas
37b305b0f1Sespie static void
print_movxy(op,rn,rm,fprintf_fn,stream)38b305b0f1Sespie print_movxy (op, rn, rm, fprintf_fn, stream)
39c074d1c9Sdrahn const sh_opcode_info *op;
40b305b0f1Sespie int rn, rm;
41b305b0f1Sespie fprintf_ftype fprintf_fn;
42b305b0f1Sespie void *stream;
43b305b0f1Sespie {
44b305b0f1Sespie int n;
45b305b0f1Sespie
46b305b0f1Sespie fprintf_fn (stream, "%s\t", op->name);
47b305b0f1Sespie for (n = 0; n < 2; n++)
48b305b0f1Sespie {
49b305b0f1Sespie switch (op->arg[n])
50b305b0f1Sespie {
51b305b0f1Sespie case A_IND_N:
52*007c2a45Smiod case AX_IND_N:
53*007c2a45Smiod case AXY_IND_N:
54*007c2a45Smiod case AY_IND_N:
55*007c2a45Smiod case AYX_IND_N:
56b305b0f1Sespie fprintf_fn (stream, "@r%d", rn);
57b305b0f1Sespie break;
58b305b0f1Sespie case A_INC_N:
59*007c2a45Smiod case AX_INC_N:
60*007c2a45Smiod case AXY_INC_N:
61*007c2a45Smiod case AY_INC_N:
62*007c2a45Smiod case AYX_INC_N:
63b305b0f1Sespie fprintf_fn (stream, "@r%d+", rn);
64b305b0f1Sespie break;
65*007c2a45Smiod case AX_PMOD_N:
66*007c2a45Smiod case AXY_PMOD_N:
67b305b0f1Sespie fprintf_fn (stream, "@r%d+r8", rn);
68b305b0f1Sespie break;
69*007c2a45Smiod case AY_PMOD_N:
70*007c2a45Smiod case AYX_PMOD_N:
71b305b0f1Sespie fprintf_fn (stream, "@r%d+r9", rn);
72b305b0f1Sespie break;
73*007c2a45Smiod case DSP_REG_A_M:
74b305b0f1Sespie fprintf_fn (stream, "a%c", '0' + rm);
75b305b0f1Sespie break;
76b305b0f1Sespie case DSP_REG_X:
77b305b0f1Sespie fprintf_fn (stream, "x%c", '0' + rm);
78b305b0f1Sespie break;
79b305b0f1Sespie case DSP_REG_Y:
80b305b0f1Sespie fprintf_fn (stream, "y%c", '0' + rm);
81b305b0f1Sespie break;
82*007c2a45Smiod case DSP_REG_AX:
83*007c2a45Smiod fprintf_fn (stream, "%c%c",
84*007c2a45Smiod (rm & 1) ? 'x' : 'a',
85*007c2a45Smiod (rm & 2) ? '1' : '0');
86*007c2a45Smiod break;
87*007c2a45Smiod case DSP_REG_XY:
88*007c2a45Smiod fprintf_fn (stream, "%c%c",
89*007c2a45Smiod (rm & 1) ? 'y' : 'x',
90*007c2a45Smiod (rm & 2) ? '1' : '0');
91*007c2a45Smiod break;
92*007c2a45Smiod case DSP_REG_AY:
93*007c2a45Smiod fprintf_fn (stream, "%c%c",
94*007c2a45Smiod (rm & 2) ? 'y' : 'a',
95*007c2a45Smiod (rm & 1) ? '1' : '0');
96*007c2a45Smiod break;
97*007c2a45Smiod case DSP_REG_YX:
98*007c2a45Smiod fprintf_fn (stream, "%c%c",
99*007c2a45Smiod (rm & 2) ? 'x' : 'y',
100*007c2a45Smiod (rm & 1) ? '1' : '0');
101*007c2a45Smiod break;
102b305b0f1Sespie default:
103b305b0f1Sespie abort ();
104b305b0f1Sespie }
105b305b0f1Sespie if (n == 0)
106b305b0f1Sespie fprintf_fn (stream, ",");
107b305b0f1Sespie }
108b305b0f1Sespie }
109b305b0f1Sespie
110b305b0f1Sespie /* Print a double data transfer insn. INSN is just the lower three
111b305b0f1Sespie nibbles of the insn, i.e. field a and the bit that indicates if
112b305b0f1Sespie a parallel processing insn follows.
113b305b0f1Sespie Return nonzero if a field b of a parallel processing insns follows. */
114b55d4692Sfgsch
115b305b0f1Sespie static void
print_insn_ddt(insn,info)116b305b0f1Sespie print_insn_ddt (insn, info)
117b305b0f1Sespie int insn;
118b305b0f1Sespie struct disassemble_info *info;
119b305b0f1Sespie {
120b305b0f1Sespie fprintf_ftype fprintf_fn = info->fprintf_func;
121b305b0f1Sespie void *stream = info->stream;
122b305b0f1Sespie
123b305b0f1Sespie /* If this is just a nop, make sure to emit something. */
124b305b0f1Sespie if (insn == 0x000)
125b305b0f1Sespie fprintf_fn (stream, "nopx\tnopy");
126b305b0f1Sespie
127b305b0f1Sespie /* If a parallel processing insn was printed before,
128b305b0f1Sespie and we got a non-nop, emit a tab. */
129b305b0f1Sespie if ((insn & 0x800) && (insn & 0x3ff))
130b305b0f1Sespie fprintf_fn (stream, "\t");
131b305b0f1Sespie
132b305b0f1Sespie /* Check if either the x or y part is invalid. */
133b305b0f1Sespie if (((insn & 0xc) == 0 && (insn & 0x2a0))
134b305b0f1Sespie || ((insn & 3) == 0 && (insn & 0x150)))
135*007c2a45Smiod if (info->mach != bfd_mach_sh_dsp
136*007c2a45Smiod && info->mach != bfd_mach_sh3_dsp)
137*007c2a45Smiod {
138*007c2a45Smiod static const sh_opcode_info *first_movx, *first_movy;
139*007c2a45Smiod const sh_opcode_info *op;
140*007c2a45Smiod int is_movy;
141*007c2a45Smiod
142*007c2a45Smiod if (! first_movx)
143*007c2a45Smiod {
144*007c2a45Smiod for (first_movx = sh_table; first_movx->nibbles[1] != MOVX_NOPY;)
145*007c2a45Smiod first_movx++;
146*007c2a45Smiod for (first_movy = first_movx; first_movy->nibbles[1] != MOVY_NOPX;)
147*007c2a45Smiod first_movy++;
148*007c2a45Smiod }
149*007c2a45Smiod
150*007c2a45Smiod is_movy = ((insn & 3) != 0);
151*007c2a45Smiod
152*007c2a45Smiod if (is_movy)
153*007c2a45Smiod op = first_movy;
154*007c2a45Smiod else
155*007c2a45Smiod op = first_movx;
156*007c2a45Smiod
157*007c2a45Smiod while (op->nibbles[2] != (unsigned) ((insn >> 4) & 3)
158*007c2a45Smiod || op->nibbles[3] != (unsigned) (insn & 0xf))
159*007c2a45Smiod op++;
160*007c2a45Smiod
161*007c2a45Smiod print_movxy (op,
162*007c2a45Smiod (4 * ((insn & (is_movy ? 0x200 : 0x100)) == 0)
163*007c2a45Smiod + 2 * is_movy
164*007c2a45Smiod + 1 * ((insn & (is_movy ? 0x100 : 0x200)) != 0)),
165*007c2a45Smiod (insn >> 6) & 3,
166*007c2a45Smiod fprintf_fn, stream);
167*007c2a45Smiod }
168*007c2a45Smiod else
169b305b0f1Sespie fprintf_fn (stream, ".word 0x%x", insn);
170b305b0f1Sespie else
171b305b0f1Sespie {
172c074d1c9Sdrahn static const sh_opcode_info *first_movx, *first_movy;
173c074d1c9Sdrahn const sh_opcode_info *opx, *opy;
174b55d4692Sfgsch unsigned int insn_x, insn_y;
175b305b0f1Sespie
176b305b0f1Sespie if (! first_movx)
177b305b0f1Sespie {
178b305b0f1Sespie for (first_movx = sh_table; first_movx->nibbles[1] != MOVX;)
179b305b0f1Sespie first_movx++;
180b305b0f1Sespie for (first_movy = first_movx; first_movy->nibbles[1] != MOVY;)
181b305b0f1Sespie first_movy++;
182b305b0f1Sespie }
183b305b0f1Sespie insn_x = (insn >> 2) & 0xb;
184b305b0f1Sespie if (insn_x)
185b305b0f1Sespie {
186b55d4692Sfgsch for (opx = first_movx; opx->nibbles[2] != insn_x;)
187b55d4692Sfgsch opx++;
188b305b0f1Sespie print_movxy (opx, ((insn >> 9) & 1) + 4, (insn >> 7) & 1,
189b305b0f1Sespie fprintf_fn, stream);
190b305b0f1Sespie }
191b305b0f1Sespie insn_y = (insn & 3) | ((insn >> 1) & 8);
192b305b0f1Sespie if (insn_y)
193b305b0f1Sespie {
194b305b0f1Sespie if (insn_x)
195b305b0f1Sespie fprintf_fn (stream, "\t");
196b55d4692Sfgsch for (opy = first_movy; opy->nibbles[2] != insn_y;)
197b55d4692Sfgsch opy++;
198b305b0f1Sespie print_movxy (opy, ((insn >> 8) & 1) + 6, (insn >> 6) & 1,
199b305b0f1Sespie fprintf_fn, stream);
200b305b0f1Sespie }
201b305b0f1Sespie }
202b305b0f1Sespie }
203b305b0f1Sespie
204b305b0f1Sespie static void
print_dsp_reg(rm,fprintf_fn,stream)205b305b0f1Sespie print_dsp_reg (rm, fprintf_fn, stream)
206b305b0f1Sespie int rm;
207b305b0f1Sespie fprintf_ftype fprintf_fn;
208b305b0f1Sespie void *stream;
209b305b0f1Sespie {
210b305b0f1Sespie switch (rm)
211b305b0f1Sespie {
212b305b0f1Sespie case A_A1_NUM:
213b305b0f1Sespie fprintf_fn (stream, "a1");
214b305b0f1Sespie break;
215b305b0f1Sespie case A_A0_NUM:
216b305b0f1Sespie fprintf_fn (stream, "a0");
217b305b0f1Sespie break;
218b305b0f1Sespie case A_X0_NUM:
219b305b0f1Sespie fprintf_fn (stream, "x0");
220b305b0f1Sespie break;
221b305b0f1Sespie case A_X1_NUM:
222b305b0f1Sespie fprintf_fn (stream, "x1");
223b305b0f1Sespie break;
224b305b0f1Sespie case A_Y0_NUM:
225b305b0f1Sespie fprintf_fn (stream, "y0");
226b305b0f1Sespie break;
227b305b0f1Sespie case A_Y1_NUM:
228b305b0f1Sespie fprintf_fn (stream, "y1");
229b305b0f1Sespie break;
230b305b0f1Sespie case A_M0_NUM:
231b305b0f1Sespie fprintf_fn (stream, "m0");
232b305b0f1Sespie break;
233b305b0f1Sespie case A_A1G_NUM:
234b305b0f1Sespie fprintf_fn (stream, "a1g");
235b305b0f1Sespie break;
236b305b0f1Sespie case A_M1_NUM:
237b305b0f1Sespie fprintf_fn (stream, "m1");
238b305b0f1Sespie break;
239b305b0f1Sespie case A_A0G_NUM:
240b305b0f1Sespie fprintf_fn (stream, "a0g");
241b305b0f1Sespie break;
242b305b0f1Sespie default:
243b305b0f1Sespie fprintf_fn (stream, "0x%x", rm);
244b305b0f1Sespie break;
245b305b0f1Sespie }
246b305b0f1Sespie }
247b305b0f1Sespie
248b305b0f1Sespie static void
print_insn_ppi(field_b,info)249b305b0f1Sespie print_insn_ppi (field_b, info)
250b305b0f1Sespie int field_b;
251b305b0f1Sespie struct disassemble_info *info;
252b305b0f1Sespie {
253b305b0f1Sespie static char *sx_tab[] = { "x0", "x1", "a0", "a1" };
254b305b0f1Sespie static char *sy_tab[] = { "y0", "y1", "m0", "m1" };
255b305b0f1Sespie fprintf_ftype fprintf_fn = info->fprintf_func;
256b305b0f1Sespie void *stream = info->stream;
257b55d4692Sfgsch unsigned int nib1, nib2, nib3;
258*007c2a45Smiod unsigned int altnib1, nib4;
259b55d4692Sfgsch char *dc = NULL;
260c074d1c9Sdrahn const sh_opcode_info *op;
261b305b0f1Sespie
262b305b0f1Sespie if ((field_b & 0xe800) == 0)
263b305b0f1Sespie {
264b305b0f1Sespie fprintf_fn (stream, "psh%c\t#%d,",
265b305b0f1Sespie field_b & 0x1000 ? 'a' : 'l',
266b305b0f1Sespie (field_b >> 4) & 127);
267b305b0f1Sespie print_dsp_reg (field_b & 0xf, fprintf_fn, stream);
268b305b0f1Sespie return;
269b305b0f1Sespie }
270b305b0f1Sespie if ((field_b & 0xc000) == 0x4000 && (field_b & 0x3000) != 0x1000)
271b305b0f1Sespie {
272b305b0f1Sespie static char *du_tab[] = { "x0", "y0", "a0", "a1" };
273b305b0f1Sespie static char *se_tab[] = { "x0", "x1", "y0", "a1" };
274b305b0f1Sespie static char *sf_tab[] = { "y0", "y1", "x0", "a1" };
275b305b0f1Sespie static char *sg_tab[] = { "m0", "m1", "a0", "a1" };
276b305b0f1Sespie
277b305b0f1Sespie if (field_b & 0x2000)
278b305b0f1Sespie {
279b305b0f1Sespie fprintf_fn (stream, "p%s %s,%s,%s\t",
280b305b0f1Sespie (field_b & 0x1000) ? "add" : "sub",
281b305b0f1Sespie sx_tab[(field_b >> 6) & 3],
282b305b0f1Sespie sy_tab[(field_b >> 4) & 3],
283b305b0f1Sespie du_tab[(field_b >> 0) & 3]);
284b305b0f1Sespie }
285*007c2a45Smiod else if ((field_b & 0xf0) == 0x10
286*007c2a45Smiod && info->mach != bfd_mach_sh_dsp
287*007c2a45Smiod && info->mach != bfd_mach_sh3_dsp)
288*007c2a45Smiod {
289*007c2a45Smiod fprintf_fn (stream, "pclr %s \t", du_tab[(field_b >> 0) & 3]);
290*007c2a45Smiod }
291*007c2a45Smiod else if ((field_b & 0xf3) != 0)
292*007c2a45Smiod {
293*007c2a45Smiod fprintf_fn (stream, ".word 0x%x\t", field_b);
294*007c2a45Smiod }
295b305b0f1Sespie fprintf_fn (stream, "pmuls%c%s,%s,%s",
296b305b0f1Sespie field_b & 0x2000 ? ' ' : '\t',
297b305b0f1Sespie se_tab[(field_b >> 10) & 3],
298b305b0f1Sespie sf_tab[(field_b >> 8) & 3],
299b305b0f1Sespie sg_tab[(field_b >> 2) & 3]);
300b305b0f1Sespie return;
301b305b0f1Sespie }
302b305b0f1Sespie
303b305b0f1Sespie nib1 = PPIC;
304b305b0f1Sespie nib2 = field_b >> 12 & 0xf;
305b305b0f1Sespie nib3 = field_b >> 8 & 0xf;
306*007c2a45Smiod nib4 = field_b >> 4 & 0xf;
307b305b0f1Sespie switch (nib3 & 0x3)
308b305b0f1Sespie {
309b305b0f1Sespie case 0:
310b305b0f1Sespie dc = "";
311b305b0f1Sespie nib1 = PPI3;
312b305b0f1Sespie break;
313b305b0f1Sespie case 1:
314b305b0f1Sespie dc = "";
315b305b0f1Sespie break;
316b305b0f1Sespie case 2:
317b305b0f1Sespie dc = "dct ";
318b305b0f1Sespie nib3 -= 1;
319b305b0f1Sespie break;
320b305b0f1Sespie case 3:
321b305b0f1Sespie dc = "dcf ";
322b305b0f1Sespie nib3 -= 2;
323b305b0f1Sespie break;
324b305b0f1Sespie }
325*007c2a45Smiod if (nib1 == PPI3)
326*007c2a45Smiod altnib1 = PPI3NC;
327*007c2a45Smiod else
328*007c2a45Smiod altnib1 = nib1;
329b305b0f1Sespie for (op = sh_table; op->name; op++)
330b305b0f1Sespie {
331*007c2a45Smiod if ((op->nibbles[1] == nib1 || op->nibbles[1] == altnib1)
332b305b0f1Sespie && op->nibbles[2] == nib2
333b305b0f1Sespie && op->nibbles[3] == nib3)
334b305b0f1Sespie {
335b305b0f1Sespie int n;
336b305b0f1Sespie
337*007c2a45Smiod switch (op->nibbles[4])
338*007c2a45Smiod {
339*007c2a45Smiod case HEX_0:
340*007c2a45Smiod break;
341*007c2a45Smiod case HEX_XX00:
342*007c2a45Smiod if ((nib4 & 3) != 0)
343*007c2a45Smiod continue;
344*007c2a45Smiod break;
345*007c2a45Smiod case HEX_1:
346*007c2a45Smiod if ((nib4 & 3) != 1)
347*007c2a45Smiod continue;
348*007c2a45Smiod break;
349*007c2a45Smiod case HEX_00YY:
350*007c2a45Smiod if ((nib4 & 0xc) != 0)
351*007c2a45Smiod continue;
352*007c2a45Smiod break;
353*007c2a45Smiod case HEX_4:
354*007c2a45Smiod if ((nib4 & 0xc) != 4)
355*007c2a45Smiod continue;
356*007c2a45Smiod break;
357*007c2a45Smiod default:
358*007c2a45Smiod abort ();
359*007c2a45Smiod }
360b305b0f1Sespie fprintf_fn (stream, "%s%s\t", dc, op->name);
361b305b0f1Sespie for (n = 0; n < 3 && op->arg[n] != A_END; n++)
362b305b0f1Sespie {
363b305b0f1Sespie if (n && op->arg[1] != A_END)
364b305b0f1Sespie fprintf_fn (stream, ",");
365b305b0f1Sespie switch (op->arg[n])
366b305b0f1Sespie {
367b305b0f1Sespie case DSP_REG_N:
368b305b0f1Sespie print_dsp_reg (field_b & 0xf, fprintf_fn, stream);
369b305b0f1Sespie break;
370b305b0f1Sespie case DSP_REG_X:
371b305b0f1Sespie fprintf_fn (stream, sx_tab[(field_b >> 6) & 3]);
372b305b0f1Sespie break;
373b305b0f1Sespie case DSP_REG_Y:
374b305b0f1Sespie fprintf_fn (stream, sy_tab[(field_b >> 4) & 3]);
375b305b0f1Sespie break;
376b305b0f1Sespie case A_MACH:
377b305b0f1Sespie fprintf_fn (stream, "mach");
378b305b0f1Sespie break;
379b305b0f1Sespie case A_MACL:
380b305b0f1Sespie fprintf_fn (stream, "macl");
381b305b0f1Sespie break;
382b305b0f1Sespie default:
383b305b0f1Sespie abort ();
384b305b0f1Sespie }
385b305b0f1Sespie }
386b305b0f1Sespie return;
387b305b0f1Sespie }
388b305b0f1Sespie }
389b305b0f1Sespie /* Not found. */
390b305b0f1Sespie fprintf_fn (stream, ".word 0x%x", field_b);
391b305b0f1Sespie }
392b305b0f1Sespie
393c074d1c9Sdrahn int
print_insn_sh(memaddr,info)394c074d1c9Sdrahn print_insn_sh (memaddr, info)
3952159047fSniklas bfd_vma memaddr;
3962159047fSniklas struct disassemble_info *info;
3972159047fSniklas {
398b305b0f1Sespie fprintf_ftype fprintf_fn = info->fprintf_func;
3992159047fSniklas void *stream = info->stream;
400*007c2a45Smiod unsigned char insn[4];
4012159047fSniklas unsigned char nibs[4];
4022159047fSniklas int status;
403b305b0f1Sespie bfd_vma relmask = ~(bfd_vma) 0;
404c074d1c9Sdrahn const sh_opcode_info *op;
405b305b0f1Sespie int target_arch;
406b305b0f1Sespie
407b305b0f1Sespie switch (info->mach)
408b305b0f1Sespie {
409b305b0f1Sespie case bfd_mach_sh:
410b305b0f1Sespie target_arch = arch_sh1;
411c074d1c9Sdrahn /* SH coff object files lack information about the machine type, so
412c074d1c9Sdrahn we end up with bfd_mach_sh unless it was set explicitly (which
413c074d1c9Sdrahn could have happended if this is a call from gdb or the simulator.) */
414c074d1c9Sdrahn if (info->symbols
415c074d1c9Sdrahn && bfd_asymbol_flavour(*info->symbols) == bfd_target_coff_flavour)
416c074d1c9Sdrahn target_arch = arch_sh4;
417b305b0f1Sespie break;
418b305b0f1Sespie case bfd_mach_sh2:
419b305b0f1Sespie target_arch = arch_sh2;
420b305b0f1Sespie break;
421c074d1c9Sdrahn case bfd_mach_sh2e:
422c074d1c9Sdrahn target_arch = arch_sh2e;
423c074d1c9Sdrahn break;
424b305b0f1Sespie case bfd_mach_sh_dsp:
425b305b0f1Sespie target_arch = arch_sh_dsp;
426b305b0f1Sespie break;
427b305b0f1Sespie case bfd_mach_sh3:
428b305b0f1Sespie target_arch = arch_sh3;
429b305b0f1Sespie break;
430b305b0f1Sespie case bfd_mach_sh3_dsp:
431b305b0f1Sespie target_arch = arch_sh3_dsp;
432b305b0f1Sespie break;
433b305b0f1Sespie case bfd_mach_sh3e:
434b305b0f1Sespie target_arch = arch_sh3e;
435b305b0f1Sespie break;
436b305b0f1Sespie case bfd_mach_sh4:
437*007c2a45Smiod case bfd_mach_sh4_nofpu:
438b305b0f1Sespie target_arch = arch_sh4;
439b305b0f1Sespie break;
440*007c2a45Smiod case bfd_mach_sh4a:
441*007c2a45Smiod case bfd_mach_sh4a_nofpu:
442*007c2a45Smiod target_arch = arch_sh4a;
443*007c2a45Smiod break;
444*007c2a45Smiod case bfd_mach_sh4al_dsp:
445*007c2a45Smiod target_arch = arch_sh4al_dsp;
446*007c2a45Smiod break;
447c074d1c9Sdrahn case bfd_mach_sh5:
448c074d1c9Sdrahn #ifdef INCLUDE_SHMEDIA
449c074d1c9Sdrahn status = print_insn_sh64 (memaddr, info);
450c074d1c9Sdrahn if (status != -2)
451c074d1c9Sdrahn return status;
452c074d1c9Sdrahn #endif
453c074d1c9Sdrahn /* When we get here for sh64, it's because we want to disassemble
454c074d1c9Sdrahn SHcompact, i.e. arch_sh4. */
455c074d1c9Sdrahn target_arch = arch_sh4;
456c074d1c9Sdrahn break;
457b305b0f1Sespie default:
458b305b0f1Sespie abort ();
459b305b0f1Sespie }
4602159047fSniklas
4612159047fSniklas status = info->read_memory_func (memaddr, insn, 2, info);
4622159047fSniklas
4632159047fSniklas if (status != 0)
4642159047fSniklas {
4652159047fSniklas info->memory_error_func (status, memaddr, info);
4662159047fSniklas return -1;
4672159047fSniklas }
4682159047fSniklas
469c074d1c9Sdrahn if (info->endian == BFD_ENDIAN_LITTLE)
4702159047fSniklas {
4712159047fSniklas nibs[0] = (insn[1] >> 4) & 0xf;
4722159047fSniklas nibs[1] = insn[1] & 0xf;
4732159047fSniklas
4742159047fSniklas nibs[2] = (insn[0] >> 4) & 0xf;
4752159047fSniklas nibs[3] = insn[0] & 0xf;
4762159047fSniklas }
4772159047fSniklas else
4782159047fSniklas {
4792159047fSniklas nibs[0] = (insn[0] >> 4) & 0xf;
4802159047fSniklas nibs[1] = insn[0] & 0xf;
4812159047fSniklas
4822159047fSniklas nibs[2] = (insn[1] >> 4) & 0xf;
4832159047fSniklas nibs[3] = insn[1] & 0xf;
4842159047fSniklas }
4852159047fSniklas
486b305b0f1Sespie if (nibs[0] == 0xf && (nibs[1] & 4) == 0 && target_arch & arch_sh_dsp_up)
487b305b0f1Sespie {
488b305b0f1Sespie if (nibs[1] & 8)
489b305b0f1Sespie {
490b305b0f1Sespie int field_b;
491b305b0f1Sespie
492b305b0f1Sespie status = info->read_memory_func (memaddr + 2, insn, 2, info);
493b305b0f1Sespie
494b305b0f1Sespie if (status != 0)
495b305b0f1Sespie {
496b305b0f1Sespie info->memory_error_func (status, memaddr + 2, info);
497b305b0f1Sespie return -1;
498b305b0f1Sespie }
499b305b0f1Sespie
500c074d1c9Sdrahn if (info->endian == BFD_ENDIAN_LITTLE)
501b305b0f1Sespie field_b = insn[1] << 8 | insn[0];
502b305b0f1Sespie else
503b305b0f1Sespie field_b = insn[0] << 8 | insn[1];
504b305b0f1Sespie
505b305b0f1Sespie print_insn_ppi (field_b, info);
506b305b0f1Sespie print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info);
507b305b0f1Sespie return 4;
508b305b0f1Sespie }
509b305b0f1Sespie print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info);
510b305b0f1Sespie return 2;
511b305b0f1Sespie }
5122159047fSniklas for (op = sh_table; op->name; op++)
5132159047fSniklas {
5142159047fSniklas int n;
515b305b0f1Sespie int imm = 0;
516b305b0f1Sespie int rn = 0;
517b305b0f1Sespie int rm = 0;
518b305b0f1Sespie int rb = 0;
519b305b0f1Sespie int disp_pc;
520b305b0f1Sespie bfd_vma disp_pc_addr = 0;
521c88b1d6cSniklas
522b305b0f1Sespie if ((op->arch & target_arch) == 0)
523b305b0f1Sespie goto fail;
524b305b0f1Sespie for (n = 0; n < 4; n++)
525b305b0f1Sespie {
5262159047fSniklas int i = op->nibbles[n];
527b305b0f1Sespie
5282159047fSniklas if (i < 16)
5292159047fSniklas {
530b305b0f1Sespie if (nibs[n] == i)
531b305b0f1Sespie continue;
5322159047fSniklas goto fail;
5332159047fSniklas }
5342159047fSniklas switch (i)
5352159047fSniklas {
5362159047fSniklas case BRANCH_8:
5372159047fSniklas imm = (nibs[2] << 4) | (nibs[3]);
5382159047fSniklas if (imm & 0x80)
5392159047fSniklas imm |= ~0xff;
5402159047fSniklas imm = ((char) imm) * 2 + 4;
5412159047fSniklas goto ok;
5422159047fSniklas case BRANCH_12:
5432159047fSniklas imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]);
5442159047fSniklas if (imm & 0x800)
5452159047fSniklas imm |= ~0xfff;
5462159047fSniklas imm = imm * 2 + 4;
5472159047fSniklas goto ok;
548b55d4692Sfgsch case IMM0_4:
549b55d4692Sfgsch case IMM1_4:
5502159047fSniklas imm = nibs[3];
5512159047fSniklas goto ok;
552b55d4692Sfgsch case IMM0_4BY2:
553b55d4692Sfgsch case IMM1_4BY2:
5542159047fSniklas imm = nibs[3] << 1;
5552159047fSniklas goto ok;
556b55d4692Sfgsch case IMM0_4BY4:
557b55d4692Sfgsch case IMM1_4BY4:
5582159047fSniklas imm = nibs[3] << 2;
5592159047fSniklas goto ok;
560b55d4692Sfgsch case IMM0_8:
561b55d4692Sfgsch case IMM1_8:
5622159047fSniklas imm = (nibs[2] << 4) | nibs[3];
5632159047fSniklas goto ok;
5642159047fSniklas case PCRELIMM_8BY2:
5652159047fSniklas imm = ((nibs[2] << 4) | nibs[3]) << 1;
566b305b0f1Sespie relmask = ~(bfd_vma) 1;
5672159047fSniklas goto ok;
5682159047fSniklas case PCRELIMM_8BY4:
5692159047fSniklas imm = ((nibs[2] << 4) | nibs[3]) << 2;
570b305b0f1Sespie relmask = ~(bfd_vma) 3;
5712159047fSniklas goto ok;
572b55d4692Sfgsch case IMM0_8BY2:
573b55d4692Sfgsch case IMM1_8BY2:
5742159047fSniklas imm = ((nibs[2] << 4) | nibs[3]) << 1;
5752159047fSniklas goto ok;
576b55d4692Sfgsch case IMM0_8BY4:
577b55d4692Sfgsch case IMM1_8BY4:
5782159047fSniklas imm = ((nibs[2] << 4) | nibs[3]) << 2;
5792159047fSniklas goto ok;
580*007c2a45Smiod case REG_N_D:
581*007c2a45Smiod if ((nibs[n] & 1) != 0)
582*007c2a45Smiod goto fail;
583*007c2a45Smiod /* fall through */
5842159047fSniklas case REG_N:
5852159047fSniklas rn = nibs[n];
5862159047fSniklas break;
5872159047fSniklas case REG_M:
5882159047fSniklas rm = nibs[n];
5892159047fSniklas break;
590*007c2a45Smiod case REG_N_B01:
591*007c2a45Smiod if ((nibs[n] & 0x3) != 1 /* binary 01 */)
592*007c2a45Smiod goto fail;
593*007c2a45Smiod rn = (nibs[n] & 0xc) >> 2;
594*007c2a45Smiod break;
595b305b0f1Sespie case REG_NM:
596b305b0f1Sespie rn = (nibs[n] & 0xc) >> 2;
597b305b0f1Sespie rm = (nibs[n] & 0x3);
598b305b0f1Sespie break;
599c88b1d6cSniklas case REG_B:
600c88b1d6cSniklas rb = nibs[n] & 0x07;
601c88b1d6cSniklas break;
602b305b0f1Sespie case SDT_REG_N:
603b305b0f1Sespie /* sh-dsp: single data transfer. */
604b305b0f1Sespie rn = nibs[n];
605b305b0f1Sespie if ((rn & 0xc) != 4)
606b305b0f1Sespie goto fail;
607b305b0f1Sespie rn = rn & 0x3;
608c074d1c9Sdrahn rn |= (!(rn & 2)) << 2;
609b305b0f1Sespie break;
610b305b0f1Sespie case PPI:
611b55d4692Sfgsch case REPEAT:
612b305b0f1Sespie goto fail;
6132159047fSniklas default:
6142159047fSniklas abort ();
6152159047fSniklas }
6162159047fSniklas }
617b305b0f1Sespie
6182159047fSniklas ok:
619b305b0f1Sespie fprintf_fn (stream, "%s\t", op->name);
620b305b0f1Sespie disp_pc = 0;
6212159047fSniklas for (n = 0; n < 3 && op->arg[n] != A_END; n++)
6222159047fSniklas {
6232159047fSniklas if (n && op->arg[1] != A_END)
624b305b0f1Sespie fprintf_fn (stream, ",");
6252159047fSniklas switch (op->arg[n])
6262159047fSniklas {
6272159047fSniklas case A_IMM:
628b305b0f1Sespie fprintf_fn (stream, "#%d", (char) (imm));
6292159047fSniklas break;
6302159047fSniklas case A_R0:
631b305b0f1Sespie fprintf_fn (stream, "r0");
6322159047fSniklas break;
6332159047fSniklas case A_REG_N:
634b305b0f1Sespie fprintf_fn (stream, "r%d", rn);
6352159047fSniklas break;
6362159047fSniklas case A_INC_N:
637*007c2a45Smiod case AS_INC_N:
638b305b0f1Sespie fprintf_fn (stream, "@r%d+", rn);
6392159047fSniklas break;
6402159047fSniklas case A_DEC_N:
641*007c2a45Smiod case AS_DEC_N:
642b305b0f1Sespie fprintf_fn (stream, "@-r%d", rn);
6432159047fSniklas break;
6442159047fSniklas case A_IND_N:
645*007c2a45Smiod case AS_IND_N:
646b305b0f1Sespie fprintf_fn (stream, "@r%d", rn);
6472159047fSniklas break;
6482159047fSniklas case A_DISP_REG_N:
649b305b0f1Sespie fprintf_fn (stream, "@(%d,r%d)", imm, rn);
650b305b0f1Sespie break;
651*007c2a45Smiod case AS_PMOD_N:
652b305b0f1Sespie fprintf_fn (stream, "@r%d+r8", rn);
6532159047fSniklas break;
6542159047fSniklas case A_REG_M:
655b305b0f1Sespie fprintf_fn (stream, "r%d", rm);
6562159047fSniklas break;
6572159047fSniklas case A_INC_M:
658b305b0f1Sespie fprintf_fn (stream, "@r%d+", rm);
6592159047fSniklas break;
6602159047fSniklas case A_DEC_M:
661b305b0f1Sespie fprintf_fn (stream, "@-r%d", rm);
6622159047fSniklas break;
6632159047fSniklas case A_IND_M:
664b305b0f1Sespie fprintf_fn (stream, "@r%d", rm);
6652159047fSniklas break;
6662159047fSniklas case A_DISP_REG_M:
667b305b0f1Sespie fprintf_fn (stream, "@(%d,r%d)", imm, rm);
6682159047fSniklas break;
669c88b1d6cSniklas case A_REG_B:
670b305b0f1Sespie fprintf_fn (stream, "r%d_bank", rb);
671c88b1d6cSniklas break;
6722159047fSniklas case A_DISP_PC:
673b305b0f1Sespie disp_pc = 1;
674b305b0f1Sespie disp_pc_addr = imm + 4 + (memaddr & relmask);
675b305b0f1Sespie (*info->print_address_func) (disp_pc_addr, info);
6762159047fSniklas break;
6772159047fSniklas case A_IND_R0_REG_N:
678b305b0f1Sespie fprintf_fn (stream, "@(r0,r%d)", rn);
6792159047fSniklas break;
6802159047fSniklas case A_IND_R0_REG_M:
681b305b0f1Sespie fprintf_fn (stream, "@(r0,r%d)", rm);
6822159047fSniklas break;
6832159047fSniklas case A_DISP_GBR:
684b305b0f1Sespie fprintf_fn (stream, "@(%d,gbr)", imm);
6852159047fSniklas break;
6862159047fSniklas case A_R0_GBR:
687b305b0f1Sespie fprintf_fn (stream, "@(r0,gbr)");
6882159047fSniklas break;
6892159047fSniklas case A_BDISP12:
6902159047fSniklas case A_BDISP8:
6912159047fSniklas (*info->print_address_func) (imm + memaddr, info);
6922159047fSniklas break;
6932159047fSniklas case A_SR:
694b305b0f1Sespie fprintf_fn (stream, "sr");
6952159047fSniklas break;
6962159047fSniklas case A_GBR:
697b305b0f1Sespie fprintf_fn (stream, "gbr");
6982159047fSniklas break;
6992159047fSniklas case A_VBR:
700b305b0f1Sespie fprintf_fn (stream, "vbr");
701b305b0f1Sespie break;
702b305b0f1Sespie case A_DSR:
703b305b0f1Sespie fprintf_fn (stream, "dsr");
704b305b0f1Sespie break;
705b305b0f1Sespie case A_MOD:
706b305b0f1Sespie fprintf_fn (stream, "mod");
707b305b0f1Sespie break;
708b305b0f1Sespie case A_RE:
709b305b0f1Sespie fprintf_fn (stream, "re");
710b305b0f1Sespie break;
711b305b0f1Sespie case A_RS:
712b305b0f1Sespie fprintf_fn (stream, "rs");
713b305b0f1Sespie break;
714b305b0f1Sespie case A_A0:
715b305b0f1Sespie fprintf_fn (stream, "a0");
716b305b0f1Sespie break;
717b305b0f1Sespie case A_X0:
718b305b0f1Sespie fprintf_fn (stream, "x0");
719b305b0f1Sespie break;
720b305b0f1Sespie case A_X1:
721b305b0f1Sespie fprintf_fn (stream, "x1");
722b305b0f1Sespie break;
723b305b0f1Sespie case A_Y0:
724b305b0f1Sespie fprintf_fn (stream, "y0");
725b305b0f1Sespie break;
726b305b0f1Sespie case A_Y1:
727b305b0f1Sespie fprintf_fn (stream, "y1");
728b305b0f1Sespie break;
729b305b0f1Sespie case DSP_REG_M:
730b305b0f1Sespie print_dsp_reg (rm, fprintf_fn, stream);
7312159047fSniklas break;
732c88b1d6cSniklas case A_SSR:
733b305b0f1Sespie fprintf_fn (stream, "ssr");
734c88b1d6cSniklas break;
735c88b1d6cSniklas case A_SPC:
736b305b0f1Sespie fprintf_fn (stream, "spc");
737c88b1d6cSniklas break;
7382159047fSniklas case A_MACH:
739b305b0f1Sespie fprintf_fn (stream, "mach");
7402159047fSniklas break;
7412159047fSniklas case A_MACL:
742b305b0f1Sespie fprintf_fn (stream, "macl");
7432159047fSniklas break;
7442159047fSniklas case A_PR:
745b305b0f1Sespie fprintf_fn (stream, "pr");
746b305b0f1Sespie break;
747b305b0f1Sespie case A_SGR:
748b305b0f1Sespie fprintf_fn (stream, "sgr");
749b305b0f1Sespie break;
750b305b0f1Sespie case A_DBR:
751b305b0f1Sespie fprintf_fn (stream, "dbr");
7522159047fSniklas break;
753c88b1d6cSniklas case F_REG_N:
754b305b0f1Sespie fprintf_fn (stream, "fr%d", rn);
755c88b1d6cSniklas break;
756c88b1d6cSniklas case F_REG_M:
757b305b0f1Sespie fprintf_fn (stream, "fr%d", rm);
758b305b0f1Sespie break;
759b305b0f1Sespie case DX_REG_N:
760b305b0f1Sespie if (rn & 1)
761b305b0f1Sespie {
762b305b0f1Sespie fprintf_fn (stream, "xd%d", rn & ~1);
763b305b0f1Sespie break;
764b305b0f1Sespie }
765b305b0f1Sespie case D_REG_N:
766b305b0f1Sespie fprintf_fn (stream, "dr%d", rn);
767b305b0f1Sespie break;
768b305b0f1Sespie case DX_REG_M:
769b305b0f1Sespie if (rm & 1)
770b305b0f1Sespie {
771b305b0f1Sespie fprintf_fn (stream, "xd%d", rm & ~1);
772b305b0f1Sespie break;
773b305b0f1Sespie }
774b305b0f1Sespie case D_REG_M:
775b305b0f1Sespie fprintf_fn (stream, "dr%d", rm);
776c88b1d6cSniklas break;
777c88b1d6cSniklas case FPSCR_M:
778c88b1d6cSniklas case FPSCR_N:
779b305b0f1Sespie fprintf_fn (stream, "fpscr");
780c88b1d6cSniklas break;
781c88b1d6cSniklas case FPUL_M:
782c88b1d6cSniklas case FPUL_N:
783b305b0f1Sespie fprintf_fn (stream, "fpul");
784c88b1d6cSniklas break;
785c88b1d6cSniklas case F_FR0:
786b305b0f1Sespie fprintf_fn (stream, "fr0");
787b305b0f1Sespie break;
788b305b0f1Sespie case V_REG_N:
789b305b0f1Sespie fprintf_fn (stream, "fv%d", rn * 4);
790b305b0f1Sespie break;
791b305b0f1Sespie case V_REG_M:
792b305b0f1Sespie fprintf_fn (stream, "fv%d", rm * 4);
793b305b0f1Sespie break;
794b305b0f1Sespie case XMTRX_M4:
795b305b0f1Sespie fprintf_fn (stream, "xmtrx");
796c88b1d6cSniklas break;
7972159047fSniklas default:
7982159047fSniklas abort ();
7992159047fSniklas }
8002159047fSniklas }
801b305b0f1Sespie
802b305b0f1Sespie #if 0
803b305b0f1Sespie /* This code prints instructions in delay slots on the same line
804b305b0f1Sespie as the instruction which needs the delay slots. This can be
805b305b0f1Sespie confusing, since other disassembler don't work this way, and
806b305b0f1Sespie it means that the instructions are not all in a line. So I
807b305b0f1Sespie disabled it. Ian. */
8082159047fSniklas if (!(info->flags & 1)
8092159047fSniklas && (op->name[0] == 'j'
8102159047fSniklas || (op->name[0] == 'b'
8112159047fSniklas && (op->name[1] == 'r'
8122159047fSniklas || op->name[1] == 's'))
8132159047fSniklas || (op->name[0] == 'r' && op->name[1] == 't')
8142159047fSniklas || (op->name[0] == 'b' && op->name[2] == '.')))
8152159047fSniklas {
8162159047fSniklas info->flags |= 1;
817b305b0f1Sespie fprintf_fn (stream, "\t(slot ");
818c074d1c9Sdrahn print_insn_sh (memaddr + 2, info);
8192159047fSniklas info->flags &= ~1;
820b305b0f1Sespie fprintf_fn (stream, ")");
8212159047fSniklas return 4;
8222159047fSniklas }
823b305b0f1Sespie #endif
824b305b0f1Sespie
825b305b0f1Sespie if (disp_pc && strcmp (op->name, "mova") != 0)
826b305b0f1Sespie {
827b305b0f1Sespie int size;
828b305b0f1Sespie bfd_byte bytes[4];
829b305b0f1Sespie
830b305b0f1Sespie if (relmask == ~(bfd_vma) 1)
831b305b0f1Sespie size = 2;
832b305b0f1Sespie else
833b305b0f1Sespie size = 4;
834b305b0f1Sespie status = info->read_memory_func (disp_pc_addr, bytes, size, info);
835b305b0f1Sespie if (status == 0)
836b305b0f1Sespie {
837b305b0f1Sespie unsigned int val;
838b305b0f1Sespie
839b305b0f1Sespie if (size == 2)
840b305b0f1Sespie {
841c074d1c9Sdrahn if (info->endian == BFD_ENDIAN_LITTLE)
842b305b0f1Sespie val = bfd_getl16 (bytes);
843b305b0f1Sespie else
844b305b0f1Sespie val = bfd_getb16 (bytes);
845b305b0f1Sespie }
846b305b0f1Sespie else
847b305b0f1Sespie {
848c074d1c9Sdrahn if (info->endian == BFD_ENDIAN_LITTLE)
849b305b0f1Sespie val = bfd_getl32 (bytes);
850b305b0f1Sespie else
851b305b0f1Sespie val = bfd_getb32 (bytes);
852b305b0f1Sespie }
853b305b0f1Sespie fprintf_fn (stream, "\t! 0x%x", val);
854b305b0f1Sespie }
855b305b0f1Sespie }
8562159047fSniklas
8572159047fSniklas return 2;
8582159047fSniklas fail:
8592159047fSniklas ;
8602159047fSniklas
8612159047fSniklas }
862b305b0f1Sespie fprintf_fn (stream, ".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]);
8632159047fSniklas return 2;
8642159047fSniklas }
865