Commit | Line | Data |
---|---|---|
f6c1a2d5 | 1 | /* xgate-dis.c -- Freescale XGATE disassembly |
250d07de | 2 | Copyright (C) 2009-2021 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> |
88c1242d | 24 | #include "disassemble.h" |
f6c1a2d5 NC |
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 | { | |
dee33451 NC |
172 | operandOne = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, raw_code); |
173 | operandTwo = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, raw_code); | |
0e1c2434 SK |
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. */ | |
7ef412cf | 196 | relAddr *= 2; /* Multiply by two as per processor docs. */ |
f6c1a2d5 NC |
197 | } |
198 | else | |
199 | { | |
200 | relAddr = raw_code & 0xff; | |
7ef412cf | 201 | relAddr = relAddr * 2 + 2; |
f6c1a2d5 | 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. */ | |
7ef412cf | 215 | relAddr *= 2; /* Multiply by two as per processor docs. */ |
f6c1a2d5 NC |
216 | } |
217 | else | |
218 | { | |
219 | relAddr = raw_code & 0x1FF; | |
7ef412cf | 220 | relAddr = relAddr * 2 + 2; |
f6c1a2d5 NC |
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 | { | |
0e1c2434 | 257 | } |
f6c1a2d5 NC |
258 | else |
259 | { | |
0e1c2434 | 260 | (*info->fprintf_func)(info->stream, " unhandled mode %s", |
dee33451 | 261 | decodePTR->opcodePTR->constraints); |
f6c1a2d5 | 262 | } |
f6c1a2d5 NC |
263 | perviousBin = raw_code; |
264 | } | |
265 | else | |
266 | { | |
267 | (*info->fprintf_func)(info->stream, | |
df7b86aa | 268 | " unable to find opcode match #0%x", raw_code); |
f6c1a2d5 NC |
269 | } |
270 | } | |
271 | return bytesRead; | |
272 | } | |
273 | ||
274 | int | |
275 | print_insn_xgate (bfd_vma memaddr, struct disassemble_info* info) | |
276 | { | |
277 | return print_insn (memaddr, info); | |
278 | } | |
279 | ||
280 | static int | |
281 | read_memory (bfd_vma memaddr, bfd_byte* buffer, int size, | |
282 | struct disassemble_info* info) | |
283 | { | |
284 | int status; | |
285 | status = (*info->read_memory_func) (memaddr, buffer, size, info); | |
286 | if (status != 0) | |
287 | { | |
288 | (*info->memory_error_func) (status, memaddr, info); | |
289 | return -1; | |
290 | } | |
291 | return 0; | |
292 | } | |
293 | ||
294 | static int | |
df7b86aa NC |
295 | ripBits (unsigned int *operandBitsRemaining, |
296 | int numBitsRequested, | |
297 | struct xgate_opcode *opcodePTR, | |
298 | unsigned int memory) | |
f6c1a2d5 NC |
299 | { |
300 | unsigned int currentBit; | |
7ef412cf | 301 | unsigned int operand = 0; |
f6c1a2d5 | 302 | int numBitsFound; |
df7b86aa | 303 | |
7ef412cf AM |
304 | for (numBitsFound = 0, currentBit = 1u << ((opcodePTR->size * 8) - 1); |
305 | numBitsFound < numBitsRequested && currentBit != 0; | |
306 | currentBit >>= 1) | |
f6c1a2d5 | 307 | { |
df7b86aa NC |
308 | if (currentBit & *operandBitsRemaining) |
309 | { | |
310 | *operandBitsRemaining &= ~(currentBit); /* Consume the current bit. */ | |
311 | operand <<= 1; /* Make room for our next bit. */ | |
312 | numBitsFound++; | |
313 | operand |= (currentBit & memory) > 0; | |
314 | } | |
315 | } | |
f6c1a2d5 NC |
316 | return operand; |
317 | } | |
318 | ||
df7b86aa NC |
319 | static int |
320 | macro_search (char *currentName, char *lastName) | |
f6c1a2d5 NC |
321 | { |
322 | int i; | |
323 | int length = 0; | |
324 | char *where; | |
df7b86aa | 325 | |
f6c1a2d5 NC |
326 | for (i = 0; i < xgate_num_opcodes; i++) |
327 | { | |
df7b86aa NC |
328 | where = strstr (xgate_opcodes[i].constraints, lastName); |
329 | ||
f6c1a2d5 NC |
330 | if (where) |
331 | { | |
df7b86aa | 332 | length = strlen (where); |
f6c1a2d5 NC |
333 | } |
334 | if (length) | |
335 | { | |
df7b86aa | 336 | where = strstr (xgate_opcodes[i].constraints, currentName); |
f6c1a2d5 NC |
337 | if (where) |
338 | { | |
df7b86aa | 339 | length = strlen (where); |
f6c1a2d5 NC |
340 | return 1; |
341 | } | |
342 | } | |
343 | } | |
344 | return 0; | |
345 | } | |
346 | ||
df7b86aa NC |
347 | static struct decodeInfo * |
348 | find_match (unsigned int raw_code) | |
f6c1a2d5 NC |
349 | { |
350 | struct decodeInfo *decodeTablePTR = 0; | |
351 | int i; | |
352 | ||
353 | for (i = 0, decodeTablePTR = decodeTable; i < xgate_num_opcodes; | |
354 | i++, decodeTablePTR++) | |
355 | { | |
356 | if ((raw_code & decodeTablePTR->operMask) | |
357 | == decodeTablePTR->opcodePTR->bin_opcode) | |
358 | { | |
df7b86aa | 359 | /* Make sure we didn't run into a macro or alias. */ |
f6c1a2d5 NC |
360 | if (decodeTablePTR->opcodePTR->cycles_min != 0) |
361 | { | |
362 | return decodeTablePTR; | |
363 | break; | |
364 | } | |
365 | else | |
df7b86aa | 366 | continue; |
f6c1a2d5 NC |
367 | } |
368 | } | |
369 | return 0; | |
370 | } |