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 |
0e1c2434 SK |
127 | still are unable to pinpoint the operands |
128 | we analyze the opcodes constraint string. */ | |
129 | if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON_R_C)) | |
130 | { | |
131 | (*info->fprintf_func)(info->stream, " R%x, CCR", | |
132 | (raw_code >> 8) & 0x7); | |
133 | } | |
134 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON_C_R)) | |
135 | { | |
136 | (*info->fprintf_func)(info->stream, " CCR, R%x", | |
137 | (raw_code >> 8) & 0x7); | |
138 | } | |
139 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON_R_P)) | |
140 | { | |
141 | (*info->fprintf_func)(info->stream, " R%x, PC", | |
142 | (raw_code >> 8) & 0x7); | |
143 | } | |
144 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_TRI)) | |
145 | { | |
146 | (*info->fprintf_func)(info->stream, " R%x, R%x, R%x", | |
147 | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | |
148 | (raw_code >> 2) & 0x7); | |
149 | } | |
150 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IDR)) | |
151 | { | |
152 | if (raw_code & 0x01) | |
153 | { | |
154 | (*info->fprintf_func)(info->stream, " R%x, (R%x, R%x+)", | |
155 | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | |
156 | (raw_code >> 2) & 0x7); | |
157 | } | |
158 | else if (raw_code & 0x02) | |
159 | { | |
160 | (*info->fprintf_func)(info->stream, " R%x, (R%x, -R%x)", | |
161 | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | |
162 | (raw_code >> 2) & 0x7); | |
163 | } | |
164 | else | |
165 | { | |
166 | (*info->fprintf_func)(info->stream, " R%x, (R%x, R%x)", | |
167 | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | |
168 | (raw_code >> 2) & 0x7); | |
169 | } | |
170 | } | |
171 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_DYA)) | |
172 | { | |
173 | operandOne = ripBits (&operMaskReg, 3, opcodePTR, raw_code); | |
174 | operandTwo = ripBits (&operMaskReg, 3, opcodePTR, raw_code); | |
175 | ( *info->fprintf_func)(info->stream, " R%x, R%x", operandOne, | |
176 | operandTwo); | |
177 | } | |
178 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IDO5)) | |
179 | { | |
180 | (*info->fprintf_func)(info->stream, " R%x, (R%x, #0x%x)", | |
181 | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, raw_code & 0x1f); | |
182 | } | |
183 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON)) | |
184 | { | |
185 | operandOne = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, | |
186 | raw_code); | |
187 | (*info->fprintf_func)(info->stream, " R%x", operandOne); | |
188 | } | |
189 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_REL9)) | |
f6c1a2d5 | 190 | { |
df7b86aa | 191 | /* If address is negative handle it accordingly. */ |
f6c1a2d5 NC |
192 | if (raw_code & XGATE_NINE_SIGNBIT) |
193 | { | |
df7b86aa NC |
194 | relAddr = XGATE_NINE_BITS >> 1; /* Clip sign bit. */ |
195 | relAddr = ~relAddr; /* Make signed. */ | |
196 | relAddr |= (raw_code & 0xFF) + 1; /* Apply our value. */ | |
197 | relAddr <<= 1; /* Multiply by two as per processor docs. */ | |
f6c1a2d5 NC |
198 | } |
199 | else | |
200 | { | |
201 | relAddr = raw_code & 0xff; | |
202 | relAddr = (relAddr << 1) + 2; | |
203 | } | |
0e1c2434 SK |
204 | (*info->fprintf_func)(info->stream, " *%d", relAddr); |
205 | (*info->fprintf_func)(info->stream, " Abs* 0x"); | |
206 | (*info->print_address_func)(memaddr + relAddr, info); | |
207 | } | |
df7b86aa | 208 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_REL10)) |
f6c1a2d5 | 209 | { |
df7b86aa | 210 | /* If address is negative handle it accordingly. */ |
f6c1a2d5 NC |
211 | if (raw_code & XGATE_TEN_SIGNBIT) |
212 | { | |
df7b86aa NC |
213 | relAddr = XGATE_TEN_BITS >> 1; /* Clip sign bit. */ |
214 | relAddr = ~relAddr; /* Make signed. */ | |
215 | relAddr |= (raw_code & 0x1FF) + 1; /* Apply our value. */ | |
216 | relAddr <<= 1; /* Multiply by two as per processor docs. */ | |
f6c1a2d5 NC |
217 | } |
218 | else | |
219 | { | |
220 | relAddr = raw_code & 0x1FF; | |
221 | relAddr = (relAddr << 1) + 2; | |
222 | } | |
223 | (*info->fprintf_func)(info->stream, " *%d", relAddr); | |
224 | (*info->fprintf_func)(info->stream, " Abs* 0x"); | |
225 | (*info->print_address_func)(memaddr + relAddr, info); | |
226 | } | |
0e1c2434 SK |
227 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM4)) |
228 | { | |
229 | (*info->fprintf_func)(info->stream, " R%x, #0x%02x", | |
230 | (raw_code >> 8) & 0x7, (raw_code >> 4) & 0xF); | |
231 | } | |
232 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM8)) | |
233 | { | |
234 | if (macro_search (decodePTR->opcodePTR->name, previousOpName) && | |
235 | previousOpName[0]) | |
236 | { | |
237 | absAddress = (0xFF & raw_code) << 8; | |
238 | absAddress |= perviousBin & 0xFF; | |
239 | (*info->fprintf_func)(info->stream, " R%x, #0x%02x Abs* 0x", | |
240 | (raw_code >> 8) & 0x7, raw_code & 0xff); | |
241 | (*info->print_address_func)(absAddress, info); | |
242 | previousOpName[0] = 0; | |
243 | } | |
244 | else | |
245 | { | |
246 | strcpy (previousOpName, decodePTR->opcodePTR->name); | |
247 | (*info->fprintf_func)(info->stream, " R%x, #0x%02x", | |
248 | (raw_code >> 8) & 0x7, raw_code & 0xff); | |
249 | } | |
250 | } | |
251 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM3)) | |
252 | { | |
253 | (*info->fprintf_func)(info->stream, " #0x%x", | |
254 | (raw_code >> 8) & 0x7); | |
255 | } | |
256 | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_INH)) | |
257 | { | |
258 | // | |
259 | } | |
f6c1a2d5 NC |
260 | else |
261 | { | |
0e1c2434 SK |
262 | (*info->fprintf_func)(info->stream, " unhandled mode %s", |
263 | opcodePTR->constraints); | |
f6c1a2d5 | 264 | } |
f6c1a2d5 NC |
265 | perviousBin = raw_code; |
266 | } | |
267 | else | |
268 | { | |
269 | (*info->fprintf_func)(info->stream, | |
df7b86aa | 270 | " unable to find opcode match #0%x", raw_code); |
f6c1a2d5 NC |
271 | } |
272 | } | |
273 | return bytesRead; | |
274 | } | |
275 | ||
276 | int | |
277 | print_insn_xgate (bfd_vma memaddr, struct disassemble_info* info) | |
278 | { | |
279 | return print_insn (memaddr, info); | |
280 | } | |
281 | ||
282 | static int | |
283 | read_memory (bfd_vma memaddr, bfd_byte* buffer, int size, | |
284 | struct disassemble_info* info) | |
285 | { | |
286 | int status; | |
287 | status = (*info->read_memory_func) (memaddr, buffer, size, info); | |
288 | if (status != 0) | |
289 | { | |
290 | (*info->memory_error_func) (status, memaddr, info); | |
291 | return -1; | |
292 | } | |
293 | return 0; | |
294 | } | |
295 | ||
296 | static int | |
df7b86aa NC |
297 | ripBits (unsigned int *operandBitsRemaining, |
298 | int numBitsRequested, | |
299 | struct xgate_opcode *opcodePTR, | |
300 | unsigned int memory) | |
f6c1a2d5 NC |
301 | { |
302 | unsigned int currentBit; | |
303 | int operand; | |
304 | int numBitsFound; | |
df7b86aa | 305 | |
f6c1a2d5 | 306 | for (operand = 0, numBitsFound = 0, currentBit = 1 |
df7b86aa NC |
307 | << ((opcodePTR->size * 8) - 1); |
308 | (numBitsFound < numBitsRequested) && currentBit; currentBit >>= 1) | |
f6c1a2d5 | 309 | { |
df7b86aa NC |
310 | if (currentBit & *operandBitsRemaining) |
311 | { | |
312 | *operandBitsRemaining &= ~(currentBit); /* Consume the current bit. */ | |
313 | operand <<= 1; /* Make room for our next bit. */ | |
314 | numBitsFound++; | |
315 | operand |= (currentBit & memory) > 0; | |
316 | } | |
317 | } | |
f6c1a2d5 NC |
318 | return operand; |
319 | } | |
320 | ||
df7b86aa NC |
321 | static int |
322 | macro_search (char *currentName, char *lastName) | |
f6c1a2d5 NC |
323 | { |
324 | int i; | |
325 | int length = 0; | |
326 | char *where; | |
df7b86aa | 327 | |
f6c1a2d5 NC |
328 | for (i = 0; i < xgate_num_opcodes; i++) |
329 | { | |
df7b86aa NC |
330 | where = strstr (xgate_opcodes[i].constraints, lastName); |
331 | ||
f6c1a2d5 NC |
332 | if (where) |
333 | { | |
df7b86aa | 334 | length = strlen (where); |
f6c1a2d5 NC |
335 | } |
336 | if (length) | |
337 | { | |
df7b86aa | 338 | where = strstr (xgate_opcodes[i].constraints, currentName); |
f6c1a2d5 NC |
339 | if (where) |
340 | { | |
df7b86aa | 341 | length = strlen (where); |
f6c1a2d5 NC |
342 | return 1; |
343 | } | |
344 | } | |
345 | } | |
346 | return 0; | |
347 | } | |
348 | ||
df7b86aa NC |
349 | static struct decodeInfo * |
350 | find_match (unsigned int raw_code) | |
f6c1a2d5 NC |
351 | { |
352 | struct decodeInfo *decodeTablePTR = 0; | |
353 | int i; | |
354 | ||
355 | for (i = 0, decodeTablePTR = decodeTable; i < xgate_num_opcodes; | |
356 | i++, decodeTablePTR++) | |
357 | { | |
358 | if ((raw_code & decodeTablePTR->operMask) | |
359 | == decodeTablePTR->opcodePTR->bin_opcode) | |
360 | { | |
df7b86aa | 361 | /* Make sure we didn't run into a macro or alias. */ |
f6c1a2d5 NC |
362 | if (decodeTablePTR->opcodePTR->cycles_min != 0) |
363 | { | |
364 | return decodeTablePTR; | |
365 | break; | |
366 | } | |
367 | else | |
df7b86aa | 368 | continue; |
f6c1a2d5 NC |
369 | } |
370 | } | |
371 | return 0; | |
372 | } |