Commit | Line | Data |
---|---|---|
886a2506 | 1 | /* ARC target-dependent stuff. Extension structure access functions |
6f2750fe | 2 | Copyright (C) 1995-2016 Free Software Foundation, Inc. |
0d2bcfaf | 3 | |
9b201bb5 | 4 | This file is part of libopcodes. |
0d2bcfaf | 5 | |
9b201bb5 | 6 | This library is free software; you can redistribute it and/or modify |
0d2bcfaf | 7 | it under the terms of the GNU General Public License as published by |
9b201bb5 NC |
8 | the Free Software Foundation; either version 3, or (at your option) |
9 | any later version. | |
0d2bcfaf | 10 | |
9b201bb5 NC |
11 | It is distributed in the hope that it will be useful, but WITHOUT |
12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
14 | License for more details. | |
0d2bcfaf NC |
15 | |
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; if not, write to the Free Software | |
9b201bb5 NC |
18 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
19 | MA 02110-1301, USA. */ | |
0d2bcfaf | 20 | |
5bd67f35 | 21 | #include "sysdep.h" |
0d2bcfaf NC |
22 | #include <stdlib.h> |
23 | #include <stdio.h> | |
886a2506 | 24 | |
0d2bcfaf NC |
25 | #include "bfd.h" |
26 | #include "arc-ext.h" | |
886a2506 | 27 | #include "elf/arc.h" |
0d2bcfaf NC |
28 | #include "libiberty.h" |
29 | ||
0d2bcfaf | 30 | |
886a2506 NC |
31 | /* This module provides support for extensions to the ARC processor |
32 | architecture. */ | |
0d2bcfaf | 33 | |
0d2bcfaf | 34 | |
886a2506 | 35 | /* Local constants. */ |
0d2bcfaf | 36 | |
886a2506 NC |
37 | #define FIRST_EXTENSION_CORE_REGISTER 32 |
38 | #define LAST_EXTENSION_CORE_REGISTER 59 | |
39 | #define FIRST_EXTENSION_CONDITION_CODE 0x10 | |
40 | #define LAST_EXTENSION_CONDITION_CODE 0x1f | |
0d2bcfaf | 41 | |
886a2506 NC |
42 | #define NUM_EXT_CORE \ |
43 | (LAST_EXTENSION_CORE_REGISTER - FIRST_EXTENSION_CORE_REGISTER + 1) | |
44 | #define NUM_EXT_COND \ | |
45 | (LAST_EXTENSION_CONDITION_CODE - FIRST_EXTENSION_CONDITION_CODE + 1) | |
46 | #define INST_HASH_BITS 6 | |
47 | #define INST_HASH_SIZE (1 << INST_HASH_BITS) | |
48 | #define INST_HASH_MASK (INST_HASH_SIZE - 1) | |
0d2bcfaf | 49 | |
0d2bcfaf | 50 | |
886a2506 | 51 | /* Local types. */ |
0d2bcfaf | 52 | |
886a2506 | 53 | /* These types define the information stored in the table. */ |
0d2bcfaf | 54 | |
886a2506 NC |
55 | struct ExtInstruction |
56 | { | |
57 | char major; | |
58 | char minor; | |
59 | char flags; | |
60 | char* name; | |
61 | struct ExtInstruction* next; | |
62 | }; | |
63 | ||
64 | struct ExtAuxRegister | |
65 | { | |
66 | long address; | |
67 | char* name; | |
68 | struct ExtAuxRegister* next; | |
69 | }; | |
0d2bcfaf | 70 | |
886a2506 NC |
71 | struct ExtCoreRegister |
72 | { | |
73 | short number; | |
74 | enum ExtReadWrite rw; | |
75 | char* name; | |
76 | }; | |
0d2bcfaf | 77 | |
886a2506 | 78 | struct arcExtMap |
0d2bcfaf | 79 | { |
886a2506 NC |
80 | struct ExtAuxRegister* auxRegisters; |
81 | struct ExtInstruction* instructions[INST_HASH_SIZE]; | |
82 | struct ExtCoreRegister coreRegisters[NUM_EXT_CORE]; | |
83 | char* condCodes[NUM_EXT_COND]; | |
84 | }; | |
5bd67f35 | 85 | |
0d2bcfaf | 86 | |
886a2506 | 87 | /* Local data. */ |
0d2bcfaf | 88 | |
886a2506 NC |
89 | /* Extension table. */ |
90 | static struct arcExtMap arc_extension_map; | |
5bd67f35 | 91 | |
5bd67f35 | 92 | |
886a2506 | 93 | /* Local macros. */ |
5bd67f35 | 94 | |
886a2506 NC |
95 | /* A hash function used to map instructions into the table. */ |
96 | #define INST_HASH(MAJOR, MINOR) ((((MAJOR) << 3) ^ (MINOR)) & INST_HASH_MASK) | |
5bd67f35 | 97 | |
0d2bcfaf | 98 | |
886a2506 | 99 | /* Local functions. */ |
5bd67f35 | 100 | |
886a2506 NC |
101 | static void |
102 | create_map (unsigned char *block, | |
103 | unsigned long length) | |
104 | { | |
105 | unsigned char *p = block; | |
0d2bcfaf | 106 | |
5bd67f35 | 107 | while (p && p < (block + length)) |
0d2bcfaf NC |
108 | { |
109 | /* p[0] == length of record | |
110 | p[1] == type of record | |
111 | For instructions: | |
112 | p[2] = opcode | |
113 | p[3] = minor opcode (if opcode == 3) | |
114 | p[4] = flags | |
115 | p[5]+ = name | |
116 | For core regs and condition codes: | |
117 | p[2] = value | |
118 | p[3]+ = name | |
886a2506 | 119 | For auxiliary regs: |
0d2bcfaf NC |
120 | p[2..5] = value |
121 | p[6]+ = name | |
886a2506 | 122 | (value is p[2]<<24|p[3]<<16|p[4]<<8|p[5]). */ |
0d2bcfaf | 123 | |
886a2506 NC |
124 | /* The sequence of records is temrinated by an "empty" |
125 | record. */ | |
0d2bcfaf | 126 | if (p[0] == 0) |
886a2506 | 127 | break; |
5bd67f35 | 128 | |
0d2bcfaf NC |
129 | switch (p[1]) |
130 | { | |
131 | case EXT_INSTRUCTION: | |
132 | { | |
886a2506 NC |
133 | struct ExtInstruction *insn = XNEW (struct ExtInstruction); |
134 | int major = p[2]; | |
135 | int minor = p[3]; | |
136 | struct ExtInstruction **bucket = | |
137 | &arc_extension_map.instructions[INST_HASH (major, minor)]; | |
138 | ||
139 | insn->name = xstrdup ((char *) (p + 5)); | |
140 | insn->major = major; | |
141 | insn->minor = minor; | |
142 | insn->flags = p[4]; | |
143 | insn->next = *bucket; | |
144 | *bucket = insn; | |
145 | break; | |
0d2bcfaf | 146 | } |
5bd67f35 AJ |
147 | |
148 | case EXT_CORE_REGISTER: | |
0d2bcfaf | 149 | { |
886a2506 NC |
150 | unsigned char number = p[2]; |
151 | char* name = (char *) (p + 3); | |
152 | ||
153 | arc_extension_map. | |
154 | coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].number | |
155 | = number; | |
156 | arc_extension_map. | |
157 | coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].rw | |
158 | = REG_READWRITE; | |
159 | arc_extension_map. | |
160 | coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].name | |
161 | = xstrdup (name); | |
162 | break; | |
163 | } | |
0d2bcfaf | 164 | |
886a2506 NC |
165 | case EXT_LONG_CORE_REGISTER: |
166 | { | |
167 | unsigned char number = p[2]; | |
168 | char* name = (char *) (p + 7); | |
169 | enum ExtReadWrite rw = p[6]; | |
170 | ||
171 | arc_extension_map. | |
172 | coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].number | |
173 | = number; | |
174 | arc_extension_map. | |
175 | coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].rw | |
176 | = rw; | |
177 | arc_extension_map. | |
178 | coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].name | |
179 | = xstrdup (name); | |
0d2bcfaf | 180 | } |
5bd67f35 AJ |
181 | |
182 | case EXT_COND_CODE: | |
0d2bcfaf | 183 | { |
886a2506 NC |
184 | char *cc_name = xstrdup ((char *) (p + 3)); |
185 | ||
186 | arc_extension_map. | |
187 | condCodes[p[2] - FIRST_EXTENSION_CONDITION_CODE] | |
188 | = cc_name; | |
189 | break; | |
5bd67f35 | 190 | } |
5bd67f35 AJ |
191 | |
192 | case EXT_AUX_REGISTER: | |
0d2bcfaf | 193 | { |
886a2506 NC |
194 | /* Trickier -- need to store linked list of these. */ |
195 | struct ExtAuxRegister *newAuxRegister | |
196 | = XNEW (struct ExtAuxRegister); | |
197 | char *aux_name = xstrdup ((char *) (p + 6)); | |
0d2bcfaf | 198 | |
0d2bcfaf | 199 | newAuxRegister->name = aux_name; |
886a2506 NC |
200 | newAuxRegister->address = (p[2] << 24) | (p[3] << 16) |
201 | | (p[4] << 8) | p[5]; | |
0d2bcfaf NC |
202 | newAuxRegister->next = arc_extension_map.auxRegisters; |
203 | arc_extension_map.auxRegisters = newAuxRegister; | |
886a2506 | 204 | break; |
0d2bcfaf | 205 | } |
5bd67f35 | 206 | |
0d2bcfaf | 207 | default: |
886a2506 NC |
208 | break; |
209 | } | |
210 | ||
211 | p += p[0]; /* Move on to next record. */ | |
212 | } | |
213 | } | |
214 | ||
215 | ||
216 | /* Free memory that has been allocated for the extensions. */ | |
217 | ||
218 | static void | |
219 | destroy_map (void) | |
220 | { | |
221 | struct ExtAuxRegister *r; | |
222 | unsigned int i; | |
223 | ||
224 | /* Free auxiliary registers. */ | |
225 | r = arc_extension_map.auxRegisters; | |
226 | while (r) | |
227 | { | |
228 | /* N.B. after r has been freed, r->next is invalid! */ | |
229 | struct ExtAuxRegister* next = r->next; | |
230 | ||
231 | free (r->name); | |
232 | free (r); | |
233 | r = next; | |
234 | } | |
235 | ||
236 | /* Free instructions. */ | |
237 | for (i = 0; i < INST_HASH_SIZE; i++) | |
238 | { | |
239 | struct ExtInstruction *insn = arc_extension_map.instructions[i]; | |
240 | ||
241 | while (insn) | |
242 | { | |
243 | /* N.B. after insn has been freed, insn->next is invalid! */ | |
244 | struct ExtInstruction *next = insn->next; | |
245 | ||
246 | free (insn->name); | |
247 | free (insn); | |
248 | insn = next; | |
249 | } | |
250 | } | |
251 | ||
252 | /* Free core registers. */ | |
253 | for (i = 0; i < NUM_EXT_CORE; i++) | |
254 | { | |
255 | if (arc_extension_map.coreRegisters[i].name) | |
256 | free (arc_extension_map.coreRegisters[i].name); | |
257 | } | |
5bd67f35 | 258 | |
886a2506 NC |
259 | /* Free condition codes. */ |
260 | for (i = 0; i < NUM_EXT_COND; i++) | |
261 | { | |
262 | if (arc_extension_map.condCodes[i]) | |
263 | free (arc_extension_map.condCodes[i]); | |
264 | } | |
265 | ||
266 | memset (&arc_extension_map, 0, sizeof (arc_extension_map)); | |
267 | } | |
268 | ||
269 | ||
270 | static const char * | |
271 | ExtReadWrite_image (enum ExtReadWrite val) | |
272 | { | |
273 | switch (val) | |
274 | { | |
275 | case REG_INVALID : return "INVALID"; | |
276 | case REG_READ : return "RO"; | |
277 | case REG_WRITE : return "WO"; | |
278 | case REG_READWRITE: return "R/W"; | |
279 | default : return "???"; | |
280 | } | |
281 | } | |
282 | ||
283 | ||
284 | /* Externally visible functions. */ | |
285 | ||
286 | /* Get the name of an extension instruction. */ | |
287 | ||
288 | const char * | |
289 | arcExtMap_instName (int opcode, | |
290 | int insn, | |
291 | int *flags) | |
292 | { | |
293 | /* Here the following tasks need to be done. First of all, the | |
294 | opcode stored in the Extension Map is the real opcode. However, | |
295 | the subopcode stored in the instruction to be disassembled is | |
296 | mangled. We pass (in minor opcode), the instruction word. Here | |
297 | we will un-mangle it and get the real subopcode which we can look | |
298 | for in the Extension Map. This function is used both for the | |
299 | ARCTangent and the ARCompact, so we would also need some sort of | |
300 | a way to distinguish between the two architectures. This is | |
301 | because the ARCTangent does not do any of this mangling so we | |
302 | have no issues there. */ | |
303 | ||
304 | /* If P[22:23] is 0 or 2 then un-mangle using iiiiiI. If it is 1 | |
305 | then use iiiiIi. Now, if P is 3 then check M[5:5] and if it is 0 | |
306 | then un-mangle using iiiiiI else iiiiii. */ | |
307 | ||
308 | unsigned char minor; | |
309 | struct ExtInstruction *temp; | |
310 | ||
311 | /* 16-bit instructions. */ | |
312 | if (0x08 <= opcode && opcode <= 0x0b) | |
313 | { | |
314 | unsigned char b, c, i; | |
315 | ||
316 | b = (insn & 0x0700) >> 8; | |
317 | c = (insn & 0x00e0) >> 5; | |
318 | i = (insn & 0x001f); | |
319 | ||
320 | if (i) | |
321 | minor = i; | |
322 | else | |
323 | minor = (c == 0x07) ? b : c; | |
324 | } | |
325 | /* 32-bit instructions. */ | |
326 | else | |
327 | { | |
328 | unsigned char I, A, B; | |
329 | ||
330 | I = (insn & 0x003f0000) >> 16; | |
331 | A = (insn & 0x0000003f); | |
332 | B = ((insn & 0x07000000) >> 24) | ((insn & 0x00007000) >> 9); | |
333 | ||
334 | if (I != 0x2f) | |
335 | { | |
336 | #ifndef UNMANGLED | |
337 | switch (P) | |
338 | { | |
339 | case 3: | |
340 | if (M) | |
341 | { | |
342 | minor = I; | |
343 | break; | |
344 | } | |
345 | case 0: | |
346 | case 2: | |
347 | minor = (I >> 1) | ((I & 0x1) << 5); | |
348 | break; | |
349 | case 1: | |
350 | minor = (I >> 1) | (I & 0x1) | ((I & 0x2) << 4); | |
351 | } | |
352 | #else | |
353 | minor = I; | |
354 | #endif | |
355 | } | |
356 | else | |
357 | { | |
358 | if (A != 0x3f) | |
359 | minor = A; | |
360 | else | |
361 | minor = B; | |
362 | } | |
363 | } | |
364 | ||
365 | temp = arc_extension_map.instructions[INST_HASH (opcode, minor)]; | |
366 | while (temp) | |
367 | { | |
368 | if ((temp->major == opcode) && (temp->minor == minor)) | |
369 | { | |
370 | *flags = temp->flags; | |
371 | return temp->name; | |
0d2bcfaf | 372 | } |
886a2506 | 373 | temp = temp->next; |
0d2bcfaf | 374 | } |
5bd67f35 | 375 | |
886a2506 | 376 | return NULL; |
0d2bcfaf NC |
377 | } |
378 | ||
886a2506 | 379 | /* Get the name of an extension core register. */ |
0d2bcfaf | 380 | |
886a2506 NC |
381 | const char * |
382 | arcExtMap_coreRegName (int regnum) | |
383 | { | |
384 | if (regnum < FIRST_EXTENSION_CORE_REGISTER | |
385 | || regnum > LAST_EXTENSION_CONDITION_CODE) | |
386 | return NULL; | |
387 | return arc_extension_map. | |
388 | coreRegisters[regnum - FIRST_EXTENSION_CORE_REGISTER].name; | |
389 | } | |
390 | ||
391 | /* Get the access mode of an extension core register. */ | |
392 | ||
393 | enum ExtReadWrite | |
394 | arcExtMap_coreReadWrite (int regnum) | |
0d2bcfaf | 395 | { |
886a2506 NC |
396 | if (regnum < FIRST_EXTENSION_CORE_REGISTER |
397 | || regnum > LAST_EXTENSION_CONDITION_CODE) | |
398 | return REG_INVALID; | |
399 | return arc_extension_map. | |
400 | coreRegisters[regnum - FIRST_EXTENSION_CORE_REGISTER].rw; | |
401 | } | |
402 | ||
403 | /* Get the name of an extension condition code. */ | |
404 | ||
405 | const char * | |
406 | arcExtMap_condCodeName (int code) | |
407 | { | |
408 | if (code < FIRST_EXTENSION_CONDITION_CODE | |
409 | || code > LAST_EXTENSION_CONDITION_CODE) | |
410 | return NULL; | |
411 | return arc_extension_map. | |
412 | condCodes[code - FIRST_EXTENSION_CONDITION_CODE]; | |
413 | } | |
414 | ||
415 | /* Get the name of an extension auxiliary register. */ | |
416 | ||
417 | const char * | |
418 | arcExtMap_auxRegName (long address) | |
419 | { | |
420 | /* Walk the list of auxiliary register names and find the name. */ | |
421 | struct ExtAuxRegister *r; | |
422 | ||
423 | for (r = arc_extension_map.auxRegisters; r; r = r->next) | |
424 | { | |
425 | if (r->address == address) | |
426 | return (const char *)r->name; | |
427 | } | |
428 | return NULL; | |
429 | } | |
430 | ||
431 | /* Load extensions described in .arcextmap and | |
432 | .gnu.linkonce.arcextmap.* ELF section. */ | |
0d2bcfaf | 433 | |
886a2506 NC |
434 | void |
435 | build_ARC_extmap (bfd *text_bfd) | |
436 | { | |
437 | asection *sect; | |
438 | ||
439 | /* The map is built each time gdb loads an executable file - so free | |
440 | any existing map, as the map defined by the new file may differ | |
441 | from the old. */ | |
442 | destroy_map (); | |
443 | ||
444 | for (sect = text_bfd->sections; sect != NULL; sect = sect->next) | |
445 | if (!strncmp (sect->name, | |
446 | ".gnu.linkonce.arcextmap.", | |
447 | sizeof (".gnu.linkonce.arcextmap.") - 1) | |
448 | || !strcmp (sect->name,".arcextmap")) | |
0d2bcfaf | 449 | { |
886a2506 NC |
450 | bfd_size_type count = bfd_get_section_size (sect); |
451 | unsigned char* buffer = xmalloc (count); | |
452 | ||
453 | if (buffer) | |
454 | { | |
455 | if (bfd_get_section_contents (text_bfd, sect, buffer, 0, count)) | |
456 | create_map (buffer, count); | |
457 | free (buffer); | |
458 | } | |
0d2bcfaf NC |
459 | } |
460 | } | |
886a2506 NC |
461 | |
462 | ||
463 | void | |
464 | dump_ARC_extmap (void) | |
465 | { | |
466 | struct ExtAuxRegister *r; | |
467 | int i; | |
468 | ||
469 | r = arc_extension_map.auxRegisters; | |
470 | ||
471 | while (r) | |
472 | { | |
473 | printf ("AUX : %s %ld\n", r->name, r->address); | |
474 | r = r->next; | |
475 | } | |
476 | ||
477 | for (i = 0; i < INST_HASH_SIZE; i++) | |
478 | { | |
479 | struct ExtInstruction *insn; | |
480 | ||
481 | for (insn = arc_extension_map.instructions[i]; | |
482 | insn != NULL; insn = insn->next) | |
483 | printf ("INST: %d %d %x %s\n", insn->major, insn->minor, | |
484 | insn->flags, insn->name); | |
485 | } | |
486 | ||
487 | for (i = 0; i < NUM_EXT_CORE; i++) | |
488 | { | |
489 | struct ExtCoreRegister reg = arc_extension_map.coreRegisters[i]; | |
490 | ||
491 | if (reg.name) | |
492 | printf ("CORE: %s %d %s\n", reg.name, reg.number, | |
493 | ExtReadWrite_image (reg.rw)); | |
494 | } | |
495 | ||
496 | for (i = 0; i < NUM_EXT_COND; i++) | |
497 | if (arc_extension_map.condCodes[i]) | |
498 | printf ("COND: %s\n", arc_extension_map.condCodes[i]); | |
499 | } |