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