cpu/
[external/binutils.git] / cpu / frv.opc
1 /* Fujitsu FRV opcode support, for GNU Binutils.  -*- C -*-
2
3    Copyright 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
4
5    Contributed by Red Hat Inc; developed under contract from Fujitsu.
6
7    This file is part of the GNU Binutils.
8
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.
13
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.
18
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.
22
23 */
24
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.
31
32    Each section is delimited with start and end markers.
33
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"
39 */
40 \f
41 /* -- opc.h */
42
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)
47
48 /* Allows reason codes to be output when assembler errors occur.  */
49 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
50
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];
55
56 typedef struct
57 {
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;
67
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 /* -- */
78 \f
79 /* -- opc.c */
80 #include "elf/frv.h"
81 #include <stdio.h>
82
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 *));
99
100 int
101 frv_is_branch_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
102 {
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     }
114
115   return 0; /* not a branch */
116 }
117
118 int
119 frv_is_float_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
120 {
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     }
130
131   return 0; /* not a branch */
132 }
133
134 int
135 frv_is_media_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
136 {
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     }
148
149   return 0; /* not a branch */
150 }
151
152 int
153 frv_is_branch_insn (const CGEN_INSN *insn)
154 {
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;
161
162   return 0;
163 }
164
165 int
166 frv_is_float_insn (const CGEN_INSN *insn)
167 {
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;
174
175   return 0;
176 }
177
178 int
179 frv_is_media_insn (const CGEN_INSN *insn)
180 {
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;
187
188   return 0;
189 }
190
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[] =
196 {
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 }
206 };
207
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[] =
213 {
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 }
226 };
227
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[] =
231 {
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 }
261 };
262
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[] =
267 {
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.  */
295 };
296
297 static CGEN_ATTR_VALUE_TYPE fr500_unit_mapping[] =
298 {
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.  */
326 };
327
328 static CGEN_ATTR_VALUE_TYPE fr550_unit_mapping[] =
329 {
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.         */
357 };
358
359 void
360 frv_vliw_reset (FRV_VLIW *vliw, unsigned long mach, unsigned long elf_flags)
361 {
362   vliw->next_slot = 0;
363   vliw->constraint_violation = 0;
364   vliw->mach = mach;
365   vliw->elf_flags = elf_flags;
366
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     }
382 }
383
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)
390 {
391   /* Map any specialized implementation units to actual ones.  */
392   unit1 = vliw->unit_mapping[unit1];
393
394   if (unit1 == unit2)
395     return 1;
396   if (unit1 < unit2)
397     return 0;
398
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     }
419
420   return 0;
421 }
422
423 /* Return 1 if the vliws match, 0 otherwise.  */
424
425 static int
426 match_vliw (VLIW_COMBO *vliw1, VLIW_COMBO *vliw2, int vliw_size)
427 {
428   int i;
429
430   for (i = 0; i < vliw_size; ++i)
431     {
432       if ((*vliw1)[i] != (*vliw2)[i])
433         return 0;
434     }
435
436   return 1;
437 }
438
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.  */
441
442 static VLIW_COMBO *
443 add_next_to_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE unit)
444 {
445   int           next    = vliw->next_slot;
446   VLIW_COMBO    *current = vliw->current_vliw;
447   VLIW_COMBO    *potential;
448
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     }
455
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));
466
467   return NULL;
468 }
469
470 /* Look for the given major insn type in the given vliw. Return 1 if found,
471    return 0 otherwise.  */
472
473 static int
474 find_major_in_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major)
475 {
476   int i;
477
478   for (i = 0; i < vliw->next_slot; ++i)
479     if (vliw->major[i] == major)
480       return 1;
481
482   return 0;
483 }
484
485 /* Check for constraints between the insns in the vliw due to major insn
486    types.  */
487
488 static int
489 fr400_check_insn_major_constraints (
490   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
491 )
492 {
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     case FR400_MAJOR_M_1:
503       return !find_major_in_vliw (vliw, FR400_MAJOR_M_2);
504     default:
505       break;
506     }
507   return 1;
508 }
509
510 static int
511 find_unit_in_vliw (
512   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE unit
513 )
514 {
515   int i;
516   for (i = 0; i < vliw->next_slot; ++i)
517     if (CGEN_INSN_ATTR_VALUE (vliw->insn[i], CGEN_INSN_UNIT) == unit)
518       return 1;
519
520   return 0; /* not found */
521 }
522
523 static int
524 find_major_in_slot (
525   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, CGEN_ATTR_VALUE_TYPE slot
526 )
527 {
528   int i;
529
530   for (i = 0; i < vliw->next_slot; ++i)
531     if (vliw->major[i] == major && (*vliw->current_vliw)[i] == slot)
532       return 1;
533
534   return 0;
535 }
536
537 static int
538 fr550_find_media_in_vliw (FRV_VLIW *vliw)
539 {
540   int i;
541
542   for (i = 0; i < vliw->next_slot; ++i)
543     {
544       if (vliw->major[i] < FR550_MAJOR_M_1 || vliw->major[i] > FR550_MAJOR_M_5)
545         continue;
546
547       /* Found a media insn, however, MNOP and MCLRACC don't count.  */
548       if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MNOP
549           || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_0
550           || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_1)
551         continue;
552
553       return 1; /* found one */
554     }
555
556   return 0;
557 }
558
559 static int
560 fr550_find_float_in_vliw (FRV_VLIW *vliw)
561 {
562   int i;
563
564   for (i = 0; i < vliw->next_slot; ++i)
565     {
566       if (vliw->major[i] < FR550_MAJOR_F_1 || vliw->major[i] > FR550_MAJOR_F_4)
567         continue;
568
569       /* Found a floating point insn, however, FNOP doesn't count.  */
570       if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_FNOP)
571         continue;
572
573       return 1; /* found one */
574     }
575
576   return 0;
577 }
578
579 static int
580 fr550_check_insn_major_constraints (
581   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, const CGEN_INSN *insn
582 )
583 {
584   CGEN_ATTR_VALUE_TYPE unit;
585   CGEN_ATTR_VALUE_TYPE slot = (*vliw->current_vliw)[vliw->next_slot];
586   switch (slot)
587     {
588     case UNIT_I2:
589       /* If it's a store, then there must be another store in I1 */
590       unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
591       if (unit == UNIT_STORE)
592         return find_unit_in_vliw (vliw, UNIT_STORE);
593       break;
594     case UNIT_FM2:
595     case UNIT_FM3:
596       /* Floating point insns other than FNOP in slot f2 or f3 cannot coexist with
597          media insns.  */
598       if (major >= FR550_MAJOR_F_1 && major <= FR550_MAJOR_F_4
599           && CGEN_INSN_NUM (insn) != FRV_INSN_FNOP)
600         return ! fr550_find_media_in_vliw (vliw);
601       /* Media insns other than MNOP in slot m2 or m3 cannot coexist with
602          floating point insns.  */
603       if (major >= FR550_MAJOR_M_1 && major <= FR550_MAJOR_M_5
604           && CGEN_INSN_NUM (insn) != FRV_INSN_MNOP)
605         return ! fr550_find_float_in_vliw (vliw);
606       /* F-2 in slot f2 or f3 cannot coexist with F-2 or F-4 in slot f1 or f2
607          respectively.
608        */
609       if (major == FR550_MAJOR_F_2)
610         return ! find_major_in_slot (vliw, FR550_MAJOR_F_2, slot - (UNIT_FM2 - UNIT_FM0))
611           &&   ! find_major_in_slot (vliw, FR550_MAJOR_F_4, slot - (UNIT_FM2 - UNIT_FM0));
612       /* M-2 or M-5 in slot m2 or m3 cannot coexist with M-2 in slot m1 or m2
613          respectively.  */
614       if (major == FR550_MAJOR_M_2 || major == FR550_MAJOR_M_5)
615         return ! find_major_in_slot (vliw, FR550_MAJOR_M_2, slot - (UNIT_FM2 - UNIT_FM0));
616       /* M-4 in slot m2 or m3 cannot coexist with M-4 in slot m1 or m2
617          respectively.  */
618       if (major == FR550_MAJOR_M_4)
619         return ! find_major_in_slot (vliw, FR550_MAJOR_M_4, slot - (UNIT_FM2 - UNIT_FM0));
620       break;
621     default:
622       break;
623     }
624   return 1; /* all ok */
625 }
626
627 static int
628 fr500_check_insn_major_constraints (
629   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
630 )
631 {
632   /* TODO: A table might be faster for some of the more complex instances
633      here.  */
634   switch (major)
635     {
636     case FR500_MAJOR_I_1:
637     case FR500_MAJOR_I_4:
638     case FR500_MAJOR_I_5:
639     case FR500_MAJOR_I_6:
640     case FR500_MAJOR_B_1:
641     case FR500_MAJOR_B_2:
642     case FR500_MAJOR_B_3:
643     case FR500_MAJOR_B_4:
644     case FR500_MAJOR_B_5:
645     case FR500_MAJOR_B_6:
646     case FR500_MAJOR_F_4:
647     case FR500_MAJOR_F_8:
648     case FR500_MAJOR_M_8:
649       return 1; /* OK */
650     case FR500_MAJOR_I_2:
651       /* Cannot coexist with I-3 insn.  */
652       return ! find_major_in_vliw (vliw, FR500_MAJOR_I_3);
653     case FR500_MAJOR_I_3:
654       /* Cannot coexist with I-2 insn.  */
655       return ! find_major_in_vliw (vliw, FR500_MAJOR_I_2);
656     case FR500_MAJOR_F_1:
657     case FR500_MAJOR_F_2:
658       /* Cannot coexist with F-5, F-6, or M-7 insn.  */
659       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
660         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
661         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
662     case FR500_MAJOR_F_3:
663       /* Cannot coexist with F-7, or M-7 insn.  */
664       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
665         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
666     case FR500_MAJOR_F_5:
667       /* Cannot coexist with F-1, F-2, F-6, F-7, or M-7 insn.  */
668       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
669         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
670         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
671         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
672         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
673     case FR500_MAJOR_F_6:
674       /* Cannot coexist with F-1, F-2, F-5, F-6, or M-7 insn.  */
675       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
676         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
677         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
678         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
679         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
680     case FR500_MAJOR_F_7:
681       /* Cannot coexist with F-3, F-5, F-7, or M-7 insn.  */
682       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
683         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
684         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
685         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
686     case FR500_MAJOR_M_1:
687       /* Cannot coexist with M-7 insn.  */
688       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
689     case FR500_MAJOR_M_2:
690     case FR500_MAJOR_M_3:
691       /* Cannot coexist with M-5, M-6 or M-7 insn.  */
692       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
693         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
694         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
695     case FR500_MAJOR_M_4:
696       /* Cannot coexist with M-6 insn.  */
697       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_6);
698     case FR500_MAJOR_M_5:
699       /* Cannot coexist with M-2, M-3, M-5, M-6  or M-7 insn.  */
700       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
701         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
702         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
703         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
704         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
705     case FR500_MAJOR_M_6:
706       /* Cannot coexist with M-2, M-3, M-4, M-5, M-6  or M-7 insn.  */
707       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
708         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
709         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_4)
710         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
711         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
712         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
713     case FR500_MAJOR_M_7:
714       /* Cannot coexist with M-1, M-2, M-3, M-5, M-6  or M-7 insn.  */
715       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_1)
716         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
717         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
718         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
719         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
720         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7)
721         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
722         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
723         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
724         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
725         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
726         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7);
727     default:
728       fprintf (stderr, "frv-opc.c, line %d: bad major code, aborting.\n",
729                __LINE__);
730       abort ();
731       break;
732     }
733   return 1;
734 }
735
736 static int
737 check_insn_major_constraints (
738   FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, const CGEN_INSN *insn
739 )
740 {
741   int rc;
742   switch (vliw->mach)
743     {
744     case bfd_mach_fr400:
745       rc = fr400_check_insn_major_constraints (vliw, major);
746       break;
747     case bfd_mach_fr550:
748       rc = fr550_check_insn_major_constraints (vliw, major, insn);
749       break;
750     default:
751       rc = fr500_check_insn_major_constraints (vliw, major);
752       break;
753     }
754   return rc;
755 }
756
757 /* Add in insn to the VLIW vliw if possible. Return 0 if successful,
758    non-zero otherwise.  */
759 int
760 frv_vliw_add_insn (FRV_VLIW *vliw, const CGEN_INSN *insn)
761 {
762   int index;
763   CGEN_ATTR_VALUE_TYPE major;
764   CGEN_ATTR_VALUE_TYPE unit;
765   VLIW_COMBO *new_vliw;
766
767   if (vliw->constraint_violation || CGEN_INSN_INVALID_P (insn))
768     return 1;
769
770   index = vliw->next_slot;
771   if (index >= FRV_VLIW_SIZE)
772     return 1;
773
774   unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
775   if (unit == UNIT_NIL)
776     {
777       fprintf (stderr, "frv-opc.c line %d: bad insn unit.\n",
778                __LINE__);
779       abort (); /* no UNIT specified for this insn in frv.cpu  */
780     }
781
782   switch (vliw->mach)
783     {
784     case bfd_mach_fr400:
785       major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR);
786       break;
787     case bfd_mach_fr550:
788       major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR550_MAJOR);
789       break;
790     default:
791       major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR);
792       break;
793     }
794
795   if (index <= 0)
796     {
797       /* Any insn can be added to slot 0.  */
798       while (! match_unit (vliw, unit, (*vliw->current_vliw)[0]))
799         ++vliw->current_vliw;
800       vliw->major[0] = major;
801       vliw->insn[0] = insn;
802       vliw->next_slot = 1;
803       return 0;
804     }
805
806   /* If there are already insns in the vliw(s) check to see that
807      this one can be added.  Do this by finding an allowable vliw
808      combination that can accept the new insn.  */
809   if (! (vliw->elf_flags & EF_FRV_NOPACK))
810     {
811       new_vliw = add_next_to_vliw (vliw, unit);
812       if (new_vliw && check_insn_major_constraints (vliw, major, insn))
813         {
814           vliw->current_vliw = new_vliw;
815           vliw->major[index] = major;
816           vliw->insn[index] = insn;
817           vliw->next_slot++;
818           return 0;
819         }
820
821       /* The frv machine supports all packing conbinations.  If we fail,
822          to add the insn, then it could not be handled as if it was the fr500.
823          Just return as if it was handled ok.  */
824       if (vliw->mach == bfd_mach_frv)
825         return 0;
826     }
827
828   vliw->constraint_violation = 1;
829   return 1;
830 }
831
832 int
833 spr_valid (regno)
834      long regno;
835 {
836   if (regno < 0)     return 0;
837   if (regno <= 4095) return 1;
838   return 0;
839 }
840 /* -- */
841 \f
842 /* -- asm.c */
843 static const char * parse_ulo16
844   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
845 static const char * parse_uslo16
846   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
847 static const char * parse_uhi16
848   PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
849 static long parse_register_number
850   PARAMS ((const char **));
851 static const char * parse_spr
852   PARAMS ((CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *));
853 static const char * parse_d12
854   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
855 static const char * parse_s12
856   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
857 static const char * parse_u12
858   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
859 static const char * parse_even_register
860   PARAMS ((CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *));
861 static const char * parse_A0
862   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
863 static const char * parse_A1
864   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
865 static const char * parse_A
866   PARAMS ((CGEN_CPU_DESC, const char **, int, long *, long));
867
868 static const char *
869 parse_ulo16 (cd, strp, opindex, valuep)
870      CGEN_CPU_DESC cd;
871      const char **strp;
872      int opindex;
873      unsigned long *valuep;
874 {
875   const char *errmsg;
876   enum cgen_parse_operand_result result_type;
877   bfd_vma value;
878  
879   if (**strp == '#' || **strp == '%')
880     {
881       if (strncasecmp (*strp + 1, "lo(", 3) == 0)
882         {
883           *strp += 4;
884           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
885                                        &result_type, &value);
886           if (**strp != ')')
887             return "missing `)'";
888           ++*strp;
889           if (errmsg == NULL
890               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
891             value &= 0xffff;
892           *valuep = value;
893           return errmsg;
894         }
895       if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
896         {
897           *strp += 9;
898           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELLO,
899                                        &result_type, &value);
900           if (**strp != ')')
901             return "missing ')'";
902           ++*strp;
903           if (errmsg == NULL
904               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
905             value &= 0xffff;
906           *valuep = value;
907           return errmsg;
908         }
909       else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
910         {
911           *strp += 7;
912           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTLO,
913                                        &result_type, &value);
914           if (**strp != ')')
915             return "missing ')'";
916           ++*strp;
917           if (errmsg == NULL
918               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
919             value &= 0xffff;
920           *valuep = value;
921           return errmsg;
922         }
923       else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
924         {
925           *strp += 15;
926           errmsg = cgen_parse_address (cd, strp, opindex,
927                                        BFD_RELOC_FRV_FUNCDESC_GOTLO,
928                                        &result_type, &value);
929           if (**strp != ')')
930             return "missing ')'";
931           ++*strp;
932           if (errmsg == NULL
933               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
934             value &= 0xffff;
935           *valuep = value;
936           return errmsg;
937         }
938       else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
939         {
940           *strp += 10;
941           errmsg = cgen_parse_address (cd, strp, opindex,
942                                        BFD_RELOC_FRV_GOTOFFLO,
943                                        &result_type, &value);
944           if (**strp != ')')
945             return "missing ')'";
946           ++*strp;
947           if (errmsg == NULL
948               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
949             value &= 0xffff;
950           *valuep = value;
951           return errmsg;
952         }
953       else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
954         {
955           *strp += 18;
956           errmsg = cgen_parse_address (cd, strp, opindex,
957                                        BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
958                                        &result_type, &value);
959           if (**strp != ')')
960             return "missing ')'";
961           ++*strp;
962           if (errmsg == NULL
963               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
964             value &= 0xffff;
965           *valuep = value;
966           return errmsg;
967         }
968     }
969   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
970 }
971
972 static const char *
973 parse_uslo16 (cd, strp, opindex, valuep)
974      CGEN_CPU_DESC cd;
975      const char **strp;
976      int opindex;
977      unsigned long *valuep;
978 {
979   const char *errmsg;
980   enum cgen_parse_operand_result result_type;
981   bfd_vma value;
982  
983   if (**strp == '#' || **strp == '%')
984     {
985       if (strncasecmp (*strp + 1, "lo(", 3) == 0)
986         {
987           *strp += 4;
988           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
989                                        &result_type, &value);
990           if (**strp != ')')
991             return "missing `)'";
992           ++*strp;
993           if (errmsg == NULL
994               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
995             value &= 0xffff;
996           *valuep = value;
997           return errmsg;
998         }
999       else if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
1000         {
1001           *strp += 9;
1002           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELLO,
1003                                        &result_type, &value);
1004           if (**strp != ')')
1005             return "missing ')'";
1006           ++*strp;
1007           if (errmsg == NULL
1008               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1009             value &= 0xffff;
1010           *valuep = value;
1011           return errmsg;
1012         }
1013       else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
1014         {
1015           *strp += 7;
1016           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTLO,
1017                                        &result_type, &value);
1018           if (**strp != ')')
1019             return "missing ')'";
1020           ++*strp;
1021           if (errmsg == NULL
1022               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1023             value &= 0xffff;
1024           *valuep = value;
1025           return errmsg;
1026         }
1027       else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
1028         {
1029           *strp += 15;
1030           errmsg = cgen_parse_address (cd, strp, opindex,
1031                                        BFD_RELOC_FRV_FUNCDESC_GOTLO,
1032                                        &result_type, &value);
1033           if (**strp != ')')
1034             return "missing ')'";
1035           ++*strp;
1036           if (errmsg == NULL
1037               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1038             value &= 0xffff;
1039           *valuep = value;
1040           return errmsg;
1041         }
1042       else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
1043         {
1044           *strp += 10;
1045           errmsg = cgen_parse_address (cd, strp, opindex,
1046                                        BFD_RELOC_FRV_GOTOFFLO,
1047                                        &result_type, &value);
1048           if (**strp != ')')
1049             return "missing ')'";
1050           ++*strp;
1051           if (errmsg == NULL
1052               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1053             value &= 0xffff;
1054           *valuep = value;
1055           return errmsg;
1056         }
1057       else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
1058         {
1059           *strp += 18;
1060           errmsg = cgen_parse_address (cd, strp, opindex,
1061                                        BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
1062                                        &result_type, &value);
1063           if (**strp != ')')
1064             return "missing ')'";
1065           ++*strp;
1066           if (errmsg == NULL
1067               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1068             value &= 0xffff;
1069           *valuep = value;
1070           return errmsg;
1071         }
1072     }
1073   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1074 }
1075
1076 static const char *
1077 parse_uhi16 (cd, strp, opindex, valuep)
1078      CGEN_CPU_DESC cd;
1079      const char **strp;
1080      int opindex;
1081      unsigned long *valuep;
1082 {
1083   const char *errmsg;
1084   enum cgen_parse_operand_result result_type;
1085   bfd_vma value;
1086  
1087   if (**strp == '#' || **strp == '%')
1088     {
1089       if (strncasecmp (*strp + 1, "hi(", 3) == 0)
1090         {
1091           *strp += 4;
1092           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_HI16,
1093                                        &result_type, &value);
1094           if (**strp != ')')
1095             return "missing `)'";
1096           ++*strp;
1097           if (errmsg == NULL
1098               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1099             value >>= 16;
1100           *valuep = value;
1101           return errmsg;
1102         }
1103       else if (strncasecmp (*strp + 1, "gprelhi(", 8) == 0)
1104         {
1105           *strp += 9;
1106           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELHI,
1107                                        &result_type, &value);
1108           if (**strp != ')')
1109             return "missing ')'";
1110           ++*strp;
1111           if (errmsg == NULL
1112               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1113             value >>= 16;
1114           *valuep = value;
1115           return errmsg;
1116         }
1117       else if (strncasecmp (*strp + 1, "gothi(", 6) == 0)
1118         {
1119           *strp += 7;
1120           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTHI,
1121                                        &result_type, &value);
1122           if (**strp != ')')
1123             return "missing ')'";
1124           ++*strp;
1125           if (errmsg == NULL
1126               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1127             value >>= 16;
1128           *valuep = value;
1129           return errmsg;
1130         }
1131       else if (strncasecmp (*strp + 1, "gotfuncdeschi(", 14) == 0)
1132         {
1133           *strp += 15;
1134           errmsg = cgen_parse_address (cd, strp, opindex,
1135                                        BFD_RELOC_FRV_FUNCDESC_GOTHI,
1136                                        &result_type, &value);
1137           if (**strp != ')')
1138             return "missing ')'";
1139           ++*strp;
1140           if (errmsg == NULL
1141               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1142             value >>= 16;
1143           *valuep = value;
1144           return errmsg;
1145         }
1146       else if (strncasecmp (*strp + 1, "gotoffhi(", 9) == 0)
1147         {
1148           *strp += 10;
1149           errmsg = cgen_parse_address (cd, strp, opindex,
1150                                        BFD_RELOC_FRV_GOTOFFHI,
1151                                        &result_type, &value);
1152           if (**strp != ')')
1153             return "missing ')'";
1154           ++*strp;
1155           if (errmsg == NULL
1156               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1157             value >>= 16;
1158           *valuep = value;
1159           return errmsg;
1160         }
1161       else if (strncasecmp (*strp + 1, "gotofffuncdeschi(", 17) == 0)
1162         {
1163           *strp += 18;
1164           errmsg = cgen_parse_address (cd, strp, opindex,
1165                                        BFD_RELOC_FRV_FUNCDESC_GOTOFFHI,
1166                                        &result_type, &value);
1167           if (**strp != ')')
1168             return "missing ')'";
1169           ++*strp;
1170           if (errmsg == NULL
1171               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1172             value >>= 16;
1173           *valuep = value;
1174           return errmsg;
1175         }
1176     }
1177   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1178 }
1179
1180 static long
1181 parse_register_number (strp)
1182      const char **strp;
1183 {
1184   int regno;
1185   if (**strp < '0' || **strp > '9')
1186     return -1; /* error */
1187
1188   regno = **strp - '0';
1189   for (++*strp; **strp >= '0' && **strp <= '9'; ++*strp)
1190     regno = regno * 10 + (**strp - '0');
1191
1192   return regno;
1193 }
1194
1195 static const char *
1196 parse_spr (cd, strp, table, valuep)
1197      CGEN_CPU_DESC cd;
1198      const char **strp;
1199      CGEN_KEYWORD * table;
1200      long *valuep;
1201 {
1202   const char *save_strp;
1203   long regno;
1204
1205   /* Check for spr index notation.  */
1206   if (strncasecmp (*strp, "spr[", 4) == 0)
1207     {
1208       *strp += 4;
1209       regno = parse_register_number (strp);
1210       if (**strp != ']')
1211         return "missing `]'";
1212       ++*strp;
1213       if (! spr_valid (regno))
1214         return "Special purpose register number is out of range";
1215       *valuep = regno;
1216       return NULL;
1217     }
1218
1219   save_strp = *strp;
1220   regno = parse_register_number (strp);
1221   if (regno != -1)
1222     {
1223       if (! spr_valid (regno))
1224         return "Special purpose register number is out of range";
1225       *valuep = regno;
1226       return NULL;
1227     }
1228
1229   *strp = save_strp;
1230   return cgen_parse_keyword (cd, strp, table, valuep);
1231 }
1232
1233 static const char *
1234 parse_d12 (cd, strp, opindex, valuep)
1235      CGEN_CPU_DESC cd;
1236      const char **strp;
1237      int opindex;
1238      long *valuep;
1239 {
1240   const char *errmsg;
1241   enum cgen_parse_operand_result result_type;
1242   bfd_vma value;
1243  
1244   /* Check for small data reference.  */
1245   if (**strp == '#' || **strp == '%')
1246     {
1247       if (strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1248         {
1249           *strp += 9;
1250           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPREL12,
1251                                        &result_type, &value);
1252           if (**strp != ')')
1253             return "missing `)'";
1254           ++*strp;
1255           *valuep = value;
1256           return errmsg;
1257         }
1258       else if (strncasecmp (*strp + 1, "got12(", 6) == 0)
1259         {
1260           *strp += 7;
1261           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOT12,
1262                                        &result_type, &value);
1263           if (**strp != ')')
1264             return "missing ')'";
1265           ++*strp;
1266           *valuep = value;
1267           return errmsg;
1268         }
1269       else if (strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
1270         {
1271           *strp += 15;
1272           errmsg = cgen_parse_address (cd, strp, opindex,
1273                                        BFD_RELOC_FRV_FUNCDESC_GOT12,
1274                                        &result_type, &value);
1275           if (**strp != ')')
1276             return "missing ')'";
1277           ++*strp;
1278           *valuep = value;
1279           return errmsg;
1280         }
1281       else if (strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
1282         {
1283           *strp += 10;
1284           errmsg = cgen_parse_address (cd, strp, opindex,
1285                                        BFD_RELOC_FRV_GOTOFF12,
1286                                        &result_type, &value);
1287           if (**strp != ')')
1288             return "missing ')'";
1289           ++*strp;
1290           *valuep = value;
1291           return errmsg;
1292         }
1293       else if (strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
1294         {
1295           *strp += 18;
1296           errmsg = cgen_parse_address (cd, strp, opindex,
1297                                        BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
1298                                        &result_type, &value);
1299           if (**strp != ')')
1300             return "missing ')'";
1301           ++*strp;
1302           *valuep = value;
1303           return errmsg;
1304         }
1305     }
1306   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1307 }
1308
1309 static const char *
1310 parse_s12 (cd, strp, opindex, valuep)
1311      CGEN_CPU_DESC cd;
1312      const char **strp;
1313      int opindex;
1314      long *valuep;
1315 {
1316   const char *errmsg;
1317   enum cgen_parse_operand_result result_type;
1318   bfd_vma value;
1319  
1320   /* Check for small data reference.  */
1321   if ((**strp == '#' || **strp == '%')
1322       && strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1323     {
1324       *strp += 9;
1325       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPREL12,
1326                                     &result_type, &value);
1327       if (**strp != ')')
1328         return "missing `)'";
1329       ++*strp;
1330       *valuep = value;
1331       return errmsg;
1332     }
1333   else if ((**strp == '#' || **strp == '%')
1334            && strncasecmp (*strp + 1, "got12(", 6) == 0)
1335     {
1336       *strp += 7;
1337       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOT12,
1338                                    &result_type, &value);
1339       if (**strp != ')')
1340         return "missing ')'";
1341       ++*strp;
1342       *valuep = value;
1343       return errmsg;
1344     }
1345   else if ((**strp == '#' || **strp == '%')
1346            && strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
1347     {
1348       *strp += 15;
1349       errmsg = cgen_parse_address (cd, strp, opindex,
1350                                    BFD_RELOC_FRV_FUNCDESC_GOT12,
1351                                    &result_type, &value);
1352       if (**strp != ')')
1353         return "missing ')'";
1354       ++*strp;
1355       *valuep = value;
1356       return errmsg;
1357     }
1358   else if ((**strp == '#' || **strp == '%')
1359            && strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
1360     {
1361       *strp += 10;
1362       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTOFF12,
1363                                    &result_type, &value);
1364       if (**strp != ')')
1365         return "missing ')'";
1366       ++*strp;
1367       *valuep = value;
1368       return errmsg;
1369     }
1370   else if ((**strp == '#' || **strp == '%')
1371            && strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
1372     {
1373       *strp += 18;
1374       errmsg = cgen_parse_address (cd, strp, opindex,
1375                                    BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
1376                                    &result_type, &value);
1377       if (**strp != ')')
1378         return "missing ')'";
1379       ++*strp;
1380       *valuep = value;
1381       return errmsg;
1382     }
1383   else
1384     {
1385       if (**strp == '#')
1386         ++*strp;
1387       return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1388     }
1389 }
1390
1391 static const char *
1392 parse_u12 (cd, strp, opindex, valuep)
1393      CGEN_CPU_DESC cd;
1394      const char **strp;
1395      int opindex;
1396      long *valuep;
1397 {
1398   const char *errmsg;
1399   enum cgen_parse_operand_result result_type;
1400   bfd_vma value;
1401  
1402   /* Check for small data reference.  */
1403   if ((**strp == '#' || **strp == '%')
1404       && strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1405     {
1406       *strp += 9;
1407       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELU12,
1408                                     &result_type, &value);
1409       if (**strp != ')')
1410         return "missing `)'";
1411       ++*strp;
1412       *valuep = value;
1413       return errmsg;
1414     }
1415   else
1416     {
1417       if (**strp == '#')
1418         ++*strp;
1419       return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1420     }
1421 }
1422
1423 static const char *
1424 parse_A (cd, strp, opindex, valuep, A)
1425      CGEN_CPU_DESC cd;
1426      const char **strp;
1427      int opindex;
1428      long *valuep;
1429      long A;
1430 {
1431   const char *errmsg;
1432  
1433   if (**strp == '#')
1434     ++*strp;
1435
1436   errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1437   if (errmsg)
1438     return errmsg;
1439
1440   if (*valuep != A)
1441     return "Value of A operand must be 0 or 1";
1442
1443   return NULL;
1444 }
1445
1446 static const char *
1447 parse_A0 (cd, strp, opindex, valuep)
1448      CGEN_CPU_DESC cd;
1449      const char **strp;
1450      int opindex;
1451      long *valuep;
1452 {
1453   return parse_A (cd, strp, opindex, valuep, 0);
1454 }
1455
1456 static const char *
1457 parse_A1 (cd, strp, opindex, valuep)
1458      CGEN_CPU_DESC cd;
1459      const char **strp;
1460      int opindex;
1461      long *valuep;
1462 {
1463   return parse_A (cd, strp, opindex, valuep, 1);
1464 }
1465
1466 static const char *
1467 parse_even_register (cd, strP, tableP, valueP)
1468      CGEN_CPU_DESC  cd;
1469      const char **  strP;
1470      CGEN_KEYWORD * tableP;
1471      long *         valueP;
1472 {
1473   const char * errmsg;
1474   const char * saved_star_strP = * strP;
1475
1476   errmsg = cgen_parse_keyword (cd, strP, tableP, valueP);
1477
1478   if (errmsg == NULL && ((* valueP) & 1))
1479     {
1480       errmsg = _("register number must be even");
1481       * strP = saved_star_strP;
1482     }
1483
1484   return errmsg;
1485 }
1486 /* -- */
1487 \f
1488 /* -- dis.c */
1489 static void print_spr
1490   PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned));
1491 static void print_hi
1492   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
1493 static void print_lo
1494   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
1495
1496 static void
1497 print_spr (cd, dis_info, names, regno, attrs)
1498      CGEN_CPU_DESC cd;
1499      PTR dis_info;
1500      CGEN_KEYWORD *names;
1501      long regno;
1502      unsigned int attrs;
1503 {
1504   /* Use the register index format for any unnamed registers.  */
1505   if (cgen_keyword_lookup_value (names, regno) == NULL)
1506     {
1507       disassemble_info *info = (disassemble_info *) dis_info;
1508       (*info->fprintf_func) (info->stream, "spr[%ld]", regno);
1509     }
1510   else
1511     print_keyword (cd, dis_info, names, regno, attrs);
1512 }
1513
1514 static void
1515 print_hi (cd, dis_info, value, attrs, pc, length)
1516      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
1517      PTR dis_info;
1518      long value;
1519      unsigned int attrs ATTRIBUTE_UNUSED;
1520      bfd_vma pc ATTRIBUTE_UNUSED;
1521      int length ATTRIBUTE_UNUSED;
1522 {
1523   disassemble_info *info = (disassemble_info *) dis_info;
1524   if (value)
1525     (*info->fprintf_func) (info->stream, "0x%lx", value);
1526   else
1527     (*info->fprintf_func) (info->stream, "hi(0x%lx)", value);
1528 }
1529
1530 static void
1531 print_lo (cd, dis_info, value, attrs, pc, length)
1532      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
1533      PTR dis_info;
1534      long value;
1535      unsigned int attrs ATTRIBUTE_UNUSED;
1536      bfd_vma pc ATTRIBUTE_UNUSED;
1537      int length ATTRIBUTE_UNUSED;
1538 {
1539   disassemble_info *info = (disassemble_info *) dis_info;
1540   if (value)
1541     (*info->fprintf_func) (info->stream, "0x%lx", value);
1542   else
1543     (*info->fprintf_func) (info->stream, "lo(0x%lx)", value);
1544 }
1545
1546 /* -- */