xref: /openbsd/gnu/usr.bin/binutils/cpu/frv.opc (revision cf2f2c56)
1/* Fujitsu FRV opcode support, for GNU Binutils.  -*- C -*-
2
3   Copyright 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
4
5   Contributed by Red Hat Inc; developed under contract from Fujitsu.
6
7   This file is part of the GNU Binutils.
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23*/
24
25/* This file is an addendum to frv.cpu.  Heavy use of C code isn't
26   appropriate in .cpu files, so it resides here.  This especially applies
27   to assembly/disassembly where parsing/printing can be quite involved.
28   Such things aren't really part of the specification of the cpu, per se,
29   so .cpu files provide the general framework and .opc files handle the
30   nitty-gritty details as necessary.
31
32   Each section is delimited with start and end markers.
33
34   <arch>-opc.h additions use: "-- opc.h"
35   <arch>-opc.c additions use: "-- opc.c"
36   <arch>-asm.c additions use: "-- asm.c"
37   <arch>-dis.c additions use: "-- dis.c"
38   <arch>-ibd.h additions use: "-- ibd.h"
39*/
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
54typedef CGEN_ATTR_VALUE_TYPE VLIW_COMBO[FRV_VLIW_SIZE];
55
56typedef struct
57{
58  int                   next_slot;
59  int                   constraint_violation;
60  unsigned long         mach;
61  unsigned long         elf_flags;
62  CGEN_ATTR_VALUE_TYPE *unit_mapping;
63  VLIW_COMBO           *current_vliw;
64  CGEN_ATTR_VALUE_TYPE  major[FRV_VLIW_SIZE];
65  const CGEN_INSN*      insn[FRV_VLIW_SIZE];
66} FRV_VLIW;
67
68int frv_is_branch_major PARAMS ((CGEN_ATTR_VALUE_TYPE, unsigned long));
69int frv_is_float_major  PARAMS ((CGEN_ATTR_VALUE_TYPE, unsigned long));
70int frv_is_media_major  PARAMS ((CGEN_ATTR_VALUE_TYPE, unsigned long));
71int frv_is_branch_insn  PARAMS ((const CGEN_INSN *));
72int frv_is_float_insn   PARAMS ((const CGEN_INSN *));
73int frv_is_media_insn   PARAMS ((const CGEN_INSN *));
74void frv_vliw_reset     PARAMS ((FRV_VLIW *, unsigned long mach, unsigned long elf_flags));
75int frv_vliw_add_insn   PARAMS ((FRV_VLIW *, const CGEN_INSN *));
76int spr_valid           PARAMS ((long));
77/* -- */
78
79/* -- opc.c */
80#include "elf/frv.h"
81#include <stdio.h>
82
83static int match_unit
84  PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE, CGEN_ATTR_VALUE_TYPE));
85static int match_vliw
86  PARAMS ((VLIW_COMBO *, VLIW_COMBO *, int));
87static VLIW_COMBO * add_next_to_vliw
88  PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
89static int find_major_in_vliw
90  PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
91static int fr400_check_insn_major_constraints
92  PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
93static int fr500_check_insn_major_constraints
94  PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE));
95static int fr550_check_insn_major_constraints
96  PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE, const CGEN_INSN *));
97static int check_insn_major_constraints
98  PARAMS ((FRV_VLIW *, CGEN_ATTR_VALUE_TYPE, const CGEN_INSN *));
99
100int
101frv_is_branch_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
102{
103  switch (mach)
104    {
105    case bfd_mach_fr400:
106      if (major >= FR400_MAJOR_B_1 && major <= FR400_MAJOR_B_6)
107	return 1; /* is a branch */
108      break;
109    default:
110      if (major >= FR500_MAJOR_B_1 && major <= FR500_MAJOR_B_6)
111	return 1; /* is a branch */
112      break;
113    }
114
115  return 0; /* not a branch */
116}
117
118int
119frv_is_float_major (CGEN_ATTR_VALUE_TYPE major, unsigned long mach)
120{
121  switch (mach)
122    {
123    case bfd_mach_fr400:
124      return 0; /* No float insns */
125    default:
126      if (major >= FR500_MAJOR_F_1 && major <= FR500_MAJOR_F_8)
127	return 1; /* is a float insn */
128      break;
129    }
130
131  return 0; /* not a branch */
132}
133
134int
135frv_is_media_major (CGEN_ATTR_VALUE_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 1; /* is a media insn */
142      break;
143    default:
144      if (major >= FR500_MAJOR_M_1 && major <= FR500_MAJOR_M_8)
145	return 1; /* is a media insn */
146      break;
147    }
148
149  return 0; /* not a branch */
150}
151
152int
153frv_is_branch_insn (const CGEN_INSN *insn)
154{
155  if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
156			   bfd_mach_fr400))
157    return 1;
158  if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
159			   bfd_mach_fr500))
160    return 1;
161
162  return 0;
163}
164
165int
166frv_is_float_insn (const CGEN_INSN *insn)
167{
168  if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
169			  bfd_mach_fr400))
170    return 1;
171  if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
172			  bfd_mach_fr500))
173    return 1;
174
175  return 0;
176}
177
178int
179frv_is_media_insn (const CGEN_INSN *insn)
180{
181  if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
182			  bfd_mach_fr400))
183    return 1;
184  if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
185			  bfd_mach_fr500))
186    return 1;
187
188  return 0;
189}
190
191/* This table represents the allowable packing for vliw insns for the fr400.
192   The fr400 has only 2 vliw slots. Represent this by not allowing any insns
193   in the extra slots.
194   Subsets of any given row are also allowed.  */
195static VLIW_COMBO fr400_allowed_vliw[] =
196{
197  /*  slot0       slot1       slot2       slot3    */
198  {  UNIT_I0,    UNIT_I1,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
199  {  UNIT_I0,    UNIT_FM0,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
200  {  UNIT_I0,    UNIT_B0,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
201  {  UNIT_FM0,   UNIT_FM1,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
202  {  UNIT_FM0,   UNIT_B0,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
203  {  UNIT_B0,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
204  {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
205  {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO }
206};
207
208/* This table represents the allowable packing for vliw insns for the fr500.
209   The fr500 has only 4 vliw slots. Represent this by not allowing any insns
210   in the extra slots.
211   Subsets of any given row are also allowed.  */
212static VLIW_COMBO fr500_allowed_vliw[] =
213{
214  /*  slot0       slot1       slot2       slot3    */
215  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1  PAD_VLIW_COMBO },
216  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0   PAD_VLIW_COMBO },
217  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0   PAD_VLIW_COMBO },
218  {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
219  {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
220  {  UNIT_I0,    UNIT_B0,    UNIT_B1,    UNIT_NIL  PAD_VLIW_COMBO },
221  {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
222  {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL  PAD_VLIW_COMBO },
223  {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
224  {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
225  {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO }
226};
227
228/* This table represents the allowable packing for vliw insns for the fr550.
229   Subsets of any given row are also allowed.  */
230static VLIW_COMBO fr550_allowed_vliw[] =
231{
232  /*  slot0       slot1       slot2       slot3       slot4       slot5       slot6       slot7   */
233  {  UNIT_I0,    UNIT_I1,    UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL },
234  {  UNIT_I0,    UNIT_I1,    UNIT_I2,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
235  {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
236  {  UNIT_I0,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
237  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_I3,    UNIT_FM3 },
238  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_I3,    UNIT_B0  },
239  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_FM3,   UNIT_B0  },
240  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_B0,    UNIT_B1  },
241  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1  },
242  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_B0,    UNIT_B1,    UNIT_NIL },
243  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1  },
244  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1  },
245  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL },
246  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
247  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1,    UNIT_NIL },
248  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_I2,    UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
249  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
250  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1,    UNIT_NIL },
251  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
252  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
253  {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
254  {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
255  {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
256  {  UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
257  {  UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
258  {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
259  {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
260  {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL }
261};
262
263/* Some insns are assigned specialized implementation units which map to
264   different actual implementation units on different machines.  These
265   tables perform that mapping.  */
266static CGEN_ATTR_VALUE_TYPE fr400_unit_mapping[] =
267{
268/* unit in insn    actual unit */
269/* NIL      */     UNIT_NIL,
270/* I0       */     UNIT_I0,
271/* I1       */     UNIT_I1,
272/* I01      */     UNIT_I01,
273/* I2       */     UNIT_NIL, /* no I2 or I3 unit */
274/* I3       */     UNIT_NIL,
275/* IALL     */     UNIT_I01, /* only I0 and I1 units */
276/* FM0      */     UNIT_FM0,
277/* FM1      */     UNIT_FM1,
278/* FM01     */     UNIT_FM01,
279/* FM2      */     UNIT_NIL, /* no F2 or M2 units */
280/* FM3      */     UNIT_NIL, /* no F3 or M3 units */
281/* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
282/* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
283/* B0       */     UNIT_B0,  /* branches only in B0 unit.  */
284/* B1       */     UNIT_B0,
285/* B01      */     UNIT_B0,
286/* C        */     UNIT_C,
287/* MULT-DIV */     UNIT_I0,  /* multiply and divide only in I0  unit.  */
288/* IACC     */     UNIT_I01, /* iacc multiply       in I0 or I1 unit.  */
289/* LOAD     */     UNIT_I0,  /* load                only in I0  unit.  */
290/* STORE    */     UNIT_I0,  /* store               only in I0  unit.  */
291/* SCAN     */     UNIT_I0,  /* scan                only in I0  unit.  */
292/* DCPL     */     UNIT_C,   /* dcpl                only in C   unit.  */
293/* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
294/* MCLRACC-1*/     UNIT_FM0  /* mclracc,A==1   insn only in FM0 unit.  */
295};
296
297static CGEN_ATTR_VALUE_TYPE fr500_unit_mapping[] =
298{
299/* unit in insn    actual unit */
300/* NIL      */     UNIT_NIL,
301/* I0       */     UNIT_I0,
302/* I1       */     UNIT_I1,
303/* I01      */     UNIT_I01,
304/* I2       */     UNIT_NIL, /* no I2 or I3 unit */
305/* I3       */     UNIT_NIL,
306/* IALL     */     UNIT_I01, /* only I0 and I1 units */
307/* FM0      */     UNIT_FM0,
308/* FM1      */     UNIT_FM1,
309/* FM01     */     UNIT_FM01,
310/* FM2      */     UNIT_NIL, /* no F2 or M2 units */
311/* FM3      */     UNIT_NIL, /* no F3 or M2 units */
312/* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
313/* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
314/* B0       */     UNIT_B0,
315/* B1       */     UNIT_B1,
316/* B01      */     UNIT_B01,
317/* C        */     UNIT_C,
318/* MULT-DIV */     UNIT_I01, /* multiply and divide in I0 or I1 unit.  */
319/* IACC     */     UNIT_NIL, /* iacc multiply       not implemented */
320/* LOAD     */     UNIT_I01, /* load                in I0 or I1 unit.  */
321/* STORE    */     UNIT_I0,  /* store               only in I0 unit.  */
322/* SCAN     */     UNIT_I01, /* scan                in I0 or I1 unit.  */
323/* DCPL     */     UNIT_C,   /* dcpl                only in C unit.  */
324/* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
325/* MCLRACC-1*/     UNIT_FM01 /* mclracc,A==1 in FM0 or FM1 unit.  */
326};
327
328static CGEN_ATTR_VALUE_TYPE fr550_unit_mapping[] =
329{
330/* unit in insn    actual unit */
331/* NIL      */     UNIT_NIL,
332/* I0       */     UNIT_I0,
333/* I1       */     UNIT_I1,
334/* I01      */     UNIT_I01,
335/* I2       */     UNIT_I2,
336/* I3       */     UNIT_I3,
337/* IALL     */     UNIT_IALL,
338/* FM0      */     UNIT_FM0,
339/* FM1      */     UNIT_FM1,
340/* FM01     */     UNIT_FM01,
341/* FM2      */     UNIT_FM2,
342/* FM3      */     UNIT_FM3,
343/* FMALL    */     UNIT_FMALL,
344/* FMLOW    */     UNIT_FM01, /* Only F0,F1,M0,M1 units */
345/* B0       */     UNIT_B0,
346/* B1       */     UNIT_B1,
347/* B01      */     UNIT_B01,
348/* C        */     UNIT_C,
349/* MULT-DIV */     UNIT_I01,  /* multiply and divide in I0 or I1 unit.    */
350/* IACC     */     UNIT_NIL,  /* iacc multiply       not implemented.     */
351/* LOAD     */     UNIT_I01,  /* load                in I0 or I1 unit.    */
352/* STORE    */     UNIT_I01,  /* store               in I0 or I1 unit.    */
353/* SCAN     */     UNIT_IALL, /* scan                in any integer unit. */
354/* DCPL     */     UNIT_I0,   /* dcpl                only in I0 unit.     */
355/* MDUALACC */     UNIT_FMALL,/* media dual acc insn in all media units   */
356/* MCLRACC-1*/     UNIT_FM01  /* mclracc,A==1 in FM0 or FM1 unit.         */
357};
358
359void
360frv_vliw_reset (FRV_VLIW *vliw, unsigned long mach, unsigned long elf_flags)
361{
362  vliw->next_slot = 0;
363  vliw->constraint_violation = 0;
364  vliw->mach = mach;
365  vliw->elf_flags = elf_flags;
366
367  switch (mach)
368    {
369    case bfd_mach_fr400:
370      vliw->current_vliw = fr400_allowed_vliw;
371      vliw->unit_mapping = fr400_unit_mapping;
372      break;
373    case bfd_mach_fr550:
374      vliw->current_vliw = fr550_allowed_vliw;
375      vliw->unit_mapping = fr550_unit_mapping;
376      break;
377    default:
378      vliw->current_vliw = fr500_allowed_vliw;
379      vliw->unit_mapping = fr500_unit_mapping;
380      break;
381    }
382}
383
384/* Return 1 if unit1 is a match for unit2.
385   Unit1 comes from the insn's UNIT attribute. unit2 comes from one of the
386   *_allowed_vliw tables above.  */
387static int
388match_unit (FRV_VLIW *vliw,
389	    CGEN_ATTR_VALUE_TYPE unit1, CGEN_ATTR_VALUE_TYPE unit2)
390{
391  /* Map any specialized implementation units to actual ones.  */
392  unit1 = vliw->unit_mapping[unit1];
393
394  if (unit1 == unit2)
395    return 1;
396  if (unit1 < unit2)
397    return 0;
398
399  switch (unit1)
400    {
401    case UNIT_I01:
402    case UNIT_FM01:
403    case UNIT_B01:
404      /* The 01 versions of these units are within 2 enums of the 0 or 1
405	 versions.  */
406      if (unit1 - unit2 <= 2)
407	return 1;
408      break;
409    case UNIT_IALL:
410    case UNIT_FMALL:
411      /* The ALL versions of these units are within 5 enums of the 0, 1, 2 or 3
412	 versions.  */
413      if (unit1 - unit2 <= 5)
414	return 1;
415      break;
416    default:
417      break;
418    }
419
420  return 0;
421}
422
423/* Return 1 if the vliws match, 0 otherwise.  */
424
425static int
426match_vliw (VLIW_COMBO *vliw1, VLIW_COMBO *vliw2, int vliw_size)
427{
428  int i;
429
430  for (i = 0; i < vliw_size; ++i)
431    {
432      if ((*vliw1)[i] != (*vliw2)[i])
433	return 0;
434    }
435
436  return 1;
437}
438
439/* Find the next vliw vliw in the table that can accomodate the new insn.
440   If one is found then return it. Otherwise return NULL.  */
441
442static VLIW_COMBO *
443add_next_to_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE unit)
444{
445  int           next    = vliw->next_slot;
446  VLIW_COMBO    *current = vliw->current_vliw;
447  VLIW_COMBO    *potential;
448
449  if (next <= 0)
450    {
451      fprintf (stderr, "frv-opc.c line %d: bad vliw->next_slot value.\n",
452	       __LINE__);
453      abort (); /* Should never happen */
454    }
455
456  /* The table is sorted by units allowed within slots, so vliws with
457     identical starting sequences are together.  */
458  potential = current;
459  do
460    {
461      if (match_unit (vliw, unit, (*potential)[next]))
462	return potential;
463      ++potential;
464    }
465  while (match_vliw (potential, current, next));
466
467  return NULL;
468}
469
470/* Look for the given major insn type in the given vliw. Return 1 if found,
471   return 0 otherwise.  */
472
473static int
474find_major_in_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major)
475{
476  int i;
477
478  for (i = 0; i < vliw->next_slot; ++i)
479    if (vliw->major[i] == major)
480      return 1;
481
482  return 0;
483}
484
485/* Check for constraints between the insns in the vliw due to major insn
486   types.  */
487
488static int
489fr400_check_insn_major_constraints (
490  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
491)
492{
493  /* In the cpu file, all media insns are represented as being allowed in
494     both media units. This makes it easier since this is the case for fr500.
495     Catch the invalid combinations here.  Insns of major class FR400_MAJOR_M_2
496     cannot coexist with any other media insn in a vliw.  */
497  switch (major)
498    {
499    case FR400_MAJOR_M_2:
500      return ! find_major_in_vliw (vliw, FR400_MAJOR_M_1)
501	&&   ! find_major_in_vliw (vliw, FR400_MAJOR_M_2);
502    default:
503      break;
504    }
505  return 1;
506}
507
508static int
509find_unit_in_vliw (
510  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE unit
511)
512{
513  int i;
514  for (i = 0; i < vliw->next_slot; ++i)
515    if (CGEN_INSN_ATTR_VALUE (vliw->insn[i], CGEN_INSN_UNIT) == unit)
516      return 1;
517
518  return 0; /* not found */
519}
520
521static int
522find_major_in_slot (
523  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, CGEN_ATTR_VALUE_TYPE slot
524)
525{
526  int i;
527
528  for (i = 0; i < vliw->next_slot; ++i)
529    if (vliw->major[i] == major && (*vliw->current_vliw)[i] == slot)
530      return 1;
531
532  return 0;
533}
534
535static int
536fr550_find_media_in_vliw (FRV_VLIW *vliw)
537{
538  int i;
539
540  for (i = 0; i < vliw->next_slot; ++i)
541    {
542      if (vliw->major[i] < FR550_MAJOR_M_1 || vliw->major[i] > FR550_MAJOR_M_5)
543	continue;
544
545      /* Found a media insn, however, MNOP and MCLRACC don't count.  */
546      if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MNOP
547	  || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_0
548	  || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_1)
549	continue;
550
551      return 1; /* found one */
552    }
553
554  return 0;
555}
556
557static int
558fr550_find_float_in_vliw (FRV_VLIW *vliw)
559{
560  int i;
561
562  for (i = 0; i < vliw->next_slot; ++i)
563    {
564      if (vliw->major[i] < FR550_MAJOR_F_1 || vliw->major[i] > FR550_MAJOR_F_4)
565	continue;
566
567      /* Found a floating point insn, however, FNOP doesn't count.  */
568      if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_FNOP)
569	continue;
570
571      return 1; /* found one */
572    }
573
574  return 0;
575}
576
577static int
578fr550_check_insn_major_constraints (
579  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, const CGEN_INSN *insn
580)
581{
582  CGEN_ATTR_VALUE_TYPE unit;
583  CGEN_ATTR_VALUE_TYPE slot = (*vliw->current_vliw)[vliw->next_slot];
584  switch (slot)
585    {
586    case UNIT_I2:
587      /* If it's a store, then there must be another store in I1 */
588      unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
589      if (unit == UNIT_STORE)
590	return find_unit_in_vliw (vliw, UNIT_STORE);
591      break;
592    case UNIT_FM2:
593    case UNIT_FM3:
594      /* Floating point insns other than FNOP in slot f2 or f3 cannot coexist with
595	 media insns.  */
596      if (major >= FR550_MAJOR_F_1 && major <= FR550_MAJOR_F_4
597	  && CGEN_INSN_NUM (insn) != FRV_INSN_FNOP)
598	return ! fr550_find_media_in_vliw (vliw);
599      /* Media insns other than MNOP in slot m2 or m3 cannot coexist with
600	 floating point insns.  */
601      if (major >= FR550_MAJOR_M_1 && major <= FR550_MAJOR_M_5
602	  && CGEN_INSN_NUM (insn) != FRV_INSN_MNOP)
603	return ! fr550_find_float_in_vliw (vliw);
604      /* F-2 in slot f2 or f3 cannot coexist with F-2 or F-4 in slot f1 or f2
605	 respectively.
606       */
607      if (major == FR550_MAJOR_F_2)
608	return ! find_major_in_slot (vliw, FR550_MAJOR_F_2, slot - (UNIT_FM2 - UNIT_FM0))
609	  &&   ! find_major_in_slot (vliw, FR550_MAJOR_F_4, slot - (UNIT_FM2 - UNIT_FM0));
610      /* M-2 or M-5 in slot m2 or m3 cannot coexist with M-2 in slot m1 or m2
611	 respectively.  */
612      if (major == FR550_MAJOR_M_2 || major == FR550_MAJOR_M_5)
613	return ! find_major_in_slot (vliw, FR550_MAJOR_M_2, slot - (UNIT_FM2 - UNIT_FM0));
614      /* M-4 in slot m2 or m3 cannot coexist with M-4 in slot m1 or m2
615	 respectively.  */
616      if (major == FR550_MAJOR_M_4)
617	return ! find_major_in_slot (vliw, FR550_MAJOR_M_4, slot - (UNIT_FM2 - UNIT_FM0));
618      break;
619    default:
620      break;
621    }
622  return 1; /* all ok */
623}
624
625static int
626fr500_check_insn_major_constraints (
627  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major
628)
629{
630  /* TODO: A table might be faster for some of the more complex instances
631     here.  */
632  switch (major)
633    {
634    case FR500_MAJOR_I_1:
635    case FR500_MAJOR_I_4:
636    case FR500_MAJOR_I_5:
637    case FR500_MAJOR_I_6:
638    case FR500_MAJOR_B_1:
639    case FR500_MAJOR_B_2:
640    case FR500_MAJOR_B_3:
641    case FR500_MAJOR_B_4:
642    case FR500_MAJOR_B_5:
643    case FR500_MAJOR_B_6:
644    case FR500_MAJOR_F_4:
645    case FR500_MAJOR_F_8:
646    case FR500_MAJOR_M_8:
647      return 1; /* OK */
648    case FR500_MAJOR_I_2:
649      /* Cannot coexist with I-3 insn.  */
650      return ! find_major_in_vliw (vliw, FR500_MAJOR_I_3);
651    case FR500_MAJOR_I_3:
652      /* Cannot coexist with I-2 insn.  */
653      return ! find_major_in_vliw (vliw, FR500_MAJOR_I_2);
654    case FR500_MAJOR_F_1:
655    case FR500_MAJOR_F_2:
656      /* Cannot coexist with F-5, F-6, or M-7 insn.  */
657      return ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
658	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
659	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
660    case FR500_MAJOR_F_3:
661      /* Cannot coexist with F-7, or M-7 insn.  */
662      return ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
663	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
664    case FR500_MAJOR_F_5:
665      /* Cannot coexist with F-1, F-2, F-6, F-7, or M-7 insn.  */
666      return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
667	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
668	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
669	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
670	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
671    case FR500_MAJOR_F_6:
672      /* Cannot coexist with F-1, F-2, F-5, F-6, or M-7 insn.  */
673      return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
674	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
675	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
676	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
677	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
678    case FR500_MAJOR_F_7:
679      /* Cannot coexist with F-3, F-5, F-7, or M-7 insn.  */
680      return ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
681	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
682	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
683	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
684    case FR500_MAJOR_M_1:
685      /* Cannot coexist with M-7 insn.  */
686      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
687    case FR500_MAJOR_M_2:
688    case FR500_MAJOR_M_3:
689      /* Cannot coexist with M-5, M-6 or M-7 insn.  */
690      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
691	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
692	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
693    case FR500_MAJOR_M_4:
694      /* Cannot coexist with M-6 insn.  */
695      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_6);
696    case FR500_MAJOR_M_5:
697      /* Cannot coexist with M-2, M-3, M-5, M-6  or M-7 insn.  */
698      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
699	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
700	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
701	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
702	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
703    case FR500_MAJOR_M_6:
704      /* Cannot coexist with M-2, M-3, M-4, M-5, M-6  or M-7 insn.  */
705      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
706	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
707	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_4)
708	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
709	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
710	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
711    case FR500_MAJOR_M_7:
712      /* Cannot coexist with M-1, M-2, M-3, M-5, M-6  or M-7 insn.  */
713      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_1)
714	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
715	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
716	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
717	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
718	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7)
719	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
720	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
721	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
722	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
723	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
724	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7);
725    default:
726      fprintf (stderr, "frv-opc.c, line %d: bad major code, aborting.\n",
727	       __LINE__);
728      abort ();
729      break;
730    }
731  return 1;
732}
733
734static int
735check_insn_major_constraints (
736  FRV_VLIW *vliw, CGEN_ATTR_VALUE_TYPE major, const CGEN_INSN *insn
737)
738{
739  int rc;
740  switch (vliw->mach)
741    {
742    case bfd_mach_fr400:
743      rc = fr400_check_insn_major_constraints (vliw, major);
744      break;
745    case bfd_mach_fr550:
746      rc = fr550_check_insn_major_constraints (vliw, major, insn);
747      break;
748    default:
749      rc = fr500_check_insn_major_constraints (vliw, major);
750      break;
751    }
752  return rc;
753}
754
755/* Add in insn to the VLIW vliw if possible. Return 0 if successful,
756   non-zero otherwise.  */
757int
758frv_vliw_add_insn (FRV_VLIW *vliw, const CGEN_INSN *insn)
759{
760  int index;
761  CGEN_ATTR_VALUE_TYPE major;
762  CGEN_ATTR_VALUE_TYPE unit;
763  VLIW_COMBO *new_vliw;
764
765  if (vliw->constraint_violation || CGEN_INSN_INVALID_P (insn))
766    return 1;
767
768  index = vliw->next_slot;
769  if (index >= FRV_VLIW_SIZE)
770    return 1;
771
772  unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
773  if (unit == UNIT_NIL)
774    {
775      fprintf (stderr, "frv-opc.c line %d: bad insn unit.\n",
776	       __LINE__);
777      abort (); /* no UNIT specified for this insn in frv.cpu  */
778    }
779
780  switch (vliw->mach)
781    {
782    case bfd_mach_fr400:
783      major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR);
784      break;
785    case bfd_mach_fr550:
786      major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR550_MAJOR);
787      break;
788    default:
789      major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR);
790      break;
791    }
792
793  if (index <= 0)
794    {
795      /* Any insn can be added to slot 0.  */
796      while (! match_unit (vliw, unit, (*vliw->current_vliw)[0]))
797	++vliw->current_vliw;
798      vliw->major[0] = major;
799      vliw->insn[0] = insn;
800      vliw->next_slot = 1;
801      return 0;
802    }
803
804  /* If there are already insns in the vliw(s) check to see that
805     this one can be added.  Do this by finding an allowable vliw
806     combination that can accept the new insn.  */
807  if (! (vliw->elf_flags & EF_FRV_NOPACK))
808    {
809      new_vliw = add_next_to_vliw (vliw, unit);
810      if (new_vliw && check_insn_major_constraints (vliw, major, insn))
811	{
812	  vliw->current_vliw = new_vliw;
813	  vliw->major[index] = major;
814	  vliw->insn[index] = insn;
815	  vliw->next_slot++;
816	  return 0;
817	}
818
819      /* The frv machine supports all packing conbinations.  If we fail,
820	 to add the insn, then it could not be handled as if it was the fr500.
821	 Just return as if it was handled ok.  */
822      if (vliw->mach == bfd_mach_frv)
823	return 0;
824    }
825
826  vliw->constraint_violation = 1;
827  return 1;
828}
829
830int
831spr_valid (regno)
832     long regno;
833{
834  if (regno < 0)     return 0;
835  if (regno <= 4095) return 1;
836  return 0;
837}
838/* -- */
839
840/* -- asm.c */
841static const char * parse_ulo16
842  PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
843static const char * parse_uslo16
844  PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
845static const char * parse_uhi16
846  PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
847static long parse_register_number
848  PARAMS ((const char **));
849static const char * parse_spr
850  PARAMS ((CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *));
851static const char * parse_d12
852  PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
853static const char * parse_s12
854  PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
855static const char * parse_u12
856  PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
857static const char * parse_even_register
858  PARAMS ((CGEN_CPU_DESC, const char **, CGEN_KEYWORD *, long *));
859static const char * parse_A0
860  PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
861static const char * parse_A1
862  PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
863static const char * parse_A
864  PARAMS ((CGEN_CPU_DESC, const char **, int, long *, long));
865
866static const char *
867parse_ulo16 (cd, strp, opindex, valuep)
868     CGEN_CPU_DESC cd;
869     const char **strp;
870     int opindex;
871     unsigned long *valuep;
872{
873  const char *errmsg;
874  enum cgen_parse_operand_result result_type;
875  bfd_vma value;
876
877  if (**strp == '#' || **strp == '%')
878    {
879      if (strncasecmp (*strp + 1, "lo(", 3) == 0)
880	{
881	  *strp += 4;
882	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
883				       &result_type, &value);
884	  if (**strp != ')')
885	    return "missing `)'";
886	  ++*strp;
887	  if (errmsg == NULL
888	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
889	    value &= 0xffff;
890	  *valuep = value;
891	  return errmsg;
892	}
893      if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
894	{
895	  *strp += 9;
896	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELLO,
897				       &result_type, &value);
898	  if (**strp != ')')
899	    return "missing ')'";
900	  ++*strp;
901	  if (errmsg == NULL
902	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
903	    value &= 0xffff;
904	  *valuep = value;
905	  return errmsg;
906	}
907      else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
908	{
909	  *strp += 7;
910	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTLO,
911				       &result_type, &value);
912	  if (**strp != ')')
913	    return "missing ')'";
914	  ++*strp;
915	  if (errmsg == NULL
916	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
917	    value &= 0xffff;
918	  *valuep = value;
919	  return errmsg;
920	}
921      else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
922	{
923	  *strp += 15;
924	  errmsg = cgen_parse_address (cd, strp, opindex,
925				       BFD_RELOC_FRV_FUNCDESC_GOTLO,
926				       &result_type, &value);
927	  if (**strp != ')')
928	    return "missing ')'";
929	  ++*strp;
930	  if (errmsg == NULL
931	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
932	    value &= 0xffff;
933	  *valuep = value;
934	  return errmsg;
935	}
936      else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
937	{
938	  *strp += 10;
939	  errmsg = cgen_parse_address (cd, strp, opindex,
940				       BFD_RELOC_FRV_GOTOFFLO,
941				       &result_type, &value);
942	  if (**strp != ')')
943	    return "missing ')'";
944	  ++*strp;
945	  if (errmsg == NULL
946	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
947	    value &= 0xffff;
948	  *valuep = value;
949	  return errmsg;
950	}
951      else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
952	{
953	  *strp += 18;
954	  errmsg = cgen_parse_address (cd, strp, opindex,
955				       BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
956				       &result_type, &value);
957	  if (**strp != ')')
958	    return "missing ')'";
959	  ++*strp;
960	  if (errmsg == NULL
961	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
962	    value &= 0xffff;
963	  *valuep = value;
964	  return errmsg;
965	}
966    }
967  return cgen_parse_signed_integer (cd, strp, opindex, valuep);
968}
969
970static const char *
971parse_uslo16 (cd, strp, opindex, valuep)
972     CGEN_CPU_DESC cd;
973     const char **strp;
974     int opindex;
975     unsigned long *valuep;
976{
977  const char *errmsg;
978  enum cgen_parse_operand_result result_type;
979  bfd_vma value;
980
981  if (**strp == '#' || **strp == '%')
982    {
983      if (strncasecmp (*strp + 1, "lo(", 3) == 0)
984	{
985	  *strp += 4;
986	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
987				       &result_type, &value);
988	  if (**strp != ')')
989	    return "missing `)'";
990	  ++*strp;
991	  if (errmsg == NULL
992	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
993	    value &= 0xffff;
994	  *valuep = value;
995	  return errmsg;
996	}
997      else if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
998	{
999	  *strp += 9;
1000	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELLO,
1001				       &result_type, &value);
1002	  if (**strp != ')')
1003	    return "missing ')'";
1004	  ++*strp;
1005	  if (errmsg == NULL
1006	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1007	    value &= 0xffff;
1008	  *valuep = value;
1009	  return errmsg;
1010	}
1011      else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
1012	{
1013	  *strp += 7;
1014	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTLO,
1015				       &result_type, &value);
1016	  if (**strp != ')')
1017	    return "missing ')'";
1018	  ++*strp;
1019	  if (errmsg == NULL
1020	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1021	    value &= 0xffff;
1022	  *valuep = value;
1023	  return errmsg;
1024	}
1025      else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
1026	{
1027	  *strp += 15;
1028	  errmsg = cgen_parse_address (cd, strp, opindex,
1029				       BFD_RELOC_FRV_FUNCDESC_GOTLO,
1030				       &result_type, &value);
1031	  if (**strp != ')')
1032	    return "missing ')'";
1033	  ++*strp;
1034	  if (errmsg == NULL
1035	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1036	    value &= 0xffff;
1037	  *valuep = value;
1038	  return errmsg;
1039	}
1040      else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
1041	{
1042	  *strp += 10;
1043	  errmsg = cgen_parse_address (cd, strp, opindex,
1044				       BFD_RELOC_FRV_GOTOFFLO,
1045				       &result_type, &value);
1046	  if (**strp != ')')
1047	    return "missing ')'";
1048	  ++*strp;
1049	  if (errmsg == NULL
1050	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1051	    value &= 0xffff;
1052	  *valuep = value;
1053	  return errmsg;
1054	}
1055      else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
1056	{
1057	  *strp += 18;
1058	  errmsg = cgen_parse_address (cd, strp, opindex,
1059				       BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
1060				       &result_type, &value);
1061	  if (**strp != ')')
1062	    return "missing ')'";
1063	  ++*strp;
1064	  if (errmsg == NULL
1065	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1066	    value &= 0xffff;
1067	  *valuep = value;
1068	  return errmsg;
1069	}
1070    }
1071  return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1072}
1073
1074static const char *
1075parse_uhi16 (cd, strp, opindex, valuep)
1076     CGEN_CPU_DESC cd;
1077     const char **strp;
1078     int opindex;
1079     unsigned long *valuep;
1080{
1081  const char *errmsg;
1082  enum cgen_parse_operand_result result_type;
1083  bfd_vma value;
1084
1085  if (**strp == '#' || **strp == '%')
1086    {
1087      if (strncasecmp (*strp + 1, "hi(", 3) == 0)
1088	{
1089	  *strp += 4;
1090	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_HI16,
1091				       &result_type, &value);
1092	  if (**strp != ')')
1093	    return "missing `)'";
1094	  ++*strp;
1095	  if (errmsg == NULL
1096	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1097	    value >>= 16;
1098	  *valuep = value;
1099	  return errmsg;
1100	}
1101      else if (strncasecmp (*strp + 1, "gprelhi(", 8) == 0)
1102	{
1103	  *strp += 9;
1104	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELHI,
1105				       &result_type, &value);
1106	  if (**strp != ')')
1107	    return "missing ')'";
1108	  ++*strp;
1109	  if (errmsg == NULL
1110	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1111	    value >>= 16;
1112	  *valuep = value;
1113	  return errmsg;
1114	}
1115      else if (strncasecmp (*strp + 1, "gothi(", 6) == 0)
1116	{
1117	  *strp += 7;
1118	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTHI,
1119				       &result_type, &value);
1120	  if (**strp != ')')
1121	    return "missing ')'";
1122	  ++*strp;
1123	  if (errmsg == NULL
1124	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1125	    value >>= 16;
1126	  *valuep = value;
1127	  return errmsg;
1128	}
1129      else if (strncasecmp (*strp + 1, "gotfuncdeschi(", 14) == 0)
1130	{
1131	  *strp += 15;
1132	  errmsg = cgen_parse_address (cd, strp, opindex,
1133				       BFD_RELOC_FRV_FUNCDESC_GOTHI,
1134				       &result_type, &value);
1135	  if (**strp != ')')
1136	    return "missing ')'";
1137	  ++*strp;
1138	  if (errmsg == NULL
1139	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1140	    value >>= 16;
1141	  *valuep = value;
1142	  return errmsg;
1143	}
1144      else if (strncasecmp (*strp + 1, "gotoffhi(", 9) == 0)
1145	{
1146	  *strp += 10;
1147	  errmsg = cgen_parse_address (cd, strp, opindex,
1148				       BFD_RELOC_FRV_GOTOFFHI,
1149				       &result_type, &value);
1150	  if (**strp != ')')
1151	    return "missing ')'";
1152	  ++*strp;
1153	  if (errmsg == NULL
1154	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1155	    value >>= 16;
1156	  *valuep = value;
1157	  return errmsg;
1158	}
1159      else if (strncasecmp (*strp + 1, "gotofffuncdeschi(", 17) == 0)
1160	{
1161	  *strp += 18;
1162	  errmsg = cgen_parse_address (cd, strp, opindex,
1163				       BFD_RELOC_FRV_FUNCDESC_GOTOFFHI,
1164				       &result_type, &value);
1165	  if (**strp != ')')
1166	    return "missing ')'";
1167	  ++*strp;
1168	  if (errmsg == NULL
1169	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
1170	    value >>= 16;
1171	  *valuep = value;
1172	  return errmsg;
1173	}
1174    }
1175  return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1176}
1177
1178static long
1179parse_register_number (strp)
1180     const char **strp;
1181{
1182  int regno;
1183  if (**strp < '0' || **strp > '9')
1184    return -1; /* error */
1185
1186  regno = **strp - '0';
1187  for (++*strp; **strp >= '0' && **strp <= '9'; ++*strp)
1188    regno = regno * 10 + (**strp - '0');
1189
1190  return regno;
1191}
1192
1193static const char *
1194parse_spr (cd, strp, table, valuep)
1195     CGEN_CPU_DESC cd;
1196     const char **strp;
1197     CGEN_KEYWORD * table;
1198     long *valuep;
1199{
1200  const char *save_strp;
1201  long regno;
1202
1203  /* Check for spr index notation.  */
1204  if (strncasecmp (*strp, "spr[", 4) == 0)
1205    {
1206      *strp += 4;
1207      regno = parse_register_number (strp);
1208      if (**strp != ']')
1209        return "missing `]'";
1210      ++*strp;
1211      if (! spr_valid (regno))
1212	return "Special purpose register number is out of range";
1213      *valuep = regno;
1214      return NULL;
1215    }
1216
1217  save_strp = *strp;
1218  regno = parse_register_number (strp);
1219  if (regno != -1)
1220    {
1221      if (! spr_valid (regno))
1222	return "Special purpose register number is out of range";
1223      *valuep = regno;
1224      return NULL;
1225    }
1226
1227  *strp = save_strp;
1228  return cgen_parse_keyword (cd, strp, table, valuep);
1229}
1230
1231static const char *
1232parse_d12 (cd, strp, opindex, valuep)
1233     CGEN_CPU_DESC cd;
1234     const char **strp;
1235     int opindex;
1236     long *valuep;
1237{
1238  const char *errmsg;
1239  enum cgen_parse_operand_result result_type;
1240  bfd_vma value;
1241
1242  /* Check for small data reference.  */
1243  if (**strp == '#' || **strp == '%')
1244    {
1245      if (strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1246        {
1247          *strp += 9;
1248          errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPREL12,
1249                                       &result_type, &value);
1250          if (**strp != ')')
1251            return "missing `)'";
1252          ++*strp;
1253          *valuep = value;
1254          return errmsg;
1255        }
1256      else if (strncasecmp (*strp + 1, "got12(", 6) == 0)
1257	{
1258	  *strp += 7;
1259	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOT12,
1260				       &result_type, &value);
1261	  if (**strp != ')')
1262	    return "missing ')'";
1263	  ++*strp;
1264	  *valuep = value;
1265	  return errmsg;
1266	}
1267      else if (strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
1268	{
1269	  *strp += 15;
1270	  errmsg = cgen_parse_address (cd, strp, opindex,
1271				       BFD_RELOC_FRV_FUNCDESC_GOT12,
1272				       &result_type, &value);
1273	  if (**strp != ')')
1274	    return "missing ')'";
1275	  ++*strp;
1276	  *valuep = value;
1277	  return errmsg;
1278	}
1279      else if (strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
1280	{
1281	  *strp += 10;
1282	  errmsg = cgen_parse_address (cd, strp, opindex,
1283				       BFD_RELOC_FRV_GOTOFF12,
1284				       &result_type, &value);
1285	  if (**strp != ')')
1286	    return "missing ')'";
1287	  ++*strp;
1288	  *valuep = value;
1289	  return errmsg;
1290	}
1291      else if (strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
1292	{
1293	  *strp += 18;
1294	  errmsg = cgen_parse_address (cd, strp, opindex,
1295				       BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
1296				       &result_type, &value);
1297	  if (**strp != ')')
1298	    return "missing ')'";
1299	  ++*strp;
1300	  *valuep = value;
1301	  return errmsg;
1302	}
1303    }
1304  return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1305}
1306
1307static const char *
1308parse_s12 (cd, strp, opindex, valuep)
1309     CGEN_CPU_DESC cd;
1310     const char **strp;
1311     int opindex;
1312     long *valuep;
1313{
1314  const char *errmsg;
1315  enum cgen_parse_operand_result result_type;
1316  bfd_vma value;
1317
1318  /* Check for small data reference.  */
1319  if ((**strp == '#' || **strp == '%')
1320      && strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1321    {
1322      *strp += 9;
1323      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPREL12,
1324                                    &result_type, &value);
1325      if (**strp != ')')
1326        return "missing `)'";
1327      ++*strp;
1328      *valuep = value;
1329      return errmsg;
1330    }
1331  else if ((**strp == '#' || **strp == '%')
1332	   && strncasecmp (*strp + 1, "got12(", 6) == 0)
1333    {
1334      *strp += 7;
1335      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOT12,
1336				   &result_type, &value);
1337      if (**strp != ')')
1338	return "missing ')'";
1339      ++*strp;
1340      *valuep = value;
1341      return errmsg;
1342    }
1343  else if ((**strp == '#' || **strp == '%')
1344	   && strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
1345    {
1346      *strp += 15;
1347      errmsg = cgen_parse_address (cd, strp, opindex,
1348				   BFD_RELOC_FRV_FUNCDESC_GOT12,
1349				   &result_type, &value);
1350      if (**strp != ')')
1351	return "missing ')'";
1352      ++*strp;
1353      *valuep = value;
1354      return errmsg;
1355    }
1356  else if ((**strp == '#' || **strp == '%')
1357	   && strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
1358    {
1359      *strp += 10;
1360      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GOTOFF12,
1361				   &result_type, &value);
1362      if (**strp != ')')
1363	return "missing ')'";
1364      ++*strp;
1365      *valuep = value;
1366      return errmsg;
1367    }
1368  else if ((**strp == '#' || **strp == '%')
1369	   && strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
1370    {
1371      *strp += 18;
1372      errmsg = cgen_parse_address (cd, strp, opindex,
1373				   BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
1374				   &result_type, &value);
1375      if (**strp != ')')
1376	return "missing ')'";
1377      ++*strp;
1378      *valuep = value;
1379      return errmsg;
1380    }
1381  else
1382    {
1383      if (**strp == '#')
1384        ++*strp;
1385      return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1386    }
1387}
1388
1389static const char *
1390parse_u12 (cd, strp, opindex, valuep)
1391     CGEN_CPU_DESC cd;
1392     const char **strp;
1393     int opindex;
1394     long *valuep;
1395{
1396  const char *errmsg;
1397  enum cgen_parse_operand_result result_type;
1398  bfd_vma value;
1399
1400  /* Check for small data reference.  */
1401  if ((**strp == '#' || **strp == '%')
1402      && strncasecmp (*strp + 1, "gprel12(", 8) == 0)
1403    {
1404      *strp += 9;
1405      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_GPRELU12,
1406                                    &result_type, &value);
1407      if (**strp != ')')
1408        return "missing `)'";
1409      ++*strp;
1410      *valuep = value;
1411      return errmsg;
1412    }
1413  else
1414    {
1415      if (**strp == '#')
1416        ++*strp;
1417      return cgen_parse_signed_integer (cd, strp, opindex, valuep);
1418    }
1419}
1420
1421static const char *
1422parse_A (cd, strp, opindex, valuep, A)
1423     CGEN_CPU_DESC cd;
1424     const char **strp;
1425     int opindex;
1426     long *valuep;
1427     long A;
1428{
1429  const char *errmsg;
1430
1431  if (**strp == '#')
1432    ++*strp;
1433
1434  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
1435  if (errmsg)
1436    return errmsg;
1437
1438  if (*valuep != A)
1439    return "Value of A operand must be 0 or 1";
1440
1441  return NULL;
1442}
1443
1444static const char *
1445parse_A0 (cd, strp, opindex, valuep)
1446     CGEN_CPU_DESC cd;
1447     const char **strp;
1448     int opindex;
1449     long *valuep;
1450{
1451  return parse_A (cd, strp, opindex, valuep, 0);
1452}
1453
1454static const char *
1455parse_A1 (cd, strp, opindex, valuep)
1456     CGEN_CPU_DESC cd;
1457     const char **strp;
1458     int opindex;
1459     long *valuep;
1460{
1461  return parse_A (cd, strp, opindex, valuep, 1);
1462}
1463
1464static const char *
1465parse_even_register (cd, strP, tableP, valueP)
1466     CGEN_CPU_DESC  cd;
1467     const char **  strP;
1468     CGEN_KEYWORD * tableP;
1469     long *         valueP;
1470{
1471  const char * errmsg;
1472  const char * saved_star_strP = * strP;
1473
1474  errmsg = cgen_parse_keyword (cd, strP, tableP, valueP);
1475
1476  if (errmsg == NULL && ((* valueP) & 1))
1477    {
1478      errmsg = _("register number must be even");
1479      * strP = saved_star_strP;
1480    }
1481
1482  return errmsg;
1483}
1484/* -- */
1485
1486/* -- dis.c */
1487static void print_spr
1488  PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned));
1489static void print_hi
1490  PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
1491static void print_lo
1492  PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
1493
1494static void
1495print_spr (cd, dis_info, names, regno, attrs)
1496     CGEN_CPU_DESC cd;
1497     PTR dis_info;
1498     CGEN_KEYWORD *names;
1499     long regno;
1500     unsigned int attrs;
1501{
1502  /* Use the register index format for any unnamed registers.  */
1503  if (cgen_keyword_lookup_value (names, regno) == NULL)
1504    {
1505      disassemble_info *info = (disassemble_info *) dis_info;
1506      (*info->fprintf_func) (info->stream, "spr[%ld]", regno);
1507    }
1508  else
1509    print_keyword (cd, dis_info, names, regno, attrs);
1510}
1511
1512static void
1513print_hi (cd, dis_info, value, attrs, pc, length)
1514     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
1515     PTR dis_info;
1516     long value;
1517     unsigned int attrs ATTRIBUTE_UNUSED;
1518     bfd_vma pc ATTRIBUTE_UNUSED;
1519     int length ATTRIBUTE_UNUSED;
1520{
1521  disassemble_info *info = (disassemble_info *) dis_info;
1522  if (value)
1523    (*info->fprintf_func) (info->stream, "0x%lx", value);
1524  else
1525    (*info->fprintf_func) (info->stream, "hi(0x%lx)", value);
1526}
1527
1528static void
1529print_lo (cd, dis_info, value, attrs, pc, length)
1530     CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
1531     PTR dis_info;
1532     long value;
1533     unsigned int attrs ATTRIBUTE_UNUSED;
1534     bfd_vma pc ATTRIBUTE_UNUSED;
1535     int length ATTRIBUTE_UNUSED;
1536{
1537  disassemble_info *info = (disassemble_info *) dis_info;
1538  if (value)
1539    (*info->fprintf_func) (info->stream, "0x%lx", value);
1540  else
1541    (*info->fprintf_func) (info->stream, "lo(0x%lx)", value);
1542}
1543
1544/* -- */
1545