Wed Nov 4 18:46:47 1998 Dave Brolley <brolley@cygnus.com>
[external/binutils.git] / opcodes / fr30-opc.c
1 /* Generic opcode table support for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3
4 THIS FILE IS USED TO GENERATE fr30-opc.c.
5
6 Copyright (C) 1998 Free Software Foundation, Inc.
7
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation, Inc.,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
23
24 #include "sysdep.h"
25 #include <stdio.h>
26 #include "ansidecl.h"
27 #include "libiberty.h"
28 #include "bfd.h"
29 #include "symcat.h"
30 #include "fr30-opc.h"
31 #include "opintl.h"
32
33 /* The hash functions are recorded here to help keep assembler code out of
34    the disassembler and vice versa.  */
35
36 static int asm_hash_insn_p PARAMS ((const CGEN_INSN *));
37 static unsigned int asm_hash_insn PARAMS ((const char *));
38 static int dis_hash_insn_p PARAMS ((const CGEN_INSN *));
39 static unsigned int dis_hash_insn PARAMS ((const char *, unsigned long));
40
41 /* Cover function to read and properly byteswap an insn value.  */
42
43 CGEN_INSN_INT
44 cgen_get_insn_value (od, buf, length)
45      CGEN_OPCODE_DESC od;
46      unsigned char *buf;
47      int length;
48 {
49   CGEN_INSN_INT value;
50
51   switch (length)
52     {
53     case 8:
54       value = *buf;
55       break;
56     case 16:
57       if (CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG)
58         value = bfd_getb16 (buf);
59       else
60         value = bfd_getl16 (buf);
61       break;
62     case 32:
63       if (CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG)
64         value = bfd_getb32 (buf);
65       else
66         value = bfd_getl32 (buf);
67       break;
68     default:
69       abort ();
70     }
71
72   return value;
73 }
74
75 /* Cover function to store an insn value properly byteswapped.  */
76
77 void
78 cgen_put_insn_value (od, buf, length, value)
79      CGEN_OPCODE_DESC od;
80      unsigned char *buf;
81      int length;
82      CGEN_INSN_INT value;
83 {
84   switch (length)
85     {
86     case 8:
87       buf[0] = value;
88       break;
89     case 16:
90       if (CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG)
91         bfd_putb16 (value, buf);
92       else
93         bfd_putl16 (value, buf);
94       break;
95     case 32:
96       if (CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG)
97         bfd_putb32 (value, buf);
98       else
99         bfd_putl32 (value, buf);
100       break;
101     default:
102       abort ();
103     }
104 }
105
106 /* Look up instruction INSN_VALUE and extract its fields.
107    INSN, if non-null, is the insn table entry.
108    Otherwise INSN_VALUE is examined to compute it.
109    LENGTH is the bit length of INSN_VALUE if known, otherwise 0.
110    0 is only valid if `insn == NULL && ! CGEN_INT_INSN_P'.
111    If INSN != NULL, LENGTH must be valid.
112    ALIAS_P is non-zero if alias insns are to be included in the search.
113
114    The result a pointer to the insn table entry, or NULL if the instruction
115    wasn't recognized.  */
116
117 const CGEN_INSN *
118 fr30_cgen_lookup_insn (od, insn, insn_value, length, fields, alias_p)
119      CGEN_OPCODE_DESC od;
120      const CGEN_INSN *insn;
121      CGEN_INSN_BYTES insn_value;
122      int length;
123      CGEN_FIELDS *fields;
124      int alias_p;
125 {
126   unsigned char buf[16];
127   unsigned char *bufp;
128   unsigned int base_insn;
129 #if CGEN_INT_INSN_P
130   CGEN_EXTRACT_INFO *info = NULL;
131 #else
132   CGEN_EXTRACT_INFO ex_info;
133   CGEN_EXTRACT_INFO *info = &ex_info;
134 #endif
135
136 #if ! CGEN_INT_INSN_P
137   ex_info.dis_info = NULL;
138   ex_info.bytes = insn_value;
139   ex_info.valid = -1;
140 #endif
141
142   if (!insn)
143     {
144       const CGEN_INSN_LIST *insn_list;
145
146 #if CGEN_INT_INSN_P
147       cgen_put_insn_value (od, buf, length, insn_value);
148       bufp = buf;
149       base_insn = insn_value; /*???*/
150 #else
151       base_insn = cgen_get_insn_value (od, buf, length);
152       bufp = insn_value;
153 #endif
154
155       /* The instructions are stored in hash lists.
156          Pick the first one and keep trying until we find the right one.  */
157
158       insn_list = CGEN_DIS_LOOKUP_INSN (od, bufp, base_insn);
159       while (insn_list != NULL)
160         {
161           insn = insn_list->insn;
162
163           if (alias_p
164               || ! CGEN_INSN_ATTR (insn, CGEN_INSN_ALIAS))
165             {
166               /* Basic bit mask must be correct.  */
167               /* ??? May wish to allow target to defer this check until the
168                  extract handler.  */
169               if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
170                 {
171                   /* ??? 0 is passed for `pc' */
172                   int elength = (*CGEN_EXTRACT_FN (insn)) (od, insn, info,
173                                                            insn_value, fields,
174                                                            (bfd_vma) 0);
175                   if (elength > 0)
176                     {
177                       /* sanity check */
178                       if (length != 0 && length != elength)
179                         abort ();
180                       return insn;
181                     }
182                 }
183             }
184
185           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
186         }
187     }
188   else
189     {
190       /* Sanity check: can't pass an alias insn if ! alias_p.  */
191       if (! alias_p
192           && CGEN_INSN_ATTR (insn, CGEN_INSN_ALIAS))
193         abort ();
194       /* Sanity check: length must be correct.  */
195       if (length != CGEN_INSN_BITSIZE (insn))
196         abort ();
197
198       /* ??? 0 is passed for `pc' */
199       length = (*CGEN_EXTRACT_FN (insn)) (od, insn, info, insn_value, fields,
200                                           (bfd_vma) 0);
201       /* Sanity check: must succeed.
202          Could relax this later if it ever proves useful.  */
203       if (length == 0)
204         abort ();
205       return insn;
206     }
207
208   return NULL;
209 }
210
211 /* Fill in the operand instances used by INSN whose operands are FIELDS.
212    INDICES is a pointer to a buffer of MAX_OPERAND_INSTANCES ints to be filled
213    in.  */
214
215 void
216 fr30_cgen_get_insn_operands (od, insn, fields, indices)
217      CGEN_OPCODE_DESC od;
218      const CGEN_INSN * insn;
219      const CGEN_FIELDS * fields;
220      int *indices;
221 {
222   const CGEN_OPERAND_INSTANCE *opinst;
223   int i;
224
225   for (i = 0, opinst = CGEN_INSN_OPERANDS (insn);
226        opinst != NULL
227          && CGEN_OPERAND_INSTANCE_TYPE (opinst) != CGEN_OPERAND_INSTANCE_END;
228        ++i, ++opinst)
229     {
230       const CGEN_OPERAND *op = CGEN_OPERAND_INSTANCE_OPERAND (opinst);
231       if (op == NULL)
232         indices[i] = CGEN_OPERAND_INSTANCE_INDEX (opinst);
233       else
234         indices[i] = fr30_cgen_get_int_operand (CGEN_OPERAND_INDEX (op),
235                                                   fields);
236     }
237 }
238
239 /* Cover function to fr30_cgen_get_insn_operands when either INSN or FIELDS
240    isn't known.
241    The INSN, INSN_VALUE, and LENGTH arguments are passed to
242    fr30_cgen_lookup_insn unchanged.
243
244    The result is the insn table entry or NULL if the instruction wasn't
245    recognized.  */
246
247 const CGEN_INSN *
248 fr30_cgen_lookup_get_insn_operands (od, insn, insn_value, length, indices)
249      CGEN_OPCODE_DESC od;
250      const CGEN_INSN *insn;
251      CGEN_INSN_BYTES insn_value;
252      int length;
253      int *indices;
254 {
255   CGEN_FIELDS fields;
256
257   /* Pass non-zero for ALIAS_P only if INSN != NULL.
258      If INSN == NULL, we want a real insn.  */
259   insn = fr30_cgen_lookup_insn (od, insn, insn_value, length, &fields,
260                                   insn != NULL);
261   if (! insn)
262     return NULL;
263
264   fr30_cgen_get_insn_operands (od, insn, &fields, indices);
265   return insn;
266 }
267 /* Attributes.  */
268
269 static const CGEN_ATTR_ENTRY MACH_attr[] =
270 {
271   { "base", MACH_BASE },
272   { "fr30", MACH_FR30 },
273   { "max", MACH_MAX },
274   { 0, 0 }
275 };
276
277 const CGEN_ATTR_TABLE fr30_cgen_hardware_attr_table[] =
278 {
279   { "CACHE-ADDR", NULL },
280   { "PC", NULL },
281   { "PROFILE", NULL },
282   { 0, 0 }
283 };
284
285 const CGEN_ATTR_TABLE fr30_cgen_operand_attr_table[] =
286 {
287   { "ABS-ADDR", NULL },
288   { "FAKE", NULL },
289   { "NEGATIVE", NULL },
290   { "PCREL-ADDR", NULL },
291   { "RELAX", NULL },
292   { "SIGN-OPT", NULL },
293   { "UNSIGNED", NULL },
294   { 0, 0 }
295 };
296
297 const CGEN_ATTR_TABLE fr30_cgen_insn_attr_table[] =
298 {
299   { "ALIAS", NULL },
300   { "COND-CTI", NULL },
301   { "NO-DIS", NULL },
302   { "RELAX", NULL },
303   { "RELAXABLE", NULL },
304   { "SKIP-CTI", NULL },
305   { "UNCOND-CTI", NULL },
306   { "VIRTUAL", NULL },
307   { 0, 0 }
308 };
309
310 CGEN_KEYWORD_ENTRY fr30_cgen_opval_h_gr_entries[] = 
311 {
312   { "ac", 13 },
313   { "fp", 14 },
314   { "sp", 15 },
315   { "r0", 0 },
316   { "r1", 1 },
317   { "r2", 2 },
318   { "r3", 3 },
319   { "r4", 4 },
320   { "r5", 5 },
321   { "r6", 6 },
322   { "r7", 7 },
323   { "r8", 8 },
324   { "r9", 9 },
325   { "r10", 10 },
326   { "r11", 11 },
327   { "r12", 12 },
328   { "r13", 13 },
329   { "r14", 14 },
330   { "r15", 15 }
331 };
332
333 CGEN_KEYWORD fr30_cgen_opval_h_gr = 
334 {
335   & fr30_cgen_opval_h_gr_entries[0],
336   19
337 };
338
339
340 /* The hardware table.  */
341
342 #define HW_ENT(n) fr30_cgen_hw_entries[n]
343 static const CGEN_HW_ENTRY fr30_cgen_hw_entries[] =
344 {
345   { HW_H_PC, & HW_ENT (HW_H_PC + 1), "h-pc", CGEN_ASM_KEYWORD, (PTR) 0, { 0, 0|(1<<CGEN_HW_PROFILE)|(1<<CGEN_HW_PC), { 0 } } },
346   { HW_H_MEMORY, & HW_ENT (HW_H_MEMORY + 1), "h-memory", CGEN_ASM_KEYWORD, (PTR) 0, { 0, 0, { 0 } } },
347   { HW_H_SINT, & HW_ENT (HW_H_SINT + 1), "h-sint", CGEN_ASM_KEYWORD, (PTR) 0, { 0, 0, { 0 } } },
348   { HW_H_UINT, & HW_ENT (HW_H_UINT + 1), "h-uint", CGEN_ASM_KEYWORD, (PTR) 0, { 0, 0, { 0 } } },
349   { HW_H_ADDR, & HW_ENT (HW_H_ADDR + 1), "h-addr", CGEN_ASM_KEYWORD, (PTR) 0, { 0, 0, { 0 } } },
350   { HW_H_IADDR, & HW_ENT (HW_H_IADDR + 1), "h-iaddr", CGEN_ASM_KEYWORD, (PTR) 0, { 0, 0, { 0 } } },
351   { HW_H_GR, & HW_ENT (HW_H_GR + 1), "h-gr", CGEN_ASM_KEYWORD, (PTR) & fr30_cgen_opval_h_gr, { 0, 0|(1<<CGEN_HW_CACHE_ADDR)|(1<<CGEN_HW_PROFILE), { 0 } } },
352   { 0 }
353 };
354
355 /* The operand table.  */
356
357 #define OPERAND(op) CONCAT2 (FR30_OPERAND_,op)
358 #define OP_ENT(op) fr30_cgen_operand_table[OPERAND (op)]
359
360 const CGEN_OPERAND fr30_cgen_operand_table[MAX_OPERANDS] =
361 {
362 /* pc: program counter */
363   { "pc", & HW_ENT (HW_H_PC), 0, 0,
364     { 0, 0|(1<<CGEN_OPERAND_FAKE), { 0 } }  },
365 /* Ri: destination register */
366   { "Ri", & HW_ENT (HW_H_GR), 12, 4,
367     { 0, 0|(1<<CGEN_OPERAND_UNSIGNED), { 0 } }  },
368 /* Rj: source register */
369   { "Rj", & HW_ENT (HW_H_GR), 8, 4,
370     { 0, 0|(1<<CGEN_OPERAND_UNSIGNED), { 0 } }  },
371 };
372
373 /* Operand references.  */
374
375 #define INPUT CGEN_OPERAND_INSTANCE_INPUT
376 #define OUTPUT CGEN_OPERAND_INSTANCE_OUTPUT
377
378 static const CGEN_OPERAND_INSTANCE fmt_ADD_ops[] = {
379   { INPUT, "Rj", & HW_ENT (HW_H_GR), CGEN_MODE_SI, & OP_ENT (RJ), 0 },
380   { INPUT, "Ri", & HW_ENT (HW_H_GR), CGEN_MODE_SI, & OP_ENT (RI), 0 },
381   { OUTPUT, "Ri", & HW_ENT (HW_H_GR), CGEN_MODE_SI, & OP_ENT (RI), 0 },
382   { 0 }
383 };
384
385 #undef INPUT
386 #undef OUTPUT
387
388 #define A(a) (1 << CONCAT2 (CGEN_INSN_,a))
389 #define MNEM CGEN_SYNTAX_MNEMONIC /* syntax value for mnemonic */
390 #define OP(field) CGEN_SYNTAX_MAKE_FIELD (OPERAND (field))
391
392 /* The instruction table.
393    This is currently non-static because the simulator accesses it
394    directly.  */
395
396 const CGEN_INSN fr30_cgen_insn_table_entries[MAX_INSNS] =
397 {
398   /* Special null first entry.
399      A `num' value of zero is thus invalid.
400      Also, the special `invalid' insn resides here.  */
401   { { 0 }, 0 },
402 /* ADD $Rj,$Ri */
403   {
404     { 1, 1, 1, 1 },
405     FR30_INSN_ADD, "ADD", "ADD",
406     { { MNEM, ' ', OP (RJ), ',', OP (RI), 0 } },
407     { 16, 16, 0xff00 }, 0xa600,
408     (PTR) & fmt_ADD_ops[0],
409     { 0, 0, { 0 } }
410   },
411 };
412
413 #undef A
414 #undef MNEM
415 #undef OP
416
417 static const CGEN_INSN_TABLE insn_table =
418 {
419   & fr30_cgen_insn_table_entries[0],
420   sizeof (CGEN_INSN),
421   MAX_INSNS,
422   NULL
423 };
424
425 /* Each non-simple macro entry points to an array of expansion possibilities.  */
426
427 #define A(a) (1 << CONCAT2 (CGEN_INSN_,a))
428 #define MNEM CGEN_SYNTAX_MNEMONIC /* syntax value for mnemonic */
429 #define OP(field) CGEN_SYNTAX_MAKE_FIELD (OPERAND (field))
430
431 /* The macro instruction table.  */
432
433 static const CGEN_INSN macro_insn_table_entries[] =
434 {
435 };
436
437 #undef A
438 #undef MNEM
439 #undef OP
440
441 static const CGEN_INSN_TABLE macro_insn_table =
442 {
443   & macro_insn_table_entries[0],
444   sizeof (CGEN_INSN),
445   (sizeof (macro_insn_table_entries) /
446    sizeof (macro_insn_table_entries[0])),
447   NULL
448 };
449
450 static void
451 init_tables ()
452 {
453 }
454
455 /* Return non-zero if INSN is to be added to the hash table.
456    Targets are free to override CGEN_{ASM,DIS}_HASH_P in the .opc file.  */
457
458 static int
459 asm_hash_insn_p (insn)
460      const CGEN_INSN * insn;
461 {
462   return CGEN_ASM_HASH_P (insn);
463 }
464
465 static int
466 dis_hash_insn_p (insn)
467      const CGEN_INSN * insn;
468 {
469   /* If building the hash table and the NO-DIS attribute is present,
470      ignore.  */
471   if (CGEN_INSN_ATTR (insn, CGEN_INSN_NO_DIS))
472     return 0;
473   return CGEN_DIS_HASH_P (insn);
474 }
475
476 /* The result is the hash value of the insn.
477    Targets are free to override CGEN_{ASM,DIS}_HASH in the .opc file.  */
478
479 static unsigned int
480 asm_hash_insn (mnem)
481      const char * mnem;
482 {
483   return CGEN_ASM_HASH (mnem);
484 }
485
486 /* BUF is a pointer to the insn's bytes in target order.
487    VALUE is an integer of the first CGEN_BASE_INSN_BITSIZE bits,
488    host order.  */
489
490 static unsigned int
491 dis_hash_insn (buf, value)
492      const char * buf;
493      unsigned long value;
494 {
495   return CGEN_DIS_HASH (buf, value);
496 }
497
498 /* Initialize an opcode table and return a descriptor.
499    It's much like opening a file, and must be the first function called.  */
500
501 CGEN_OPCODE_DESC
502 fr30_cgen_opcode_open (mach, endian)
503      int mach;
504      enum cgen_endian endian;
505 {
506   CGEN_OPCODE_TABLE * table = (CGEN_OPCODE_TABLE *) xmalloc (sizeof (CGEN_OPCODE_TABLE));
507   static int init_p;
508
509   if (! init_p)
510     {
511       init_tables ();
512       init_p = 1;
513     }
514
515   memset (table, 0, sizeof (*table));
516
517   CGEN_OPCODE_MACH (table) = mach;
518   CGEN_OPCODE_ENDIAN (table) = endian;
519   /* FIXME: for the sparc case we can determine insn-endianness statically.
520      The worry here is where both data and insn endian can be independently
521      chosen, in which case this function will need another argument.
522      Actually, will want to allow for more arguments in the future anyway.  */
523   CGEN_OPCODE_INSN_ENDIAN (table) = endian;
524
525   CGEN_OPCODE_HW_LIST (table) = & fr30_cgen_hw_entries[0];
526
527   CGEN_OPCODE_OPERAND_TABLE (table) = & fr30_cgen_operand_table[0];
528
529   * CGEN_OPCODE_INSN_TABLE (table) = insn_table;
530
531   * CGEN_OPCODE_MACRO_INSN_TABLE (table) = macro_insn_table;
532
533   CGEN_OPCODE_ASM_HASH_P (table) = asm_hash_insn_p;
534   CGEN_OPCODE_ASM_HASH (table) = asm_hash_insn;
535   CGEN_OPCODE_ASM_HASH_SIZE (table) = CGEN_ASM_HASH_SIZE;
536
537   CGEN_OPCODE_DIS_HASH_P (table) = dis_hash_insn_p;
538   CGEN_OPCODE_DIS_HASH (table) = dis_hash_insn;
539   CGEN_OPCODE_DIS_HASH_SIZE (table) = CGEN_DIS_HASH_SIZE;
540
541   return (CGEN_OPCODE_DESC) table;
542 }
543
544 /* Close an opcode table.  */
545
546 void
547 fr30_cgen_opcode_close (desc)
548      CGEN_OPCODE_DESC desc;
549 {
550   free (desc);
551 }
552
553 /* Getting values from cgen_fields is handled by a collection of functions.
554    They are distinguished by the type of the VALUE argument they return.
555    TODO: floating point, inlining support, remove cases where result type
556    not appropriate.  */
557
558 int
559 fr30_cgen_get_int_operand (opindex, fields)
560      int opindex;
561      const CGEN_FIELDS * fields;
562 {
563   int value;
564
565   switch (opindex)
566     {
567     case FR30_OPERAND_RI :
568       value = fields->f_Ri;
569       break;
570     case FR30_OPERAND_RJ :
571       value = fields->f_Rj;
572       break;
573
574     default :
575       /* xgettext:c-format */
576       fprintf (stderr, _("Unrecognized field %d while getting int operand.\n"),
577                        opindex);
578       abort ();
579   }
580
581   return value;
582 }
583
584 bfd_vma
585 fr30_cgen_get_vma_operand (opindex, fields)
586      int opindex;
587      const CGEN_FIELDS * fields;
588 {
589   bfd_vma value;
590
591   switch (opindex)
592     {
593     case FR30_OPERAND_RI :
594       value = fields->f_Ri;
595       break;
596     case FR30_OPERAND_RJ :
597       value = fields->f_Rj;
598       break;
599
600     default :
601       /* xgettext:c-format */
602       fprintf (stderr, _("Unrecognized field %d while getting vma operand.\n"),
603                        opindex);
604       abort ();
605   }
606
607   return value;
608 }
609
610 /* Stuffing values in cgen_fields is handled by a collection of functions.
611    They are distinguished by the type of the VALUE argument they accept.
612    TODO: floating point, inlining support, remove cases where argument type
613    not appropriate.  */
614
615 void
616 fr30_cgen_set_int_operand (opindex, fields, value)
617      int opindex;
618      CGEN_FIELDS * fields;
619      int value;
620 {
621   switch (opindex)
622     {
623     case FR30_OPERAND_RI :
624       fields->f_Ri = value;
625       break;
626     case FR30_OPERAND_RJ :
627       fields->f_Rj = value;
628       break;
629
630     default :
631       /* xgettext:c-format */
632       fprintf (stderr, _("Unrecognized field %d while setting int operand.\n"),
633                        opindex);
634       abort ();
635   }
636 }
637
638 void
639 fr30_cgen_set_vma_operand (opindex, fields, value)
640      int opindex;
641      CGEN_FIELDS * fields;
642      bfd_vma value;
643 {
644   switch (opindex)
645     {
646     case FR30_OPERAND_RI :
647       fields->f_Ri = value;
648       break;
649     case FR30_OPERAND_RJ :
650       fields->f_Rj = value;
651       break;
652
653     default :
654       /* xgettext:c-format */
655       fprintf (stderr, _("Unrecognized field %d while setting vma operand.\n"),
656                        opindex);
657       abort ();
658   }
659 }
660