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