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