source: trunk/src/binutils/opcodes/ia64-opc.c@ 462

Last change on this file since 462 was 10, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 17.6 KB
Line 
1/* ia64-opc.c -- Functions to access the compacted opcode table
2 Copyright 1999, 2000 Free Software Foundation, Inc.
3 Written by Bob Manson of Cygnus Solutions, <manson@cygnus.com>
4
5 This file is part of GDB, GAS, and the GNU binutils.
6
7 GDB, GAS, and the GNU binutils are free software; you can redistribute
8 them and/or modify them under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either version
10 2, or (at your option) any later version.
11
12 GDB, GAS, and the GNU binutils are distributed in the hope that they
13 will be useful, but WITHOUT ANY WARRANTY; without even the implied
14 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this file; see the file COPYING. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA. */
21
22#include "ansidecl.h"
23#include "libiberty.h"
24#include "sysdep.h"
25#include "ia64-asmtab.h"
26#include "ia64-asmtab.c"
27
28const struct ia64_templ_desc ia64_templ_desc[16] =
29 {
30 { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" }, /* 0 */
31 { 2, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_I }, "MII" },
32 { 0, { IA64_UNIT_M, IA64_UNIT_L, IA64_UNIT_X }, "MLX" },
33 { 0, { 0, }, "-3-" },
34 { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" }, /* 4 */
35 { 1, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_I }, "MMI" },
36 { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_I }, "MFI" },
37 { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_F }, "MMF" },
38 { 0, { IA64_UNIT_M, IA64_UNIT_I, IA64_UNIT_B }, "MIB" }, /* 8 */
39 { 0, { IA64_UNIT_M, IA64_UNIT_B, IA64_UNIT_B }, "MBB" },
40 { 0, { 0, }, "-a-" },
41 { 0, { IA64_UNIT_B, IA64_UNIT_B, IA64_UNIT_B }, "BBB" },
42 { 0, { IA64_UNIT_M, IA64_UNIT_M, IA64_UNIT_B }, "MMB" }, /* c */
43 { 0, { 0, }, "-d-" },
44 { 0, { IA64_UNIT_M, IA64_UNIT_F, IA64_UNIT_B }, "MFB" },
45 { 0, { 0, }, "-f-" },
46 };
47
48
49/* Copy the prefix contained in *PTR (up to a '.' or a NUL) to DEST.
50 PTR will be adjusted to point to the start of the next portion
51 of the opcode, or at the NUL character. */
52
53static void
54get_opc_prefix (ptr, dest)
55 const char **ptr;
56 char *dest;
57{
58 char *c = strchr (*ptr, '.');
59 if (c != NULL)
60 {
61 memcpy (dest, *ptr, c - *ptr);
62 dest[c - *ptr] = '\0';
63 *ptr = c + 1;
64 }
65 else
66 {
67 int l = strlen (*ptr);
68 memcpy (dest, *ptr, l);
69 dest[l] = '\0';
70 *ptr += l;
71 }
72}
73
74
75/* Find the index of the entry in the string table corresponding to
76 STR; return -1 if one does not exist. */
77
78static short
79find_string_ent (str)
80 const char *str;
81{
82 short start = 0;
83 short end = sizeof (ia64_strings) / sizeof (const char *);
84 short i = (start + end) / 2;
85
86 if (strcmp (str, ia64_strings[end - 1]) > 0)
87 {
88 return -1;
89 }
90 while (start <= end)
91 {
92 int c = strcmp (str, ia64_strings[i]);
93 if (c < 0)
94 {
95 end = i - 1;
96 }
97 else if (c == 0)
98 {
99 return i;
100 }
101 else
102 {
103 start = i + 1;
104 }
105 i = (start + end) / 2;
106 }
107 return -1;
108}
109
110
111/* Find the opcode in the main opcode table whose name is STRINGINDEX, or
112 return -1 if one does not exist. */
113
114static short
115find_main_ent (nameindex)
116 short nameindex;
117{
118 short start = 0;
119 short end = sizeof (main_table) / sizeof (struct ia64_main_table);
120 short i = (start + end) / 2;
121
122 if (nameindex < main_table[0].name_index
123 || nameindex > main_table[end - 1].name_index)
124 {
125 return -1;
126 }
127 while (start <= end)
128 {
129 if (nameindex < main_table[i].name_index)
130 {
131 end = i - 1;
132 }
133 else if (nameindex == main_table[i].name_index)
134 {
135 while (i > 0 && main_table[i - 1].name_index == nameindex)
136 {
137 i--;
138 }
139 return i;
140 }
141 else
142 {
143 start = i + 1;
144 }
145 i = (start + end) / 2;
146 }
147 return -1;
148}
149
150
151/* Find the index of the entry in the completer table that is part of
152 MAIN_ENT (starting from PREV_COMPLETER) that matches NAME, or
153 return -1 if one does not exist. */
154
155static short
156find_completer (main_ent, prev_completer, name)
157 short main_ent;
158 short prev_completer;
159 const char *name;
160{
161 short name_index = find_string_ent (name);
162
163 if (name_index < 0)
164 {
165 return -1;
166 }
167
168 if (prev_completer == -1)
169 {
170 prev_completer = main_table[main_ent].completers;
171 }
172 else
173 {
174 prev_completer = completer_table[prev_completer].subentries;
175 }
176
177 while (prev_completer != -1)
178 {
179 if (completer_table[prev_completer].name_index == name_index)
180 {
181 return prev_completer;
182 }
183 prev_completer = completer_table[prev_completer].alternative;
184 }
185 return -1;
186}
187
188
189/* Apply the completer referred to by COMPLETER_INDEX to OPCODE, and
190 return the result. */
191
192static ia64_insn
193apply_completer (opcode, completer_index)
194 ia64_insn opcode;
195 int completer_index;
196{
197 ia64_insn mask = completer_table[completer_index].mask;
198 ia64_insn bits = completer_table[completer_index].bits;
199 int shiftamt = (completer_table[completer_index].offset & 63);
200
201 mask = mask << shiftamt;
202 bits = bits << shiftamt;
203 opcode = (opcode & ~mask) | bits;
204 return opcode;
205}
206
207
208/* Extract BITS number of bits starting from OP_POINTER + BITOFFSET in
209 the dis_table array, and return its value. (BITOFFSET is numbered
210 starting from MSB to LSB, so a BITOFFSET of 0 indicates the MSB of the
211 first byte in OP_POINTER.) */
212
213static int
214extract_op_bits (op_pointer, bitoffset, bits)
215 int op_pointer;
216 int bitoffset;
217 int bits;
218{
219 int res = 0;
220
221 op_pointer += (bitoffset / 8);
222
223 if (bitoffset % 8)
224 {
225 unsigned int op = dis_table[op_pointer++];
226 int numb = 8 - (bitoffset % 8);
227 int mask = (1 << numb) - 1;
228 int bata = (bits < numb) ? bits : numb;
229 int delta = numb - bata;
230
231 res = (res << bata) | ((op & mask) >> delta);
232 bitoffset += bata;
233 bits -= bata;
234 }
235 while (bits >= 8)
236 {
237 res = (res << 8) | (dis_table[op_pointer++] & 255);
238 bits -= 8;
239 }
240 if (bits > 0)
241 {
242 unsigned int op = (dis_table[op_pointer++] & 255);
243 res = (res << bits) | (op >> (8 - bits));
244 }
245 return res;
246}
247
248
249/* Examine the state machine entry at OP_POINTER in the dis_table
250 array, and extract its values into OPVAL and OP. The length of the
251 state entry in bits is returned. */
252
253static int
254extract_op (op_pointer, opval, op)
255 int op_pointer;
256 int *opval;
257 unsigned int *op;
258{
259 int oplen = 5;
260
261 *op = dis_table[op_pointer];
262
263 if ((*op) & 0x40)
264 {
265 opval[0] = extract_op_bits (op_pointer, oplen, 5);
266 oplen += 5;
267 }
268 switch ((*op) & 0x30)
269 {
270 case 0x10:
271 {
272 opval[1] = extract_op_bits (op_pointer, oplen, 8);
273 oplen += 8;
274 opval[1] += op_pointer;
275 break;
276 }
277 case 0x20:
278 {
279 opval[1] = extract_op_bits (op_pointer, oplen, 16);
280 if (! (opval[1] & 32768))
281 {
282 opval[1] += op_pointer;
283 }
284 oplen += 16;
285 break;
286 }
287 case 0x30:
288 {
289 oplen--;
290 opval[2] = extract_op_bits (op_pointer, oplen, 12);
291 oplen += 12;
292 opval[2] |= 32768;
293 break;
294 }
295 }
296 if (((*op) & 0x08) && (((*op) & 0x30) != 0x30))
297 {
298 opval[2] = extract_op_bits (op_pointer, oplen, 16);
299 oplen += 16;
300 if (! (opval[2] & 32768))
301 {
302 opval[2] += op_pointer;
303 }
304 }
305 return oplen;
306}
307
308
309/* Returns a non-zero value if the opcode in the main_table list at
310 PLACE matches OPCODE and is of type TYPE. */
311
312static int
313opcode_verify (opcode, place, type)
314 ia64_insn opcode;
315 int place;
316 enum ia64_insn_type type;
317{
318 if (main_table[place].opcode_type != type)
319 {
320 return 0;
321 }
322 if (main_table[place].flags
323 & (IA64_OPCODE_F2_EQ_F3 | IA64_OPCODE_LEN_EQ_64MCNT))
324 {
325 const struct ia64_operand *o1, *o2;
326 ia64_insn f2, f3;
327
328 if (main_table[place].flags & IA64_OPCODE_F2_EQ_F3)
329 {
330 o1 = elf64_ia64_operands + IA64_OPND_F2;
331 o2 = elf64_ia64_operands + IA64_OPND_F3;
332 (*o1->extract) (o1, opcode, &f2);
333 (*o2->extract) (o2, opcode, &f3);
334 if (f2 != f3)
335 return 0;
336 }
337 else
338 {
339 ia64_insn len, count;
340
341 /* length must equal 64-count: */
342 o1 = elf64_ia64_operands + IA64_OPND_LEN6;
343 o2 = elf64_ia64_operands + main_table[place].operands[2];
344 (*o1->extract) (o1, opcode, &len);
345 (*o2->extract) (o2, opcode, &count);
346 if (len != 64 - count)
347 return 0;
348 }
349 }
350 return 1;
351}
352
353
354/* Find an instruction entry in the ia64_dis_names array that matches
355 opcode OPCODE and is of type TYPE. Returns either a positive index
356 into the array, or a negative value if an entry for OPCODE could
357 not be found. Checks all matches and returns the one with the highest
358 priority. */
359
360static int
361locate_opcode_ent (opcode, type)
362 ia64_insn opcode;
363 enum ia64_insn_type type;
364{
365 int currtest[41];
366 int bitpos[41];
367 int op_ptr[41];
368 int currstatenum = 0;
369 short found_disent = -1;
370 short found_priority = -1;
371
372 currtest[currstatenum] = 0;
373 op_ptr[currstatenum] = 0;
374 bitpos[currstatenum] = 40;
375
376 while (1)
377 {
378 int op_pointer = op_ptr[currstatenum];
379 unsigned int op;
380 int currbitnum = bitpos[currstatenum];
381 int oplen;
382 int opval[3];
383 int next_op;
384 int currbit;
385
386 oplen = extract_op (op_pointer, opval, &op);
387
388 bitpos[currstatenum] = currbitnum;
389
390 /* Skip opval[0] bits in the instruction. */
391 if (op & 0x40)
392 {
393 currbitnum -= opval[0];
394 }
395
396 /* The value of the current bit being tested. */
397 currbit = opcode & (((ia64_insn) 1) << currbitnum) ? 1 : 0;
398 next_op = -1;
399
400 /* We always perform the tests specified in the current state in
401 a particular order, falling through to the next test if the
402 previous one failed. */
403 switch (currtest[currstatenum])
404 {
405 case 0:
406 currtest[currstatenum]++;
407 if (currbit == 0 && (op & 0x80))
408 {
409 /* Check for a zero bit. If this test solely checks for
410 a zero bit, we can check for up to 8 consecutive zero
411 bits (the number to check is specified by the lower 3
412 bits in the state code.)
413
414 If the state instruction matches, we go to the very
415 next state instruction; otherwise, try the next test. */
416
417 if ((op & 0xf8) == 0x80)
418 {
419 int count = op & 0x7;
420 int x;
421
422 for (x = 0; x <= count; x++)
423 {
424 int i =
425 opcode & (((ia64_insn) 1) << (currbitnum - x)) ? 1 : 0;
426 if (i)
427 {
428 break;
429 }
430 }
431 if (x > count)
432 {
433 next_op = op_pointer + ((oplen + 7) / 8);
434 currbitnum -= count;
435 break;
436 }
437 }
438 else if (! currbit)
439 {
440 next_op = op_pointer + ((oplen + 7) / 8);
441 break;
442 }
443 }
444 /* FALLTHROUGH */
445 case 1:
446 /* If the bit in the instruction is one, go to the state
447 instruction specified by opval[1]. */
448 currtest[currstatenum]++;
449 if (currbit && (op & 0x30) != 0 && ((op & 0x30) != 0x30))
450 {
451 next_op = opval[1];
452 break;
453 }
454 /* FALLTHROUGH */
455 case 2:
456 /* Don't care. Skip the current bit and go to the state
457 instruction specified by opval[2].
458
459 An encoding of 0x30 is special; this means that a 12-bit
460 offset into the ia64_dis_names[] array is specified. */
461 currtest[currstatenum]++;
462 if ((op & 0x08) || ((op & 0x30) == 0x30))
463 {
464 next_op = opval[2];
465 break;
466 }
467 }
468
469 /* If bit 15 is set in the address of the next state, an offset
470 in the ia64_dis_names array was specified instead. We then
471 check to see if an entry in the list of opcodes matches the
472 opcode we were given; if so, we have succeeded. */
473
474 if ((next_op >= 0) && (next_op & 32768))
475 {
476 short disent = next_op & 32767;
477 short priority = -1;
478
479 if (next_op > 65535)
480 {
481 abort ();
482 }
483
484 /* Run through the list of opcodes to check, trying to find
485 one that matches. */
486 while (disent >= 0)
487 {
488 int place = ia64_dis_names[disent].insn_index;
489
490 priority = ia64_dis_names[disent].priority;
491
492 if (opcode_verify (opcode, place, type)
493 && priority > found_priority)
494 {
495 break;
496 }
497 if (ia64_dis_names[disent].next_flag)
498 {
499 disent++;
500 }
501 else
502 {
503 disent = -1;
504 }
505 }
506
507 if (disent >= 0)
508 {
509 found_disent = disent;
510 found_priority = priority;
511 }
512 /* Try the next test in this state, regardless of whether a match
513 was found. */
514 next_op = -2;
515 }
516
517 /* next_op == -1 is "back up to the previous state".
518 next_op == -2 is "stay in this state and try the next test".
519 Otherwise, transition to the state indicated by next_op. */
520
521 if (next_op == -1)
522 {
523 currstatenum--;
524 if (currstatenum < 0)
525 {
526 return found_disent;
527 }
528 }
529 else if (next_op >= 0)
530 {
531 currstatenum++;
532 bitpos[currstatenum] = currbitnum - 1;
533 op_ptr[currstatenum] = next_op;
534 currtest[currstatenum] = 0;
535 }
536 }
537}
538
539
540/* Construct an ia64_opcode entry based on OPCODE, NAME and PLACE. */
541
542static struct ia64_opcode *
543make_ia64_opcode (opcode, name, place, depind)
544 ia64_insn opcode;
545 const char *name;
546 int place;
547 int depind;
548{
549 struct ia64_opcode *res =
550 (struct ia64_opcode *) xmalloc (sizeof (struct ia64_opcode));
551 res->name = xstrdup (name);
552 res->type = main_table[place].opcode_type;
553 res->num_outputs = main_table[place].num_outputs;
554 res->opcode = opcode;
555 res->mask = main_table[place].mask;
556 res->operands[0] = main_table[place].operands[0];
557 res->operands[1] = main_table[place].operands[1];
558 res->operands[2] = main_table[place].operands[2];
559 res->operands[3] = main_table[place].operands[3];
560 res->operands[4] = main_table[place].operands[4];
561 res->flags = main_table[place].flags;
562 res->ent_index = place;
563 res->dependencies = &op_dependencies[depind];
564 return res;
565}
566
567
568/* Determine the ia64_opcode entry for the opcode specified by INSN
569 and TYPE. If a valid entry is not found, return NULL. */
570struct ia64_opcode *
571ia64_dis_opcode (insn, type)
572 ia64_insn insn;
573 enum ia64_insn_type type;
574{
575 int disent = locate_opcode_ent (insn, type);
576
577 if (disent < 0)
578 {
579 return NULL;
580 }
581 else
582 {
583 unsigned int cb = ia64_dis_names[disent].completer_index;
584 static char name[128];
585 int place = ia64_dis_names[disent].insn_index;
586 int ci = main_table[place].completers;
587 ia64_insn tinsn = main_table[place].opcode;
588
589 strcpy (name, ia64_strings [main_table[place].name_index]);
590
591 while (cb)
592 {
593 if (cb & 1)
594 {
595 int cname = completer_table[ci].name_index;
596
597 tinsn = apply_completer (tinsn, ci);
598
599 if (ia64_strings[cname][0] != '\0')
600 {
601 strcat (name, ".");
602 strcat (name, ia64_strings[cname]);
603 }
604 if (cb != 1)
605 {
606 ci = completer_table[ci].subentries;
607 }
608 }
609 else
610 {
611 ci = completer_table[ci].alternative;
612 }
613 if (ci < 0)
614 {
615 abort ();
616 }
617 cb = cb >> 1;
618 }
619 if (tinsn != (insn & main_table[place].mask))
620 {
621 abort ();
622 }
623 return make_ia64_opcode (insn, name, place,
624 completer_table[ci].dependencies);
625 }
626}
627
628
629/* Search the main_opcode table starting from PLACE for an opcode that
630 matches NAME. Return NULL if one is not found. */
631
632static struct ia64_opcode *
633ia64_find_matching_opcode (name, place)
634 const char *name;
635 short place;
636{
637 char op[129];
638 const char *suffix;
639 short name_index;
640
641 if (strlen (name) > 128)
642 {
643 return NULL;
644 }
645 suffix = name;
646 get_opc_prefix (&suffix, op);
647 name_index = find_string_ent (op);
648 if (name_index < 0)
649 {
650 return NULL;
651 }
652
653 while (main_table[place].name_index == name_index)
654 {
655 const char *curr_suffix = suffix;
656 ia64_insn curr_insn = main_table[place].opcode;
657 short completer = -1;
658
659 do {
660 if (suffix[0] == '\0')
661 {
662 completer = find_completer (place, completer, suffix);
663 }
664 else
665 {
666 get_opc_prefix (&curr_suffix, op);
667 completer = find_completer (place, completer, op);
668 }
669 if (completer != -1)
670 {
671 curr_insn = apply_completer (curr_insn, completer);
672 }
673 } while (completer != -1 && curr_suffix[0] != '\0');
674
675 if (completer != -1 && curr_suffix[0] == '\0'
676 && completer_table[completer].terminal_completer)
677 {
678 int depind = completer_table[completer].dependencies;
679 return make_ia64_opcode (curr_insn, name, place, depind);
680 }
681 else
682 {
683 place++;
684 }
685 }
686 return NULL;
687}
688
689
690/* Find the next opcode after PREV_ENT that matches PREV_ENT, or return NULL
691 if one does not exist.
692
693 It is the caller's responsibility to invoke ia64_free_opcode () to
694 release any resources used by the returned entry. */
695
696struct ia64_opcode *
697ia64_find_next_opcode (prev_ent)
698 struct ia64_opcode *prev_ent;
699{
700 return ia64_find_matching_opcode (prev_ent->name,
701 prev_ent->ent_index + 1);
702}
703
704/* Find the first opcode that matches NAME, or return NULL if it does
705 not exist.
706
707 It is the caller's responsibility to invoke ia64_free_opcode () to
708 release any resources used by the returned entry. */
709
710struct ia64_opcode *
711ia64_find_opcode (name)
712 const char *name;
713{
714 char op[129];
715 const char *suffix;
716 short place;
717 short name_index;
718
719 if (strlen (name) > 128)
720 {
721 return NULL;
722 }
723 suffix = name;
724 get_opc_prefix (&suffix, op);
725 name_index = find_string_ent (op);
726 if (name_index < 0)
727 {
728 return NULL;
729 }
730
731 place = find_main_ent (name_index);
732
733 if (place < 0)
734 {
735 return NULL;
736 }
737 return ia64_find_matching_opcode (name, place);
738}
739
740/* Free any resources used by ENT. */
741void
742ia64_free_opcode (ent)
743 struct ia64_opcode *ent;
744{
745 free ((void *)ent->name);
746 free (ent);
747}
748
749const struct ia64_dependency *
750ia64_find_dependency (index)
751 int index;
752{
753 index = DEP(index);
754
755 if (index < 0
756 || index >= (int)(sizeof(dependencies) / sizeof(dependencies[0])))
757 return NULL;
758
759 return &dependencies[index];
760}
Note: See TracBrowser for help on using the repository browser.