x86: drop bogus IgnoreSize from AVX512_4* insns
[external/binutils.git] / cpu / frv.opc
1 /* Fujitsu FRV opcode support, for GNU Binutils.  -*- C -*-
2
3    Copyright 2000, 2001, 2003, 2004, 2005, 2007, 2009
4    Free Software Foundation, Inc.
5
6    Contributed by Red Hat Inc; developed under contract from Fujitsu.
7
8    This file is part of the GNU Binutils.
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
23    MA 02110-1301, USA.  */
24
25
26 /* This file is an addendum to frv.cpu.  Heavy use of C code isn't
27    appropriate in .cpu files, so it resides here.  This especially applies
28    to assembly/disassembly where parsing/printing can be quite involved.
29    Such things aren't really part of the specification of the cpu, per se,
30    so .cpu files provide the general framework and .opc files handle the
31    nitty-gritty details as necessary.
32
33    Each section is delimited with start and end markers.
34
35    <arch>-opc.h additions use: "-- opc.h"
36    <arch>-opc.c additions use: "-- opc.c"
37    <arch>-asm.c additions use: "-- asm.c"
38    <arch>-dis.c additions use: "-- dis.c"
39    <arch>-ibd.h additions use: "-- ibd.h".  */
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
55 typedef CGEN_ATTR_VALUE_ENUM_TYPE VLIW_COMBO[FRV_VLIW_SIZE];
56
57 typedef struct
58 {
59   int                    next_slot;
60   int                    constraint_violation;
61   unsigned long          mach;
62   unsigned long          elf_flags;
63   CGEN_ATTR_VALUE_ENUM_TYPE * unit_mapping;
64   VLIW_COMBO *           current_vliw;
65   CGEN_ATTR_VALUE_ENUM_TYPE   major[FRV_VLIW_SIZE];
66   const CGEN_INSN *      insn[FRV_VLIW_SIZE];
67 } FRV_VLIW;
68
69 int frv_is_branch_major (CGEN_ATTR_VALUE_ENUM_TYPE, unsigned long);
70 int frv_is_float_major  (CGEN_ATTR_VALUE_ENUM_TYPE, unsigned long);
71 int frv_is_media_major  (CGEN_ATTR_VALUE_ENUM_TYPE, unsigned long);
72 int frv_is_branch_insn  (const CGEN_INSN *);
73 int frv_is_float_insn   (const CGEN_INSN *);
74 int frv_is_media_insn   (const CGEN_INSN *);
75 void frv_vliw_reset     (FRV_VLIW *, unsigned long, unsigned long);
76 int frv_vliw_add_insn   (FRV_VLIW *, const CGEN_INSN *);
77 int spr_valid           (long);
78 /* -- */
79 \f
80 /* -- opc.c */
81 #include "opintl.h"
82 #include "elf/frv.h"
83 #include <stdio.h>
84
85 /* DEBUG appears below as argument of OP macro.  */
86 #undef DEBUG
87
88 /* Returns TRUE if {MAJOR,MACH} is a major branch of the FRV
89    development tree.  */
90
91 bfd_boolean
92 frv_is_branch_major (CGEN_ATTR_VALUE_ENUM_TYPE major, unsigned long mach)
93 {
94   switch (mach)
95     {
96     case bfd_mach_fr400:
97       if (major >= FR400_MAJOR_B_1 && major <= FR400_MAJOR_B_6)
98         return TRUE;
99       break;
100     case bfd_mach_fr450:
101       if (major >= FR450_MAJOR_B_1 && major <= FR450_MAJOR_B_6)
102         return TRUE;
103       break;
104     default:
105       if (major >= FR500_MAJOR_B_1 && major <= FR500_MAJOR_B_6)
106         return TRUE;
107       break;
108     }
109
110   return FALSE;
111 }
112
113 /* Returns TRUE if {MAJOR,MACH} supports floating point insns.  */
114
115 bfd_boolean
116 frv_is_float_major (CGEN_ATTR_VALUE_ENUM_TYPE major, unsigned long mach)
117 {
118   switch (mach)
119     {
120     case bfd_mach_fr400:
121     case bfd_mach_fr450:
122       return FALSE;
123     default:
124       if (major >= FR500_MAJOR_F_1 && major <= FR500_MAJOR_F_8)
125         return TRUE;
126       break;
127     }
128
129   return FALSE;
130 }
131
132 /* Returns TRUE if {MAJOR,MACH} supports media insns.  */
133
134 bfd_boolean
135 frv_is_media_major (CGEN_ATTR_VALUE_ENUM_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 TRUE;
142       break;
143     case bfd_mach_fr450:
144       if (major >= FR450_MAJOR_M_1 && major <= FR450_MAJOR_M_6)
145         return TRUE;
146       break;
147     default:
148       if (major >= FR500_MAJOR_M_1 && major <= FR500_MAJOR_M_8)
149         return TRUE;
150       break;
151     }
152
153   return FALSE;
154 }
155
156 bfd_boolean
157 frv_is_branch_insn (const CGEN_INSN *insn)
158 {
159   if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
160                            bfd_mach_fr400))
161     return TRUE;
162   if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
163                            bfd_mach_fr450))
164     return TRUE;
165   if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
166                            bfd_mach_fr500))
167     return TRUE;
168
169   return FALSE;
170 }
171
172 bfd_boolean
173 frv_is_float_insn (const CGEN_INSN *insn)
174 {
175   if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
176                           bfd_mach_fr400))
177     return TRUE;
178   if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
179                           bfd_mach_fr450))
180     return TRUE;
181   if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
182                           bfd_mach_fr500))
183     return TRUE;
184
185   return FALSE;
186 }
187
188 bfd_boolean
189 frv_is_media_insn (const CGEN_INSN *insn)
190 {
191   if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
192                           bfd_mach_fr400))
193     return TRUE;
194   if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
195                           bfd_mach_fr450))
196     return TRUE;
197   if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
198                           bfd_mach_fr500))
199     return TRUE;
200
201   return FALSE;
202 }
203
204 /* This table represents the allowable packing for vliw insns for the fr400.
205    The fr400 has only 2 vliw slots. Represent this by not allowing any insns
206    in the extra slots.
207    Subsets of any given row are also allowed.  */
208 static VLIW_COMBO fr400_allowed_vliw[] =
209 {
210   /*  slot0       slot1       slot2       slot3    */
211   {  UNIT_I0,    UNIT_I1,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
212   {  UNIT_I0,    UNIT_FM0,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
213   {  UNIT_I0,    UNIT_B0,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
214   {  UNIT_FM0,   UNIT_FM1,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
215   {  UNIT_FM0,   UNIT_B0,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
216   {  UNIT_B0,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
217   {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
218   {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO }
219 };
220
221 /* This table represents the allowable packing for vliw insns for the fr500.
222    The fr500 has only 4 vliw slots. Represent this by not allowing any insns
223    in the extra slots.
224    Subsets of any given row are also allowed.  */
225 static VLIW_COMBO fr500_allowed_vliw[] =
226 {
227   /*  slot0       slot1       slot2       slot3    */
228   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1  PAD_VLIW_COMBO },
229   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0   PAD_VLIW_COMBO },
230   {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0   PAD_VLIW_COMBO },
231   {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
232   {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
233   {  UNIT_I0,    UNIT_B0,    UNIT_B1,    UNIT_NIL  PAD_VLIW_COMBO },
234   {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
235   {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL  PAD_VLIW_COMBO },
236   {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
237   {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
238   {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO }
239 };
240
241 /* This table represents the allowable packing for vliw insns for the fr550.
242    Subsets of any given row are also allowed.  */
243 static VLIW_COMBO fr550_allowed_vliw[] =
244 {
245   /*  slot0       slot1       slot2       slot3       slot4       slot5       slot6       slot7   */
246   {  UNIT_I0,    UNIT_I1,    UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL },
247   {  UNIT_I0,    UNIT_I1,    UNIT_I2,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
248   {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
249   {  UNIT_I0,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
250   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_I3,    UNIT_FM3 },
251   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_I3,    UNIT_B0  },
252   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_FM3,   UNIT_B0  },
253   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_B0,    UNIT_B1  },
254   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1  },
255   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_B0,    UNIT_B1,    UNIT_NIL },
256   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1  },
257   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1  },
258   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL },
259   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
260   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1,    UNIT_NIL },
261   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_I2,    UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
262   {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
263   {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1,    UNIT_NIL },
264   {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
265   {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
266   {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
267   {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
268   {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
269   {  UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
270   {  UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
271   {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
272   {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
273   {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL }
274 };
275
276 /* Some insns are assigned specialized implementation units which map to
277    different actual implementation units on different machines.  These
278    tables perform that mapping.  */
279 static CGEN_ATTR_VALUE_ENUM_TYPE fr400_unit_mapping[] =
280 {
281 /* unit in insn    actual unit */
282 /* NIL      */     UNIT_NIL,
283 /* I0       */     UNIT_I0,
284 /* I1       */     UNIT_I1,
285 /* I01      */     UNIT_I01, 
286 /* I2       */     UNIT_NIL, /* no I2 or I3 unit */
287 /* I3       */     UNIT_NIL,
288 /* IALL     */     UNIT_I01, /* only I0 and I1 units */
289 /* FM0      */     UNIT_FM0,
290 /* FM1      */     UNIT_FM1,
291 /* FM01     */     UNIT_FM01,
292 /* FM2      */     UNIT_NIL, /* no F2 or M2 units */
293 /* FM3      */     UNIT_NIL, /* no F3 or M3 units */
294 /* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
295 /* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
296 /* B0       */     UNIT_B0,  /* branches only in B0 unit.  */
297 /* B1       */     UNIT_B0,
298 /* B01      */     UNIT_B0,
299 /* C        */     UNIT_C,
300 /* MULT-DIV */     UNIT_I0,  /* multiply and divide only in I0  unit.  */
301 /* IACC     */     UNIT_I01, /* iacc multiply       in I0 or I1 unit.  */
302 /* LOAD     */     UNIT_I0,  /* load                only in I0  unit.  */
303 /* STORE    */     UNIT_I0,  /* store               only in I0  unit.  */
304 /* SCAN     */     UNIT_I0,  /* scan                only in I0  unit.  */
305 /* DCPL     */     UNIT_C,   /* dcpl                only in C   unit.  */
306 /* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
307 /* MDCUTSSI */     UNIT_FM0, /* mdcutssi            only in FM0 unit.  */
308 /* MCLRACC-1*/     UNIT_FM0  /* mclracc,A==1   insn only in FM0 unit.  */
309 };
310
311 /* Some insns are assigned specialized implementation units which map to
312    different actual implementation units on different machines.  These
313    tables perform that mapping.  */
314 static CGEN_ATTR_VALUE_ENUM_TYPE fr450_unit_mapping[] =
315 {
316 /* unit in insn    actual unit */
317 /* NIL      */     UNIT_NIL,
318 /* I0       */     UNIT_I0,
319 /* I1       */     UNIT_I1,
320 /* I01      */     UNIT_I01, 
321 /* I2       */     UNIT_NIL, /* no I2 or I3 unit */
322 /* I3       */     UNIT_NIL,
323 /* IALL     */     UNIT_I01, /* only I0 and I1 units */
324 /* FM0      */     UNIT_FM0,
325 /* FM1      */     UNIT_FM1,
326 /* FM01     */     UNIT_FM01,
327 /* FM2      */     UNIT_NIL, /* no F2 or M2 units */
328 /* FM3      */     UNIT_NIL, /* no F3 or M3 units */
329 /* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
330 /* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
331 /* B0       */     UNIT_B0,  /* branches only in B0 unit.  */
332 /* B1       */     UNIT_B0,
333 /* B01      */     UNIT_B0,
334 /* C        */     UNIT_C,
335 /* MULT-DIV */     UNIT_I0,  /* multiply and divide only in I0  unit.  */
336 /* IACC     */     UNIT_I01, /* iacc multiply       in I0 or I1 unit.  */
337 /* LOAD     */     UNIT_I0,  /* load                only in I0  unit.  */
338 /* STORE    */     UNIT_I0,  /* store               only in I0  unit.  */
339 /* SCAN     */     UNIT_I0,  /* scan                only in I0  unit.  */
340 /* DCPL     */     UNIT_I0,  /* dcpl                only in I0  unit.  */
341 /* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
342 /* MDCUTSSI */     UNIT_FM01, /* mdcutssi           in FM0 or FM1.  */
343 /* MCLRACC-1*/     UNIT_FM0  /* mclracc,A==1   insn only in FM0 unit.  */
344 };
345
346 static CGEN_ATTR_VALUE_ENUM_TYPE fr500_unit_mapping[] =
347 {
348 /* unit in insn    actual unit */
349 /* NIL      */     UNIT_NIL,
350 /* I0       */     UNIT_I0,
351 /* I1       */     UNIT_I1,
352 /* I01      */     UNIT_I01, 
353 /* I2       */     UNIT_NIL, /* no I2 or I3 unit */
354 /* I3       */     UNIT_NIL,
355 /* IALL     */     UNIT_I01, /* only I0 and I1 units */
356 /* FM0      */     UNIT_FM0,
357 /* FM1      */     UNIT_FM1,
358 /* FM01     */     UNIT_FM01,
359 /* FM2      */     UNIT_NIL, /* no F2 or M2 units */
360 /* FM3      */     UNIT_NIL, /* no F3 or M2 units */
361 /* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
362 /* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
363 /* B0       */     UNIT_B0,
364 /* B1       */     UNIT_B1,
365 /* B01      */     UNIT_B01,
366 /* C        */     UNIT_C,
367 /* MULT-DIV */     UNIT_I01, /* multiply and divide in I0 or I1 unit.  */
368 /* IACC     */     UNIT_NIL, /* iacc multiply       not implemented */
369 /* LOAD     */     UNIT_I01, /* load                in I0 or I1 unit.  */
370 /* STORE    */     UNIT_I0,  /* store               only in I0 unit.  */
371 /* SCAN     */     UNIT_I01, /* scan                in I0 or I1 unit.  */
372 /* DCPL     */     UNIT_C,   /* dcpl                only in C unit.  */
373 /* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
374 /* MDCUTSSI */     UNIT_FM0, /* mdcutssi            only in FM0 unit.  */
375 /* MCLRACC-1*/     UNIT_FM01 /* mclracc,A==1 in FM0 or FM1 unit.  */
376 };
377
378 static CGEN_ATTR_VALUE_ENUM_TYPE fr550_unit_mapping[] =
379 {
380 /* unit in insn    actual unit */
381 /* NIL      */     UNIT_NIL,
382 /* I0       */     UNIT_I0,
383 /* I1       */     UNIT_I1,
384 /* I01      */     UNIT_I01, 
385 /* I2       */     UNIT_I2,
386 /* I3       */     UNIT_I3,
387 /* IALL     */     UNIT_IALL, 
388 /* FM0      */     UNIT_FM0,
389 /* FM1      */     UNIT_FM1,
390 /* FM01     */     UNIT_FM01,
391 /* FM2      */     UNIT_FM2,
392 /* FM3      */     UNIT_FM3,
393 /* FMALL    */     UNIT_FMALL,
394 /* FMLOW    */     UNIT_FM01, /* Only F0,F1,M0,M1 units */
395 /* B0       */     UNIT_B0,
396 /* B1       */     UNIT_B1,
397 /* B01      */     UNIT_B01,
398 /* C        */     UNIT_C,
399 /* MULT-DIV */     UNIT_I01,  /* multiply and divide in I0 or I1 unit.    */
400 /* IACC     */     UNIT_NIL,  /* iacc multiply       not implemented.     */
401 /* LOAD     */     UNIT_I01,  /* load                in I0 or I1 unit.    */
402 /* STORE    */     UNIT_I01,  /* store               in I0 or I1 unit.    */
403 /* SCAN     */     UNIT_IALL, /* scan                in any integer unit. */
404 /* DCPL     */     UNIT_I0,   /* dcpl                only in I0 unit.     */
405 /* MDUALACC */     UNIT_FMALL,/* media dual acc insn in all media units   */
406 /* MDCUTSSI */     UNIT_FM01, /* mdcutssi            in FM0 or FM1 unit.  */
407 /* MCLRACC-1*/     UNIT_FM01  /* mclracc,A==1 in FM0 or FM1 unit.         */
408 };
409
410 void
411 frv_vliw_reset (FRV_VLIW *vliw, unsigned long mach, unsigned long elf_flags)
412 {
413   vliw->next_slot = 0;
414   vliw->constraint_violation = 0;
415   vliw->mach = mach;
416   vliw->elf_flags = elf_flags;
417
418   switch (mach)
419     {
420     case bfd_mach_fr400:
421       vliw->current_vliw = fr400_allowed_vliw;
422       vliw->unit_mapping = fr400_unit_mapping;
423       break;
424     case bfd_mach_fr450:
425       vliw->current_vliw = fr400_allowed_vliw;
426       vliw->unit_mapping = fr450_unit_mapping;
427       break;
428     case bfd_mach_fr550:
429       vliw->current_vliw = fr550_allowed_vliw;
430       vliw->unit_mapping = fr550_unit_mapping;
431       break;
432     default:
433       vliw->current_vliw = fr500_allowed_vliw;
434       vliw->unit_mapping = fr500_unit_mapping;
435       break;
436     }
437 }
438
439 /* Return TRUE if unit1 is a match for unit2.
440    Unit1 comes from the insn's UNIT attribute. unit2 comes from one of the
441    *_allowed_vliw tables above.  */
442 static bfd_boolean
443 match_unit (FRV_VLIW *vliw,
444             CGEN_ATTR_VALUE_ENUM_TYPE unit1, CGEN_ATTR_VALUE_ENUM_TYPE unit2)
445 {
446   /* Map any specialized implementation units to actual ones.  */
447   unit1 = vliw->unit_mapping[unit1];
448
449   if (unit1 == unit2)
450     return TRUE;
451   if (unit1 < unit2)
452     return FALSE;
453
454   switch (unit1)
455     {
456     case UNIT_I01:
457     case UNIT_FM01:
458     case UNIT_B01:
459       /* The 01 versions of these units are within 2 enums of the 0 or 1
460          versions.  */
461       if (unit1 - unit2 <= 2)
462         return TRUE;
463       break;
464     case UNIT_IALL:
465     case UNIT_FMALL:
466       /* The ALL versions of these units are within 5 enums of the 0, 1, 2 or 3
467          versions.  */
468       if (unit1 - unit2 <= 5)
469         return TRUE;
470       break;
471     default:
472       break;
473     }
474
475   return FALSE;
476 }
477
478 /* Return TRUE if the vliws match, FALSE otherwise.  */
479
480 static bfd_boolean
481 match_vliw (VLIW_COMBO *vliw1, VLIW_COMBO *vliw2, int vliw_size)
482 {
483   int i;
484
485   for (i = 0; i < vliw_size; ++i)
486     if ((*vliw1)[i] != (*vliw2)[i])
487       return FALSE;
488
489   return TRUE;
490 }
491
492 /* Find the next vliw vliw in the table that can accomodate the new insn.
493    If one is found then return it. Otherwise return NULL.  */
494
495 static VLIW_COMBO *
496 add_next_to_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE unit)
497 {
498   int           next    = vliw->next_slot;
499   VLIW_COMBO    *current = vliw->current_vliw;
500   VLIW_COMBO    *potential;
501
502   if (next <= 0)
503     {
504       /* xgettext:c-format */
505       opcodes_error_handler (_("internal error: bad vliw->next_slot value"));
506       abort ();
507     }
508
509   /* The table is sorted by units allowed within slots, so vliws with
510      identical starting sequences are together.  */
511   potential = current;
512   do
513     {
514       if (match_unit (vliw, unit, (*potential)[next]))
515         return potential;
516       ++potential;
517     }
518   while (match_vliw (potential, current, next));
519
520   return NULL;
521 }
522
523 /* Look for the given major insn type in the given vliw.
524    Returns TRUE if found, FALSE otherwise.  */
525
526 static bfd_boolean
527 find_major_in_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
528 {
529   int i;
530
531   for (i = 0; i < vliw->next_slot; ++i)
532     if (vliw->major[i] == major)
533       return TRUE;
534
535   return FALSE;
536 }
537
538 /* Check for constraints between the insns in the vliw due to major insn
539    types.  */
540
541 static bfd_boolean
542 fr400_check_insn_major_constraints (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
543 {
544   /* In the cpu file, all media insns are represented as being allowed in
545      both media units. This makes it easier since this is the case for fr500.
546      Catch the invalid combinations here.  Insns of major class FR400_MAJOR_M_2
547      cannot coexist with any other media insn in a vliw.  */
548   switch (major)
549     {
550     case FR400_MAJOR_M_2:
551       return ! find_major_in_vliw (vliw, FR400_MAJOR_M_1)
552         &&   ! find_major_in_vliw (vliw, FR400_MAJOR_M_2);
553     case FR400_MAJOR_M_1:
554       return ! find_major_in_vliw (vliw, FR400_MAJOR_M_2);
555     default:
556       break;
557     }
558   return TRUE;
559 }
560
561 static bfd_boolean
562 fr450_check_insn_major_constraints (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
563 {
564   CGEN_ATTR_VALUE_ENUM_TYPE other_major;
565
566   /* Our caller guarantees there's at least one other instruction.  */
567   other_major = CGEN_INSN_ATTR_VALUE (vliw->insn[0], CGEN_INSN_FR450_MAJOR);
568
569   /* (M4, M5) and (M4, M6) are allowed.  */
570   if (other_major == FR450_MAJOR_M_4)
571     if (major == FR450_MAJOR_M_5 || major == FR450_MAJOR_M_6)
572       return TRUE;
573
574   /* Otherwise, instructions in even-numbered media categories cannot be
575      executed in parallel with other media instructions.  */
576   switch (major)
577     {
578     case FR450_MAJOR_M_2:
579     case FR450_MAJOR_M_4:
580     case FR450_MAJOR_M_6:
581       return !(other_major >= FR450_MAJOR_M_1
582                && other_major <= FR450_MAJOR_M_6);
583
584     case FR450_MAJOR_M_1:
585     case FR450_MAJOR_M_3:
586     case FR450_MAJOR_M_5:
587       return !(other_major == FR450_MAJOR_M_2
588                || other_major == FR450_MAJOR_M_4
589                || other_major == FR450_MAJOR_M_6);
590
591     default:
592       return TRUE;
593     }
594 }
595
596 static bfd_boolean
597 find_unit_in_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE unit)
598 {
599   int i;
600
601   for (i = 0; i < vliw->next_slot; ++i)
602     if (CGEN_INSN_ATTR_VALUE (vliw->insn[i], CGEN_INSN_UNIT) == unit)
603       return TRUE;
604
605   return FALSE; /* Not found.  */
606 }
607
608 static bfd_boolean
609 find_major_in_slot (FRV_VLIW *vliw,
610                     CGEN_ATTR_VALUE_ENUM_TYPE major,
611                     CGEN_ATTR_VALUE_ENUM_TYPE slot)
612 {
613   int i;
614
615   for (i = 0; i < vliw->next_slot; ++i)
616     if (vliw->major[i] == major && (*vliw->current_vliw)[i] == slot)
617       return TRUE;
618
619   return FALSE;
620 }
621
622 static bfd_boolean
623 fr550_find_media_in_vliw (FRV_VLIW *vliw)
624 {
625   int i;
626
627   for (i = 0; i < vliw->next_slot; ++i)
628     {
629       if (vliw->major[i] < FR550_MAJOR_M_1 || vliw->major[i] > FR550_MAJOR_M_5)
630         continue;
631
632       /* Found a media insn, however, MNOP and MCLRACC don't count.  */
633       if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MNOP
634           || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_0
635           || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_1)
636         continue;
637
638       return TRUE; /* Found one.  */
639     }
640
641   return FALSE;
642 }
643
644 static bfd_boolean
645 fr550_find_float_in_vliw (FRV_VLIW *vliw)
646 {
647   int i;
648
649   for (i = 0; i < vliw->next_slot; ++i)
650     {
651       if (vliw->major[i] < FR550_MAJOR_F_1 || vliw->major[i] > FR550_MAJOR_F_4)
652         continue;
653
654       /* Found a floating point insn, however, FNOP doesn't count.  */
655       if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_FNOP)
656         continue;
657
658       return TRUE; /* Found one.  */
659     }
660
661   return FALSE;
662 }
663
664 static bfd_boolean
665 fr550_check_insn_major_constraints (FRV_VLIW *vliw,
666                                     CGEN_ATTR_VALUE_ENUM_TYPE major,
667                                     const CGEN_INSN *insn)
668 {
669   CGEN_ATTR_VALUE_ENUM_TYPE unit;
670   CGEN_ATTR_VALUE_ENUM_TYPE slot = (*vliw->current_vliw)[vliw->next_slot];
671   switch (slot)
672     {
673     case UNIT_I2:
674       /* If it's a store, then there must be another store in I1 */
675       unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
676       if (unit == UNIT_STORE)
677         return find_unit_in_vliw (vliw, UNIT_STORE);
678       break;
679     case UNIT_FM2:
680     case UNIT_FM3:
681       /* Floating point insns other than FNOP in slot f2 or f3 cannot coexist
682          with media insns.  */
683       if (major >= FR550_MAJOR_F_1 && major <= FR550_MAJOR_F_4
684           && CGEN_INSN_NUM (insn) != FRV_INSN_FNOP)
685         return ! fr550_find_media_in_vliw (vliw);
686       /* Media insns other than MNOP in slot m2 or m3 cannot coexist with
687          floating point insns.  */
688       if (major >= FR550_MAJOR_M_1 && major <= FR550_MAJOR_M_5
689           && CGEN_INSN_NUM (insn) != FRV_INSN_MNOP)
690         return ! fr550_find_float_in_vliw (vliw);
691       /* F-2 in slot f2 or f3 cannot coexist with F-2 or F-4 in slot f1 or f2
692          respectively.  */
693       if (major == FR550_MAJOR_F_2)
694         return ! find_major_in_slot (vliw, FR550_MAJOR_F_2,
695                                      slot - (UNIT_FM2 - UNIT_FM0))
696           &&   ! find_major_in_slot (vliw, FR550_MAJOR_F_4,
697                                      slot - (UNIT_FM2 - UNIT_FM0));
698       /* M-2 or M-5 in slot m2 or m3 cannot coexist with M-2 in slot m1 or m2
699          respectively.  */
700       if (major == FR550_MAJOR_M_2 || major == FR550_MAJOR_M_5)
701         return ! find_major_in_slot (vliw, FR550_MAJOR_M_2,
702                                      slot - (UNIT_FM2 - UNIT_FM0));
703       /* M-4 in slot m2 or m3 cannot coexist with M-4 in slot m1 or m2
704          respectively.  */
705       if (major == FR550_MAJOR_M_4)
706         return ! find_major_in_slot (vliw, FR550_MAJOR_M_4,
707                                      slot - (UNIT_FM2 - UNIT_FM0));
708       break;
709     default:
710       break;
711     }
712   return TRUE; /* All OK.  */
713 }
714
715 static bfd_boolean
716 fr500_check_insn_major_constraints (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
717 {
718   /* TODO: A table might be faster for some of the more complex instances
719      here.  */
720   switch (major)
721     {
722     case FR500_MAJOR_I_1:
723     case FR500_MAJOR_I_4:
724     case FR500_MAJOR_I_5:
725     case FR500_MAJOR_I_6:
726     case FR500_MAJOR_B_1:
727     case FR500_MAJOR_B_2:
728     case FR500_MAJOR_B_3:
729     case FR500_MAJOR_B_4:
730     case FR500_MAJOR_B_5:
731     case FR500_MAJOR_B_6:
732     case FR500_MAJOR_F_4:
733     case FR500_MAJOR_F_8:
734     case FR500_MAJOR_M_8:
735       return TRUE; /* OK */
736     case FR500_MAJOR_I_2:
737       /* Cannot coexist with I-3 insn.  */
738       return ! find_major_in_vliw (vliw, FR500_MAJOR_I_3);
739     case FR500_MAJOR_I_3:
740       /* Cannot coexist with I-2 insn.  */
741       return ! find_major_in_vliw (vliw, FR500_MAJOR_I_2);
742     case FR500_MAJOR_F_1:
743     case FR500_MAJOR_F_2:
744       /* Cannot coexist with F-5, F-6, or M-7 insn.  */
745       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
746         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
747         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
748     case FR500_MAJOR_F_3:
749       /* Cannot coexist with F-7, or M-7 insn.  */
750       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
751         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
752     case FR500_MAJOR_F_5:
753       /* Cannot coexist with F-1, F-2, F-6, F-7, or M-7 insn.  */
754       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
755         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
756         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
757         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
758         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
759     case FR500_MAJOR_F_6:
760       /* Cannot coexist with F-1, F-2, F-5, F-6, or M-7 insn.  */
761       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
762         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
763         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
764         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
765         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
766     case FR500_MAJOR_F_7:
767       /* Cannot coexist with F-3, F-5, F-7, or M-7 insn.  */
768       return ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
769         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
770         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
771         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
772     case FR500_MAJOR_M_1:
773       /* Cannot coexist with M-7 insn.  */
774       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
775     case FR500_MAJOR_M_2:
776     case FR500_MAJOR_M_3:
777       /* Cannot coexist with M-5, M-6 or M-7 insn.  */
778       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
779         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
780         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
781     case FR500_MAJOR_M_4:
782       /* Cannot coexist with M-6 insn.  */
783       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_6);
784     case FR500_MAJOR_M_5:
785       /* Cannot coexist with M-2, M-3, M-5, M-6  or M-7 insn.  */
786       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
787         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
788         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
789         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
790         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
791     case FR500_MAJOR_M_6:
792       /* Cannot coexist with M-2, M-3, M-4, M-5, M-6  or M-7 insn.  */
793       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
794         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
795         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_4)
796         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
797         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
798         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
799     case FR500_MAJOR_M_7:
800       /* Cannot coexist with M-1, M-2, M-3, M-5, M-6  or M-7 insn.  */
801       return ! find_major_in_vliw (vliw, FR500_MAJOR_M_1)
802         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
803         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
804         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
805         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
806         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7)
807         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
808         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
809         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
810         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
811         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
812         &&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7);
813     default:
814       /* xgettext:c-format */
815       opcodes_error_handler (_("internal error: bad major code"));
816       abort ();
817       break;
818     }
819   return TRUE;
820 }
821
822 static bfd_boolean
823 check_insn_major_constraints (FRV_VLIW *vliw,
824                               CGEN_ATTR_VALUE_ENUM_TYPE major,
825                               const CGEN_INSN *insn)
826 {
827   switch (vliw->mach)
828     {
829     case bfd_mach_fr400:
830       return fr400_check_insn_major_constraints (vliw, major);
831
832     case bfd_mach_fr450:
833       return fr450_check_insn_major_constraints (vliw, major);
834
835     case bfd_mach_fr550:
836       return fr550_check_insn_major_constraints (vliw, major, insn);
837
838     default:
839       return fr500_check_insn_major_constraints (vliw, major);
840     }
841 }
842
843 /* Add in insn to the VLIW vliw if possible.
844    Return 0 if successful, non-zero otherwise.  */
845
846 int
847 frv_vliw_add_insn (FRV_VLIW *vliw, const CGEN_INSN *insn)
848 {
849   int slot_index;
850   CGEN_ATTR_VALUE_ENUM_TYPE major;
851   CGEN_ATTR_VALUE_ENUM_TYPE unit;
852   VLIW_COMBO *new_vliw;
853
854   if (vliw->constraint_violation || CGEN_INSN_INVALID_P (insn))
855     return 1;
856
857   slot_index = vliw->next_slot;
858   if (slot_index >= FRV_VLIW_SIZE)
859     return 1;
860
861   unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
862   if (unit == UNIT_NIL)
863     {
864       /* xgettext:c-format */
865       opcodes_error_handler (_("internal error: bad insn unit"));
866       abort ();
867     }
868
869   switch (vliw->mach)
870     {
871     case bfd_mach_fr400:
872       major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR);
873       break;
874     case bfd_mach_fr450:
875       major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR);
876       break;
877     case bfd_mach_fr550:
878       major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR550_MAJOR);
879       break;
880     default:
881       major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR);
882       break;
883     }
884
885   if (slot_index <= 0)
886     {
887       /* Any insn can be added to slot 0.  */
888       while (! match_unit (vliw, unit, (*vliw->current_vliw)[0]))
889         ++vliw->current_vliw;
890       vliw->major[0] = major;
891       vliw->insn[0] = insn;
892       vliw->next_slot = 1;
893       return 0;
894     }
895
896   /* If there are already insns in the vliw(s) check to see that
897      this one can be added.  Do this by finding an allowable vliw
898      combination that can accept the new insn.  */
899   if (! (vliw->elf_flags & EF_FRV_NOPACK))
900     {
901       new_vliw = add_next_to_vliw (vliw, unit);
902       if (new_vliw && check_insn_major_constraints (vliw, major, insn))
903         {
904           vliw->current_vliw = new_vliw;
905           vliw->major[slot_index] = major;
906           vliw->insn[slot_index] = insn;
907           vliw->next_slot++;
908           return 0;
909         }
910
911       /* The frv machine supports all packing conbinations.  If we fail,
912          to add the insn, then it could not be handled as if it was the fr500.
913          Just return as if it was handled ok.  */
914       if (vliw->mach == bfd_mach_frv)
915         return 0;
916     }
917
918   vliw->constraint_violation = 1;
919   return 1;
920 }
921
922 bfd_boolean
923 spr_valid (long regno)
924 {
925   if (regno < 0)     return FALSE;
926   if (regno <= 4095) return TRUE;
927   return FALSE;
928 }
929 /* -- */
930 \f
931 /* -- asm.c */
932 inline static const char *
933 parse_symbolic_address (CGEN_CPU_DESC cd,
934                         const char **strp,
935                         int opindex,
936                         int opinfo,
937                         enum cgen_parse_operand_result *resultp,
938                         bfd_vma *valuep)
939 {
940   enum cgen_parse_operand_result result_type;
941   const char *errmsg = (* cd->parse_operand_fn)
942     (cd, CGEN_PARSE_OPERAND_SYMBOLIC, strp, opindex, opinfo,
943      &result_type, valuep);
944
945   if (errmsg == NULL
946       && result_type != CGEN_PARSE_OPERAND_RESULT_QUEUED)
947     return "symbolic expression required";
948
949   if (resultp)
950     *resultp = result_type;
951
952   return errmsg;
953 }
954
955 static const char *
956 parse_ldd_annotation (CGEN_CPU_DESC cd,
957                       const char **strp,
958                       int opindex,
959                       unsigned long *valuep)
960 {
961   const char *errmsg;
962   enum cgen_parse_operand_result result_type;
963   bfd_vma value;
964
965   if (**strp == '#' || **strp == '%')
966     {
967       if (strncasecmp (*strp + 1, "tlsdesc(", 8) == 0)
968         {
969           *strp += 9;
970           errmsg = parse_symbolic_address (cd, strp, opindex,
971                                            BFD_RELOC_FRV_TLSDESC_RELAX,
972                                            &result_type, &value);
973           if (**strp != ')')
974             return "missing ')'";
975           if (valuep)
976             *valuep = value;
977           ++*strp;
978           if (errmsg)
979             return errmsg;
980         }
981     }
982   
983   while (**strp == ' ' || **strp == '\t')
984     ++*strp;
985   
986   if (**strp != '@')
987     return "missing `@'";
988
989   ++*strp;
990
991   return NULL;
992 }
993
994 static const char *
995 parse_call_annotation (CGEN_CPU_DESC cd,
996                        const char **strp,
997                        int opindex,
998                        unsigned long *valuep)
999 {
1000   const char *errmsg;
1001   enum cgen_parse_operand_result result_type;
1002   bfd_vma value;
1003
1004   if (**strp == '#' || **strp == '%')
1005     {
1006       if (strncasecmp (*strp + 1, "gettlsoff(", 10) == 0)
1007         {
1008           *strp += 11;
1009           errmsg = parse_symbolic_address (cd, strp, opindex,
1010                                            BFD_RELOC_FRV_GETTLSOFF_RELAX,
1011                                            &result_type, &value);
1012           if (**strp != ')')
1013             return "missing ')'";
1014           if (valuep)
1015             *valuep = value;
1016           ++*strp;
1017           if (errmsg)
1018             return errmsg;
1019         }
1020     }
1021   
1022   while (**strp == ' ' || **strp == '\t')
1023     ++*strp;
1024   
1025   if (**strp != '@')
1026     return "missing `@'";
1027
1028   ++*strp;
1029
1030   return NULL;
1031 }
1032
1033 static const char *
1034 parse_ld_annotation (CGEN_CPU_DESC cd,
1035                      const char **strp,
1036                      int opindex,
1037                      unsigned long *valuep)
1038 {
1039   const char *errmsg;
1040   enum cgen_parse_operand_result result_type;
1041   bfd_vma value;
1042
1043   if (**strp == '#' || **strp == '%')
1044     {
1045       if (strncasecmp (*strp + 1, "tlsoff(", 7) == 0)
1046         {
1047           *strp += 8;
1048           errmsg = parse_symbolic_address (cd, strp, opindex,
1049                                            BFD_RELOC_FRV_TLSOFF_RELAX,
1050                                            &result_type, &value);
1051           if (**strp != ')')
1052             return "missing ')'";
1053           if (valuep)
1054             *valuep = value;
1055           ++*strp;
1056           if (errmsg)
1057             return errmsg;
1058         }
1059     }
1060   
1061   while (**strp == ' ' || **strp == '\t')
1062     ++*strp;
1063   
1064   if (**strp != '@')
1065     return "missing `@'";
1066
1067   ++*strp;
1068
1069   return NULL;
1070 }
1071
1072 static const char *
1073 parse_ulo16 (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, "lo(", 3) == 0)
1085         {
1086           *strp += 4;
1087           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
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 &= 0xffff;
1095           *valuep = value;
1096           return errmsg;
1097         }
1098       if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
1099         {
1100           *strp += 9;
1101           errmsg = parse_symbolic_address (cd, strp, opindex,
1102                                            BFD_RELOC_FRV_GPRELLO,
1103                                            & result_type, & value);
1104           if (**strp != ')')
1105             return "missing ')'";
1106           ++*strp;
1107           *valuep = value;
1108           return errmsg;
1109         }
1110       else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
1111         {
1112           *strp += 7;
1113           errmsg = parse_symbolic_address (cd, strp, opindex,
1114                                            BFD_RELOC_FRV_GOTLO,
1115                                            & result_type, & value);
1116           if (**strp != ')')
1117             return "missing ')'";
1118           ++*strp;
1119           *valuep = value;
1120           return errmsg;
1121         }
1122       else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
1123         {
1124           *strp += 15;
1125           errmsg = parse_symbolic_address (cd, strp, opindex,
1126                                            BFD_RELOC_FRV_FUNCDESC_GOTLO,
1127                                            & result_type, & value);
1128           if (**strp != ')')
1129             return "missing ')'";
1130           ++*strp;
1131           *valuep = value;
1132           return errmsg;
1133         }
1134       else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
1135         {
1136           *strp += 10;
1137           errmsg = parse_symbolic_address (cd, strp, opindex,
1138                                            BFD_RELOC_FRV_GOTOFFLO,
1139                                            & result_type, & value);
1140           if (**strp != ')')
1141             return "missing ')'";
1142           ++*strp;
1143           *valuep = value;
1144           return errmsg;
1145         }
1146       else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
1147         {
1148           *strp += 18;
1149           errmsg = parse_symbolic_address (cd, strp, opindex,
1150                                            BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
1151                                            & result_type, & value);
1152           if (**strp != ')')
1153             return "missing ')'";
1154           ++*strp;
1155           *valuep = value;
1156           return errmsg;
1157         }
1158       else if (strncasecmp (*strp + 1, "gottlsdesclo(", 13) == 0)
1159         {
1160           *strp += 14;
1161           errmsg = parse_symbolic_address (cd, strp, opindex,
1162                                            BFD_RELOC_FRV_GOTTLSDESCLO,
1163                                            & result_type, & value);
1164           if (**strp != ')')
1165             return "missing ')'";
1166           ++*strp;
1167           *valuep = value;
1168           return errmsg;
1169         }
1170       else if (strncasecmp (*strp + 1, "tlsmofflo(", 10) == 0)
1171         {
1172           *strp += 11;
1173           errmsg = parse_symbolic_address (cd, strp, opindex,
1174                                            BFD_RELOC_FRV_TLSMOFFLO,
1175                                            & result_type, & value);
1176           if (**strp != ')')
1177             return "missing ')'";
1178           ++*strp;
1179           *valuep = value;
1180           return errmsg;
1181         }
1182       else if (strncasecmp (*strp + 1, "gottlsofflo(", 12) == 0)
1183         {
1184           *strp += 13;
1185           errmsg = parse_symbolic_address (cd, strp, opindex,
1186                                            BFD_RELOC_FRV_GOTTLSOFFLO,
1187                                            & result_type, & value);
1188           if (**strp != ')')
1189             return "missing ')'";
1190           ++*strp;
1191           *valuep = value;
1192           return errmsg;
1193         }
1194     }
1195   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1196 }
1197
1198 static const char *
1199 parse_uslo16 (CGEN_CPU_DESC cd,
1200               const char **strp,
1201               int opindex,
1202               signed long *valuep)
1203 {
1204   const char *errmsg;
1205   enum cgen_parse_operand_result result_type;
1206   bfd_vma value;
1207  
1208   if (**strp == '#' || **strp == '%')
1209     {
1210       if (strncasecmp (*strp + 1, "lo(", 3) == 0)
1211         {
1212           *strp += 4;
1213           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
1214                                        & result_type, & value);
1215           if (**strp != ')')
1216             return "missing `)'";
1217           ++*strp;
1218           if (errmsg == NULL
1219               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1220             value &= 0xffff;
1221           *valuep = value;
1222           return errmsg;
1223         }
1224       else if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
1225         {
1226           *strp += 9;
1227           errmsg = parse_symbolic_address (cd, strp, opindex,
1228                                            BFD_RELOC_FRV_GPRELLO,
1229                                            & result_type, & value);
1230           if (**strp != ')')
1231             return "missing ')'";
1232           ++*strp;
1233           *valuep = value;
1234           return errmsg;
1235         }
1236       else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
1237         {
1238           *strp += 7;
1239           errmsg = parse_symbolic_address (cd, strp, opindex,
1240                                            BFD_RELOC_FRV_GOTLO,
1241                                            & result_type, & value);
1242           if (**strp != ')')
1243             return "missing ')'";
1244           ++*strp;
1245           *valuep = value;
1246           return errmsg;
1247         }
1248       else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
1249         {
1250           *strp += 15;
1251           errmsg = parse_symbolic_address (cd, strp, opindex,
1252                                            BFD_RELOC_FRV_FUNCDESC_GOTLO,
1253                                            & result_type, & value);
1254           if (**strp != ')')
1255             return "missing ')'";
1256           ++*strp;
1257           *valuep = value;
1258           return errmsg;
1259         }
1260       else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
1261         {
1262           *strp += 10;
1263           errmsg = parse_symbolic_address (cd, strp, opindex,
1264                                            BFD_RELOC_FRV_GOTOFFLO,
1265                                            & result_type, & value);
1266           if (**strp != ')')
1267             return "missing ')'";
1268           ++*strp;
1269           *valuep = value;
1270           return errmsg;
1271         }
1272       else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
1273         {
1274           *strp += 18;
1275           errmsg = parse_symbolic_address (cd, strp, opindex,
1276                                            BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
1277                                            & result_type, & value);
1278           if (**strp != ')')
1279             return "missing ')'";
1280           ++*strp;
1281           *valuep = value;
1282           return errmsg;
1283         }
1284       else if (strncasecmp (*strp + 1, "gottlsdesclo(", 13) == 0)
1285         {
1286           *strp += 14;
1287           errmsg = parse_symbolic_address (cd, strp, opindex,
1288                                            BFD_RELOC_FRV_GOTTLSDESCLO,
1289                                            & result_type, & value);
1290           if (**strp != ')')
1291             return "missing ')'";
1292           ++*strp;
1293           *valuep = value;
1294           return errmsg;
1295         }
1296       else if (strncasecmp (*strp + 1, "tlsmofflo(", 10) == 0)
1297         {
1298           *strp += 11;
1299           errmsg = parse_symbolic_address (cd, strp, opindex,
1300                                            BFD_RELOC_FRV_TLSMOFFLO,
1301                                            & result_type, & value);
1302           if (**strp != ')')
1303             return "missing ')'";
1304           ++*strp;
1305           *valuep = value;
1306           return errmsg;
1307         }
1308       else if (strncasecmp (*strp + 1, "gottlsofflo(", 12) == 0)
1309         {
1310           *strp += 13;
1311           errmsg = parse_symbolic_address (cd, strp, opindex,
1312                                            BFD_RELOC_FRV_GOTTLSOFFLO,
1313                                            & result_type, & value);
1314           if (**strp != ')')
1315             return "missing ')'";
1316           ++*strp;
1317           *valuep = value;
1318           return errmsg;
1319         }
1320     }
1321   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1322 }
1323
1324 static const char *
1325 parse_uhi16 (CGEN_CPU_DESC cd,
1326              const char **strp,
1327              int opindex,
1328              unsigned long *valuep)
1329 {
1330   const char *errmsg;
1331   enum cgen_parse_operand_result result_type;
1332   bfd_vma value;
1333  
1334   if (**strp == '#' || **strp == '%')
1335     {
1336       if (strncasecmp (*strp + 1, "hi(", 3) == 0)
1337         {
1338           *strp += 4;
1339           errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_HI16,
1340                                        & result_type, & value);
1341           if (**strp != ')')
1342             return "missing `)'";
1343           ++*strp;
1344           if (errmsg == NULL
1345               && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1346             {
1347               /* If value is wider than 32 bits then be
1348                  careful about how we extract bits 16-31.  */
1349               if (sizeof (value) > 4)
1350                 value &= (((bfd_vma)1 << 16) << 16) - 1;
1351
1352               value >>= 16;
1353             }
1354           *valuep = value;
1355           return errmsg;
1356         }
1357       else if (strncasecmp (*strp + 1, "gprelhi(", 8) == 0)
1358         {
1359           *strp += 9;
1360           errmsg = parse_symbolic_address (cd, strp, opindex,
1361                                            BFD_RELOC_FRV_GPRELHI,
1362                                            & result_type, & value);
1363           if (**strp != ')')
1364             return "missing ')'";
1365           ++*strp;
1366           *valuep = value;
1367           return errmsg;
1368         }
1369       else if (strncasecmp (*strp + 1, "gothi(", 6) == 0)
1370         {
1371           *strp += 7;
1372           errmsg = parse_symbolic_address (cd, strp, opindex,
1373                                            BFD_RELOC_FRV_GOTHI,
1374                                            & result_type, & value);
1375           if (**strp != ')')
1376             return "missing ')'";
1377           ++*strp;
1378           *valuep = value;
1379           return errmsg;
1380         }
1381       else if (strncasecmp (*strp + 1, "gotfuncdeschi(", 14) == 0)
1382         {
1383           *strp += 15;
1384           errmsg = parse_symbolic_address (cd, strp, opindex,
1385                                            BFD_RELOC_FRV_FUNCDESC_GOTHI,
1386                                            & result_type, & value);
1387           if (**strp != ')')
1388             return "missing ')'";
1389           ++*strp;
1390           *valuep = value;
1391           return errmsg;
1392         }
1393       else if (strncasecmp (*strp + 1, "gotoffhi(", 9) == 0)
1394         {
1395           *strp += 10;
1396           errmsg = parse_symbolic_address (cd, strp, opindex,
1397                                            BFD_RELOC_FRV_GOTOFFHI,
1398                                            & result_type, & value);
1399           if (**strp != ')')
1400             return "missing ')'";
1401           ++*strp;
1402           *valuep = value;
1403           return errmsg;
1404         }
1405       else if (strncasecmp (*strp + 1, "gotofffuncdeschi(", 17) == 0)
1406         {
1407           *strp += 18;
1408           errmsg = parse_symbolic_address (cd, strp, opindex,
1409                                            BFD_RELOC_FRV_FUNCDESC_GOTOFFHI,
1410                                            & result_type, & value);
1411           if (**strp != ')')
1412             return "missing ')'";
1413           ++*strp;
1414           *valuep = value;
1415           return errmsg;
1416         }
1417       else if (strncasecmp (*strp + 1, "gottlsdeschi(", 13) == 0)
1418         {
1419           *strp += 14;
1420           errmsg = parse_symbolic_address (cd, strp, opindex,
1421                                            BFD_RELOC_FRV_GOTTLSDESCHI,
1422                                            &result_type, &value);
1423           if (**strp != ')')
1424             return "missing ')'";
1425           ++*strp;
1426           *valuep = value;
1427           return errmsg;
1428         }
1429       else if (strncasecmp (*strp + 1, "tlsmoffhi(", 10) == 0)
1430         {
1431           *strp += 11;
1432           errmsg = parse_symbolic_address (cd, strp, opindex,
1433                                            BFD_RELOC_FRV_TLSMOFFHI,
1434                                            & result_type, & value);
1435           if (**strp != ')')
1436             return "missing ')'";
1437           ++*strp;
1438           *valuep = value;
1439           return errmsg;
1440         }
1441       else if (strncasecmp (*strp + 1, "gottlsoffhi(", 12) == 0)
1442         {
1443           *strp += 13;
1444           errmsg = parse_symbolic_address (cd, strp, opindex,
1445                                            BFD_RELOC_FRV_GOTTLSOFFHI,
1446                                            & result_type, & value);
1447           if (**strp != ')')
1448             return "missing ')'";
1449           ++*strp;
1450           *valuep = value;
1451           return errmsg;
1452         }
1453     }
1454   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1455 }
1456
1457 static long
1458 parse_register_number (const char **strp)
1459 {
1460   int regno;
1461
1462   if (**strp < '0' || **strp > '9')
1463     return -1; /* error */
1464
1465   regno = **strp - '0';
1466   for (++*strp; **strp >= '0' && **strp <= '9'; ++*strp)
1467     regno = regno * 10 + (**strp - '0');
1468
1469   return regno;
1470 }
1471
1472 static const char *
1473 parse_spr (CGEN_CPU_DESC cd,
1474            const char **strp,
1475            CGEN_KEYWORD * table,
1476            long *valuep)
1477 {
1478   const char *save_strp;
1479   long regno;
1480
1481   /* Check for spr index notation.  */
1482   if (strncasecmp (*strp, "spr[", 4) == 0)
1483     {
1484       *strp += 4;
1485       regno = parse_register_number (strp);
1486       if (**strp != ']')
1487         return _("missing `]'");
1488       ++*strp;
1489       if (! spr_valid (regno))
1490         return _("Special purpose register number is out of range");
1491       *valuep = regno;
1492       return NULL;
1493     }
1494
1495   save_strp = *strp;
1496   regno = parse_register_number (strp);
1497   if (regno != -1)
1498     {
1499       if (! spr_valid (regno))
1500         return _("Special purpose register number is out of range");
1501       *valuep = regno;
1502       return NULL;
1503     }
1504
1505   *strp = save_strp;
1506   return cgen_parse_keyword (cd, strp, table, valuep);
1507 }
1508
1509 static const char *
1510 parse_d12 (CGEN_CPU_DESC cd,
1511            const char **strp,
1512            int opindex,
1513            long *valuep)
1514 {
1515   const char *errmsg;
1516   enum cgen_parse_operand_result result_type;
1517   bfd_vma value;
1518  
1519   /* Check for small data reference.  */
1520   if (**strp == '#' || **strp == '%')
1521     {
1522       if (strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1523         {
1524           *strp += 9;
1525           errmsg = parse_symbolic_address (cd, strp, opindex,
1526                                            BFD_RELOC_FRV_GPREL12,
1527                                            & result_type, & value);
1528           if (**strp != ')')
1529             return "missing `)'";
1530           ++*strp;
1531           *valuep = value;
1532           return errmsg;
1533         }
1534       else if (strncasecmp (*strp + 1, "got12(", 6) == 0)
1535         {
1536           *strp += 7;
1537           errmsg = parse_symbolic_address (cd, strp, opindex,
1538                                            BFD_RELOC_FRV_GOT12,
1539                                            & result_type, & value);
1540           if (**strp != ')')
1541             return "missing ')'";
1542           ++*strp;
1543           *valuep = value;
1544           return errmsg;
1545         }
1546       else if (strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
1547         {
1548           *strp += 15;
1549           errmsg = parse_symbolic_address (cd, strp, opindex,
1550                                            BFD_RELOC_FRV_FUNCDESC_GOT12,
1551                                            & result_type, & value);
1552           if (**strp != ')')
1553             return "missing ')'";
1554           ++*strp;
1555           *valuep = value;
1556           return errmsg;
1557         }
1558       else if (strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
1559         {
1560           *strp += 10;
1561           errmsg = parse_symbolic_address (cd, strp, opindex,
1562                                            BFD_RELOC_FRV_GOTOFF12,
1563                                            & result_type, & value);
1564           if (**strp != ')')
1565             return "missing ')'";
1566           ++*strp;
1567           *valuep = value;
1568           return errmsg;
1569         }
1570       else if (strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
1571         {
1572           *strp += 18;
1573           errmsg = parse_symbolic_address (cd, strp, opindex,
1574                                            BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
1575                                            & result_type, & value);
1576           if (**strp != ')')
1577             return "missing ')'";
1578           ++*strp;
1579           *valuep = value;
1580           return errmsg;
1581         }
1582       else if (strncasecmp (*strp + 1, "gottlsdesc12(", 13) == 0)
1583         {
1584           *strp += 14;
1585           errmsg = parse_symbolic_address (cd, strp, opindex,
1586                                            BFD_RELOC_FRV_GOTTLSDESC12,
1587                                            & result_type, & value);
1588           if (**strp != ')')
1589             return "missing ')'";
1590           ++*strp;
1591           *valuep = value;
1592           return errmsg;
1593         }
1594       else if (strncasecmp (*strp + 1, "tlsmoff12(", 10) == 0)
1595         {
1596           *strp += 11;
1597           errmsg = parse_symbolic_address (cd, strp, opindex,
1598                                            BFD_RELOC_FRV_TLSMOFF12,
1599                                            & result_type, & value);
1600           if (**strp != ')')
1601             return "missing ')'";
1602           ++*strp;
1603           *valuep = value;
1604           return errmsg;
1605         }
1606       else if (strncasecmp (*strp + 1, "gottlsoff12(", 12) == 0)
1607         {
1608           *strp += 13;
1609           errmsg = parse_symbolic_address (cd, strp, opindex,
1610                                            BFD_RELOC_FRV_GOTTLSOFF12,
1611                                            & result_type, & value);
1612           if (**strp != ')')
1613             return "missing ')'";
1614           ++*strp;
1615           *valuep = value;
1616           return errmsg;
1617         }
1618     }
1619   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1620 }
1621
1622 static const char *
1623 parse_s12 (CGEN_CPU_DESC cd,
1624            const char **strp,
1625            int opindex,
1626            long *valuep)
1627 {
1628   const char *errmsg;
1629   enum cgen_parse_operand_result result_type;
1630   bfd_vma value;
1631  
1632   /* Check for small data reference.  */
1633   if (**strp == '#' || **strp == '%')
1634     {
1635       if (strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1636         {
1637           *strp += 9;
1638           errmsg = parse_symbolic_address (cd, strp, opindex,
1639                                            BFD_RELOC_FRV_GPREL12,
1640                                            & result_type, & value);
1641           if (**strp != ')')
1642             return "missing `)'";
1643           ++*strp;
1644           *valuep = value;
1645           return errmsg;
1646         }
1647       else if (strncasecmp (*strp + 1, "got12(", 6) == 0)
1648         {
1649           *strp += 7;
1650           errmsg = parse_symbolic_address (cd, strp, opindex,
1651                                            BFD_RELOC_FRV_GOT12,
1652                                            & result_type, & value);
1653           if (**strp != ')')
1654             return "missing ')'";
1655           ++*strp;
1656           *valuep = value;
1657           return errmsg;
1658         }
1659       else if (strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
1660         {
1661           *strp += 15;
1662           errmsg = parse_symbolic_address (cd, strp, opindex,
1663                                            BFD_RELOC_FRV_FUNCDESC_GOT12,
1664                                            & result_type, & value);
1665           if (**strp != ')')
1666             return "missing ')'";
1667           ++*strp;
1668           *valuep = value;
1669           return errmsg;
1670         }
1671       else if (strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
1672         {
1673           *strp += 10;
1674           errmsg = parse_symbolic_address (cd, strp, opindex,
1675                                            BFD_RELOC_FRV_GOTOFF12,
1676                                            & result_type, & value);
1677           if (**strp != ')')
1678             return "missing ')'";
1679           ++*strp;
1680           *valuep = value;
1681           return errmsg;
1682         }
1683       else if (strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
1684         {
1685           *strp += 18;
1686           errmsg = parse_symbolic_address (cd, strp, opindex,
1687                                            BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
1688                                            & result_type, & value);
1689           if (**strp != ')')
1690             return "missing ')'";
1691           ++*strp;
1692           *valuep = value;
1693           return errmsg;
1694         }
1695       else if (strncasecmp (*strp + 1, "gottlsdesc12(", 13) == 0)
1696         {
1697           *strp += 14;
1698           errmsg = parse_symbolic_address (cd, strp, opindex,
1699                                            BFD_RELOC_FRV_GOTTLSDESC12,
1700                                            & result_type, & value);
1701           if (**strp != ')')
1702             return "missing ')'";
1703           ++*strp;
1704           *valuep = value;
1705           return errmsg;
1706         }
1707       else if (strncasecmp (*strp + 1, "tlsmoff12(", 10) == 0)
1708         {
1709           *strp += 11;
1710           errmsg = parse_symbolic_address (cd, strp, opindex,
1711                                            BFD_RELOC_FRV_TLSMOFF12,
1712                                            & result_type, & value);
1713           if (**strp != ')')
1714             return "missing ')'";
1715           ++*strp;
1716           *valuep = value;
1717           return errmsg;
1718         }
1719       else if (strncasecmp (*strp + 1, "gottlsoff12(", 12) == 0)
1720         {
1721           *strp += 13;
1722           errmsg = parse_symbolic_address (cd, strp, opindex,
1723                                            BFD_RELOC_FRV_GOTTLSOFF12,
1724                                            & result_type, & value);
1725           if (**strp != ')')
1726             return "missing ')'";
1727           ++*strp;
1728           *valuep = value;
1729           return errmsg;
1730         }
1731     }
1732
1733   if (**strp == '#')
1734     ++*strp;
1735   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1736 }
1737
1738 static const char *
1739 parse_u12 (CGEN_CPU_DESC cd,
1740            const char **strp,
1741            int opindex,
1742            long *valuep)
1743 {
1744   const char *errmsg;
1745   enum cgen_parse_operand_result result_type;
1746   bfd_vma value;
1747  
1748   /* Check for small data reference.  */
1749   if ((**strp == '#' || **strp == '%')
1750       && strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1751     {
1752       *strp += 9;
1753       errmsg = parse_symbolic_address (cd, strp, opindex,
1754                                        BFD_RELOC_FRV_GPRELU12,
1755                                        & result_type, & value);
1756       if (**strp != ')')
1757         return "missing `)'";
1758       ++*strp;
1759       *valuep = value;
1760       return errmsg;
1761     }
1762   else
1763     {
1764       if (**strp == '#')
1765         ++*strp;
1766       return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1767     }
1768 }
1769
1770 static const char *
1771 parse_A (CGEN_CPU_DESC cd,
1772          const char **strp,
1773          int opindex,
1774          unsigned long *valuep,
1775          unsigned long A)
1776 {
1777   const char *errmsg;
1778  
1779   if (**strp == '#')
1780     ++*strp;
1781
1782   errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1783   if (errmsg)
1784     return errmsg;
1785
1786   if (*valuep != A)
1787     return _("Value of A operand must be 0 or 1");
1788
1789   return NULL;
1790 }
1791
1792 static const char *
1793 parse_A0 (CGEN_CPU_DESC cd,
1794           const char **strp,
1795           int opindex,
1796           unsigned long *valuep)
1797 {
1798   return parse_A (cd, strp, opindex, valuep, 0);
1799 }
1800
1801 static const char *
1802 parse_A1 (CGEN_CPU_DESC cd,
1803           const char **strp,
1804           int opindex,
1805           unsigned long *valuep)
1806 {
1807   return parse_A (cd, strp, opindex, valuep, 1);
1808 }
1809
1810 static const char *
1811 parse_even_register (CGEN_CPU_DESC  cd,
1812                      const char **  strP,
1813                      CGEN_KEYWORD * tableP,
1814                      long *         valueP)
1815 {
1816   const char * errmsg;
1817   const char * saved_star_strP = * strP;
1818
1819   errmsg = cgen_parse_keyword (cd, strP, tableP, valueP);
1820
1821   if (errmsg == NULL && ((* valueP) & 1))
1822     {
1823       errmsg = _("register number must be even");
1824       * strP = saved_star_strP;
1825     }
1826
1827   return errmsg;
1828 }
1829
1830 static const char *
1831 parse_call_label (CGEN_CPU_DESC cd,
1832                   const char **strp,
1833                   int opindex,
1834                   int opinfo,
1835                   enum cgen_parse_operand_result *resultp,
1836                   bfd_vma *valuep)
1837 {
1838   const char *errmsg;
1839   bfd_vma value;
1840  
1841   /* Check for small data reference.  */
1842   if (opinfo == 0 && (**strp == '#' || **strp == '%'))
1843     {
1844       if (strncasecmp (*strp + 1, "gettlsoff(", 10) == 0)
1845         {
1846           *strp += 11;
1847           errmsg = parse_symbolic_address (cd, strp, opindex,
1848                                            BFD_RELOC_FRV_GETTLSOFF,
1849                                            resultp, &value);
1850           if (**strp != ')')
1851             return _("missing `)'");
1852           ++*strp;
1853           *valuep = value;
1854           return errmsg;
1855         }
1856     }
1857
1858   return cgen_parse_address (cd, strp, opindex, opinfo, resultp, valuep);
1859 }
1860
1861 /* -- */
1862 \f
1863 /* -- dis.c */
1864 static void
1865 print_at (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1866           void * dis_info,
1867           long reloc_ann ATTRIBUTE_UNUSED,
1868           long value ATTRIBUTE_UNUSED,
1869           bfd_vma pc ATTRIBUTE_UNUSED,
1870           int length ATTRIBUTE_UNUSED)
1871 {
1872   disassemble_info *info = (disassemble_info *) dis_info;
1873
1874   (*info->fprintf_func) (info->stream, "@");
1875 }  
1876
1877 static void
1878 print_spr (CGEN_CPU_DESC cd,
1879            void * dis_info,
1880            CGEN_KEYWORD *names,
1881            long regno,
1882            unsigned int attrs)
1883 {
1884   /* Use the register index format for any unnamed registers.  */
1885   if (cgen_keyword_lookup_value (names, regno) == NULL)
1886     {
1887       disassemble_info *info = (disassemble_info *) dis_info;
1888       (*info->fprintf_func) (info->stream, "spr[%ld]", regno);
1889     }
1890   else
1891     print_keyword (cd, dis_info, names, regno, attrs);
1892 }
1893
1894 static void
1895 print_hi (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1896           void * dis_info,
1897           long value,
1898           unsigned int attrs ATTRIBUTE_UNUSED,
1899           bfd_vma pc ATTRIBUTE_UNUSED,
1900           int length ATTRIBUTE_UNUSED)
1901 {
1902   disassemble_info *info = (disassemble_info *) dis_info;
1903
1904   (*info->fprintf_func) (info->stream, value ? "0x%lx" : "hi(0x%lx)", value);
1905 }
1906
1907 static void
1908 print_lo (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
1909           void * dis_info,
1910           long value,
1911           unsigned int attrs ATTRIBUTE_UNUSED,
1912           bfd_vma pc ATTRIBUTE_UNUSED,
1913           int length ATTRIBUTE_UNUSED)
1914 {
1915   disassemble_info *info = (disassemble_info *) dis_info;
1916   if (value)
1917     (*info->fprintf_func) (info->stream, "0x%lx", value);
1918   else
1919     (*info->fprintf_func) (info->stream, "lo(0x%lx)", value);
1920 }
1921
1922 /* -- */