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: | |
df7b86aa | 180 | if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_DYA_MON)) |
f6c1a2d5 | 181 | { |
df7b86aa | 182 | operandOne = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, |
f6c1a2d5 | 183 | raw_code); |
df7b86aa | 184 | operandTwo = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, |
f6c1a2d5 NC |
185 | raw_code); |
186 | (*info->fprintf_func)(info->stream, " R%x, R%x", operandOne, | |
187 | operandTwo); | |
188 | } | |
df7b86aa | 189 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_DYA)) |
f6c1a2d5 | 190 | { |
df7b86aa NC |
191 | operandOne = ripBits (&operMaskReg, 3, opcodePTR, raw_code); |
192 | operandTwo = ripBits (&operMaskReg, 3, opcodePTR, raw_code); | |
f6c1a2d5 NC |
193 | (*info->fprintf_func)(info->stream, " R%x, R%x", operandOne, |
194 | operandTwo); | |
195 | } | |
196 | else | |
197 | { | |
198 | (*info->fprintf_func)(info->stream, " unhandled mode %s", | |
199 | opcodePTR->constraints); | |
200 | } | |
201 | break; | |
202 | case XG_R_R_I: | |
203 | (*info->fprintf_func)(info->stream, " R%x, (R%x, #0x%x)", | |
204 | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, raw_code & 0x1f); | |
205 | break; | |
206 | case XG_R: | |
df7b86aa | 207 | operandOne = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, |
f6c1a2d5 NC |
208 | raw_code); |
209 | (*info->fprintf_func)(info->stream, " R%x", operandOne); | |
210 | break; | |
211 | case XG_I | XG_PCREL: | |
df7b86aa | 212 | if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_REL9)) |
f6c1a2d5 | 213 | { |
df7b86aa | 214 | /* If address is negative handle it accordingly. */ |
f6c1a2d5 NC |
215 | if (raw_code & XGATE_NINE_SIGNBIT) |
216 | { | |
df7b86aa NC |
217 | relAddr = XGATE_NINE_BITS >> 1; /* Clip sign bit. */ |
218 | relAddr = ~relAddr; /* Make signed. */ | |
219 | relAddr |= (raw_code & 0xFF) + 1; /* Apply our value. */ | |
220 | relAddr <<= 1; /* Multiply by two as per processor docs. */ | |
f6c1a2d5 NC |
221 | } |
222 | else | |
223 | { | |
224 | relAddr = raw_code & 0xff; | |
225 | relAddr = (relAddr << 1) + 2; | |
226 | } | |
227 | (*info->fprintf_func)(info->stream, " *%d", relAddr); | |
228 | (*info->fprintf_func)(info->stream, " Abs* 0x"); | |
229 | (*info->print_address_func)(memaddr + relAddr, info); | |
230 | } | |
df7b86aa | 231 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_REL10)) |
f6c1a2d5 | 232 | { |
df7b86aa | 233 | /* If address is negative handle it accordingly. */ |
f6c1a2d5 NC |
234 | if (raw_code & XGATE_TEN_SIGNBIT) |
235 | { | |
df7b86aa NC |
236 | relAddr = XGATE_TEN_BITS >> 1; /* Clip sign bit. */ |
237 | relAddr = ~relAddr; /* Make signed. */ | |
238 | relAddr |= (raw_code & 0x1FF) + 1; /* Apply our value. */ | |
239 | relAddr <<= 1; /* Multiply by two as per processor docs. */ | |
f6c1a2d5 NC |
240 | } |
241 | else | |
242 | { | |
243 | relAddr = raw_code & 0x1FF; | |
244 | relAddr = (relAddr << 1) + 2; | |
245 | } | |
246 | (*info->fprintf_func)(info->stream, " *%d", relAddr); | |
247 | (*info->fprintf_func)(info->stream, " Abs* 0x"); | |
248 | (*info->print_address_func)(memaddr + relAddr, info); | |
249 | } | |
250 | else | |
251 | { | |
252 | (*info->fprintf_func)(info->stream, | |
253 | " Can't disassemble for mode) %s", | |
254 | decodePTR->opcodePTR->constraints); | |
255 | } | |
256 | break; | |
257 | case XG_R_I: | |
df7b86aa | 258 | if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM4)) |
f6c1a2d5 NC |
259 | { |
260 | (*info->fprintf_func)(info->stream, " R%x, #0x%02x", | |
261 | (raw_code >> 8) & 0x7, (raw_code >> 4) & 0xF); | |
262 | } | |
df7b86aa | 263 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM8)) |
f6c1a2d5 | 264 | { |
df7b86aa | 265 | if (macro_search (decodePTR->opcodePTR->name, previousOpName) && |
f6c1a2d5 NC |
266 | previousOpName[0]) |
267 | { | |
268 | absAddress = (0xFF & raw_code) << 8; | |
269 | absAddress |= perviousBin & 0xFF; | |
270 | (*info->fprintf_func)(info->stream, " R%x, #0x%02x Abs* 0x", | |
271 | (raw_code >> 8) & 0x7, raw_code & 0xff); | |
272 | (*info->print_address_func)(absAddress, info); | |
273 | previousOpName[0] = 0; | |
274 | } | |
275 | else | |
276 | { | |
df7b86aa | 277 | strcpy (previousOpName, decodePTR->opcodePTR->name); |
f6c1a2d5 NC |
278 | (*info->fprintf_func)(info->stream, " R%x, #0x%02x", |
279 | (raw_code >> 8) & 0x7, raw_code & 0xff); | |
280 | } | |
281 | } | |
282 | else | |
283 | { | |
284 | (*info->fprintf_func)(info->stream, | |
285 | " Can't disassemble for mode %s", | |
286 | decodePTR->opcodePTR->constraints); | |
287 | } | |
288 | break; | |
289 | case XG_I: | |
290 | (*info->fprintf_func)(info->stream, " #0x%x", | |
291 | (raw_code >> 8) & 0x7); | |
292 | break; | |
293 | default: | |
294 | (*info->fprintf_func)(info->stream, "address mode not found\t %x", | |
295 | opcodePTR->bin_opcode); | |
296 | break; | |
297 | } | |
298 | perviousBin = raw_code; | |
299 | } | |
300 | else | |
301 | { | |
302 | (*info->fprintf_func)(info->stream, | |
df7b86aa | 303 | " unable to find opcode match #0%x", raw_code); |
f6c1a2d5 NC |
304 | } |
305 | } | |
306 | return bytesRead; | |
307 | } | |
308 | ||
309 | int | |
310 | print_insn_xgate (bfd_vma memaddr, struct disassemble_info* info) | |
311 | { | |
312 | return print_insn (memaddr, info); | |
313 | } | |
314 | ||
315 | static int | |
316 | read_memory (bfd_vma memaddr, bfd_byte* buffer, int size, | |
317 | struct disassemble_info* info) | |
318 | { | |
319 | int status; | |
320 | status = (*info->read_memory_func) (memaddr, buffer, size, info); | |
321 | if (status != 0) | |
322 | { | |
323 | (*info->memory_error_func) (status, memaddr, info); | |
324 | return -1; | |
325 | } | |
326 | return 0; | |
327 | } | |
328 | ||
329 | static int | |
df7b86aa NC |
330 | ripBits (unsigned int *operandBitsRemaining, |
331 | int numBitsRequested, | |
332 | struct xgate_opcode *opcodePTR, | |
333 | unsigned int memory) | |
f6c1a2d5 NC |
334 | { |
335 | unsigned int currentBit; | |
336 | int operand; | |
337 | int numBitsFound; | |
df7b86aa | 338 | |
f6c1a2d5 | 339 | for (operand = 0, numBitsFound = 0, currentBit = 1 |
df7b86aa NC |
340 | << ((opcodePTR->size * 8) - 1); |
341 | (numBitsFound < numBitsRequested) && currentBit; currentBit >>= 1) | |
f6c1a2d5 | 342 | { |
df7b86aa NC |
343 | if (currentBit & *operandBitsRemaining) |
344 | { | |
345 | *operandBitsRemaining &= ~(currentBit); /* Consume the current bit. */ | |
346 | operand <<= 1; /* Make room for our next bit. */ | |
347 | numBitsFound++; | |
348 | operand |= (currentBit & memory) > 0; | |
349 | } | |
350 | } | |
f6c1a2d5 NC |
351 | return operand; |
352 | } | |
353 | ||
df7b86aa NC |
354 | static int |
355 | macro_search (char *currentName, char *lastName) | |
f6c1a2d5 NC |
356 | { |
357 | int i; | |
358 | int length = 0; | |
359 | char *where; | |
df7b86aa | 360 | |
f6c1a2d5 NC |
361 | for (i = 0; i < xgate_num_opcodes; i++) |
362 | { | |
df7b86aa NC |
363 | where = strstr (xgate_opcodes[i].constraints, lastName); |
364 | ||
f6c1a2d5 NC |
365 | if (where) |
366 | { | |
df7b86aa | 367 | length = strlen (where); |
f6c1a2d5 NC |
368 | } |
369 | if (length) | |
370 | { | |
df7b86aa | 371 | where = strstr (xgate_opcodes[i].constraints, currentName); |
f6c1a2d5 NC |
372 | if (where) |
373 | { | |
df7b86aa | 374 | length = strlen (where); |
f6c1a2d5 NC |
375 | return 1; |
376 | } | |
377 | } | |
378 | } | |
379 | return 0; | |
380 | } | |
381 | ||
df7b86aa NC |
382 | static struct decodeInfo * |
383 | find_match (unsigned int raw_code) | |
f6c1a2d5 NC |
384 | { |
385 | struct decodeInfo *decodeTablePTR = 0; | |
386 | int i; | |
387 | ||
388 | for (i = 0, decodeTablePTR = decodeTable; i < xgate_num_opcodes; | |
389 | i++, decodeTablePTR++) | |
390 | { | |
391 | if ((raw_code & decodeTablePTR->operMask) | |
392 | == decodeTablePTR->opcodePTR->bin_opcode) | |
393 | { | |
df7b86aa | 394 | /* Make sure we didn't run into a macro or alias. */ |
f6c1a2d5 NC |
395 | if (decodeTablePTR->opcodePTR->cycles_min != 0) |
396 | { | |
397 | return decodeTablePTR; | |
398 | break; | |
399 | } | |
400 | else | |
df7b86aa | 401 | continue; |
f6c1a2d5 NC |
402 | } |
403 | } | |
404 | return 0; | |
405 | } |