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