* elf32-frv.c (elf32_frv_always_size_sections): Initialize pointer
[binutils.git] / cpu / frv.opc
blob03c0f3e1437e1de03db7598dcf205f8b4cbc004c
1 /* Fujitsu FRV opcode support, for GNU Binutils.  -*- C -*-
3    Copyright 2000, 2001, 2003, 2004 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 /* Allows reason codes to be output when assembler errors occur.  */
49 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
51 /* Vliw support.  */
52 #define FRV_VLIW_SIZE 8 /* fr550 has largest vliw size of 8.  */
53 #define PAD_VLIW_COMBO ,UNIT_NIL,UNIT_NIL,UNIT_NIL,UNIT_NIL
54 typedef CGEN_ATTR_VALUE_TYPE VLIW_COMBO[FRV_VLIW_SIZE];
56 typedef struct
58   int                   next_slot;
59   int                   constraint_violation;
60   unsigned long         mach;
61   unsigned long         elf_flags;
62   CGEN_ATTR_VALUE_TYPE *unit_mapping;
63   VLIW_COMBO           *current_vliw;
64   CGEN_ATTR_VALUE_TYPE  major[FRV_VLIW_SIZE];
65   const CGEN_INSN*      insn[FRV_VLIW_SIZE];
66 } FRV_VLIW;
68 int frv_is_branch_major PARAMS ((CGEN_ATTR_VALUE_TYPE, unsigned long));
69 int frv_is_float_major  PARAMS ((CGEN_ATTR_VALUE_TYPE, unsigned long));
70 int frv_is_media_major  PARAMS ((CGEN_ATTR_VALUE_TYPE, unsigned long));
71 int frv_is_branch_insn  PARAMS ((const CGEN_INSN *));
72 int frv_is_float_insn   PARAMS ((const CGEN_INSN *));
73 int frv_is_media_insn   PARAMS ((const CGEN_INSN *));
74 void frv_vliw_reset     PARAMS ((FRV_VLIW *, unsigned long mach, unsigned long elf_flags));
75 int frv_vliw_add_insn   PARAMS ((FRV_VLIW *, const CGEN_INSN *));
76 int spr_valid           PARAMS ((long));
77 /* -- */
79 /* -- opc.c */
80 #include "elf/frv.h"
81 #include <stdio.h>
83 static int match_unit
84   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE, CGEN_ATTR_VALUE_TYPE));
85 static int match_vliw
86   PARAMS ((VLIW_COMBO *, VLIW_COMBO *, int));
87 static VLIW_COMBO * add_next_to_vliw
88   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
89 static int find_major_in_vliw
90   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
91 static int fr400_check_insn_major_constraints
92   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
93 static int fr500_check_insn_major_constraints
94   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
95 static int fr550_check_insn_major_constraints
96   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE, const CGEN_INSN *));
97 static int check_insn_major_constraints
98   PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE, const CGEN_INSN *));
101 frv_is_branch_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
103   switch (mach)
104     {
105     case bfd_mach_fr400:
106       if (major >= FR400_MAJOR_B_1 && major <= FR400_MAJOR_B_6)
107         return 1; /* is a branch */
108       break;
109     default:
110       if (major >= FR500_MAJOR_B_1 && major <= FR500_MAJOR_B_6)
111         return 1; /* is a branch */
112       break;
113     }
115   return 0; /* not a branch */
119 frv_is_float_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
121   switch (mach)
122     {
123     case bfd_mach_fr400:
124       return 0; /* No float insns */
125     default:
126       if (major >= FR500_MAJOR_F_1 && major <= FR500_MAJOR_F_8)
127         return 1; /* is a float insn */
128       break;
129     }
131   return 0; /* not a branch */
135 frv_is_media_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
137   switch (mach)
138     {
139     case bfd_mach_fr400:
140       if (major >= FR400_MAJOR_M_1 && major <= FR400_MAJOR_M_2)
141         return 1; /* is a media insn */
142       break;
143     default:
144       if (major >= FR500_MAJOR_M_1 && major <= FR500_MAJOR_M_8)
145         return 1; /* is a media insn */
146       break;
147     }
149   return 0; /* not a branch */
153 frv_is_branch_insn (const CGEN_INSN *insn)
155   if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
156                            bfd_mach_fr400))
157     return 1;
158   if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
159                            bfd_mach_fr500))
160     return 1;
162   return 0;
166 frv_is_float_insn (const CGEN_INSN *insn)
168   if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
169                           bfd_mach_fr400))
170     return 1;
171   if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
172                           bfd_mach_fr500))
173     return 1;
175   return 0;
179 frv_is_media_insn (const CGEN_INSN *insn)
181   if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
182                           bfd_mach_fr400))
183     return 1;
184   if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
185                           bfd_mach_fr500))
186     return 1;
188   return 0;
191 /* This table represents the allowable packing for vliw insns for the fr400.
192    The fr400 has only 2 vliw slots. Represent this by not allowing any insns
193    in the extra slots.
194    Subsets of any given row are also allowed.  */
195 static VLIW_COMBO fr400_allowed_vliw[] =
197   /*  slot0       slot1       slot2       slot3    */
198   {  UNIT_I0,    UNIT_I1,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
199   {  UNIT_I0,    UNIT_FM0,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
200   {  UNIT_I0,    UNIT_B0,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
201   {  UNIT_FM0,   UNIT_FM1,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
202   {  UNIT_FM0,   UNIT_B0,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
203   {  UNIT_B0,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
204   {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
205   {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO }
208 /* This table represents the allowable packing for vliw insns for the fr500.
209    The fr500 has only 4 vliw slots. Represent this by not allowing any insns
210    in the extra slots.
211    Subsets of any given row are also allowed.  */
212 static VLIW_COMBO fr500_allowed_vliw[] =
214   /*  slot0       slot1       slot2       slot3    */
215   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1  PAD_VLIW_COMBO },
216   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0   PAD_VLIW_COMBO },
217   {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0   PAD_VLIW_COMBO },
218   {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
219   {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
220   {  UNIT_I0,    UNIT_B0,    UNIT_B1,    UNIT_NIL  PAD_VLIW_COMBO },
221   {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
222   {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL  PAD_VLIW_COMBO },
223   {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
224   {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
225   {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO }
228 /* This table represents the allowable packing for vliw insns for the fr550.
229    Subsets of any given row are also allowed.  */
230 static VLIW_COMBO fr550_allowed_vliw[] =
232   /*  slot0       slot1       slot2       slot3       slot4       slot5       slot6       slot7   */
233   {  UNIT_I0,    UNIT_I1,    UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL },
234   {  UNIT_I0,    UNIT_I1,    UNIT_I2,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
235   {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
236   {  UNIT_I0,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
237   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_I3,    UNIT_FM3 },
238   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_I3,    UNIT_B0  },
239   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_FM3,   UNIT_B0  },
240   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_B0,    UNIT_B1  },
241   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1  },
242   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_B0,    UNIT_B1,    UNIT_NIL },
243   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1  },
244   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1  },
245   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL },
246   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
247   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1,    UNIT_NIL },
248   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_I2,    UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
249   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
250   {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1,    UNIT_NIL },
251   {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
252   {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
253   {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
254   {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
255   {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
256   {  UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
257   {  UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
258   {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
259   {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
260   {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL }
263 /* Some insns are assigned specialized implementation units which map to
264    different actual implementation units on different machines.  These
265    tables perform that mapping.  */
266 static CGEN_ATTR_VALUE_TYPE fr400_unit_mapping[] =
268 /* unit in insn    actual unit */
269 /* NIL      */     UNIT_NIL,
270 /* I0       */     UNIT_I0,
271 /* I1       */     UNIT_I1,
272 /* I01      */     UNIT_I01, 
273 /* I2       */     UNIT_NIL, /* no I2 or I3 unit */
274 /* I3       */     UNIT_NIL,
275 /* IALL     */     UNIT_I01, /* only I0 and I1 units */
276 /* FM0      */     UNIT_FM0,
277 /* FM1      */     UNIT_FM1,
278 /* FM01     */     UNIT_FM01,
279 /* FM2      */     UNIT_NIL, /* no F2 or M2 units */
280 /* FM3      */     UNIT_NIL, /* no F3 or M3 units */
281 /* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
282 /* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
283 /* B0       */     UNIT_B0,  /* branches only in B0 unit.  */
284 /* B1       */     UNIT_B0,
285 /* B01      */     UNIT_B0,
286 /* C        */     UNIT_C,
287 /* MULT-DIV */     UNIT_I0,  /* multiply and divide only in I0  unit.  */
288 /* IACC     */     UNIT_I01, /* iacc multiply       in I0 or I1 unit.  */
289 /* LOAD     */     UNIT_I0,  /* load                only in I0  unit.  */
290 /* STORE    */     UNIT_I0,  /* store               only in I0  unit.  */
291 /* SCAN     */     UNIT_I0,  /* scan                only in I0  unit.  */
292 /* DCPL     */     UNIT_C,   /* dcpl                only in C   unit.  */
293 /* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
294 /* MCLRACC-1*/     UNIT_FM0  /* mclracc,A==1   insn only in FM0 unit.  */
297 static CGEN_ATTR_VALUE_TYPE fr500_unit_mapping[] =
299 /* unit in insn    actual unit */
300 /* NIL      */     UNIT_NIL,
301 /* I0       */     UNIT_I0,
302 /* I1       */     UNIT_I1,
303 /* I01      */     UNIT_I01, 
304 /* I2       */     UNIT_NIL, /* no I2 or I3 unit */
305 /* I3       */     UNIT_NIL,
306 /* IALL     */     UNIT_I01, /* only I0 and I1 units */
307 /* FM0      */     UNIT_FM0,
308 /* FM1      */     UNIT_FM1,
309 /* FM01     */     UNIT_FM01,
310 /* FM2      */     UNIT_NIL, /* no F2 or M2 units */
311 /* FM3      */     UNIT_NIL, /* no F3 or M2 units */
312 /* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
313 /* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
314 /* B0       */     UNIT_B0,
315 /* B1       */     UNIT_B1,
316 /* B01      */     UNIT_B01,
317 /* C        */     UNIT_C,
318 /* MULT-DIV */     UNIT_I01, /* multiply and divide in I0 or I1 unit.  */
319 /* IACC     */     UNIT_NIL, /* iacc multiply       not implemented */
320 /* LOAD     */     UNIT_I01, /* load                in I0 or I1 unit.  */
321 /* STORE    */     UNIT_I0,  /* store               only in I0 unit.  */
322 /* SCAN     */     UNIT_I01, /* scan                in I0 or I1 unit.  */
323 /* DCPL     */     UNIT_C,   /* dcpl                only in C unit.  */
324 /* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
325 /* MCLRACC-1*/     UNIT_FM01 /* mclracc,A==1 in FM0 or FM1 unit.  */
328 static CGEN_ATTR_VALUE_TYPE fr550_unit_mapping[] =
330 /* unit in insn    actual unit */
331 /* NIL      */     UNIT_NIL,
332 /* I0       */     UNIT_I0,
333 /* I1       */     UNIT_I1,
334 /* I01      */     UNIT_I01, 
335 /* I2       */     UNIT_I2,
336 /* I3       */     UNIT_I3,
337 /* IALL     */     UNIT_IALL, 
338 /* FM0      */     UNIT_FM0,
339 /* FM1      */     UNIT_FM1,
340 /* FM01     */     UNIT_FM01,
341 /* FM2      */     UNIT_FM2,
342 /* FM3      */     UNIT_FM3,
343 /* FMALL    */     UNIT_FMALL,
344 /* FMLOW    */     UNIT_FM01, /* Only F0,F1,M0,M1 units */
345 /* B0       */     UNIT_B0,
346 /* B1       */     UNIT_B1,
347 /* B01      */     UNIT_B01,
348 /* C        */     UNIT_C,
349 /* MULT-DIV */     UNIT_I01,  /* multiply and divide in I0 or I1 unit.    */
350 /* IACC     */     UNIT_NIL,  /* iacc multiply       not implemented.     */
351 /* LOAD     */     UNIT_I01,  /* load                in I0 or I1 unit.    */
352 /* STORE    */     UNIT_I01,  /* store               in I0 or I1 unit.    */
353 /* SCAN     */     UNIT_IALL, /* scan                in any integer unit. */
354 /* DCPL     */     UNIT_I0,   /* dcpl                only in I0 unit.     */
355 /* MDUALACC */     UNIT_FMALL,/* media dual acc insn in all media units   */
356 /* MCLRACC-1*/     UNIT_FM01  /* mclracc,A==1 in FM0 or FM1 unit.         */
359 void
360 frv_vliw_reset (FRV_VLIW *vliw, unsigned long mach, unsigned long elf_flags)
362   vliw->next_slot = 0;
363   vliw->constraint_violation = 0;
364   vliw->mach = mach;
365   vliw->elf_flags = elf_flags;
367   switch (mach)
368     {
369     case bfd_mach_fr400:
370       vliw->current_vliw = fr400_allowed_vliw;
371       vliw->unit_mapping = fr400_unit_mapping;
372       break;
373     case bfd_mach_fr550:
374       vliw->current_vliw = fr550_allowed_vliw;
375       vliw->unit_mapping = fr550_unit_mapping;
376       break;
377     default:
378       vliw->current_vliw = fr500_allowed_vliw;
379       vliw->unit_mapping = fr500_unit_mapping;
380       break;
381     }
384 /* Return 1 if unit1 is a match for unit2.
385    Unit1 comes from the insn's UNIT attribute. unit2 comes from one of the
386    *_allowed_vliw tables above.  */
387 static int
388 match_unit (FRV_VLIW *vliw,
389             CGEN_ATTR_VALUE_TYPE unit1, CGEN_ATTR_VALUE_TYPE unit2)
391   /* Map any specialized implementation units to actual ones.  */
392   unit1 = vliw->unit_mapping[unit1];
394   if (unit1 == unit2)
395     return 1;
396   if (unit1 < unit2)
397     return 0;
399   switch (unit1)
400     {
401     case UNIT_I01:
402     case UNIT_FM01:
403     case UNIT_B01:
404       /* The 01 versions of these units are within 2 enums of the 0 or 1
405          versions.  */
406       if (unit1 - unit2 <= 2)
407         return 1;
408       break;
409     case UNIT_IALL:
410     case UNIT_FMALL:
411       /* The ALL versions of these units are within 5 enums of the 0, 1, 2 or 3
412          versions.  */
413       if (unit1 - unit2 <= 5)
414         return 1;
415       break;
416     default:
417       break;
418     }
420   return 0;
423 /* Return 1 if the vliws match, 0 otherwise.  */
425 static int
426 match_vliw (VLIW_COMBO *vliw1, VLIW_COMBO *vliw2, int vliw_size)
428   int i;
430   for (i = 0; i < vliw_size; ++i)
431     {
432       if ((*vliw1)[i] != (*vliw2)[i])
433         return 0;
434     }
436   return 1;
439 /* Find the next vliw vliw in the table that can accomodate the new insn.
440    If one is found then return it. Otherwise return NULL.  */
442 static VLIW_COMBO *
443 add_next_to_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE unit)
445   int           next    = vliw->next_slot;
446   VLIW_COMBO    *current = vliw->current_vliw;
447   VLIW_COMBO    *potential;
449   if (next <= 0)
450     {
451       fprintf (stderr, "frv-opc.c line %d: bad vliw->next_slot value.\n",
452                __LINE__);
453       abort (); /* Should never happen */
454     }
456   /* The table is sorted by units allowed within slots, so vliws with
457      identical starting sequences are together.  */
458   potential = current;
459   do
460     {
461       if (match_unit (vliw, unit, (*potential)[next]))
462         return potential;
463       ++potential;
464     }
465   while (match_vliw (potential, current, next));
467   return NULL;
470 /* Look for the given major insn type in the given vliw. Return 1 if found,
471    return 0 otherwise.  */
473 static int
474 find_major_in_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major)
476   int i;
478   for (i = 0; i < vliw->next_slot; ++i)
479     if (vliw->major[i] == major)
480       return 1;
482   return 0;
485 /* Check for constraints between the insns in the vliw due to major insn
486    types.  */
488 static int
489 fr400_check_insn_major_constraints (
490   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
493   /* In the cpu file, all media insns are represented as being allowed in
494      both media units. This makes it easier since this is the case for fr500.
495      Catch the invalid combinations here.  Insns of major class FR400_MAJOR_M_2
496      cannot coexist with any other media insn in a vliw.  */
497   switch (major)
498     {
499     case FR400_MAJOR_M_2:
500       return ! find_major_in_vliw (vliw, FR400_MAJOR_M_1)
501         &&   ! find_major_in_vliw (vliw, FR400_MAJOR_M_2);
502     default:
503       break;
504     }
505   return 1;
508 static int
509 find_unit_in_vliw (
510   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE unit
513   int i;
514   for (i = 0; i < vliw->next_slot; ++i)
515     if (CGEN_INSN_ATTR_VALUE (vliw->insn[i], CGEN_INSN_UNIT) == unit)
516       return 1;
518   return 0; /* not found */
521 static int
522 find_major_in_slot (
523   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, CGEN_ATTR_VALUE_TYPE slot
526   int i;
528   for (i = 0; i < vliw->next_slot; ++i)
529     if (vliw->major[i] == major && (*vliw->current_vliw)[i] == slot)
530       return 1;
532   return 0;
535 static int
536 fr550_find_media_in_vliw (FRV_VLIW *vliw)
538   int i;
540   for (i = 0; i < vliw->next_slot; ++i)
541     {
542       if (vliw->major[i] < FR550_MAJOR_M_1 || vliw->major[i] > FR550_MAJOR_M_5)
543         continue;
545       /* Found a media insn, however, MNOP and MCLRACC don't count.  */
546       if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MNOP
547           || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_0
548           || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_1)
549         continue;
551       return 1; /* found one */
552     }
554   return 0;
557 static int
558 fr550_find_float_in_vliw (FRV_VLIW *vliw)
560   int i;
562   for (i = 0; i < vliw->next_slot; ++i)
563     {
564       if (vliw->major[i] < FR550_MAJOR_F_1 || vliw->major[i] > FR550_MAJOR_F_4)
565         continue;
567       /* Found a floating point insn, however, FNOP doesn't count.  */
568       if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_FNOP)
569         continue;
571       return 1; /* found one */
572     }
574   return 0;
577 static int
578 fr550_check_insn_major_constraints (
579   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, const CGEN_INSN *insn
582   CGEN_ATTR_VALUE_TYPE unit;
583   CGEN_ATTR_VALUE_TYPE slot = (*vliw->current_vliw)[vliw->next_slot];
584   switch (slot)
585     {
586     case UNIT_I2:
587       /* If it's a store, then there must be another store in I1 */
588       unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
589       if (unit == UNIT_STORE)
590         return find_unit_in_vliw (vliw, UNIT_STORE);
591       break;
592     case UNIT_FM2:
593     case UNIT_FM3:
594       /* Floating point insns other than FNOP in slot f2 or f3 cannot coexist with
595          media insns.  */
596       if (major >= FR550_MAJOR_F_1 && major <= FR550_MAJOR_F_4
597           && CGEN_INSN_NUM (insn) != FRV_INSN_FNOP)
598         return ! fr550_find_media_in_vliw (vliw);
599       /* Media insns other than MNOP in slot m2 or m3 cannot coexist with
600          floating point insns.  */
601       if (major >= FR550_MAJOR_M_1 && major <= FR550_MAJOR_M_5
602           && CGEN_INSN_NUM (insn) != FRV_INSN_MNOP)
603         return ! fr550_find_float_in_vliw (vliw);
604       /* F-2 in slot f2 or f3 cannot coexist with F-2 or F-4 in slot f1 or f2
605          respectively.
606        */
607       if (major == FR550_MAJOR_F_2)
608         return ! find_major_in_slot (vliw, FR550_MAJOR_F_2, slot - (UNIT_FM2 - UNIT_FM0))
609           &&   ! find_major_in_slot (vliw, FR550_MAJOR_F_4, slot - (UNIT_FM2 - UNIT_FM0));
610       /* M-2 or M-5 in slot m2 or m3 cannot coexist with M-2 in slot m1 or m2
611          respectively.  */
612       if (major == FR550_MAJOR_M_2 || major == FR550_MAJOR_M_5)
613         return ! find_major_in_slot (vliw, FR550_MAJOR_M_2, slot - (UNIT_FM2 - UNIT_FM0));
614       /* M-4 in slot m2 or m3 cannot coexist with M-4 in slot m1 or m2
615          respectively.  */
616       if (major == FR550_MAJOR_M_4)
617         return ! find_major_in_slot (vliw, FR550_MAJOR_M_4, slot - (UNIT_FM2 - UNIT_FM0));
618       break;
619     default:
620       break;
621     }
622   return 1; /* all ok */
625 static int
626 fr500_check_insn_major_constraints (
627   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
630   /* TODO: A table might be faster for some of the more complex instances
631      here.  */
632   switch (major)
633     {
634     case FR500_MAJOR_I_1:
635     case FR500_MAJOR_I_4:
636     case FR500_MAJOR_I_5:
637     case FR500_MAJOR_I_6:
638     case FR500_MAJOR_B_1:
639     case FR500_MAJOR_B_2:
640     case FR500_MAJOR_B_3:
641     case FR500_MAJOR_B_4:
642     case FR500_MAJOR_B_5:
643     case FR500_MAJOR_B_6:
644     case FR500_MAJOR_F_4:
645     case FR500_MAJOR_F_8:
646     case FR500_MAJOR_M_8:
647       return 1; /* OK */
648     case FR500_MAJOR_I_2:
649       /* Cannot coexist with I-3 insn.  */
650       return ! find_major_in_vliw (vliw, FR500_MAJOR_I_3);
651     case FR500_MAJOR_I_3:
652       /* Cannot coexist with I-2 insn.  */
653       return ! find_major_in_vliw (vliw, FR500_MAJOR_I_2);
654     case FR500_MAJOR_F_1:
655     case FR500_MAJOR_F_2:
656       /* Cannot coexist with F-5, F-6, or M-7 insn.  */
657       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
658         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
659         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
660     case FR500_MAJOR_F_3:
661       /* Cannot coexist with F-7, or M-7 insn.  */
662       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
663         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
664     case FR500_MAJOR_F_5:
665       /* Cannot coexist with F-1, F-2, F-6, F-7, or M-7 insn.  */
666       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
667         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
668         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
669         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
670         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
671     case FR500_MAJOR_F_6:
672       /* Cannot coexist with F-1, F-2, F-5, F-6, or M-7 insn.  */
673       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
674         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
675         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
676         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
677         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
678     case FR500_MAJOR_F_7:
679       /* Cannot coexist with F-3, F-5, F-7, or M-7 insn.  */
680       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
681         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
682         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
683         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
684     case FR500_MAJOR_M_1:
685       /* Cannot coexist with M-7 insn.  */
686       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
687     case FR500_MAJOR_M_2:
688     case FR500_MAJOR_M_3:
689       /* Cannot coexist with M-5, M-6 or M-7 insn.  */
690       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
691         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
692         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
693     case FR500_MAJOR_M_4:
694       /* Cannot coexist with M-6 insn.  */
695       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_6);
696     case FR500_MAJOR_M_5:
697       /* Cannot coexist with M-2, M-3, M-5, M-6  or M-7 insn.  */
698       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
699         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
700         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
701         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
702         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
703     case FR500_MAJOR_M_6:
704       /* Cannot coexist with M-2, M-3, M-4, M-5, M-6  or M-7 insn.  */
705       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
706         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
707         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_4)
708         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
709         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
710         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
711     case FR500_MAJOR_M_7:
712       /* Cannot coexist with M-1, M-2, M-3, M-5, M-6  or M-7 insn.  */
713       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_1)
714         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
715         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
716         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
717         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
718         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7)
719         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
720         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
721         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
722         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
723         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
724         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7);
725     default:
726       fprintf (stderr, "frv-opc.c, line %d: bad major code, aborting.\n",
727                __LINE__);
728       abort ();
729       break;
730     }
731   return 1;
734 static int
735 check_insn_major_constraints (
736   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, const CGEN_INSN *insn
739   int rc;
740   switch (vliw->mach)
741     {
742     case bfd_mach_fr400:
743       rc = fr400_check_insn_major_constraints (vliw, major);
744       break;
745     case bfd_mach_fr550:
746       rc = fr550_check_insn_major_constraints (vliw, major, insn);
747       break;
748     default:
749       rc = fr500_check_insn_major_constraints (vliw, major);
750       break;
751     }
752   return rc;
755 /* Add in insn to the VLIW vliw if possible. Return 0 if successful,
756    non-zero otherwise.  */
758 frv_vliw_add_insn (FRV_VLIW *vliw, const CGEN_INSN *insn)
760   int index;
761   CGEN_ATTR_VALUE_TYPE major;
762   CGEN_ATTR_VALUE_TYPE unit;
763   VLIW_COMBO *new_vliw;
765   if (vliw->constraint_violation || CGEN_INSN_INVALID_P (insn))
766     return 1;
768   index = vliw->next_slot;
769   if (index >= FRV_VLIW_SIZE)
770     return 1;
772   unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
773   if (unit == UNIT_NIL)
774     {
775       fprintf (stderr, "frv-opc.c line %d: bad insn unit.\n",
776                __LINE__);
777       abort (); /* no UNIT specified for this insn in frv.cpu  */
778     }
780   switch (vliw->mach)
781     {
782     case bfd_mach_fr400:
783       major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR);
784       break;
785     case bfd_mach_fr550:
786       major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR550_MAJOR);
787       break;
788     default:
789       major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR);
790       break;
791     }
793   if (index <= 0)
794     {
795       /* Any insn can be added to slot 0.  */
796       while (! match_unit (vliw, unit, (*vliw->current_vliw)[0]))
797         ++vliw->current_vliw;
798       vliw->major[0] = major;
799       vliw->insn[0] = insn;
800       vliw->next_slot = 1;
801       return 0;
802     }
804   /* If there are already insns in the vliw(s) check to see that
805      this one can be added.  Do this by finding an allowable vliw
806      combination that can accept the new insn.  */
807   if (! (vliw->elf_flags & EF_FRV_NOPACK))
808     {
809       new_vliw = add_next_to_vliw (vliw, unit);
810       if (new_vliw && check_insn_major_constraints (vliw, major, insn))
811         {
812           vliw->current_vliw = new_vliw;
813           vliw->major[index] = major;
814           vliw->insn[index] = insn;
815           vliw->next_slot++;
816           return 0;
817         }
819       /* The frv machine supports all packing conbinations.  If we fail,
820          to add the insn, then it could not be handled as if it was the fr500.
821          Just return as if it was handled ok.  */
822       if (vliw->mach == bfd_mach_frv)
823         return 0;
824     }
826   vliw->constraint_violation = 1;
827   return 1;
831 spr_valid (regno)
832      long regno;
834   if (regno < 0)     return 0;
835   if (regno <= 4095) return 1;
836   return 0;
838 /* -- */
840 /* -- asm.c */
841 static const char * parse_ulo16
842   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
843 static const char * parse_uslo16
844   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
845 static const char * parse_uhi16
846   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
847 static long parse_register_number
848   PARAMS ((const char **));
849 static const char * parse_spr
850   PARAMS ((CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *));
851 static const char * parse_d12
852   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
853 static const char * parse_s12
854   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
855 static const char * parse_u12
856   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
857 static const char * parse_even_register
858   PARAMS ((CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *));
859 static const char * parse_A0
860   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
861 static const char * parse_A1
862   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
863 static const char * parse_A
864   PARAMS ((CGEN_CPU_DESC, const char **, int, long *, long));
866 static const char *
867 parse_ulo16 (cd, strp, opindex, valuep)
868      CGEN_CPU_DESC cd;
869      const char **strp;
870      int opindex;
871      unsigned long *valuep;
873   const char *errmsg;
874   enum cgen_parse_operand_result result_type;
875   bfd_vma value;
877   if (**strp == '#' || **strp == '%')
878     {
879       if (strncasecmp (*strp + 1, "lo(", 3) == 0)
880         {
881           *strp += 4;
882           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
883                                        &result_type, &value);
884           if (**strp != ')')
885             return "missing `)'";
886           ++*strp;
887           if (errmsg == NULL
888               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
889             value &= 0xffff;
890           *valuep = value;
891           return errmsg;
892         }
893       if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
894         {
895           *strp += 9;
896           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELLO,
897                                        &result_type, &value);
898           if (**strp != ')')
899             return "missing ')'";
900           ++*strp;
901           if (errmsg == NULL
902               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
903             value &= 0xffff;
904           *valuep = value;
905           return errmsg;
906         }
907       else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
908         {
909           *strp += 7;
910           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTLO,
911                                        &result_type, &value);
912           if (**strp != ')')
913             return "missing ')'";
914           ++*strp;
915           if (errmsg == NULL
916               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
917             value &= 0xffff;
918           *valuep = value;
919           return errmsg;
920         }
921       else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
922         {
923           *strp += 15;
924           errmsg = cgen_parse_address (cd, strp, opindex,
925                                        BFD_RELOC_FRV_FUNCDESC_GOTLO,
926                                        &result_type, &value);
927           if (**strp != ')')
928             return "missing ')'";
929           ++*strp;
930           if (errmsg == NULL
931               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
932             value &= 0xffff;
933           *valuep = value;
934           return errmsg;
935         }
936       else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
937         {
938           *strp += 10;
939           errmsg = cgen_parse_address (cd, strp, opindex,
940                                        BFD_RELOC_FRV_GOTOFFLO,
941                                        &result_type, &value);
942           if (**strp != ')')
943             return "missing ')'";
944           ++*strp;
945           if (errmsg == NULL
946               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
947             value &= 0xffff;
948           *valuep = value;
949           return errmsg;
950         }
951       else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
952         {
953           *strp += 18;
954           errmsg = cgen_parse_address (cd, strp, opindex,
955                                        BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
956                                        &result_type, &value);
957           if (**strp != ')')
958             return "missing ')'";
959           ++*strp;
960           if (errmsg == NULL
961               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
962             value &= 0xffff;
963           *valuep = value;
964           return errmsg;
965         }
966     }
967   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
970 static const char *
971 parse_uslo16 (cd, strp, opindex, valuep)
972      CGEN_CPU_DESC cd;
973      const char **strp;
974      int opindex;
975      unsigned long *valuep;
977   const char *errmsg;
978   enum cgen_parse_operand_result result_type;
979   bfd_vma value;
981   if (**strp == '#' || **strp == '%')
982     {
983       if (strncasecmp (*strp + 1, "lo(", 3) == 0)
984         {
985           *strp += 4;
986           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
987                                        &result_type, &value);
988           if (**strp != ')')
989             return "missing `)'";
990           ++*strp;
991           if (errmsg == NULL
992               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
993             value &= 0xffff;
994           *valuep = value;
995           return errmsg;
996         }
997       else if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
998         {
999           *strp += 9;
1000           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELLO,
1001                                        &result_type, &value);
1002           if (**strp != ')')
1003             return "missing ')'";
1004           ++*strp;
1005           if (errmsg == NULL
1006               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1007             value &= 0xffff;
1008           *valuep = value;
1009           return errmsg;
1010         }
1011       else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
1012         {
1013           *strp += 7;
1014           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTLO,
1015                                        &result_type, &value);
1016           if (**strp != ')')
1017             return "missing ')'";
1018           ++*strp;
1019           if (errmsg == NULL
1020               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1021             value &= 0xffff;
1022           *valuep = value;
1023           return errmsg;
1024         }
1025       else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
1026         {
1027           *strp += 15;
1028           errmsg = cgen_parse_address (cd, strp, opindex,
1029                                        BFD_RELOC_FRV_FUNCDESC_GOTLO,
1030                                        &result_type, &value);
1031           if (**strp != ')')
1032             return "missing ')'";
1033           ++*strp;
1034           if (errmsg == NULL
1035               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1036             value &= 0xffff;
1037           *valuep = value;
1038           return errmsg;
1039         }
1040       else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
1041         {
1042           *strp += 10;
1043           errmsg = cgen_parse_address (cd, strp, opindex,
1044                                        BFD_RELOC_FRV_GOTOFFLO,
1045                                        &result_type, &value);
1046           if (**strp != ')')
1047             return "missing ')'";
1048           ++*strp;
1049           if (errmsg == NULL
1050               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1051             value &= 0xffff;
1052           *valuep = value;
1053           return errmsg;
1054         }
1055       else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
1056         {
1057           *strp += 18;
1058           errmsg = cgen_parse_address (cd, strp, opindex,
1059                                        BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
1060                                        &result_type, &value);
1061           if (**strp != ')')
1062             return "missing ')'";
1063           ++*strp;
1064           if (errmsg == NULL
1065               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1066             value &= 0xffff;
1067           *valuep = value;
1068           return errmsg;
1069         }
1070     }
1071   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1074 static const char *
1075 parse_uhi16 (cd, strp, opindex, valuep)
1076      CGEN_CPU_DESC cd;
1077      const char **strp;
1078      int opindex;
1079      unsigned long *valuep;
1081   const char *errmsg;
1082   enum cgen_parse_operand_result result_type;
1083   bfd_vma value;
1085   if (**strp == '#' || **strp == '%')
1086     {
1087       if (strncasecmp (*strp + 1, "hi(", 3) == 0)
1088         {
1089           *strp += 4;
1090           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_HI16,
1091                                        &result_type, &value);
1092           if (**strp != ')')
1093             return "missing `)'";
1094           ++*strp;
1095           if (errmsg == NULL
1096               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1097             value >>= 16;
1098           *valuep = value;
1099           return errmsg;
1100         }
1101       else if (strncasecmp (*strp + 1, "gprelhi(", 8) == 0)
1102         {
1103           *strp += 9;
1104           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELHI,
1105                                        &result_type, &value);
1106           if (**strp != ')')
1107             return "missing ')'";
1108           ++*strp;
1109           if (errmsg == NULL
1110               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1111             value >>= 16;
1112           *valuep = value;
1113           return errmsg;
1114         }
1115       else if (strncasecmp (*strp + 1, "gothi(", 6) == 0)
1116         {
1117           *strp += 7;
1118           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTHI,
1119                                        &result_type, &value);
1120           if (**strp != ')')
1121             return "missing ')'";
1122           ++*strp;
1123           if (errmsg == NULL
1124               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1125             value >>= 16;
1126           *valuep = value;
1127           return errmsg;
1128         }
1129       else if (strncasecmp (*strp + 1, "gotfuncdeschi(", 14) == 0)
1130         {
1131           *strp += 15;
1132           errmsg = cgen_parse_address (cd, strp, opindex,
1133                                        BFD_RELOC_FRV_FUNCDESC_GOTHI,
1134                                        &result_type, &value);
1135           if (**strp != ')')
1136             return "missing ')'";
1137           ++*strp;
1138           if (errmsg == NULL
1139               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1140             value >>= 16;
1141           *valuep = value;
1142           return errmsg;
1143         }
1144       else if (strncasecmp (*strp + 1, "gotoffhi(", 9) == 0)
1145         {
1146           *strp += 10;
1147           errmsg = cgen_parse_address (cd, strp, opindex,
1148                                        BFD_RELOC_FRV_GOTOFFHI,
1149                                        &result_type, &value);
1150           if (**strp != ')')
1151             return "missing ')'";
1152           ++*strp;
1153           if (errmsg == NULL
1154               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1155             value >>= 16;
1156           *valuep = value;
1157           return errmsg;
1158         }
1159       else if (strncasecmp (*strp + 1, "gotofffuncdeschi(", 17) == 0)
1160         {
1161           *strp += 18;
1162           errmsg = cgen_parse_address (cd, strp, opindex,
1163                                        BFD_RELOC_FRV_FUNCDESC_GOTOFFHI,
1164                                        &result_type, &value);
1165           if (**strp != ')')
1166             return "missing ')'";
1167           ++*strp;
1168           if (errmsg == NULL
1169               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1170             value >>= 16;
1171           *valuep = value;
1172           return errmsg;
1173         }
1174     }
1175   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1178 static long
1179 parse_register_number (strp)
1180      const char **strp;
1182   int regno;
1183   if (**strp < '0' || **strp > '9')
1184     return -1; /* error */
1186   regno = **strp - '0';
1187   for (++*strp; **strp >= '0' && **strp <= '9'; ++*strp)
1188     regno = regno * 10 + (**strp - '0');
1190   return regno;
1193 static const char *
1194 parse_spr (cd, strp, table, valuep)
1195      CGEN_CPU_DESC cd;
1196      const char **strp;
1197      CGEN_KEYWORD * table;
1198      long *valuep;
1200   const char *save_strp;
1201   long regno;
1203   /* Check for spr index notation.  */
1204   if (strncasecmp (*strp, "spr[", 4) == 0)
1205     {
1206       *strp += 4;
1207       regno = parse_register_number (strp);
1208       if (**strp != ']')
1209         return "missing `]'";
1210       ++*strp;
1211       if (! spr_valid (regno))
1212         return "Special purpose register number is out of range";
1213       *valuep = regno;
1214       return NULL;
1215     }
1217   save_strp = *strp;
1218   regno = parse_register_number (strp);
1219   if (regno != -1)
1220     {
1221       if (! spr_valid (regno))
1222         return "Special purpose register number is out of range";
1223       *valuep = regno;
1224       return NULL;
1225     }
1227   *strp = save_strp;
1228   return cgen_parse_keyword (cd, strp, table, valuep);
1231 static const char *
1232 parse_d12 (cd, strp, opindex, valuep)
1233      CGEN_CPU_DESC cd;
1234      const char **strp;
1235      int opindex;
1236      long *valuep;
1238   const char *errmsg;
1239   enum cgen_parse_operand_result result_type;
1240   bfd_vma value;
1242   /* Check for small data reference.  */
1243   if (**strp == '#' || **strp == '%')
1244     {
1245       if (strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1246         {
1247           *strp += 9;
1248           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPREL12,
1249                                        &result_type, &value);
1250           if (**strp != ')')
1251             return "missing `)'";
1252           ++*strp;
1253           *valuep = value;
1254           return errmsg;
1255         }
1256       else if (strncasecmp (*strp + 1, "got12(", 6) == 0)
1257         {
1258           *strp += 7;
1259           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOT12,
1260                                        &result_type, &value);
1261           if (**strp != ')')
1262             return "missing ')'";
1263           ++*strp;
1264           *valuep = value;
1265           return errmsg;
1266         }
1267       else if (strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
1268         {
1269           *strp += 15;
1270           errmsg = cgen_parse_address (cd, strp, opindex,
1271                                        BFD_RELOC_FRV_FUNCDESC_GOT12,
1272                                        &result_type, &value);
1273           if (**strp != ')')
1274             return "missing ')'";
1275           ++*strp;
1276           *valuep = value;
1277           return errmsg;
1278         }
1279       else if (strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
1280         {
1281           *strp += 10;
1282           errmsg = cgen_parse_address (cd, strp, opindex,
1283                                        BFD_RELOC_FRV_GOTOFF12,
1284                                        &result_type, &value);
1285           if (**strp != ')')
1286             return "missing ')'";
1287           ++*strp;
1288           *valuep = value;
1289           return errmsg;
1290         }
1291       else if (strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
1292         {
1293           *strp += 18;
1294           errmsg = cgen_parse_address (cd, strp, opindex,
1295                                        BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
1296                                        &result_type, &value);
1297           if (**strp != ')')
1298             return "missing ')'";
1299           ++*strp;
1300           *valuep = value;
1301           return errmsg;
1302         }
1303     }
1304   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1307 static const char *
1308 parse_s12 (cd, strp, opindex, valuep)
1309      CGEN_CPU_DESC cd;
1310      const char **strp;
1311      int opindex;
1312      long *valuep;
1314   const char *errmsg;
1315   enum cgen_parse_operand_result result_type;
1316   bfd_vma value;
1318   /* Check for small data reference.  */
1319   if ((**strp == '#' || **strp == '%')
1320       && strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1321     {
1322       *strp += 9;
1323       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPREL12,
1324                                     &result_type, &value);
1325       if (**strp != ')')
1326         return "missing `)'";
1327       ++*strp;
1328       *valuep = value;
1329       return errmsg;
1330     }
1331   else if ((**strp == '#' || **strp == '%')
1332            && strncasecmp (*strp + 1, "got12(", 6) == 0)
1333     {
1334       *strp += 7;
1335       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOT12,
1336                                    &result_type, &value);
1337       if (**strp != ')')
1338         return "missing ')'";
1339       ++*strp;
1340       *valuep = value;
1341       return errmsg;
1342     }
1343   else if ((**strp == '#' || **strp == '%')
1344            && strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
1345     {
1346       *strp += 15;
1347       errmsg = cgen_parse_address (cd, strp, opindex,
1348                                    BFD_RELOC_FRV_FUNCDESC_GOT12,
1349                                    &result_type, &value);
1350       if (**strp != ')')
1351         return "missing ')'";
1352       ++*strp;
1353       *valuep = value;
1354       return errmsg;
1355     }
1356   else if ((**strp == '#' || **strp == '%')
1357            && strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
1358     {
1359       *strp += 10;
1360       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTOFF12,
1361                                    &result_type, &value);
1362       if (**strp != ')')
1363         return "missing ')'";
1364       ++*strp;
1365       *valuep = value;
1366       return errmsg;
1367     }
1368   else if ((**strp == '#' || **strp == '%')
1369            && strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
1370     {
1371       *strp += 18;
1372       errmsg = cgen_parse_address (cd, strp, opindex,
1373                                    BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
1374                                    &result_type, &value);
1375       if (**strp != ')')
1376         return "missing ')'";
1377       ++*strp;
1378       *valuep = value;
1379       return errmsg;
1380     }
1381   else
1382     {
1383       if (**strp == '#')
1384         ++*strp;
1385       return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1386     }
1389 static const char *
1390 parse_u12 (cd, strp, opindex, valuep)
1391      CGEN_CPU_DESC cd;
1392      const char **strp;
1393      int opindex;
1394      long *valuep;
1396   const char *errmsg;
1397   enum cgen_parse_operand_result result_type;
1398   bfd_vma value;
1400   /* Check for small data reference.  */
1401   if ((**strp == '#' || **strp == '%')
1402       && strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1403     {
1404       *strp += 9;
1405       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELU12,
1406                                     &result_type, &value);
1407       if (**strp != ')')
1408         return "missing `)'";
1409       ++*strp;
1410       *valuep = value;
1411       return errmsg;
1412     }
1413   else
1414     {
1415       if (**strp == '#')
1416         ++*strp;
1417       return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1418     }
1421 static const char *
1422 parse_A (cd, strp, opindex, valuep, A)
1423      CGEN_CPU_DESC cd;
1424      const char **strp;
1425      int opindex;
1426      long *valuep;
1427      long A;
1429   const char *errmsg;
1431   if (**strp == '#')
1432     ++*strp;
1434   errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1435   if (errmsg)
1436     return errmsg;
1438   if (*valuep != A)
1439     return "Value of A operand must be 0 or 1";
1441   return NULL;
1444 static const char *
1445 parse_A0 (cd, strp, opindex, valuep)
1446      CGEN_CPU_DESC cd;
1447      const char **strp;
1448      int opindex;
1449      long *valuep;
1451   return parse_A (cd, strp, opindex, valuep, 0);
1454 static const char *
1455 parse_A1 (cd, strp, opindex, valuep)
1456      CGEN_CPU_DESC cd;
1457      const char **strp;
1458      int opindex;
1459      long *valuep;
1461   return parse_A (cd, strp, opindex, valuep, 1);
1464 static const char *
1465 parse_even_register (cd, strP, tableP, valueP)
1466      CGEN_CPU_DESC  cd;
1467      const char **  strP;
1468      CGEN_KEYWORD * tableP;
1469      long *         valueP;
1471   const char * errmsg;
1472   const char * saved_star_strP = * strP;
1474   errmsg = cgen_parse_keyword (cd, strP, tableP, valueP);
1476   if (errmsg == NULL && ((* valueP) & 1))
1477     {
1478       errmsg = _("register number must be even");
1479       * strP = saved_star_strP;
1480     }
1482   return errmsg;
1484 /* -- */
1486 /* -- dis.c */
1487 static void print_spr
1488   PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned));
1489 static void print_hi
1490   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
1491 static void print_lo
1492   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
1494 static void
1495 print_spr (cd, dis_info, names, regno, attrs)
1496      CGEN_CPU_DESC cd;
1497      PTR dis_info;
1498      CGEN_KEYWORD *names;
1499      long regno;
1500      unsigned int attrs;
1502   /* Use the register index format for any unnamed registers.  */
1503   if (cgen_keyword_lookup_value (names, regno) == NULL)
1504     {
1505       disassemble_info *info = (disassemble_info *) dis_info;
1506       (*info->fprintf_func) (info->stream, "spr[%ld]", regno);
1507     }
1508   else
1509     print_keyword (cd, dis_info, names, regno, attrs);
1512 static void
1513 print_hi (cd, dis_info, value, attrs, pc, length)
1514      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
1515      PTR dis_info;
1516      long value;
1517      unsigned int attrs ATTRIBUTE_UNUSED;
1518      bfd_vma pc ATTRIBUTE_UNUSED;
1519      int length ATTRIBUTE_UNUSED;
1521   disassemble_info *info = (disassemble_info *) dis_info;
1522   if (value)
1523     (*info->fprintf_func) (info->stream, "0x%lx", value);
1524   else
1525     (*info->fprintf_func) (info->stream, "hi(0x%lx)", value);
1528 static void
1529 print_lo (cd, dis_info, value, attrs, pc, length)
1530      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
1531      PTR dis_info;
1532      long value;
1533      unsigned int attrs ATTRIBUTE_UNUSED;
1534      bfd_vma pc ATTRIBUTE_UNUSED;
1535      int length ATTRIBUTE_UNUSED;
1537   disassemble_info *info = (disassemble_info *) dis_info;
1538   if (value)
1539     (*info->fprintf_func) (info->stream, "0x%lx", value);
1540   else
1541     (*info->fprintf_func) (info->stream, "lo(0x%lx)", value);
1544 /* -- */