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