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