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