2003-06-03 Michael Snyder <msnyder@redhat.com>
[binutils.git] / cpu / frv.opc
blobc708a60b2edc48a82aed365d9b7a25a9021b4cfd
1 /* Fujitsu FRV opcode support, for GNU Binutils.  -*- C -*-
3    Copyright 2003 Free Software Foundation, Inc.
5    Contributed by Red Hat Inc; developed under contract from Fujitsu.
7    This file is part of the GNU Binutils.
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 /* This file is an addendum to frv.cpu.  Heavy use of C code isn't
26    appropriate in .cpu files, so it resides here.  This especially applies
27    to assembly/disassembly where parsing/printing can be quite involved.
28    Such things aren't really part of the specification of the cpu, per se,
29    so .cpu files provide the general framework and .opc files handle the
30    nitty-gritty details as necessary.
32    Each section is delimited with start and end markers.
34    <arch>-opc.h additions use: "-- opc.h"
35    <arch>-opc.c additions use: "-- opc.c"
36    <arch>-asm.c additions use: "-- asm.c"
37    <arch>-dis.c additions use: "-- dis.c"
38    <arch>-ibd.h additions use: "-- ibd.h"
41 /* -- opc.h */
43 #undef CGEN_DIS_HASH_SIZE
44 #define CGEN_DIS_HASH_SIZE 128
45 #undef CGEN_DIS_HASH
46 #define CGEN_DIS_HASH(buffer, value) (((value) >> 18) & 127)
48 /* Vliw support.  */
49 #define FRV_VLIW_SIZE 4 /* fr500 has largest vliw size of 4.  */
50 typedef CGEN_ATTR_VALUE_TYPE VLIW_COMBO[FRV_VLIW_SIZE];
52 typedef struct
54   int                   next_slot;
55   int                   constraint_violation;
56   unsigned long         mach;
57   unsigned long         elf_flags;
58   CGEN_ATTR_VALUE_TYPE *unit_mapping;
59   VLIW_COMBO           *current_vliw;
60   CGEN_ATTR_VALUE_TYPE  major[FRV_VLIW_SIZE];
61 } FRV_VLIW;
63 int frv_is_branch_major PARAMS ((CGEN_ATTR_VALUE_TYPE, unsigned long));
64 int frv_is_float_major  PARAMS ((CGEN_ATTR_VALUE_TYPE, unsigned long));
65 int frv_is_media_major  PARAMS ((CGEN_ATTR_VALUE_TYPE, unsigned long));
66 int frv_is_branch_insn  PARAMS ((const CGEN_INSN *));
67 int frv_is_float_insn   PARAMS ((const CGEN_INSN *));
68 int frv_is_media_insn   PARAMS ((const CGEN_INSN *));
69 void frv_vliw_reset     PARAMS ((FRV_VLIW *, unsigned long mach, unsigned long elf_flags));
70 int frv_vliw_add_insn   PARAMS ((FRV_VLIW *, const CGEN_INSN *));
71 int spr_valid           PARAMS ((long));
72 /* -- */
74 /* -- opc.c */
75 #include "elf/frv.h"
77 static int match_unit
78   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE, CGEN_ATTR_VALUE_TYPE));
79 static int match_vliw
80   PARAMS ((VLIW_COMBO *, VLIW_COMBO *, int));
81 static VLIW_COMBO * add_next_to_vliw
82   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
83 static int find_major_in_vliw
84   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
85 static int fr400_check_insn_major_constraints
86   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
87 static int fr500_check_insn_major_constraints
88   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
89 static int check_insn_major_constraints
90   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
92 int
93 frv_is_branch_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
95   switch (mach)
96     {
97     case bfd_mach_fr400:
98       if (major >= FR400_MAJOR_B_1 && major <= FR400_MAJOR_B_6)
99         return 1; /* is a branch */
100       break;
101     default:
102       if (major >= FR500_MAJOR_B_1 && major <= FR500_MAJOR_B_6)
103         return 1; /* is a branch */
104       break;
105     }
107   return 0; /* not a branch */
111 frv_is_float_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
113   switch (mach)
114     {
115     case bfd_mach_fr400:
116       return 0; /* No float insns */
117     default:
118       if (major >= FR500_MAJOR_F_1 && major <= FR500_MAJOR_F_8)
119         return 1; /* is a float insn */
120       break;
121     }
123   return 0; /* not a branch */
127 frv_is_media_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
129   switch (mach)
130     {
131     case bfd_mach_fr400:
132       if (major >= FR400_MAJOR_M_1 && major <= FR400_MAJOR_M_2)
133         return 1; /* is a media insn */
134       break;
135     default:
136       if (major >= FR500_MAJOR_M_1 && major <= FR500_MAJOR_M_8)
137         return 1; /* is a media insn */
138       break;
139     }
141   return 0; /* not a branch */
145 frv_is_branch_insn (const CGEN_INSN *insn)
147   if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
148                            bfd_mach_fr400))
149     return 1;
150   if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
151                            bfd_mach_fr500))
152     return 1;
154   return 0;
158 frv_is_float_insn (const CGEN_INSN *insn)
160   if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
161                           bfd_mach_fr400))
162     return 1;
163   if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
164                           bfd_mach_fr500))
165     return 1;
167   return 0;
171 frv_is_media_insn (const CGEN_INSN *insn)
173   if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
174                           bfd_mach_fr400))
175     return 1;
176   if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
177                           bfd_mach_fr500))
178     return 1;
180   return 0;
183 /* This table represents the allowable packing for vliw insns for the fr400.
184    The fr400 has only 2 vliw slots. Represent this by not allowing any insns
185    in slots 2 and 3.
186    Subsets of any given row are also allowed.  */
187 static VLIW_COMBO fr400_allowed_vliw[] =
189   /*  slot0       slot1       slot2       slot3    */
190   {  UNIT_I0,    UNIT_I1,    UNIT_NIL,   UNIT_NIL  },
191   {  UNIT_I0,    UNIT_FM0,   UNIT_NIL,   UNIT_NIL  },
192   {  UNIT_I0,    UNIT_B0,    UNIT_NIL,   UNIT_NIL  },
193   {  UNIT_FM0,   UNIT_FM1,   UNIT_NIL,   UNIT_NIL  },
194   {  UNIT_FM0,   UNIT_B0,    UNIT_NIL,   UNIT_NIL  },
195   {  UNIT_B0,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL  },
196   {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  },
197   {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  }
200 /* This table represents the allowable packing for vliw insns for the fr500.
201    Subsets of any given row are also allowed.  */
202 static VLIW_COMBO fr500_allowed_vliw[] =
204   /*  slot0       slot1       slot2       slot3    */
205   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1  },
206   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0   },
207   {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0   },
208   {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1   },
209   {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1   },
210   {  UNIT_I0,    UNIT_B0,    UNIT_B1,    UNIT_NIL  },
211   {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1   },
212   {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL  },
213   {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL  },
214   {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  },
215   {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  }
218 /* Some insns are assigned specialized implementation units which map to
219    different actual implementation units on different machines.  These
220    tables perform that mapping.  */
221 static CGEN_ATTR_VALUE_TYPE fr400_unit_mapping[] =
223 /* unit in insn    actual unit */
224 /* NIL      */     UNIT_NIL,
225 /* I0       */     UNIT_I0,
226 /* I1       */     UNIT_I1,
227 /* I01      */     UNIT_I01, 
228 /* FM0      */     UNIT_FM0,
229 /* FM1      */     UNIT_FM1,
230 /* FM01     */     UNIT_FM01,
231 /* B0       */     UNIT_B0,  /* branches only in B0 unit.  */
232 /* B1       */     UNIT_B0,
233 /* B01      */     UNIT_B0,
234 /* C        */     UNIT_C,
235 /* MULT-DIV */     UNIT_I0,  /* multiply and divide only in I0 unit.  */
236 /* LOAD     */     UNIT_I0   /* load                only in I0 unit.  */
239 static CGEN_ATTR_VALUE_TYPE fr500_unit_mapping[] =
241 /* unit in insn    actual unit */
242 /* NIL      */     UNIT_NIL,
243 /* I0       */     UNIT_I0,
244 /* I1       */     UNIT_I1,
245 /* I01      */     UNIT_I01, 
246 /* FM0      */     UNIT_FM0,
247 /* FM1      */     UNIT_FM1,
248 /* FM01     */     UNIT_FM01,
249 /* B0       */     UNIT_B0,
250 /* B1       */     UNIT_B1,
251 /* B01      */     UNIT_B01,
252 /* C        */     UNIT_C,
253 /* MULT-DIV */     UNIT_I01, /* multiply and divide in I0 or I1 unit.  */
254 /* LOAD     */     UNIT_I01  /* load                in I0 or I1 unit.  */
257 void
258 frv_vliw_reset (FRV_VLIW *vliw, unsigned long mach, unsigned long elf_flags)
260   vliw->next_slot = 0;
261   vliw->constraint_violation = 0;
262   vliw->mach = mach;
263   vliw->elf_flags = elf_flags;
265   switch (mach)
266     {
267     case bfd_mach_fr400:
268       vliw->current_vliw = fr400_allowed_vliw;
269       vliw->unit_mapping = fr400_unit_mapping;
270       break;
271     default:
272       vliw->current_vliw = fr500_allowed_vliw;
273       vliw->unit_mapping = fr500_unit_mapping;
274       break;
275     }
278 /* Return 1 if unit1 is a match for unit2.
279    Unit1 comes from the insn's UNIT attribute. unit2 comes from one of the
280    *_allowed_vliw tables above.  */
281 static int
282 match_unit (FRV_VLIW *vliw,
283             CGEN_ATTR_VALUE_TYPE unit1, CGEN_ATTR_VALUE_TYPE unit2)
285   /* Map any specialized implementation units to actual ones.  */
286   unit1 = vliw->unit_mapping[unit1];
288   if (unit1 == unit2)
289     return 1;
290   if (unit1 < unit2)
291     return 0;
293   switch (unit1)
294     {
295     case UNIT_I01:
296     case UNIT_FM01:
297     case UNIT_B01:
298       /* The 01 versions of these units are within 2 enums of the 0 or 1
299          versions.  */
300       if (unit1 - unit2 <= 2)
301         return 1;
302       break;
303     default:
304       break;
305     }
307   return 0;
310 /* Return 1 if the vliws match, 0 otherwise.  */
312 static int
313 match_vliw (VLIW_COMBO *vliw1, VLIW_COMBO *vliw2, int vliw_size)
315   int i;
317   for (i = 0; i < vliw_size; ++i)
318     {
319       if ((*vliw1)[i] != (*vliw2)[i])
320         return 0;
321     }
323   return 1;
326 /* Find the next vliw vliw in the table that can accomodate the new insn.
327    If one is found then return it. Otherwise return NULL.  */
329 static VLIW_COMBO *
330 add_next_to_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE unit)
332   int           next    = vliw->next_slot;
333   VLIW_COMBO    *current = vliw->current_vliw;
334   VLIW_COMBO    *potential;
336   if (next <= 0)
337     abort (); /* Should never happen */
339   /* The table is sorted by units allowed within slots, so vliws with
340      identical starting sequences are together.  */
341   potential = current;
342   do
343     {
344       if (match_unit (vliw, unit, (*potential)[next]))
345         return potential;
346       ++potential;
347     }
348   while (match_vliw (potential, current, next));
350   return NULL;
353 /* Look for the given major insn type in the given vliw. Return 1 if found,
354    return 0 otherwise.  */
356 static int
357 find_major_in_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major)
359   int i;
361   for (i = 0; i < vliw->next_slot; ++i)
362     if (vliw->major[i] == major)
363       return 1;
365   return 0;
368 /* Check for constraints between the insns in the vliw due to major insn
369    types.  */
371 static int
372 fr400_check_insn_major_constraints (
373   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
376   /* In the cpu file, all media insns are represented as being allowed in
377      both media units. This makes it easier since this is the case for fr500.
378      Catch the invalid combinations here.  Insns of major class FR400_MAJOR_M_2
379      cannot coexist with any other media insn in a vliw.  */
380   switch (major)
381     {
382     case FR400_MAJOR_M_2:
383       return ! find_major_in_vliw (vliw, FR400_MAJOR_M_1)
384         &&   ! find_major_in_vliw (vliw, FR400_MAJOR_M_2);
385     default:
386       break;
387     }
388   return 1;
391 static int
392 fr500_check_insn_major_constraints (
393   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
396   /* TODO: A table might be faster for some of the more complex instances
397      here.  */
398   switch (major)
399     {
400     case FR500_MAJOR_I_1:
401     case FR500_MAJOR_I_4:
402     case FR500_MAJOR_I_5:
403     case FR500_MAJOR_I_6:
404     case FR500_MAJOR_B_1:
405     case FR500_MAJOR_B_2:
406     case FR500_MAJOR_B_3:
407     case FR500_MAJOR_B_4:
408     case FR500_MAJOR_B_5:
409     case FR500_MAJOR_B_6:
410     case FR500_MAJOR_F_4:
411     case FR500_MAJOR_F_8:
412     case FR500_MAJOR_M_8:
413       return 1; /* OK */
414     case FR500_MAJOR_I_2:
415       /* Cannot coexist with I-3 insn.  */
416       return ! find_major_in_vliw (vliw, FR500_MAJOR_I_3);
417     case FR500_MAJOR_I_3:
418       /* Cannot coexist with I-2 insn.  */
419       return ! find_major_in_vliw (vliw, FR500_MAJOR_I_2);
420     case FR500_MAJOR_F_1:
421     case FR500_MAJOR_F_2:
422       /* Cannot coexist with F-5, F-6, or M-7 insn.  */
423       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
424         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
425         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
426     case FR500_MAJOR_F_3:
427       /* Cannot coexist with F-7, or M-7 insn.  */
428       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
429         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
430     case FR500_MAJOR_F_5:
431       /* Cannot coexist with F-1, F-2, F-6, F-7, or M-7 insn.  */
432       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
433         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
434         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
435         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
436         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
437     case FR500_MAJOR_F_6:
438       /* Cannot coexist with F-1, F-2, F-5, F-6, or M-7 insn.  */
439       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
440         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
441         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
442         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
443         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
444     case FR500_MAJOR_F_7:
445       /* Cannot coexist with F-3, F-5, F-7, or M-7 insn.  */
446       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
447         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
448         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
449         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
450     case FR500_MAJOR_M_1:
451       /* Cannot coexist with M-7 insn.  */
452       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
453     case FR500_MAJOR_M_2:
454     case FR500_MAJOR_M_3:
455       /* Cannot coexist with M-5, M-6 or M-7 insn.  */
456       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
457         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
458         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
459     case FR500_MAJOR_M_4:
460       /* Cannot coexist with M-6 insn.  */
461       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_6);
462     case FR500_MAJOR_M_5:
463       /* Cannot coexist with M-2, M-3, M-5, M-6  or M-7 insn.  */
464       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
465         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
466         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
467         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
468         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
469     case FR500_MAJOR_M_6:
470       /* Cannot coexist with M-2, M-3, M-4, M-5, M-6  or M-7 insn.  */
471       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
472         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
473         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_4)
474         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
475         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
476         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
477     case FR500_MAJOR_M_7:
478       /* Cannot coexist with M-1, M-2, M-3, M-5, M-6  or M-7 insn.  */
479       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_1)
480         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
481         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
482         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
483         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
484         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7)
485         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
486         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
487         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
488         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
489         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
490         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7);
491     default:
492       abort ();
493       break;
494     }
495   return 1;
498 static int
499 check_insn_major_constraints (
500   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
503   int rc;
504   switch (vliw->mach)
505     {
506     case bfd_mach_fr400:
507       rc = fr400_check_insn_major_constraints (vliw, major);
508       break;
509     default:
510       rc = fr500_check_insn_major_constraints (vliw, major);
511       break;
512     }
513   return rc;
516 /* Add in insn to the VLIW vliw if possible. Return 0 if successful,
517    non-zero otherwise.  */
519 frv_vliw_add_insn (FRV_VLIW *vliw, const CGEN_INSN *insn)
521   int index;
522   CGEN_ATTR_VALUE_TYPE major;
523   CGEN_ATTR_VALUE_TYPE unit;
524   VLIW_COMBO *new_vliw;
526   if (vliw->constraint_violation || CGEN_INSN_INVALID_P (insn))
527     return 1;
529   index = vliw->next_slot;
530   if (index >= FRV_VLIW_SIZE)
531     return 1;
533   unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
534   if (unit == UNIT_NIL)
535     abort (); /* no UNIT specified for this insn in frv.cpu  */
537   if (vliw->mach == bfd_mach_fr400)
538     major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR);
539   else
540     major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR);
542   if (index <= 0)
543     {
544       /* Any insn can be added to slot 0.  */
545       while (! match_unit (vliw, unit, (*vliw->current_vliw)[0]))
546         ++vliw->current_vliw;
547       vliw->major[0] = major;
548       vliw->next_slot = 1;
549       return 0;
550     }
552   /* If there are already insns in the vliw(s) check to see that
553      this one can be added.  Do this by finding an allowable vliw
554      combination that can accept the new insn.  */
555   if (! (vliw->elf_flags & EF_FRV_NOPACK))
556     {
557       new_vliw = add_next_to_vliw (vliw, unit);
558       if (new_vliw && check_insn_major_constraints (vliw, major))
559         {
560           vliw->current_vliw = new_vliw;
561           vliw->major[index] = major;
562           vliw->next_slot++;
563           return 0;
564         }
566       /* The frv machine supports all packing conbinations.  If we fail,
567          to add the insn, then it could not be handled as if it was the fr500.
568          Just return as if it was handled ok.  */
569       if (vliw->mach == bfd_mach_frv)
570         return 0;
571     }
573   vliw->constraint_violation = 1;
574   return 1;
578 spr_valid (regno)
579      long regno;
581   if (regno < 0)     return 0;
582   if (regno <= 4095) return 1;
583   return 0;
585 /* -- */
587 /* -- asm.c */
588 static const char * parse_ulo16
589   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
590 static const char * parse_uslo16
591   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
592 static const char * parse_uhi16
593   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
594 static long parse_register_number
595   PARAMS ((const char **));
596 static const char * parse_spr
597   PARAMS ((CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *));
598 static const char * parse_d12
599   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
600 static const char * parse_s12
601   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
602 static const char * parse_u12
603   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
605 static const char *
606 parse_ulo16 (cd, strp, opindex, valuep)
607      CGEN_CPU_DESC cd;
608      const char **strp;
609      int opindex;
610      unsigned long *valuep;
612   const char *errmsg;
613   enum cgen_parse_operand_result result_type;
614   bfd_vma value;
616   if (**strp == '#' || **strp == '%')
617     {
618       if (strncasecmp (*strp + 1, "lo(", 3) == 0)
619         {
620           *strp += 4;
621           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
622                                        &result_type, &value);
623           if (**strp != ')')
624             return "missing `)'";
625           ++*strp;
626           if (errmsg == NULL
627               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
628             value &= 0xffff;
629           *valuep = value;
630           return errmsg;
631         }
632       if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
633         {
634           *strp += 9;
635           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELLO,
636                                        &result_type, &value);
637           if (**strp != ')')
638             return "missing ')'";
639           ++*strp;
640           if (errmsg == NULL
641               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
642             value >>= 16;
643           *valuep = value;
644           return errmsg;
645         }
646     }
647   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
650 static const char *
651 parse_uslo16 (cd, strp, opindex, valuep)
652      CGEN_CPU_DESC cd;
653      const char **strp;
654      int opindex;
655      unsigned long *valuep;
657   const char *errmsg;
658   enum cgen_parse_operand_result result_type;
659   bfd_vma value;
661   if (**strp == '#' || **strp == '%')
662     {
663       if (strncasecmp (*strp + 1, "lo(", 3) == 0)
664         {
665           *strp += 4;
666           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
667                                        &result_type, &value);
668           if (**strp != ')')
669             return "missing `)'";
670           ++*strp;
671           if (errmsg == NULL
672               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
673             value &= 0xffff;
674           *valuep = value;
675           return errmsg;
676         }
677       else if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
678         {
679           *strp += 9;
680           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELLO,
681                                        &result_type, &value);
682           if (**strp != ')')
683             return "missing ')'";
684           ++*strp;
685           if (errmsg == NULL
686               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
687             value &= 0xffff;
688           *valuep = value;
689           return errmsg;
690         }
691     }
692   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
695 static const char *
696 parse_uhi16 (cd, strp, opindex, valuep)
697      CGEN_CPU_DESC cd;
698      const char **strp;
699      int opindex;
700      unsigned long *valuep;
702   const char *errmsg;
703   enum cgen_parse_operand_result result_type;
704   bfd_vma value;
706   if (**strp == '#' || **strp == '%')
707     {
708       if (strncasecmp (*strp + 1, "hi(", 3) == 0)
709         {
710           *strp += 4;
711           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_HI16,
712                                        &result_type, &value);
713           if (**strp != ')')
714             return "missing `)'";
715           ++*strp;
716           if (errmsg == NULL
717               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
718             value >>= 16;
719           *valuep = value;
720           return errmsg;
721         }
722       else if (strncasecmp (*strp + 1, "gprelhi(", 8) == 0)
723         {
724           *strp += 9;
725           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELHI,
726                                        &result_type, &value);
727           if (**strp != ')')
728             return "missing ')'";
729           ++*strp;
730           if (errmsg == NULL
731               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
732             value >>= 16;
733           *valuep = value;
734           return errmsg;
735         }
736     }
737   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
740 static long
741 parse_register_number (strp)
742      const char **strp;
744   int regno;
745   if (**strp < '0' || **strp > '9')
746     return -1; /* error */
748   regno = **strp - '0';
749   for (++*strp; **strp >= '0' && **strp <= '9'; ++*strp)
750     regno = regno * 10 + (**strp - '0');
752   return regno;
755 static const char *
756 parse_spr (cd, strp, table, valuep)
757      CGEN_CPU_DESC cd;
758      const char **strp;
759      CGEN_KEYWORD * table;
760      long *valuep;
762   const char *save_strp;
763   long regno;
765   /* Check for spr index notation.  */
766   if (strncasecmp (*strp, "spr[", 4) == 0)
767     {
768       *strp += 4;
769       regno = parse_register_number (strp);
770       if (**strp != ']')
771         return "missing `]'";
772       ++*strp;
773       if (! spr_valid (regno))
774         return "Special purpose register number is out of range";
775       *valuep = regno;
776       return NULL;
777     }
779   save_strp = *strp;
780   regno = parse_register_number (strp);
781   if (regno != -1)
782     {
783       if (! spr_valid (regno))
784         return "Special purpose register number is out of range";
785       *valuep = regno;
786       return NULL;
787     }
789   *strp = save_strp;
790   return cgen_parse_keyword (cd, strp, table, valuep);
793 static const char *
794 parse_d12 (cd, strp, opindex, valuep)
795      CGEN_CPU_DESC cd;
796      const char **strp;
797      int opindex;
798      long *valuep;
800   const char *errmsg;
801   enum cgen_parse_operand_result result_type;
802   bfd_vma value;
804   /* Check for small data reference.  */
805   if (**strp == '#' || **strp == '%')
806     {
807       if (strncasecmp (*strp + 1, "gprel12(", 8) == 0)
808         {
809           *strp += 9;
810           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPREL12,
811                                        &result_type, &value);
812           if (**strp != ')')
813             return "missing `)'";
814           ++*strp;
815           *valuep = value;
816           return errmsg;
817         }
818     }
819   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
822 static const char *
823 parse_s12 (cd, strp, opindex, valuep)
824      CGEN_CPU_DESC cd;
825      const char **strp;
826      int opindex;
827      long *valuep;
829   const char *errmsg;
830   enum cgen_parse_operand_result result_type;
831   bfd_vma value;
833   /* Check for small data reference.  */
834   if ((**strp == '#' || **strp == '%')
835       && strncasecmp (*strp + 1, "gprel12(", 8) == 0)
836     {
837       *strp += 9;
838       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPREL12,
839                                     &result_type, &value);
840       if (**strp != ')')
841         return "missing `)'";
842       ++*strp;
843       *valuep = value;
844       return errmsg;
845     }
846   else
847     {
848       if (**strp == '#')
849         ++*strp;
850       return cgen_parse_signed_integer (cd, strp, opindex, valuep);
851     }
854 static const char *
855 parse_u12 (cd, strp, opindex, valuep)
856      CGEN_CPU_DESC cd;
857      const char **strp;
858      int opindex;
859      long *valuep;
861   const char *errmsg;
862   enum cgen_parse_operand_result result_type;
863   bfd_vma value;
865   /* Check for small data reference.  */
866   if ((**strp == '#' || **strp == '%')
867       && strncasecmp (*strp + 1, "gprel12(", 8) == 0)
868     {
869       *strp += 9;
870       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELU12,
871                                     &result_type, &value);
872       if (**strp != ')')
873         return "missing `)'";
874       ++*strp;
875       *valuep = value;
876       return errmsg;
877     }
878   else
879     {
880       if (**strp == '#')
881         ++*strp;
882       return cgen_parse_signed_integer (cd, strp, opindex, valuep);
883     }
886 /* -- */
888 /* -- dis.c */
889 static void print_spr
890   PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned));
891 static void print_hi
892   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
893 static void print_lo
894   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
896 static void
897 print_spr (cd, dis_info, names, regno, attrs)
898      CGEN_CPU_DESC cd;
899      PTR dis_info;
900      CGEN_KEYWORD *names;
901      long regno;
902      unsigned int attrs;
904   /* Use the register index format for any unnamed registers.  */
905   if (cgen_keyword_lookup_value (names, regno) == NULL)
906     {
907       disassemble_info *info = (disassemble_info *) dis_info;
908       (*info->fprintf_func) (info->stream, "spr[%ld]", regno);
909     }
910   else
911     print_keyword (cd, dis_info, names, regno, attrs);
914 static void
915 print_hi (cd, dis_info, value, attrs, pc, length)
916      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
917      PTR dis_info;
918      long value;
919      unsigned int attrs ATTRIBUTE_UNUSED;
920      bfd_vma pc ATTRIBUTE_UNUSED;
921      int length ATTRIBUTE_UNUSED;
923   disassemble_info *info = (disassemble_info *) dis_info;
924   if (value)
925     (*info->fprintf_func) (info->stream, "0x%lx", value);
926   else
927     (*info->fprintf_func) (info->stream, "hi(0x%lx)", value);
930 static void
931 print_lo (cd, dis_info, value, attrs, pc, length)
932      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
933      PTR dis_info;
934      long value;
935      unsigned int attrs ATTRIBUTE_UNUSED;
936      bfd_vma pc ATTRIBUTE_UNUSED;
937      int length ATTRIBUTE_UNUSED;
939   disassemble_info *info = (disassemble_info *) dis_info;
940   if (value)
941     (*info->fprintf_func) (info->stream, "0x%lx", value);
942   else
943     (*info->fprintf_func) (info->stream, "lo(0x%lx)", value);
946 /* -- */