Commit | Line | Data |
---|---|---|
f6c1a2d5 | 1 | /* xgate-dis.c -- Freescale XGATE disassembly |
df7b86aa | 2 | Copyright 2009, 2010, 2011, 2012 |
f6c1a2d5 NC |
3 | Free Software Foundation, Inc. |
4 | Written by Sean Keys (skeys@ipdatasys.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, | |
df7b86aa | 21 | MA 02110-1301, USA. */ |
f6c1a2d5 | 22 | |
f6c1a2d5 | 23 | #include "sysdep.h" |
df7b86aa | 24 | #include <assert.h> |
f6c1a2d5 NC |
25 | #include "dis-asm.h" |
26 | #include "opintl.h" | |
27 | #include "libiberty.h" | |
28 | #include "ansidecl.h" | |
29 | #include "opcode/xgate.h" | |
30 | ||
31 | #define XGATE_TWO_BYTES 0x02 | |
32 | #define XGATE_NINE_BITS 0x1FF | |
33 | #define XGATE_TEN_BITS 0x3FF | |
34 | #define XGATE_NINE_SIGNBIT 0x100 | |
35 | #define XGATE_TEN_SIGNBIT 0x200 | |
36 | ||
df7b86aa NC |
37 | /* Structures. */ |
38 | struct decodeInfo | |
39 | { | |
f6c1a2d5 NC |
40 | unsigned int operMask; |
41 | unsigned int operMasksRegisterBits; | |
42 | struct xgate_opcode *opcodePTR; | |
43 | }; | |
44 | ||
45 | /* Prototypes for local functions. */ | |
df7b86aa NC |
46 | static int print_insn (bfd_vma, struct disassemble_info *); |
47 | static int read_memory (bfd_vma, bfd_byte*, int, struct disassemble_info *); | |
48 | static int ripBits (unsigned int *, int, | |
49 | struct xgate_opcode *, unsigned int); | |
50 | static int macro_search (char *, char *); | |
51 | static struct decodeInfo * find_match (unsigned int); | |
f6c1a2d5 | 52 | |
df7b86aa | 53 | /* Statics. */ |
f6c1a2d5 NC |
54 | static struct decodeInfo *decodeTable; |
55 | static int initialized; | |
56 | static char previousOpName[10]; | |
57 | static unsigned int perviousBin; | |
58 | ||
59 | /* Disassemble one instruction at address 'memaddr'. Returns the number | |
df7b86aa NC |
60 | of bytes used by that instruction. */ |
61 | ||
f6c1a2d5 NC |
62 | static int |
63 | print_insn (bfd_vma memaddr, struct disassemble_info* info) | |
64 | { | |
65 | int status; | |
66 | unsigned int raw_code; | |
67 | char *s = 0; | |
68 | long bytesRead = 0; | |
69 | int i = 0; | |
70 | struct xgate_opcode *opcodePTR = (struct xgate_opcode*) xgate_opcodes; | |
71 | struct decodeInfo *decodeTablePTR = 0; | |
72 | struct decodeInfo *decodePTR = 0; | |
73 | unsigned int operandRegisterBits = 0; | |
74 | signed int relAddr = 0; | |
75 | signed int operandOne = 0; | |
76 | signed int operandTwo = 0; | |
77 | bfd_byte buffer[4]; | |
78 | bfd_vma absAddress; | |
79 | ||
80 | unsigned int operMaskReg = 0; | |
df7b86aa NC |
81 | /* Initialize our array of opcode masks and check them against our constant |
82 | table. */ | |
f6c1a2d5 NC |
83 | if (!initialized) |
84 | { | |
df7b86aa | 85 | decodeTable = xmalloc (sizeof (struct decodeInfo) * xgate_num_opcodes); |
f6c1a2d5 NC |
86 | for (i = 0, decodeTablePTR = decodeTable; i < xgate_num_opcodes; |
87 | i++, decodeTablePTR++, opcodePTR++) | |
88 | { | |
89 | unsigned int bin = 0; | |
90 | unsigned int mask = 0; | |
91 | for (s = opcodePTR->format; *s; s++) | |
92 | { | |
93 | bin <<= 1; | |
94 | mask <<= 1; | |
95 | operandRegisterBits <<= 1; | |
96 | bin |= (*s == '1'); | |
97 | mask |= (*s == '0' || *s == '1'); | |
98 | operandRegisterBits |= (*s == 'r'); | |
99 | } | |
df7b86aa NC |
100 | /* Asserting will uncover inconsistencies in our table. */ |
101 | assert ((s - opcodePTR->format) == 16 || (s - opcodePTR->format) == 32); | |
102 | assert (opcodePTR->bin_opcode == bin); | |
103 | ||
f6c1a2d5 NC |
104 | decodeTablePTR->operMask = mask; |
105 | decodeTablePTR->operMasksRegisterBits = operandRegisterBits; | |
106 | decodeTablePTR->opcodePTR = opcodePTR; | |
107 | } | |
108 | initialized = 1; | |
109 | } | |
df7b86aa NC |
110 | |
111 | /* Read 16 bits. */ | |
f6c1a2d5 | 112 | bytesRead += XGATE_TWO_BYTES; |
df7b86aa | 113 | status = read_memory (memaddr, buffer, XGATE_TWO_BYTES, info); |
f6c1a2d5 NC |
114 | if (status == 0) |
115 | { | |
116 | raw_code = buffer[0]; | |
117 | raw_code <<= 8; | |
118 | raw_code += buffer[1]; | |
119 | ||
df7b86aa | 120 | decodePTR = find_match (raw_code); |
f6c1a2d5 NC |
121 | if (decodePTR) |
122 | { | |
123 | operMaskReg = decodePTR->operMasksRegisterBits; | |
124 | (*info->fprintf_func)(info->stream, "%s", decodePTR->opcodePTR->name); | |
df7b86aa | 125 | |
f6c1a2d5 | 126 | /* First we compare the shorthand format of the constraints. If we |
df7b86aa NC |
127 | still are unable to pinpoint the operands |
128 | we analyze the opcodes constraint string. */ | |
f6c1a2d5 NC |
129 | switch (decodePTR->opcodePTR->sh_format) |
130 | { | |
131 | case XG_R_C: | |
132 | (*info->fprintf_func)(info->stream, " R%x, CCR", | |
133 | (raw_code >> 8) & 0x7); | |
134 | break; | |
135 | case XG_C_R: | |
136 | (*info->fprintf_func)(info->stream, " CCR, R%x", | |
137 | (raw_code >> 8) & 0x7); | |
138 | break; | |
139 | case XG_R_P: | |
140 | (*info->fprintf_func)(info->stream, " R%x, PC", | |
141 | (raw_code >> 8) & 0x7); | |
142 | break; | |
143 | case XG_INH: | |
144 | break; | |
145 | case XG_R_R_R: | |
df7b86aa | 146 | if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_TRI)) |
f6c1a2d5 NC |
147 | { |
148 | (*info->fprintf_func)(info->stream, " R%x, R%x, R%x", | |
149 | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | |
150 | (raw_code >> 2) & 0x7); | |
151 | } | |
df7b86aa | 152 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IDR)) |
f6c1a2d5 NC |
153 | { |
154 | if (raw_code & 0x01) | |
155 | { | |
156 | (*info->fprintf_func)(info->stream, " R%x, (R%x, R%x+)", | |
157 | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | |
158 | (raw_code >> 2) & 0x7); | |
159 | } | |
160 | else if (raw_code & 0x02) | |
161 | { | |
162 | (*info->fprintf_func)(info->stream, " R%x, (R%x, -R%x)", | |
163 | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | |
164 | (raw_code >> 2) & 0x7); | |
165 | } | |
166 | else | |
167 | { | |
168 | (*info->fprintf_func)(info->stream, " R%x, (R%x, R%x)", | |
169 | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | |
170 | (raw_code >> 2) & 0x7); | |
171 | } | |
172 | } | |
173 | else | |
174 | { | |
175 | (*info->fprintf_func)(info->stream, " unhandled mode %s", | |
176 | decodePTR->opcodePTR->constraints); | |
177 | } | |
178 | break; | |
179 | case XG_R_R: | |
3879925e | 180 | if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_DYA)) |
f6c1a2d5 | 181 | { |
df7b86aa NC |
182 | operandOne = ripBits (&operMaskReg, 3, opcodePTR, raw_code); |
183 | operandTwo = ripBits (&operMaskReg, 3, opcodePTR, raw_code); | |
f6c1a2d5 NC |
184 | (*info->fprintf_func)(info->stream, " R%x, R%x", operandOne, |
185 | operandTwo); | |
186 | } | |
187 | else | |
188 | { | |
189 | (*info->fprintf_func)(info->stream, " unhandled mode %s", | |
190 | opcodePTR->constraints); | |
191 | } | |
192 | break; | |
193 | case XG_R_R_I: | |
194 | (*info->fprintf_func)(info->stream, " R%x, (R%x, #0x%x)", | |
195 | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, raw_code & 0x1f); | |
196 | break; | |
197 | case XG_R: | |
df7b86aa | 198 | operandOne = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, |
f6c1a2d5 NC |
199 | raw_code); |
200 | (*info->fprintf_func)(info->stream, " R%x", operandOne); | |
201 | break; | |
202 | case XG_I | XG_PCREL: | |
df7b86aa | 203 | if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_REL9)) |
f6c1a2d5 | 204 | { |
df7b86aa | 205 | /* If address is negative handle it accordingly. */ |
f6c1a2d5 NC |
206 | if (raw_code & XGATE_NINE_SIGNBIT) |
207 | { | |
df7b86aa NC |
208 | relAddr = XGATE_NINE_BITS >> 1; /* Clip sign bit. */ |
209 | relAddr = ~relAddr; /* Make signed. */ | |
210 | relAddr |= (raw_code & 0xFF) + 1; /* Apply our value. */ | |
211 | relAddr <<= 1; /* Multiply by two as per processor docs. */ | |
f6c1a2d5 NC |
212 | } |
213 | else | |
214 | { | |
215 | relAddr = raw_code & 0xff; | |
216 | relAddr = (relAddr << 1) + 2; | |
217 | } | |
218 | (*info->fprintf_func)(info->stream, " *%d", relAddr); | |
219 | (*info->fprintf_func)(info->stream, " Abs* 0x"); | |
220 | (*info->print_address_func)(memaddr + relAddr, info); | |
221 | } | |
df7b86aa | 222 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_REL10)) |
f6c1a2d5 | 223 | { |
df7b86aa | 224 | /* If address is negative handle it accordingly. */ |
f6c1a2d5 NC |
225 | if (raw_code & XGATE_TEN_SIGNBIT) |
226 | { | |
df7b86aa NC |
227 | relAddr = XGATE_TEN_BITS >> 1; /* Clip sign bit. */ |
228 | relAddr = ~relAddr; /* Make signed. */ | |
229 | relAddr |= (raw_code & 0x1FF) + 1; /* Apply our value. */ | |
230 | relAddr <<= 1; /* Multiply by two as per processor docs. */ | |
f6c1a2d5 NC |
231 | } |
232 | else | |
233 | { | |
234 | relAddr = raw_code & 0x1FF; | |
235 | relAddr = (relAddr << 1) + 2; | |
236 | } | |
237 | (*info->fprintf_func)(info->stream, " *%d", relAddr); | |
238 | (*info->fprintf_func)(info->stream, " Abs* 0x"); | |
239 | (*info->print_address_func)(memaddr + relAddr, info); | |
240 | } | |
241 | else | |
242 | { | |
243 | (*info->fprintf_func)(info->stream, | |
244 | " Can't disassemble for mode) %s", | |
245 | decodePTR->opcodePTR->constraints); | |
246 | } | |
247 | break; | |
248 | case XG_R_I: | |
df7b86aa | 249 | if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM4)) |
f6c1a2d5 NC |
250 | { |
251 | (*info->fprintf_func)(info->stream, " R%x, #0x%02x", | |
252 | (raw_code >> 8) & 0x7, (raw_code >> 4) & 0xF); | |
253 | } | |
df7b86aa | 254 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM8)) |
f6c1a2d5 | 255 | { |
df7b86aa | 256 | if (macro_search (decodePTR->opcodePTR->name, previousOpName) && |
f6c1a2d5 NC |
257 | previousOpName[0]) |
258 | { | |
259 | absAddress = (0xFF & raw_code) << 8; | |
260 | absAddress |= perviousBin & 0xFF; | |
261 | (*info->fprintf_func)(info->stream, " R%x, #0x%02x Abs* 0x", | |
262 | (raw_code >> 8) & 0x7, raw_code & 0xff); | |
263 | (*info->print_address_func)(absAddress, info); | |
264 | previousOpName[0] = 0; | |
265 | } | |
266 | else | |
267 | { | |
df7b86aa | 268 | strcpy (previousOpName, decodePTR->opcodePTR->name); |
f6c1a2d5 NC |
269 | (*info->fprintf_func)(info->stream, " R%x, #0x%02x", |
270 | (raw_code >> 8) & 0x7, raw_code & 0xff); | |
271 | } | |
272 | } | |
273 | else | |
274 | { | |
275 | (*info->fprintf_func)(info->stream, | |
276 | " Can't disassemble for mode %s", | |
277 | decodePTR->opcodePTR->constraints); | |
278 | } | |
279 | break; | |
280 | case XG_I: | |
281 | (*info->fprintf_func)(info->stream, " #0x%x", | |
282 | (raw_code >> 8) & 0x7); | |
283 | break; | |
284 | default: | |
285 | (*info->fprintf_func)(info->stream, "address mode not found\t %x", | |
286 | opcodePTR->bin_opcode); | |
287 | break; | |
288 | } | |
289 | perviousBin = raw_code; | |
290 | } | |
291 | else | |
292 | { | |
293 | (*info->fprintf_func)(info->stream, | |
df7b86aa | 294 | " unable to find opcode match #0%x", raw_code); |
f6c1a2d5 NC |
295 | } |
296 | } | |
297 | return bytesRead; | |
298 | } | |
299 | ||
300 | int | |
301 | print_insn_xgate (bfd_vma memaddr, struct disassemble_info* info) | |
302 | { | |
303 | return print_insn (memaddr, info); | |
304 | } | |
305 | ||
306 | static int | |
307 | read_memory (bfd_vma memaddr, bfd_byte* buffer, int size, | |
308 | struct disassemble_info* info) | |
309 | { | |
310 | int status; | |
311 | status = (*info->read_memory_func) (memaddr, buffer, size, info); | |
312 | if (status != 0) | |
313 | { | |
314 | (*info->memory_error_func) (status, memaddr, info); | |
315 | return -1; | |
316 | } | |
317 | return 0; | |
318 | } | |
319 | ||
320 | static int | |
df7b86aa NC |
321 | ripBits (unsigned int *operandBitsRemaining, |
322 | int numBitsRequested, | |
323 | struct xgate_opcode *opcodePTR, | |
324 | unsigned int memory) | |
f6c1a2d5 NC |
325 | { |
326 | unsigned int currentBit; | |
327 | int operand; | |
328 | int numBitsFound; | |
df7b86aa | 329 | |
f6c1a2d5 | 330 | for (operand = 0, numBitsFound = 0, currentBit = 1 |
df7b86aa NC |
331 | << ((opcodePTR->size * 8) - 1); |
332 | (numBitsFound < numBitsRequested) && currentBit; currentBit >>= 1) | |
f6c1a2d5 | 333 | { |
df7b86aa NC |
334 | if (currentBit & *operandBitsRemaining) |
335 | { | |
336 | *operandBitsRemaining &= ~(currentBit); /* Consume the current bit. */ | |
337 | operand <<= 1; /* Make room for our next bit. */ | |
338 | numBitsFound++; | |
339 | operand |= (currentBit & memory) > 0; | |
340 | } | |
341 | } | |
f6c1a2d5 NC |
342 | return operand; |
343 | } | |
344 | ||
df7b86aa NC |
345 | static int |
346 | macro_search (char *currentName, char *lastName) | |
f6c1a2d5 NC |
347 | { |
348 | int i; | |
349 | int length = 0; | |
350 | char *where; | |
df7b86aa | 351 | |
f6c1a2d5 NC |
352 | for (i = 0; i < xgate_num_opcodes; i++) |
353 | { | |
df7b86aa NC |
354 | where = strstr (xgate_opcodes[i].constraints, lastName); |
355 | ||
f6c1a2d5 NC |
356 | if (where) |
357 | { | |
df7b86aa | 358 | length = strlen (where); |
f6c1a2d5 NC |
359 | } |
360 | if (length) | |
361 | { | |
df7b86aa | 362 | where = strstr (xgate_opcodes[i].constraints, currentName); |
f6c1a2d5 NC |
363 | if (where) |
364 | { | |
df7b86aa | 365 | length = strlen (where); |
f6c1a2d5 NC |
366 | return 1; |
367 | } | |
368 | } | |
369 | } | |
370 | return 0; | |
371 | } | |
372 | ||
df7b86aa NC |
373 | static struct decodeInfo * |
374 | find_match (unsigned int raw_code) | |
f6c1a2d5 NC |
375 | { |
376 | struct decodeInfo *decodeTablePTR = 0; | |
377 | int i; | |
378 | ||
379 | for (i = 0, decodeTablePTR = decodeTable; i < xgate_num_opcodes; | |
380 | i++, decodeTablePTR++) | |
381 | { | |
382 | if ((raw_code & decodeTablePTR->operMask) | |
383 | == decodeTablePTR->opcodePTR->bin_opcode) | |
384 | { | |
df7b86aa | 385 | /* Make sure we didn't run into a macro or alias. */ |
f6c1a2d5 NC |
386 | if (decodeTablePTR->opcodePTR->cycles_min != 0) |
387 | { | |
388 | return decodeTablePTR; | |
389 | break; | |
390 | } | |
391 | else | |
df7b86aa | 392 | continue; |
f6c1a2d5 NC |
393 | } |
394 | } | |
395 | return 0; | |
396 | } |