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