1 /* Disassembler for the i860.
2    Copyright (C) 2000-2016 Free Software Foundation, Inc.
3 
4    Contributed by Jason Eckhardt <jle@cygnus.com>.
5 
6    This file is part of the GNU opcodes library.
7 
8    This library is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3, or (at your option)
11    any later version.
12 
13    It is distributed in the hope that it will be useful, but WITHOUT
14    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16    License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21    MA 02110-1301, USA.  */
22 
23 #include "sysdep.h"
24 #include "dis-asm.h"
25 #include "opcode/i860.h"
26 
27 /* Later we should probably choose the prefix based on which OS flavor.  */
28 #define I860_REG_PREFIX "%"
29 
30 /* Integer register names (encoded as 0..31 in the instruction).  */
31 static const char *const grnames[] =
32  {"r0",  "r1",  "sp",  "fp",  "r4",  "r5",  "r6",  "r7",
33   "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
34   "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
35   "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"};
36 
37 /* FP register names (encoded as 0..31 in the instruction).  */
38 static const char *const frnames[] =
39  {"f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
40   "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
41   "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
42   "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"};
43 
44 /* Control/status register names (encoded as 0..11 in the instruction).
45    Registers bear, ccr, p0, p1, p2 and p3 are XP only.  */
46 static const char *const crnames[] =
47  {"fir", "psr", "dirbase", "db", "fsr", "epsr", "bear", "ccr",
48   "p0", "p1", "p2", "p3", "--", "--", "--", "--" };
49 
50 
51 
52 /* True if opcode is xor, xorh, and, andh, or, orh, andnot, andnoth.  */
53 #define BITWISE_OP(op)  ((op) == 0x30 || (op) == 0x31		\
54 			 || (op) == 0x34 || (op) == 0x35	\
55 			 || (op) == 0x38 || (op) == 0x39	\
56 			 || (op) == 0x3c || (op) == 0x3d	\
57 			 || (op) == 0x33 || (op) == 0x37	\
58 			 || (op) == 0x3b || (op) == 0x3f)
59 
60 
61 /* Sign extend N-bit number.  */
62 static int
sign_ext(unsigned int x,int n)63 sign_ext (unsigned int x, int n)
64 {
65   int t;
66   t = x >> (n - 1);
67   t = ((-t) << n) | x;
68   return t;
69 }
70 
71 
72 /* Print a PC-relative branch offset.  VAL is the sign extended value
73    from the branch instruction.  */
74 static void
print_br_address(disassemble_info * info,bfd_vma memaddr,long val)75 print_br_address (disassemble_info *info, bfd_vma memaddr, long val)
76 {
77 
78   long adj = (long)memaddr + 4 + (val << 2);
79 
80   (*info->fprintf_func) (info->stream, "0x%08lx", adj);
81 
82   /* Attempt to obtain a symbol for the target address.  */
83 
84   if (info->print_address_func && adj != 0)
85     {
86       (*info->fprintf_func) (info->stream, "\t// ");
87       (*info->print_address_func) (adj, info);
88     }
89 }
90 
91 
92 /* Print one instruction.  */
93 int
print_insn_i860(bfd_vma memaddr,disassemble_info * info)94 print_insn_i860 (bfd_vma memaddr, disassemble_info *info)
95 {
96   bfd_byte buff[4];
97   unsigned int insn, i;
98   int status;
99   const struct i860_opcode *opcode = 0;
100 
101   status = (*info->read_memory_func) (memaddr, buff, sizeof (buff), info);
102   if (status != 0)
103     {
104       (*info->memory_error_func) (status, memaddr, info);
105       return -1;
106     }
107 
108   /* Note that i860 instructions are always accessed as little endian
109      data, regardless of the endian mode of the i860.  */
110   insn = bfd_getl32 (buff);
111 
112   status = 0;
113   i = 0;
114   while (i860_opcodes[i].name != NULL)
115     {
116       opcode = &i860_opcodes[i];
117       if ((insn & opcode->match) == opcode->match
118 	  && (insn & opcode->lose) == 0)
119 	{
120 	  status = 1;
121 	  break;
122 	}
123       ++i;
124     }
125 
126   if (status == 0)
127     {
128       /* Instruction not in opcode table.  */
129       (*info->fprintf_func) (info->stream, ".long %#08x", insn);
130     }
131   else
132     {
133       const char *s;
134       int val;
135 
136       /* If this a flop (or a shrd) and its dual bit is set,
137          prefix with 'd.'.  */
138       if (((insn & 0xfc000000) == 0x48000000
139            || (insn & 0xfc000000) == 0xb0000000)
140           && (insn & 0x200))
141 	(*info->fprintf_func) (info->stream, "d.%s\t", opcode->name);
142       else
143 	(*info->fprintf_func) (info->stream, "%s\t", opcode->name);
144 
145       for (s = opcode->args; *s; s++)
146 	{
147 	  switch (*s)
148 	    {
149 	    /* Integer register (src1).  */
150 	    case '1':
151 	      (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX,
152 				     grnames[(insn >> 11) & 0x1f]);
153 	      break;
154 
155 	    /* Integer register (src2).  */
156 	    case '2':
157 	      (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX,
158 				     grnames[(insn >> 21) & 0x1f]);
159 	      break;
160 
161 	    /* Integer destination register.  */
162 	    case 'd':
163 	      (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX,
164 				     grnames[(insn >> 16) & 0x1f]);
165 	      break;
166 
167 	    /* Floating-point register (src1).  */
168 	    case 'e':
169 	      (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX,
170 				     frnames[(insn >> 11) & 0x1f]);
171 	      break;
172 
173 	    /* Floating-point register (src2).  */
174 	    case 'f':
175 	      (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX,
176 				     frnames[(insn >> 21) & 0x1f]);
177 	      break;
178 
179 	    /* Floating-point destination register.  */
180 	    case 'g':
181 	      (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX,
182 				     frnames[(insn >> 16) & 0x1f]);
183 	      break;
184 
185 	    /* Control register.  */
186 	    case 'c':
187 	      (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX,
188 				     crnames[(insn >> 21) & 0xf]);
189 	      break;
190 
191 	    /* 16-bit immediate (sign extend, except for bitwise ops).  */
192 	    case 'i':
193 	      if (BITWISE_OP ((insn & 0xfc000000) >> 26))
194 		(*info->fprintf_func) (info->stream, "0x%04x",
195 				       (unsigned int) (insn & 0xffff));
196 	      else
197 		(*info->fprintf_func) (info->stream, "%d",
198 				       sign_ext ((insn & 0xffff), 16));
199 	      break;
200 
201 	    /* 16-bit immediate, aligned (2^0, ld.b).  */
202 	    case 'I':
203 	      (*info->fprintf_func) (info->stream, "%d",
204 				     sign_ext ((insn & 0xffff), 16));
205 	      break;
206 
207 	    /* 16-bit immediate, aligned (2^1, ld.s).  */
208 	    case 'J':
209 	      (*info->fprintf_func) (info->stream, "%d",
210 				     sign_ext ((insn & 0xfffe), 16));
211 	      break;
212 
213 	    /* 16-bit immediate, aligned (2^2, ld.l, {p}fld.l, fst.l).  */
214 	    case 'K':
215 	      (*info->fprintf_func) (info->stream, "%d",
216 				     sign_ext ((insn & 0xfffc), 16));
217 	      break;
218 
219 	    /* 16-bit immediate, aligned (2^3, {p}fld.d, fst.d).  */
220 	    case 'L':
221 	      (*info->fprintf_func) (info->stream, "%d",
222 				     sign_ext ((insn & 0xfff8), 16));
223 	      break;
224 
225 	    /* 16-bit immediate, aligned (2^4, {p}fld.q, fst.q).  */
226 	    case 'M':
227 	      (*info->fprintf_func) (info->stream, "%d",
228 				     sign_ext ((insn & 0xfff0), 16));
229 	      break;
230 
231 	    /* 5-bit immediate (zero extend).  */
232 	    case '5':
233 	      (*info->fprintf_func) (info->stream, "%d",
234 				     ((insn >> 11) & 0x1f));
235 	      break;
236 
237 	    /* Split 16 bit immediate (20..16:10..0).  */
238 	    case 's':
239 	      val = ((insn >> 5) & 0xf800) | (insn & 0x07ff);
240 	      (*info->fprintf_func) (info->stream, "%d",
241 				     sign_ext (val, 16));
242 	      break;
243 
244 	    /* Split 16 bit immediate, aligned. (2^0, st.b).  */
245 	    case 'S':
246 	      val = ((insn >> 5) & 0xf800) | (insn & 0x07ff);
247 	      (*info->fprintf_func) (info->stream, "%d",
248 				     sign_ext (val, 16));
249 	      break;
250 
251 	    /* Split 16 bit immediate, aligned. (2^1, st.s).  */
252 	    case 'T':
253 	      val = ((insn >> 5) & 0xf800) | (insn & 0x07fe);
254 	      (*info->fprintf_func) (info->stream, "%d",
255 				     sign_ext (val, 16));
256 	      break;
257 
258 	    /* Split 16 bit immediate, aligned. (2^2, st.l).  */
259 	    case 'U':
260 	      val = ((insn >> 5) & 0xf800) | (insn & 0x07fc);
261 	      (*info->fprintf_func) (info->stream, "%d",
262 				     sign_ext (val, 16));
263 	      break;
264 
265 	    /* 26-bit PC relative immediate (lbroff).  */
266 	    case 'l':
267 	      val = sign_ext ((insn & 0x03ffffff), 26);
268 	      print_br_address (info, memaddr, val);
269 	      break;
270 
271 	    /* 16-bit PC relative immediate (sbroff).  */
272 	    case 'r':
273 	      val = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
274 	      print_br_address (info, memaddr, val);
275 	      break;
276 
277 	    default:
278 	      (*info->fprintf_func) (info->stream, "%c", *s);
279 	      break;
280 	    }
281 	}
282     }
283 
284   return sizeof (insn);
285 }
286 
287