xref: /netbsd-src/external/gpl3/binutils.old/dist/cpu/frv.opc (revision e992f068c547fd6e84b3f104dc2340adcc955732)
116dce513Schristos/* Fujitsu FRV opcode support, for GNU Binutils.  -*- C -*-
216dce513Schristos
316dce513Schristos   Copyright 2000, 2001, 2003, 2004, 2005, 2007, 2009
416dce513Schristos   Free Software Foundation, Inc.
516dce513Schristos
616dce513Schristos   Contributed by Red Hat Inc; developed under contract from Fujitsu.
716dce513Schristos
816dce513Schristos   This file is part of the GNU Binutils.
916dce513Schristos
1016dce513Schristos   This program is free software; you can redistribute it and/or modify
1116dce513Schristos   it under the terms of the GNU General Public License as published by
1216dce513Schristos   the Free Software Foundation; either version 3 of the License, or
1316dce513Schristos   (at your option) any later version.
1416dce513Schristos
1516dce513Schristos   This program is distributed in the hope that it will be useful,
1616dce513Schristos   but WITHOUT ANY WARRANTY; without even the implied warranty of
1716dce513Schristos   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1816dce513Schristos   GNU General Public License for more details.
1916dce513Schristos
2016dce513Schristos   You should have received a copy of the GNU General Public License
2116dce513Schristos   along with this program; if not, write to the Free Software
2216dce513Schristos   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
2316dce513Schristos   MA 02110-1301, USA.  */
2416dce513Schristos
2516dce513Schristos
2616dce513Schristos/* This file is an addendum to frv.cpu.  Heavy use of C code isn't
2716dce513Schristos   appropriate in .cpu files, so it resides here.  This especially applies
2816dce513Schristos   to assembly/disassembly where parsing/printing can be quite involved.
2916dce513Schristos   Such things aren't really part of the specification of the cpu, per se,
3016dce513Schristos   so .cpu files provide the general framework and .opc files handle the
3116dce513Schristos   nitty-gritty details as necessary.
3216dce513Schristos
3316dce513Schristos   Each section is delimited with start and end markers.
3416dce513Schristos
3516dce513Schristos   <arch>-opc.h additions use: "-- opc.h"
3616dce513Schristos   <arch>-opc.c additions use: "-- opc.c"
3716dce513Schristos   <arch>-asm.c additions use: "-- asm.c"
3816dce513Schristos   <arch>-dis.c additions use: "-- dis.c"
3916dce513Schristos   <arch>-ibd.h additions use: "-- ibd.h".  */
4016dce513Schristos
4116dce513Schristos/* -- opc.h */
4216dce513Schristos
4316dce513Schristos#undef  CGEN_DIS_HASH_SIZE
4416dce513Schristos#define CGEN_DIS_HASH_SIZE 128
4516dce513Schristos#undef  CGEN_DIS_HASH
4616dce513Schristos#define CGEN_DIS_HASH(buffer, value) (((value) >> 18) & 127)
4716dce513Schristos
4816dce513Schristos/* Allows reason codes to be output when assembler errors occur.  */
4916dce513Schristos#define CGEN_VERBOSE_ASSEMBLER_ERRORS
5016dce513Schristos
5116dce513Schristos/* Vliw support.  */
5216dce513Schristos#define FRV_VLIW_SIZE 8 /* fr550 has largest vliw size of 8.  */
5316dce513Schristos#define PAD_VLIW_COMBO ,UNIT_NIL,UNIT_NIL,UNIT_NIL,UNIT_NIL
5416dce513Schristos
5516dce513Schristostypedef CGEN_ATTR_VALUE_ENUM_TYPE VLIW_COMBO[FRV_VLIW_SIZE];
5616dce513Schristos
5716dce513Schristostypedef struct
5816dce513Schristos{
5916dce513Schristos  int                    next_slot;
6016dce513Schristos  int                    constraint_violation;
6116dce513Schristos  unsigned long          mach;
6216dce513Schristos  unsigned long          elf_flags;
6316dce513Schristos  CGEN_ATTR_VALUE_ENUM_TYPE * unit_mapping;
6416dce513Schristos  VLIW_COMBO *           current_vliw;
6516dce513Schristos  CGEN_ATTR_VALUE_ENUM_TYPE   major[FRV_VLIW_SIZE];
6616dce513Schristos  const CGEN_INSN *      insn[FRV_VLIW_SIZE];
6716dce513Schristos} FRV_VLIW;
6816dce513Schristos
69*e992f068Schristosbool frv_is_branch_major (CGEN_ATTR_VALUE_ENUM_TYPE, unsigned long);
70*e992f068Schristosbool frv_is_float_major  (CGEN_ATTR_VALUE_ENUM_TYPE, unsigned long);
71*e992f068Schristosbool frv_is_media_major  (CGEN_ATTR_VALUE_ENUM_TYPE, unsigned long);
72*e992f068Schristosbool frv_is_branch_insn  (const CGEN_INSN *);
73*e992f068Schristosbool frv_is_float_insn   (const CGEN_INSN *);
74*e992f068Schristosbool frv_is_media_insn   (const CGEN_INSN *);
7516dce513Schristosvoid frv_vliw_reset      (FRV_VLIW *, unsigned long, unsigned long);
7616dce513Schristosint  frv_vliw_add_insn   (FRV_VLIW *, const CGEN_INSN *);
77*e992f068Schristosbool spr_valid           (long);
7816dce513Schristos/* -- */
7916dce513Schristos
8016dce513Schristos/* -- opc.c */
81ede78133Schristos#include "opintl.h"
8216dce513Schristos#include "elf/frv.h"
8316dce513Schristos#include <stdio.h>
8416dce513Schristos
8516dce513Schristos/* DEBUG appears below as argument of OP macro.  */
8616dce513Schristos#undef DEBUG
8716dce513Schristos
8816dce513Schristos/* Returns TRUE if {MAJOR,MACH} is a major branch of the FRV
8916dce513Schristos   development tree.  */
9016dce513Schristos
91*e992f068Schristosbool
9216dce513Schristosfrv_is_branch_major (CGEN_ATTR_VALUE_ENUM_TYPE major, unsigned long mach)
9316dce513Schristos{
9416dce513Schristos  switch (mach)
9516dce513Schristos    {
9616dce513Schristos    case bfd_mach_fr400:
9716dce513Schristos      if (major >= FR400_MAJOR_B_1 && major <= FR400_MAJOR_B_6)
98*e992f068Schristos	return true;
9916dce513Schristos      break;
10016dce513Schristos    case bfd_mach_fr450:
10116dce513Schristos      if (major >= FR450_MAJOR_B_1 && major <= FR450_MAJOR_B_6)
102*e992f068Schristos	return true;
10316dce513Schristos      break;
10416dce513Schristos    default:
10516dce513Schristos      if (major >= FR500_MAJOR_B_1 && major <= FR500_MAJOR_B_6)
106*e992f068Schristos	return true;
10716dce513Schristos      break;
10816dce513Schristos    }
10916dce513Schristos
110*e992f068Schristos  return false;
11116dce513Schristos}
11216dce513Schristos
11316dce513Schristos/* Returns TRUE if {MAJOR,MACH} supports floating point insns.  */
11416dce513Schristos
115*e992f068Schristosbool
11616dce513Schristosfrv_is_float_major (CGEN_ATTR_VALUE_ENUM_TYPE major, unsigned long mach)
11716dce513Schristos{
11816dce513Schristos  switch (mach)
11916dce513Schristos    {
12016dce513Schristos    case bfd_mach_fr400:
12116dce513Schristos    case bfd_mach_fr450:
122*e992f068Schristos      return false;
12316dce513Schristos    default:
12416dce513Schristos      if (major >= FR500_MAJOR_F_1 && major <= FR500_MAJOR_F_8)
125*e992f068Schristos	return true;
12616dce513Schristos      break;
12716dce513Schristos    }
12816dce513Schristos
129*e992f068Schristos  return false;
13016dce513Schristos}
13116dce513Schristos
13216dce513Schristos/* Returns TRUE if {MAJOR,MACH} supports media insns.  */
13316dce513Schristos
134*e992f068Schristosbool
13516dce513Schristosfrv_is_media_major (CGEN_ATTR_VALUE_ENUM_TYPE major, unsigned long mach)
13616dce513Schristos{
13716dce513Schristos  switch (mach)
13816dce513Schristos    {
13916dce513Schristos    case bfd_mach_fr400:
14016dce513Schristos      if (major >= FR400_MAJOR_M_1 && major <= FR400_MAJOR_M_2)
141*e992f068Schristos	return true;
14216dce513Schristos      break;
14316dce513Schristos    case bfd_mach_fr450:
14416dce513Schristos      if (major >= FR450_MAJOR_M_1 && major <= FR450_MAJOR_M_6)
145*e992f068Schristos	return true;
14616dce513Schristos      break;
14716dce513Schristos    default:
14816dce513Schristos      if (major >= FR500_MAJOR_M_1 && major <= FR500_MAJOR_M_8)
149*e992f068Schristos	return true;
15016dce513Schristos      break;
15116dce513Schristos    }
15216dce513Schristos
153*e992f068Schristos  return false;
15416dce513Schristos}
15516dce513Schristos
156*e992f068Schristosbool
15716dce513Schristosfrv_is_branch_insn (const CGEN_INSN *insn)
15816dce513Schristos{
15916dce513Schristos  if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
16016dce513Schristos			   bfd_mach_fr400))
161*e992f068Schristos    return true;
16216dce513Schristos  if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
16316dce513Schristos			   bfd_mach_fr450))
164*e992f068Schristos    return true;
16516dce513Schristos  if (frv_is_branch_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
16616dce513Schristos			   bfd_mach_fr500))
167*e992f068Schristos    return true;
16816dce513Schristos
169*e992f068Schristos  return false;
17016dce513Schristos}
17116dce513Schristos
172*e992f068Schristosbool
17316dce513Schristosfrv_is_float_insn (const CGEN_INSN *insn)
17416dce513Schristos{
17516dce513Schristos  if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
17616dce513Schristos			  bfd_mach_fr400))
177*e992f068Schristos    return true;
17816dce513Schristos  if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
17916dce513Schristos			  bfd_mach_fr450))
180*e992f068Schristos    return true;
18116dce513Schristos  if (frv_is_float_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
18216dce513Schristos			  bfd_mach_fr500))
183*e992f068Schristos    return true;
18416dce513Schristos
185*e992f068Schristos  return false;
18616dce513Schristos}
18716dce513Schristos
188*e992f068Schristosbool
18916dce513Schristosfrv_is_media_insn (const CGEN_INSN *insn)
19016dce513Schristos{
19116dce513Schristos  if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR),
19216dce513Schristos			  bfd_mach_fr400))
193*e992f068Schristos    return true;
19416dce513Schristos  if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR),
19516dce513Schristos			  bfd_mach_fr450))
196*e992f068Schristos    return true;
19716dce513Schristos  if (frv_is_media_major (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR),
19816dce513Schristos			  bfd_mach_fr500))
199*e992f068Schristos    return true;
20016dce513Schristos
201*e992f068Schristos  return false;
20216dce513Schristos}
20316dce513Schristos
20416dce513Schristos/* This table represents the allowable packing for vliw insns for the fr400.
20516dce513Schristos   The fr400 has only 2 vliw slots. Represent this by not allowing any insns
20616dce513Schristos   in the extra slots.
20716dce513Schristos   Subsets of any given row are also allowed.  */
20816dce513Schristosstatic VLIW_COMBO fr400_allowed_vliw[] =
20916dce513Schristos{
21016dce513Schristos  /*  slot0       slot1       slot2       slot3    */
21116dce513Schristos  {  UNIT_I0,    UNIT_I1,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
21216dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
21316dce513Schristos  {  UNIT_I0,    UNIT_B0,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
21416dce513Schristos  {  UNIT_FM0,   UNIT_FM1,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
21516dce513Schristos  {  UNIT_FM0,   UNIT_B0,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
21616dce513Schristos  {  UNIT_B0,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
21716dce513Schristos  {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
21816dce513Schristos  {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO }
21916dce513Schristos};
22016dce513Schristos
22116dce513Schristos/* This table represents the allowable packing for vliw insns for the fr500.
22216dce513Schristos   The fr500 has only 4 vliw slots. Represent this by not allowing any insns
22316dce513Schristos   in the extra slots.
22416dce513Schristos   Subsets of any given row are also allowed.  */
22516dce513Schristosstatic VLIW_COMBO fr500_allowed_vliw[] =
22616dce513Schristos{
22716dce513Schristos  /*  slot0       slot1       slot2       slot3    */
22816dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1  PAD_VLIW_COMBO },
22916dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0   PAD_VLIW_COMBO },
23016dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0   PAD_VLIW_COMBO },
23116dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
23216dce513Schristos  {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
23316dce513Schristos  {  UNIT_I0,    UNIT_B0,    UNIT_B1,    UNIT_NIL  PAD_VLIW_COMBO },
23416dce513Schristos  {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1   PAD_VLIW_COMBO },
23516dce513Schristos  {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL  PAD_VLIW_COMBO },
23616dce513Schristos  {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
23716dce513Schristos  {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO },
23816dce513Schristos  {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL  PAD_VLIW_COMBO }
23916dce513Schristos};
24016dce513Schristos
24116dce513Schristos/* This table represents the allowable packing for vliw insns for the fr550.
24216dce513Schristos   Subsets of any given row are also allowed.  */
24316dce513Schristosstatic VLIW_COMBO fr550_allowed_vliw[] =
24416dce513Schristos{
24516dce513Schristos  /*  slot0       slot1       slot2       slot3       slot4       slot5       slot6       slot7   */
24616dce513Schristos  {  UNIT_I0,    UNIT_I1,    UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL },
24716dce513Schristos  {  UNIT_I0,    UNIT_I1,    UNIT_I2,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
24816dce513Schristos  {  UNIT_I0,    UNIT_I1,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
24916dce513Schristos  {  UNIT_I0,    UNIT_B0,    UNIT_B1 ,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
25016dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_I3,    UNIT_FM3 },
25116dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_I3,    UNIT_B0  },
25216dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_FM3,   UNIT_B0  },
25316dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_FM2,   UNIT_B0,    UNIT_B1  },
25416dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1  },
25516dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_I2,    UNIT_B0,    UNIT_B1,    UNIT_NIL },
25616dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1  },
25716dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1  },
25816dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL },
25916dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
26016dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_I2,    UNIT_I3,    UNIT_B0,    UNIT_B1,    UNIT_NIL },
26116dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_I2,    UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
26216dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_I1,    UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
26316dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1,    UNIT_NIL },
26416dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
26516dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
26616dce513Schristos  {  UNIT_I0,    UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
26716dce513Schristos  {  UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
26816dce513Schristos  {  UNIT_C,     UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
26916dce513Schristos  {  UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_FM3,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL },
27016dce513Schristos  {  UNIT_FM0,   UNIT_FM1,   UNIT_FM2,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
27116dce513Schristos  {  UNIT_FM0,   UNIT_FM1,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
27216dce513Schristos  {  UNIT_FM0,   UNIT_B0,    UNIT_B1,    UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL },
27316dce513Schristos  {  UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL,   UNIT_NIL }
27416dce513Schristos};
27516dce513Schristos
27616dce513Schristos/* Some insns are assigned specialized implementation units which map to
27716dce513Schristos   different actual implementation units on different machines.  These
27816dce513Schristos   tables perform that mapping.  */
27916dce513Schristosstatic CGEN_ATTR_VALUE_ENUM_TYPE fr400_unit_mapping[] =
28016dce513Schristos{
28116dce513Schristos/* unit in insn    actual unit */
28216dce513Schristos/* NIL      */     UNIT_NIL,
28316dce513Schristos/* I0       */     UNIT_I0,
28416dce513Schristos/* I1       */     UNIT_I1,
28516dce513Schristos/* I01      */     UNIT_I01,
28616dce513Schristos/* I2       */     UNIT_NIL, /* no I2 or I3 unit */
28716dce513Schristos/* I3       */     UNIT_NIL,
28816dce513Schristos/* IALL     */     UNIT_I01, /* only I0 and I1 units */
28916dce513Schristos/* FM0      */     UNIT_FM0,
29016dce513Schristos/* FM1      */     UNIT_FM1,
29116dce513Schristos/* FM01     */     UNIT_FM01,
29216dce513Schristos/* FM2      */     UNIT_NIL, /* no F2 or M2 units */
29316dce513Schristos/* FM3      */     UNIT_NIL, /* no F3 or M3 units */
29416dce513Schristos/* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
29516dce513Schristos/* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
29616dce513Schristos/* B0       */     UNIT_B0,  /* branches only in B0 unit.  */
29716dce513Schristos/* B1       */     UNIT_B0,
29816dce513Schristos/* B01      */     UNIT_B0,
29916dce513Schristos/* C        */     UNIT_C,
30016dce513Schristos/* MULT-DIV */     UNIT_I0,  /* multiply and divide only in I0  unit.  */
30116dce513Schristos/* IACC     */     UNIT_I01, /* iacc multiply       in I0 or I1 unit.  */
30216dce513Schristos/* LOAD     */     UNIT_I0,  /* load                only in I0  unit.  */
30316dce513Schristos/* STORE    */     UNIT_I0,  /* store               only in I0  unit.  */
30416dce513Schristos/* SCAN     */     UNIT_I0,  /* scan                only in I0  unit.  */
30516dce513Schristos/* DCPL     */     UNIT_C,   /* dcpl                only in C   unit.  */
30616dce513Schristos/* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
30716dce513Schristos/* MDCUTSSI */     UNIT_FM0, /* mdcutssi            only in FM0 unit.  */
30816dce513Schristos/* MCLRACC-1*/     UNIT_FM0  /* mclracc,A==1   insn only in FM0 unit.  */
30916dce513Schristos};
31016dce513Schristos
31116dce513Schristos/* Some insns are assigned specialized implementation units which map to
31216dce513Schristos   different actual implementation units on different machines.  These
31316dce513Schristos   tables perform that mapping.  */
31416dce513Schristosstatic CGEN_ATTR_VALUE_ENUM_TYPE fr450_unit_mapping[] =
31516dce513Schristos{
31616dce513Schristos/* unit in insn    actual unit */
31716dce513Schristos/* NIL      */     UNIT_NIL,
31816dce513Schristos/* I0       */     UNIT_I0,
31916dce513Schristos/* I1       */     UNIT_I1,
32016dce513Schristos/* I01      */     UNIT_I01,
32116dce513Schristos/* I2       */     UNIT_NIL, /* no I2 or I3 unit */
32216dce513Schristos/* I3       */     UNIT_NIL,
32316dce513Schristos/* IALL     */     UNIT_I01, /* only I0 and I1 units */
32416dce513Schristos/* FM0      */     UNIT_FM0,
32516dce513Schristos/* FM1      */     UNIT_FM1,
32616dce513Schristos/* FM01     */     UNIT_FM01,
32716dce513Schristos/* FM2      */     UNIT_NIL, /* no F2 or M2 units */
32816dce513Schristos/* FM3      */     UNIT_NIL, /* no F3 or M3 units */
32916dce513Schristos/* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
33016dce513Schristos/* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
33116dce513Schristos/* B0       */     UNIT_B0,  /* branches only in B0 unit.  */
33216dce513Schristos/* B1       */     UNIT_B0,
33316dce513Schristos/* B01      */     UNIT_B0,
33416dce513Schristos/* C        */     UNIT_C,
33516dce513Schristos/* MULT-DIV */     UNIT_I0,  /* multiply and divide only in I0  unit.  */
33616dce513Schristos/* IACC     */     UNIT_I01, /* iacc multiply       in I0 or I1 unit.  */
33716dce513Schristos/* LOAD     */     UNIT_I0,  /* load                only in I0  unit.  */
33816dce513Schristos/* STORE    */     UNIT_I0,  /* store               only in I0  unit.  */
33916dce513Schristos/* SCAN     */     UNIT_I0,  /* scan                only in I0  unit.  */
34016dce513Schristos/* DCPL     */     UNIT_I0,  /* dcpl                only in I0  unit.  */
34116dce513Schristos/* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
34216dce513Schristos/* MDCUTSSI */     UNIT_FM01, /* mdcutssi           in FM0 or FM1.  */
34316dce513Schristos/* MCLRACC-1*/     UNIT_FM0  /* mclracc,A==1   insn only in FM0 unit.  */
34416dce513Schristos};
34516dce513Schristos
34616dce513Schristosstatic CGEN_ATTR_VALUE_ENUM_TYPE fr500_unit_mapping[] =
34716dce513Schristos{
34816dce513Schristos/* unit in insn    actual unit */
34916dce513Schristos/* NIL      */     UNIT_NIL,
35016dce513Schristos/* I0       */     UNIT_I0,
35116dce513Schristos/* I1       */     UNIT_I1,
35216dce513Schristos/* I01      */     UNIT_I01,
35316dce513Schristos/* I2       */     UNIT_NIL, /* no I2 or I3 unit */
35416dce513Schristos/* I3       */     UNIT_NIL,
35516dce513Schristos/* IALL     */     UNIT_I01, /* only I0 and I1 units */
35616dce513Schristos/* FM0      */     UNIT_FM0,
35716dce513Schristos/* FM1      */     UNIT_FM1,
35816dce513Schristos/* FM01     */     UNIT_FM01,
35916dce513Schristos/* FM2      */     UNIT_NIL, /* no F2 or M2 units */
36016dce513Schristos/* FM3      */     UNIT_NIL, /* no F3 or M2 units */
36116dce513Schristos/* FMALL    */     UNIT_FM01,/* Only F0,F1,M0,M1 units */
36216dce513Schristos/* FMLOW    */     UNIT_FM0, /* Only F0,M0 units */
36316dce513Schristos/* B0       */     UNIT_B0,
36416dce513Schristos/* B1       */     UNIT_B1,
36516dce513Schristos/* B01      */     UNIT_B01,
36616dce513Schristos/* C        */     UNIT_C,
36716dce513Schristos/* MULT-DIV */     UNIT_I01, /* multiply and divide in I0 or I1 unit.  */
36816dce513Schristos/* IACC     */     UNIT_NIL, /* iacc multiply       not implemented */
36916dce513Schristos/* LOAD     */     UNIT_I01, /* load                in I0 or I1 unit.  */
37016dce513Schristos/* STORE    */     UNIT_I0,  /* store               only in I0 unit.  */
37116dce513Schristos/* SCAN     */     UNIT_I01, /* scan                in I0 or I1 unit.  */
37216dce513Schristos/* DCPL     */     UNIT_C,   /* dcpl                only in C unit.  */
37316dce513Schristos/* MDUALACC */     UNIT_FM0, /* media dual acc insn only in FM0 unit.  */
37416dce513Schristos/* MDCUTSSI */     UNIT_FM0, /* mdcutssi            only in FM0 unit.  */
37516dce513Schristos/* MCLRACC-1*/     UNIT_FM01 /* mclracc,A==1 in FM0 or FM1 unit.  */
37616dce513Schristos};
37716dce513Schristos
37816dce513Schristosstatic CGEN_ATTR_VALUE_ENUM_TYPE fr550_unit_mapping[] =
37916dce513Schristos{
38016dce513Schristos/* unit in insn    actual unit */
38116dce513Schristos/* NIL      */     UNIT_NIL,
38216dce513Schristos/* I0       */     UNIT_I0,
38316dce513Schristos/* I1       */     UNIT_I1,
38416dce513Schristos/* I01      */     UNIT_I01,
38516dce513Schristos/* I2       */     UNIT_I2,
38616dce513Schristos/* I3       */     UNIT_I3,
38716dce513Schristos/* IALL     */     UNIT_IALL,
38816dce513Schristos/* FM0      */     UNIT_FM0,
38916dce513Schristos/* FM1      */     UNIT_FM1,
39016dce513Schristos/* FM01     */     UNIT_FM01,
39116dce513Schristos/* FM2      */     UNIT_FM2,
39216dce513Schristos/* FM3      */     UNIT_FM3,
39316dce513Schristos/* FMALL    */     UNIT_FMALL,
39416dce513Schristos/* FMLOW    */     UNIT_FM01, /* Only F0,F1,M0,M1 units */
39516dce513Schristos/* B0       */     UNIT_B0,
39616dce513Schristos/* B1       */     UNIT_B1,
39716dce513Schristos/* B01      */     UNIT_B01,
39816dce513Schristos/* C        */     UNIT_C,
39916dce513Schristos/* MULT-DIV */     UNIT_I01,  /* multiply and divide in I0 or I1 unit.    */
40016dce513Schristos/* IACC     */     UNIT_NIL,  /* iacc multiply       not implemented.     */
40116dce513Schristos/* LOAD     */     UNIT_I01,  /* load                in I0 or I1 unit.    */
40216dce513Schristos/* STORE    */     UNIT_I01,  /* store               in I0 or I1 unit.    */
40316dce513Schristos/* SCAN     */     UNIT_IALL, /* scan                in any integer unit. */
40416dce513Schristos/* DCPL     */     UNIT_I0,   /* dcpl                only in I0 unit.     */
40516dce513Schristos/* MDUALACC */     UNIT_FMALL,/* media dual acc insn in all media units   */
40616dce513Schristos/* MDCUTSSI */     UNIT_FM01, /* mdcutssi            in FM0 or FM1 unit.  */
40716dce513Schristos/* MCLRACC-1*/     UNIT_FM01  /* mclracc,A==1 in FM0 or FM1 unit.         */
40816dce513Schristos};
40916dce513Schristos
41016dce513Schristosvoid
41116dce513Schristosfrv_vliw_reset (FRV_VLIW *vliw, unsigned long mach, unsigned long elf_flags)
41216dce513Schristos{
41316dce513Schristos  vliw->next_slot = 0;
41416dce513Schristos  vliw->constraint_violation = 0;
41516dce513Schristos  vliw->mach = mach;
41616dce513Schristos  vliw->elf_flags = elf_flags;
41716dce513Schristos
41816dce513Schristos  switch (mach)
41916dce513Schristos    {
42016dce513Schristos    case bfd_mach_fr400:
42116dce513Schristos      vliw->current_vliw = fr400_allowed_vliw;
42216dce513Schristos      vliw->unit_mapping = fr400_unit_mapping;
42316dce513Schristos      break;
42416dce513Schristos    case bfd_mach_fr450:
42516dce513Schristos      vliw->current_vliw = fr400_allowed_vliw;
42616dce513Schristos      vliw->unit_mapping = fr450_unit_mapping;
42716dce513Schristos      break;
42816dce513Schristos    case bfd_mach_fr550:
42916dce513Schristos      vliw->current_vliw = fr550_allowed_vliw;
43016dce513Schristos      vliw->unit_mapping = fr550_unit_mapping;
43116dce513Schristos      break;
43216dce513Schristos    default:
43316dce513Schristos      vliw->current_vliw = fr500_allowed_vliw;
43416dce513Schristos      vliw->unit_mapping = fr500_unit_mapping;
43516dce513Schristos      break;
43616dce513Schristos    }
43716dce513Schristos}
43816dce513Schristos
43916dce513Schristos/* Return TRUE if unit1 is a match for unit2.
44016dce513Schristos   Unit1 comes from the insn's UNIT attribute. unit2 comes from one of the
44116dce513Schristos   *_allowed_vliw tables above.  */
442*e992f068Schristosstatic bool
44316dce513Schristosmatch_unit (FRV_VLIW *vliw,
44416dce513Schristos	    CGEN_ATTR_VALUE_ENUM_TYPE unit1, CGEN_ATTR_VALUE_ENUM_TYPE unit2)
44516dce513Schristos{
44616dce513Schristos  /* Map any specialized implementation units to actual ones.  */
44716dce513Schristos  unit1 = vliw->unit_mapping[unit1];
44816dce513Schristos
44916dce513Schristos  if (unit1 == unit2)
450*e992f068Schristos    return true;
45116dce513Schristos  if (unit1 < unit2)
452*e992f068Schristos    return false;
45316dce513Schristos
45416dce513Schristos  switch (unit1)
45516dce513Schristos    {
45616dce513Schristos    case UNIT_I01:
45716dce513Schristos    case UNIT_FM01:
45816dce513Schristos    case UNIT_B01:
45916dce513Schristos      /* The 01 versions of these units are within 2 enums of the 0 or 1
46016dce513Schristos	 versions.  */
46116dce513Schristos      if (unit1 - unit2 <= 2)
462*e992f068Schristos	return true;
46316dce513Schristos      break;
46416dce513Schristos    case UNIT_IALL:
46516dce513Schristos    case UNIT_FMALL:
46616dce513Schristos      /* The ALL versions of these units are within 5 enums of the 0, 1, 2 or 3
46716dce513Schristos	 versions.  */
46816dce513Schristos      if (unit1 - unit2 <= 5)
469*e992f068Schristos	return true;
47016dce513Schristos      break;
47116dce513Schristos    default:
47216dce513Schristos      break;
47316dce513Schristos    }
47416dce513Schristos
475*e992f068Schristos  return false;
47616dce513Schristos}
47716dce513Schristos
47816dce513Schristos/* Return TRUE if the vliws match, FALSE otherwise.  */
47916dce513Schristos
480*e992f068Schristosstatic bool
48116dce513Schristosmatch_vliw (VLIW_COMBO *vliw1, VLIW_COMBO *vliw2, int vliw_size)
48216dce513Schristos{
48316dce513Schristos  int i;
48416dce513Schristos
48516dce513Schristos  for (i = 0; i < vliw_size; ++i)
48616dce513Schristos    if ((*vliw1)[i] != (*vliw2)[i])
487*e992f068Schristos      return false;
48816dce513Schristos
489*e992f068Schristos  return true;
49016dce513Schristos}
49116dce513Schristos
49216dce513Schristos/* Find the next vliw vliw in the table that can accomodate the new insn.
49316dce513Schristos   If one is found then return it. Otherwise return NULL.  */
49416dce513Schristos
49516dce513Schristosstatic VLIW_COMBO *
49616dce513Schristosadd_next_to_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE unit)
49716dce513Schristos{
49816dce513Schristos  int           next    = vliw->next_slot;
49916dce513Schristos  VLIW_COMBO    *current = vliw->current_vliw;
50016dce513Schristos  VLIW_COMBO    *potential;
50116dce513Schristos
50216dce513Schristos  if (next <= 0)
50316dce513Schristos    {
504ede78133Schristos      /* xgettext:c-format */
505ede78133Schristos      opcodes_error_handler (_("internal error: bad vliw->next_slot value"));
506ede78133Schristos      abort ();
50716dce513Schristos    }
50816dce513Schristos
50916dce513Schristos  /* The table is sorted by units allowed within slots, so vliws with
51016dce513Schristos     identical starting sequences are together.  */
51116dce513Schristos  potential = current;
51216dce513Schristos  do
51316dce513Schristos    {
51416dce513Schristos      if (match_unit (vliw, unit, (*potential)[next]))
51516dce513Schristos	return potential;
51616dce513Schristos      ++potential;
51716dce513Schristos    }
51816dce513Schristos  while (match_vliw (potential, current, next));
51916dce513Schristos
52016dce513Schristos  return NULL;
52116dce513Schristos}
52216dce513Schristos
52316dce513Schristos/* Look for the given major insn type in the given vliw.
52416dce513Schristos   Returns TRUE if found, FALSE otherwise.  */
52516dce513Schristos
526*e992f068Schristosstatic bool
52716dce513Schristosfind_major_in_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
52816dce513Schristos{
52916dce513Schristos  int i;
53016dce513Schristos
53116dce513Schristos  for (i = 0; i < vliw->next_slot; ++i)
53216dce513Schristos    if (vliw->major[i] == major)
533*e992f068Schristos      return true;
53416dce513Schristos
535*e992f068Schristos  return false;
53616dce513Schristos}
53716dce513Schristos
53816dce513Schristos/* Check for constraints between the insns in the vliw due to major insn
53916dce513Schristos   types.  */
54016dce513Schristos
541*e992f068Schristosstatic bool
54216dce513Schristosfr400_check_insn_major_constraints (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
54316dce513Schristos{
54416dce513Schristos  /* In the cpu file, all media insns are represented as being allowed in
54516dce513Schristos     both media units. This makes it easier since this is the case for fr500.
54616dce513Schristos     Catch the invalid combinations here.  Insns of major class FR400_MAJOR_M_2
54716dce513Schristos     cannot coexist with any other media insn in a vliw.  */
54816dce513Schristos  switch (major)
54916dce513Schristos    {
55016dce513Schristos    case FR400_MAJOR_M_2:
55116dce513Schristos      return ! find_major_in_vliw (vliw, FR400_MAJOR_M_1)
55216dce513Schristos	&&   ! find_major_in_vliw (vliw, FR400_MAJOR_M_2);
55316dce513Schristos    case FR400_MAJOR_M_1:
55416dce513Schristos      return ! find_major_in_vliw (vliw, FR400_MAJOR_M_2);
55516dce513Schristos    default:
55616dce513Schristos      break;
55716dce513Schristos    }
558*e992f068Schristos  return true;
55916dce513Schristos}
56016dce513Schristos
561*e992f068Schristosstatic bool
56216dce513Schristosfr450_check_insn_major_constraints (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
56316dce513Schristos{
56416dce513Schristos  CGEN_ATTR_VALUE_ENUM_TYPE other_major;
56516dce513Schristos
56616dce513Schristos  /* Our caller guarantees there's at least one other instruction.  */
56716dce513Schristos  other_major = CGEN_INSN_ATTR_VALUE (vliw->insn[0], CGEN_INSN_FR450_MAJOR);
56816dce513Schristos
56916dce513Schristos  /* (M4, M5) and (M4, M6) are allowed.  */
57016dce513Schristos  if (other_major == FR450_MAJOR_M_4)
57116dce513Schristos    if (major == FR450_MAJOR_M_5 || major == FR450_MAJOR_M_6)
572*e992f068Schristos      return true;
57316dce513Schristos
57416dce513Schristos  /* Otherwise, instructions in even-numbered media categories cannot be
57516dce513Schristos     executed in parallel with other media instructions.  */
57616dce513Schristos  switch (major)
57716dce513Schristos    {
57816dce513Schristos    case FR450_MAJOR_M_2:
57916dce513Schristos    case FR450_MAJOR_M_4:
58016dce513Schristos    case FR450_MAJOR_M_6:
58116dce513Schristos      return !(other_major >= FR450_MAJOR_M_1
58216dce513Schristos	       && other_major <= FR450_MAJOR_M_6);
58316dce513Schristos
58416dce513Schristos    case FR450_MAJOR_M_1:
58516dce513Schristos    case FR450_MAJOR_M_3:
58616dce513Schristos    case FR450_MAJOR_M_5:
58716dce513Schristos      return !(other_major == FR450_MAJOR_M_2
58816dce513Schristos	       || other_major == FR450_MAJOR_M_4
58916dce513Schristos	       || other_major == FR450_MAJOR_M_6);
59016dce513Schristos
59116dce513Schristos    default:
592*e992f068Schristos      return true;
59316dce513Schristos    }
59416dce513Schristos}
59516dce513Schristos
596*e992f068Schristosstatic bool
59716dce513Schristosfind_unit_in_vliw (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE unit)
59816dce513Schristos{
59916dce513Schristos  int i;
60016dce513Schristos
60116dce513Schristos  for (i = 0; i < vliw->next_slot; ++i)
60216dce513Schristos    if (CGEN_INSN_ATTR_VALUE (vliw->insn[i], CGEN_INSN_UNIT) == unit)
603*e992f068Schristos      return true;
60416dce513Schristos
605*e992f068Schristos  return false; /* Not found.  */
60616dce513Schristos}
60716dce513Schristos
608*e992f068Schristosstatic bool
60916dce513Schristosfind_major_in_slot (FRV_VLIW *vliw,
61016dce513Schristos		    CGEN_ATTR_VALUE_ENUM_TYPE major,
61116dce513Schristos		    CGEN_ATTR_VALUE_ENUM_TYPE slot)
61216dce513Schristos{
61316dce513Schristos  int i;
61416dce513Schristos
61516dce513Schristos  for (i = 0; i < vliw->next_slot; ++i)
61616dce513Schristos    if (vliw->major[i] == major && (*vliw->current_vliw)[i] == slot)
617*e992f068Schristos      return true;
61816dce513Schristos
619*e992f068Schristos  return false;
62016dce513Schristos}
62116dce513Schristos
622*e992f068Schristosstatic bool
62316dce513Schristosfr550_find_media_in_vliw (FRV_VLIW *vliw)
62416dce513Schristos{
62516dce513Schristos  int i;
62616dce513Schristos
62716dce513Schristos  for (i = 0; i < vliw->next_slot; ++i)
62816dce513Schristos    {
62916dce513Schristos      if (vliw->major[i] < FR550_MAJOR_M_1 || vliw->major[i] > FR550_MAJOR_M_5)
63016dce513Schristos	continue;
63116dce513Schristos
63216dce513Schristos      /* Found a media insn, however, MNOP and MCLRACC don't count.  */
63316dce513Schristos      if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MNOP
63416dce513Schristos	  || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_0
63516dce513Schristos	  || CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_MCLRACC_1)
63616dce513Schristos	continue;
63716dce513Schristos
638*e992f068Schristos      return true; /* Found one.  */
63916dce513Schristos    }
64016dce513Schristos
641*e992f068Schristos  return false;
64216dce513Schristos}
64316dce513Schristos
644*e992f068Schristosstatic bool
64516dce513Schristosfr550_find_float_in_vliw (FRV_VLIW *vliw)
64616dce513Schristos{
64716dce513Schristos  int i;
64816dce513Schristos
64916dce513Schristos  for (i = 0; i < vliw->next_slot; ++i)
65016dce513Schristos    {
65116dce513Schristos      if (vliw->major[i] < FR550_MAJOR_F_1 || vliw->major[i] > FR550_MAJOR_F_4)
65216dce513Schristos	continue;
65316dce513Schristos
65416dce513Schristos      /* Found a floating point insn, however, FNOP doesn't count.  */
65516dce513Schristos      if (CGEN_INSN_NUM (vliw->insn[i]) == FRV_INSN_FNOP)
65616dce513Schristos	continue;
65716dce513Schristos
658*e992f068Schristos      return true; /* Found one.  */
65916dce513Schristos    }
66016dce513Schristos
661*e992f068Schristos  return false;
66216dce513Schristos}
66316dce513Schristos
664*e992f068Schristosstatic bool
66516dce513Schristosfr550_check_insn_major_constraints (FRV_VLIW *vliw,
66616dce513Schristos				    CGEN_ATTR_VALUE_ENUM_TYPE major,
66716dce513Schristos				    const CGEN_INSN *insn)
66816dce513Schristos{
66916dce513Schristos  CGEN_ATTR_VALUE_ENUM_TYPE unit;
67016dce513Schristos  CGEN_ATTR_VALUE_ENUM_TYPE slot = (*vliw->current_vliw)[vliw->next_slot];
67116dce513Schristos  switch (slot)
67216dce513Schristos    {
67316dce513Schristos    case UNIT_I2:
67416dce513Schristos      /* If it's a store, then there must be another store in I1 */
67516dce513Schristos      unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
67616dce513Schristos      if (unit == UNIT_STORE)
67716dce513Schristos	return find_unit_in_vliw (vliw, UNIT_STORE);
67816dce513Schristos      break;
67916dce513Schristos    case UNIT_FM2:
68016dce513Schristos    case UNIT_FM3:
68116dce513Schristos      /* Floating point insns other than FNOP in slot f2 or f3 cannot coexist
68216dce513Schristos	 with media insns.  */
68316dce513Schristos      if (major >= FR550_MAJOR_F_1 && major <= FR550_MAJOR_F_4
68416dce513Schristos	  && CGEN_INSN_NUM (insn) != FRV_INSN_FNOP)
68516dce513Schristos	return ! fr550_find_media_in_vliw (vliw);
68616dce513Schristos      /* Media insns other than MNOP in slot m2 or m3 cannot coexist with
68716dce513Schristos	 floating point insns.  */
68816dce513Schristos      if (major >= FR550_MAJOR_M_1 && major <= FR550_MAJOR_M_5
68916dce513Schristos	  && CGEN_INSN_NUM (insn) != FRV_INSN_MNOP)
69016dce513Schristos	return ! fr550_find_float_in_vliw (vliw);
69116dce513Schristos      /* F-2 in slot f2 or f3 cannot coexist with F-2 or F-4 in slot f1 or f2
69216dce513Schristos	 respectively.  */
69316dce513Schristos      if (major == FR550_MAJOR_F_2)
69416dce513Schristos	return ! find_major_in_slot (vliw, FR550_MAJOR_F_2,
69516dce513Schristos				     slot - (UNIT_FM2 - UNIT_FM0))
69616dce513Schristos	  &&   ! find_major_in_slot (vliw, FR550_MAJOR_F_4,
69716dce513Schristos				     slot - (UNIT_FM2 - UNIT_FM0));
69816dce513Schristos      /* M-2 or M-5 in slot m2 or m3 cannot coexist with M-2 in slot m1 or m2
69916dce513Schristos	 respectively.  */
70016dce513Schristos      if (major == FR550_MAJOR_M_2 || major == FR550_MAJOR_M_5)
70116dce513Schristos	return ! find_major_in_slot (vliw, FR550_MAJOR_M_2,
70216dce513Schristos				     slot - (UNIT_FM2 - UNIT_FM0));
70316dce513Schristos      /* M-4 in slot m2 or m3 cannot coexist with M-4 in slot m1 or m2
70416dce513Schristos	 respectively.  */
70516dce513Schristos      if (major == FR550_MAJOR_M_4)
70616dce513Schristos	return ! find_major_in_slot (vliw, FR550_MAJOR_M_4,
70716dce513Schristos				     slot - (UNIT_FM2 - UNIT_FM0));
70816dce513Schristos      break;
70916dce513Schristos    default:
71016dce513Schristos      break;
71116dce513Schristos    }
712*e992f068Schristos  return true; /* All OK.  */
71316dce513Schristos}
71416dce513Schristos
715*e992f068Schristosstatic bool
71616dce513Schristosfr500_check_insn_major_constraints (FRV_VLIW *vliw, CGEN_ATTR_VALUE_ENUM_TYPE major)
71716dce513Schristos{
71816dce513Schristos  /* TODO: A table might be faster for some of the more complex instances
71916dce513Schristos     here.  */
72016dce513Schristos  switch (major)
72116dce513Schristos    {
72216dce513Schristos    case FR500_MAJOR_I_1:
72316dce513Schristos    case FR500_MAJOR_I_4:
72416dce513Schristos    case FR500_MAJOR_I_5:
72516dce513Schristos    case FR500_MAJOR_I_6:
72616dce513Schristos    case FR500_MAJOR_B_1:
72716dce513Schristos    case FR500_MAJOR_B_2:
72816dce513Schristos    case FR500_MAJOR_B_3:
72916dce513Schristos    case FR500_MAJOR_B_4:
73016dce513Schristos    case FR500_MAJOR_B_5:
73116dce513Schristos    case FR500_MAJOR_B_6:
73216dce513Schristos    case FR500_MAJOR_F_4:
73316dce513Schristos    case FR500_MAJOR_F_8:
73416dce513Schristos    case FR500_MAJOR_M_8:
735*e992f068Schristos      return true; /* OK */
73616dce513Schristos    case FR500_MAJOR_I_2:
73716dce513Schristos      /* Cannot coexist with I-3 insn.  */
73816dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_I_3);
73916dce513Schristos    case FR500_MAJOR_I_3:
74016dce513Schristos      /* Cannot coexist with I-2 insn.  */
74116dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_I_2);
74216dce513Schristos    case FR500_MAJOR_F_1:
74316dce513Schristos    case FR500_MAJOR_F_2:
74416dce513Schristos      /* Cannot coexist with F-5, F-6, or M-7 insn.  */
74516dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
74616dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
74716dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
74816dce513Schristos    case FR500_MAJOR_F_3:
74916dce513Schristos      /* Cannot coexist with F-7, or M-7 insn.  */
75016dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
75116dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
75216dce513Schristos    case FR500_MAJOR_F_5:
75316dce513Schristos      /* Cannot coexist with F-1, F-2, F-6, F-7, or M-7 insn.  */
75416dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
75516dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
75616dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
75716dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
75816dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
75916dce513Schristos    case FR500_MAJOR_F_6:
76016dce513Schristos      /* Cannot coexist with F-1, F-2, F-5, F-6, or M-7 insn.  */
76116dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
76216dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
76316dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
76416dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
76516dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
76616dce513Schristos    case FR500_MAJOR_F_7:
76716dce513Schristos      /* Cannot coexist with F-3, F-5, F-7, or M-7 insn.  */
76816dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
76916dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
77016dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7)
77116dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
77216dce513Schristos    case FR500_MAJOR_M_1:
77316dce513Schristos      /* Cannot coexist with M-7 insn.  */
77416dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
77516dce513Schristos    case FR500_MAJOR_M_2:
77616dce513Schristos    case FR500_MAJOR_M_3:
77716dce513Schristos      /* Cannot coexist with M-5, M-6 or M-7 insn.  */
77816dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
77916dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
78016dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
78116dce513Schristos    case FR500_MAJOR_M_4:
78216dce513Schristos      /* Cannot coexist with M-6 insn.  */
78316dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_6);
78416dce513Schristos    case FR500_MAJOR_M_5:
78516dce513Schristos      /* Cannot coexist with M-2, M-3, M-5, M-6  or M-7 insn.  */
78616dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
78716dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
78816dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
78916dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
79016dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
79116dce513Schristos    case FR500_MAJOR_M_6:
79216dce513Schristos      /* Cannot coexist with M-2, M-3, M-4, M-5, M-6  or M-7 insn.  */
79316dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
79416dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
79516dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_4)
79616dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
79716dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
79816dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7);
79916dce513Schristos    case FR500_MAJOR_M_7:
80016dce513Schristos      /* Cannot coexist with M-1, M-2, M-3, M-5, M-6  or M-7 insn.  */
80116dce513Schristos      return ! find_major_in_vliw (vliw, FR500_MAJOR_M_1)
80216dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_2)
80316dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_3)
80416dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_5)
80516dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_6)
80616dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_M_7)
80716dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_1)
80816dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_2)
80916dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_3)
81016dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_5)
81116dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_6)
81216dce513Schristos	&&   ! find_major_in_vliw (vliw, FR500_MAJOR_F_7);
81316dce513Schristos    default:
814ede78133Schristos      /* xgettext:c-format */
815ede78133Schristos      opcodes_error_handler (_("internal error: bad major code"));
81616dce513Schristos      abort ();
81716dce513Schristos      break;
81816dce513Schristos    }
819*e992f068Schristos  return true;
82016dce513Schristos}
82116dce513Schristos
822*e992f068Schristosstatic bool
82316dce513Schristoscheck_insn_major_constraints (FRV_VLIW *vliw,
82416dce513Schristos			      CGEN_ATTR_VALUE_ENUM_TYPE major,
82516dce513Schristos			      const CGEN_INSN *insn)
82616dce513Schristos{
82716dce513Schristos  switch (vliw->mach)
82816dce513Schristos    {
82916dce513Schristos    case bfd_mach_fr400:
83016dce513Schristos      return fr400_check_insn_major_constraints (vliw, major);
83116dce513Schristos
83216dce513Schristos    case bfd_mach_fr450:
83316dce513Schristos      return fr450_check_insn_major_constraints (vliw, major);
83416dce513Schristos
83516dce513Schristos    case bfd_mach_fr550:
83616dce513Schristos      return fr550_check_insn_major_constraints (vliw, major, insn);
83716dce513Schristos
83816dce513Schristos    default:
83916dce513Schristos      return fr500_check_insn_major_constraints (vliw, major);
84016dce513Schristos    }
84116dce513Schristos}
84216dce513Schristos
84316dce513Schristos/* Add in insn to the VLIW vliw if possible.
84416dce513Schristos   Return 0 if successful, non-zero otherwise.  */
84516dce513Schristos
84616dce513Schristosint
84716dce513Schristosfrv_vliw_add_insn (FRV_VLIW *vliw, const CGEN_INSN *insn)
84816dce513Schristos{
84916dce513Schristos  int slot_index;
85016dce513Schristos  CGEN_ATTR_VALUE_ENUM_TYPE major;
85116dce513Schristos  CGEN_ATTR_VALUE_ENUM_TYPE unit;
85216dce513Schristos  VLIW_COMBO *new_vliw;
85316dce513Schristos
85416dce513Schristos  if (vliw->constraint_violation || CGEN_INSN_INVALID_P (insn))
85516dce513Schristos    return 1;
85616dce513Schristos
85716dce513Schristos  slot_index = vliw->next_slot;
85816dce513Schristos  if (slot_index >= FRV_VLIW_SIZE)
85916dce513Schristos    return 1;
86016dce513Schristos
86116dce513Schristos  unit = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_UNIT);
86216dce513Schristos  if (unit == UNIT_NIL)
86316dce513Schristos    {
864ede78133Schristos      /* xgettext:c-format */
865ede78133Schristos      opcodes_error_handler (_("internal error: bad insn unit"));
866ede78133Schristos      abort ();
86716dce513Schristos    }
86816dce513Schristos
86916dce513Schristos  switch (vliw->mach)
87016dce513Schristos    {
87116dce513Schristos    case bfd_mach_fr400:
87216dce513Schristos      major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR400_MAJOR);
87316dce513Schristos      break;
87416dce513Schristos    case bfd_mach_fr450:
87516dce513Schristos      major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR450_MAJOR);
87616dce513Schristos      break;
87716dce513Schristos    case bfd_mach_fr550:
87816dce513Schristos      major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR550_MAJOR);
87916dce513Schristos      break;
88016dce513Schristos    default:
88116dce513Schristos      major = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR500_MAJOR);
88216dce513Schristos      break;
88316dce513Schristos    }
88416dce513Schristos
88516dce513Schristos  if (slot_index <= 0)
88616dce513Schristos    {
88716dce513Schristos      /* Any insn can be added to slot 0.  */
88816dce513Schristos      while (! match_unit (vliw, unit, (*vliw->current_vliw)[0]))
88916dce513Schristos	++vliw->current_vliw;
89016dce513Schristos      vliw->major[0] = major;
89116dce513Schristos      vliw->insn[0] = insn;
89216dce513Schristos      vliw->next_slot = 1;
89316dce513Schristos      return 0;
89416dce513Schristos    }
89516dce513Schristos
89616dce513Schristos  /* If there are already insns in the vliw(s) check to see that
89716dce513Schristos     this one can be added.  Do this by finding an allowable vliw
89816dce513Schristos     combination that can accept the new insn.  */
89916dce513Schristos  if (! (vliw->elf_flags & EF_FRV_NOPACK))
90016dce513Schristos    {
90116dce513Schristos      new_vliw = add_next_to_vliw (vliw, unit);
90216dce513Schristos      if (new_vliw && check_insn_major_constraints (vliw, major, insn))
90316dce513Schristos	{
90416dce513Schristos	  vliw->current_vliw = new_vliw;
90516dce513Schristos	  vliw->major[slot_index] = major;
90616dce513Schristos	  vliw->insn[slot_index] = insn;
90716dce513Schristos	  vliw->next_slot++;
90816dce513Schristos	  return 0;
90916dce513Schristos	}
91016dce513Schristos
91116dce513Schristos      /* The frv machine supports all packing conbinations.  If we fail,
91216dce513Schristos	 to add the insn, then it could not be handled as if it was the fr500.
91316dce513Schristos	 Just return as if it was handled ok.  */
91416dce513Schristos      if (vliw->mach == bfd_mach_frv)
91516dce513Schristos	return 0;
91616dce513Schristos    }
91716dce513Schristos
91816dce513Schristos  vliw->constraint_violation = 1;
91916dce513Schristos  return 1;
92016dce513Schristos}
92116dce513Schristos
922*e992f068Schristosbool
92316dce513Schristosspr_valid (long regno)
92416dce513Schristos{
925*e992f068Schristos  if (regno < 0)     return false;
926*e992f068Schristos  if (regno <= 4095) return true;
927*e992f068Schristos  return false;
92816dce513Schristos}
92916dce513Schristos/* -- */
93016dce513Schristos
93116dce513Schristos/* -- asm.c */
93216dce513Schristosinline static const char *
93316dce513Schristosparse_symbolic_address (CGEN_CPU_DESC cd,
93416dce513Schristos			const char **strp,
93516dce513Schristos			int opindex,
93616dce513Schristos			int opinfo,
93716dce513Schristos			enum cgen_parse_operand_result *resultp,
93816dce513Schristos			bfd_vma *valuep)
93916dce513Schristos{
94016dce513Schristos  enum cgen_parse_operand_result result_type;
94116dce513Schristos  const char *errmsg = (* cd->parse_operand_fn)
94216dce513Schristos    (cd, CGEN_PARSE_OPERAND_SYMBOLIC, strp, opindex, opinfo,
94316dce513Schristos     &result_type, valuep);
94416dce513Schristos
94516dce513Schristos  if (errmsg == NULL
94616dce513Schristos      && result_type != CGEN_PARSE_OPERAND_RESULT_QUEUED)
94716dce513Schristos    return "symbolic expression required";
94816dce513Schristos
94916dce513Schristos  if (resultp)
95016dce513Schristos    *resultp = result_type;
95116dce513Schristos
95216dce513Schristos  return errmsg;
95316dce513Schristos}
95416dce513Schristos
95516dce513Schristosstatic const char *
95616dce513Schristosparse_ldd_annotation (CGEN_CPU_DESC cd,
95716dce513Schristos		      const char **strp,
95816dce513Schristos		      int opindex,
95916dce513Schristos		      unsigned long *valuep)
96016dce513Schristos{
96116dce513Schristos  const char *errmsg;
96216dce513Schristos  enum cgen_parse_operand_result result_type;
96316dce513Schristos  bfd_vma value;
96416dce513Schristos
96516dce513Schristos  if (**strp == '#' || **strp == '%')
96616dce513Schristos    {
96716dce513Schristos      if (strncasecmp (*strp + 1, "tlsdesc(", 8) == 0)
96816dce513Schristos	{
96916dce513Schristos	  *strp += 9;
97016dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
97116dce513Schristos					   BFD_RELOC_FRV_TLSDESC_RELAX,
97216dce513Schristos					   &result_type, &value);
97316dce513Schristos	  if (**strp != ')')
97416dce513Schristos	    return "missing ')'";
97516dce513Schristos	  if (valuep)
97616dce513Schristos	    *valuep = value;
97716dce513Schristos	  ++*strp;
97816dce513Schristos	  if (errmsg)
97916dce513Schristos	    return errmsg;
98016dce513Schristos	}
98116dce513Schristos    }
98216dce513Schristos
98316dce513Schristos  while (**strp == ' ' || **strp == '\t')
98416dce513Schristos    ++*strp;
98516dce513Schristos
98616dce513Schristos  if (**strp != '@')
98716dce513Schristos    return "missing `@'";
98816dce513Schristos
98916dce513Schristos  ++*strp;
99016dce513Schristos
99116dce513Schristos  return NULL;
99216dce513Schristos}
99316dce513Schristos
99416dce513Schristosstatic const char *
99516dce513Schristosparse_call_annotation (CGEN_CPU_DESC cd,
99616dce513Schristos		       const char **strp,
99716dce513Schristos		       int opindex,
99816dce513Schristos		       unsigned long *valuep)
99916dce513Schristos{
100016dce513Schristos  const char *errmsg;
100116dce513Schristos  enum cgen_parse_operand_result result_type;
100216dce513Schristos  bfd_vma value;
100316dce513Schristos
100416dce513Schristos  if (**strp == '#' || **strp == '%')
100516dce513Schristos    {
100616dce513Schristos      if (strncasecmp (*strp + 1, "gettlsoff(", 10) == 0)
100716dce513Schristos	{
100816dce513Schristos	  *strp += 11;
100916dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
101016dce513Schristos					   BFD_RELOC_FRV_GETTLSOFF_RELAX,
101116dce513Schristos					   &result_type, &value);
101216dce513Schristos	  if (**strp != ')')
101316dce513Schristos	    return "missing ')'";
101416dce513Schristos	  if (valuep)
101516dce513Schristos	    *valuep = value;
101616dce513Schristos	  ++*strp;
101716dce513Schristos	  if (errmsg)
101816dce513Schristos	    return errmsg;
101916dce513Schristos	}
102016dce513Schristos    }
102116dce513Schristos
102216dce513Schristos  while (**strp == ' ' || **strp == '\t')
102316dce513Schristos    ++*strp;
102416dce513Schristos
102516dce513Schristos  if (**strp != '@')
102616dce513Schristos    return "missing `@'";
102716dce513Schristos
102816dce513Schristos  ++*strp;
102916dce513Schristos
103016dce513Schristos  return NULL;
103116dce513Schristos}
103216dce513Schristos
103316dce513Schristosstatic const char *
103416dce513Schristosparse_ld_annotation (CGEN_CPU_DESC cd,
103516dce513Schristos		     const char **strp,
103616dce513Schristos		     int opindex,
103716dce513Schristos		     unsigned long *valuep)
103816dce513Schristos{
103916dce513Schristos  const char *errmsg;
104016dce513Schristos  enum cgen_parse_operand_result result_type;
104116dce513Schristos  bfd_vma value;
104216dce513Schristos
104316dce513Schristos  if (**strp == '#' || **strp == '%')
104416dce513Schristos    {
104516dce513Schristos      if (strncasecmp (*strp + 1, "tlsoff(", 7) == 0)
104616dce513Schristos	{
104716dce513Schristos	  *strp += 8;
104816dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
104916dce513Schristos					   BFD_RELOC_FRV_TLSOFF_RELAX,
105016dce513Schristos					   &result_type, &value);
105116dce513Schristos	  if (**strp != ')')
105216dce513Schristos	    return "missing ')'";
105316dce513Schristos	  if (valuep)
105416dce513Schristos	    *valuep = value;
105516dce513Schristos	  ++*strp;
105616dce513Schristos	  if (errmsg)
105716dce513Schristos	    return errmsg;
105816dce513Schristos	}
105916dce513Schristos    }
106016dce513Schristos
106116dce513Schristos  while (**strp == ' ' || **strp == '\t')
106216dce513Schristos    ++*strp;
106316dce513Schristos
106416dce513Schristos  if (**strp != '@')
106516dce513Schristos    return "missing `@'";
106616dce513Schristos
106716dce513Schristos  ++*strp;
106816dce513Schristos
106916dce513Schristos  return NULL;
107016dce513Schristos}
107116dce513Schristos
107216dce513Schristosstatic const char *
107316dce513Schristosparse_ulo16 (CGEN_CPU_DESC cd,
107416dce513Schristos	     const char **strp,
107516dce513Schristos	     int opindex,
107616dce513Schristos	     unsigned long *valuep)
107716dce513Schristos{
107816dce513Schristos  const char *errmsg;
107916dce513Schristos  enum cgen_parse_operand_result result_type;
108016dce513Schristos  bfd_vma value;
108116dce513Schristos
108216dce513Schristos  if (**strp == '#' || **strp == '%')
108316dce513Schristos    {
108416dce513Schristos      if (strncasecmp (*strp + 1, "lo(", 3) == 0)
108516dce513Schristos	{
108616dce513Schristos	  *strp += 4;
108716dce513Schristos	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
108816dce513Schristos				       & result_type, & value);
108916dce513Schristos	  if (**strp != ')')
109016dce513Schristos	    return "missing `)'";
109116dce513Schristos	  ++*strp;
109216dce513Schristos	  if (errmsg == NULL
109316dce513Schristos	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
109416dce513Schristos	    value &= 0xffff;
109516dce513Schristos	  *valuep = value;
109616dce513Schristos	  return errmsg;
109716dce513Schristos	}
109816dce513Schristos      if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
109916dce513Schristos	{
110016dce513Schristos	  *strp += 9;
110116dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
110216dce513Schristos					   BFD_RELOC_FRV_GPRELLO,
110316dce513Schristos					   & result_type, & value);
110416dce513Schristos	  if (**strp != ')')
110516dce513Schristos	    return "missing ')'";
110616dce513Schristos	  ++*strp;
110716dce513Schristos	  *valuep = value;
110816dce513Schristos	  return errmsg;
110916dce513Schristos	}
111016dce513Schristos      else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
111116dce513Schristos	{
111216dce513Schristos	  *strp += 7;
111316dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
111416dce513Schristos					   BFD_RELOC_FRV_GOTLO,
111516dce513Schristos					   & result_type, & value);
111616dce513Schristos	  if (**strp != ')')
111716dce513Schristos	    return "missing ')'";
111816dce513Schristos	  ++*strp;
111916dce513Schristos	  *valuep = value;
112016dce513Schristos	  return errmsg;
112116dce513Schristos	}
112216dce513Schristos      else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
112316dce513Schristos	{
112416dce513Schristos	  *strp += 15;
112516dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
112616dce513Schristos					   BFD_RELOC_FRV_FUNCDESC_GOTLO,
112716dce513Schristos					   & result_type, & value);
112816dce513Schristos	  if (**strp != ')')
112916dce513Schristos	    return "missing ')'";
113016dce513Schristos	  ++*strp;
113116dce513Schristos	  *valuep = value;
113216dce513Schristos	  return errmsg;
113316dce513Schristos	}
113416dce513Schristos      else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
113516dce513Schristos	{
113616dce513Schristos	  *strp += 10;
113716dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
113816dce513Schristos					   BFD_RELOC_FRV_GOTOFFLO,
113916dce513Schristos					   & result_type, & value);
114016dce513Schristos	  if (**strp != ')')
114116dce513Schristos	    return "missing ')'";
114216dce513Schristos	  ++*strp;
114316dce513Schristos	  *valuep = value;
114416dce513Schristos	  return errmsg;
114516dce513Schristos	}
114616dce513Schristos      else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
114716dce513Schristos	{
114816dce513Schristos	  *strp += 18;
114916dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
115016dce513Schristos					   BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
115116dce513Schristos					   & result_type, & value);
115216dce513Schristos	  if (**strp != ')')
115316dce513Schristos	    return "missing ')'";
115416dce513Schristos	  ++*strp;
115516dce513Schristos	  *valuep = value;
115616dce513Schristos	  return errmsg;
115716dce513Schristos	}
115816dce513Schristos      else if (strncasecmp (*strp + 1, "gottlsdesclo(", 13) == 0)
115916dce513Schristos	{
116016dce513Schristos	  *strp += 14;
116116dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
116216dce513Schristos					   BFD_RELOC_FRV_GOTTLSDESCLO,
116316dce513Schristos					   & result_type, & value);
116416dce513Schristos	  if (**strp != ')')
116516dce513Schristos	    return "missing ')'";
116616dce513Schristos	  ++*strp;
116716dce513Schristos	  *valuep = value;
116816dce513Schristos	  return errmsg;
116916dce513Schristos	}
117016dce513Schristos      else if (strncasecmp (*strp + 1, "tlsmofflo(", 10) == 0)
117116dce513Schristos	{
117216dce513Schristos	  *strp += 11;
117316dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
117416dce513Schristos					   BFD_RELOC_FRV_TLSMOFFLO,
117516dce513Schristos					   & result_type, & value);
117616dce513Schristos	  if (**strp != ')')
117716dce513Schristos	    return "missing ')'";
117816dce513Schristos	  ++*strp;
117916dce513Schristos	  *valuep = value;
118016dce513Schristos	  return errmsg;
118116dce513Schristos	}
118216dce513Schristos      else if (strncasecmp (*strp + 1, "gottlsofflo(", 12) == 0)
118316dce513Schristos	{
118416dce513Schristos	  *strp += 13;
118516dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
118616dce513Schristos					   BFD_RELOC_FRV_GOTTLSOFFLO,
118716dce513Schristos					   & result_type, & value);
118816dce513Schristos	  if (**strp != ')')
118916dce513Schristos	    return "missing ')'";
119016dce513Schristos	  ++*strp;
119116dce513Schristos	  *valuep = value;
119216dce513Schristos	  return errmsg;
119316dce513Schristos	}
119416dce513Schristos    }
119516dce513Schristos  return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
119616dce513Schristos}
119716dce513Schristos
119816dce513Schristosstatic const char *
119916dce513Schristosparse_uslo16 (CGEN_CPU_DESC cd,
120016dce513Schristos	      const char **strp,
120116dce513Schristos	      int opindex,
120216dce513Schristos	      signed long *valuep)
120316dce513Schristos{
120416dce513Schristos  const char *errmsg;
120516dce513Schristos  enum cgen_parse_operand_result result_type;
120616dce513Schristos  bfd_vma value;
120716dce513Schristos
120816dce513Schristos  if (**strp == '#' || **strp == '%')
120916dce513Schristos    {
121016dce513Schristos      if (strncasecmp (*strp + 1, "lo(", 3) == 0)
121116dce513Schristos	{
121216dce513Schristos	  *strp += 4;
121316dce513Schristos	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_LO16,
121416dce513Schristos				       & result_type, & value);
121516dce513Schristos	  if (**strp != ')')
121616dce513Schristos	    return "missing `)'";
121716dce513Schristos	  ++*strp;
121816dce513Schristos	  if (errmsg == NULL
121916dce513Schristos	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
122016dce513Schristos	    value &= 0xffff;
122116dce513Schristos	  *valuep = value;
122216dce513Schristos	  return errmsg;
122316dce513Schristos	}
122416dce513Schristos      else if (strncasecmp (*strp + 1, "gprello(", 8) == 0)
122516dce513Schristos	{
122616dce513Schristos	  *strp += 9;
122716dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
122816dce513Schristos					   BFD_RELOC_FRV_GPRELLO,
122916dce513Schristos					   & result_type, & value);
123016dce513Schristos	  if (**strp != ')')
123116dce513Schristos	    return "missing ')'";
123216dce513Schristos	  ++*strp;
123316dce513Schristos	  *valuep = value;
123416dce513Schristos	  return errmsg;
123516dce513Schristos	}
123616dce513Schristos      else if (strncasecmp (*strp + 1, "gotlo(", 6) == 0)
123716dce513Schristos	{
123816dce513Schristos	  *strp += 7;
123916dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
124016dce513Schristos					   BFD_RELOC_FRV_GOTLO,
124116dce513Schristos					   & result_type, & value);
124216dce513Schristos	  if (**strp != ')')
124316dce513Schristos	    return "missing ')'";
124416dce513Schristos	  ++*strp;
124516dce513Schristos	  *valuep = value;
124616dce513Schristos	  return errmsg;
124716dce513Schristos	}
124816dce513Schristos      else if (strncasecmp (*strp + 1, "gotfuncdesclo(", 14) == 0)
124916dce513Schristos	{
125016dce513Schristos	  *strp += 15;
125116dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
125216dce513Schristos					   BFD_RELOC_FRV_FUNCDESC_GOTLO,
125316dce513Schristos					   & result_type, & value);
125416dce513Schristos	  if (**strp != ')')
125516dce513Schristos	    return "missing ')'";
125616dce513Schristos	  ++*strp;
125716dce513Schristos	  *valuep = value;
125816dce513Schristos	  return errmsg;
125916dce513Schristos	}
126016dce513Schristos      else if (strncasecmp (*strp + 1, "gotofflo(", 9) == 0)
126116dce513Schristos	{
126216dce513Schristos	  *strp += 10;
126316dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
126416dce513Schristos					   BFD_RELOC_FRV_GOTOFFLO,
126516dce513Schristos					   & result_type, & value);
126616dce513Schristos	  if (**strp != ')')
126716dce513Schristos	    return "missing ')'";
126816dce513Schristos	  ++*strp;
126916dce513Schristos	  *valuep = value;
127016dce513Schristos	  return errmsg;
127116dce513Schristos	}
127216dce513Schristos      else if (strncasecmp (*strp + 1, "gotofffuncdesclo(", 17) == 0)
127316dce513Schristos	{
127416dce513Schristos	  *strp += 18;
127516dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
127616dce513Schristos					   BFD_RELOC_FRV_FUNCDESC_GOTOFFLO,
127716dce513Schristos					   & result_type, & value);
127816dce513Schristos	  if (**strp != ')')
127916dce513Schristos	    return "missing ')'";
128016dce513Schristos	  ++*strp;
128116dce513Schristos	  *valuep = value;
128216dce513Schristos	  return errmsg;
128316dce513Schristos	}
128416dce513Schristos      else if (strncasecmp (*strp + 1, "gottlsdesclo(", 13) == 0)
128516dce513Schristos	{
128616dce513Schristos	  *strp += 14;
128716dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
128816dce513Schristos					   BFD_RELOC_FRV_GOTTLSDESCLO,
128916dce513Schristos					   & result_type, & value);
129016dce513Schristos	  if (**strp != ')')
129116dce513Schristos	    return "missing ')'";
129216dce513Schristos	  ++*strp;
129316dce513Schristos	  *valuep = value;
129416dce513Schristos	  return errmsg;
129516dce513Schristos	}
129616dce513Schristos      else if (strncasecmp (*strp + 1, "tlsmofflo(", 10) == 0)
129716dce513Schristos	{
129816dce513Schristos	  *strp += 11;
129916dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
130016dce513Schristos					   BFD_RELOC_FRV_TLSMOFFLO,
130116dce513Schristos					   & result_type, & value);
130216dce513Schristos	  if (**strp != ')')
130316dce513Schristos	    return "missing ')'";
130416dce513Schristos	  ++*strp;
130516dce513Schristos	  *valuep = value;
130616dce513Schristos	  return errmsg;
130716dce513Schristos	}
130816dce513Schristos      else if (strncasecmp (*strp + 1, "gottlsofflo(", 12) == 0)
130916dce513Schristos	{
131016dce513Schristos	  *strp += 13;
131116dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
131216dce513Schristos					   BFD_RELOC_FRV_GOTTLSOFFLO,
131316dce513Schristos					   & result_type, & value);
131416dce513Schristos	  if (**strp != ')')
131516dce513Schristos	    return "missing ')'";
131616dce513Schristos	  ++*strp;
131716dce513Schristos	  *valuep = value;
131816dce513Schristos	  return errmsg;
131916dce513Schristos	}
132016dce513Schristos    }
132116dce513Schristos  return cgen_parse_signed_integer (cd, strp, opindex, valuep);
132216dce513Schristos}
132316dce513Schristos
132416dce513Schristosstatic const char *
132516dce513Schristosparse_uhi16 (CGEN_CPU_DESC cd,
132616dce513Schristos	     const char **strp,
132716dce513Schristos	     int opindex,
132816dce513Schristos	     unsigned long *valuep)
132916dce513Schristos{
133016dce513Schristos  const char *errmsg;
133116dce513Schristos  enum cgen_parse_operand_result result_type;
133216dce513Schristos  bfd_vma value;
133316dce513Schristos
133416dce513Schristos  if (**strp == '#' || **strp == '%')
133516dce513Schristos    {
133616dce513Schristos      if (strncasecmp (*strp + 1, "hi(", 3) == 0)
133716dce513Schristos	{
133816dce513Schristos	  *strp += 4;
133916dce513Schristos	  errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_FRV_HI16,
134016dce513Schristos				       & result_type, & value);
134116dce513Schristos	  if (**strp != ')')
134216dce513Schristos	    return "missing `)'";
134316dce513Schristos	  ++*strp;
134416dce513Schristos	  if (errmsg == NULL
134516dce513Schristos	      && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
134616dce513Schristos	    {
134716dce513Schristos 	      /* If value is wider than 32 bits then be
134816dce513Schristos 		 careful about how we extract bits 16-31.  */
134916dce513Schristos 	      if (sizeof (value) > 4)
135016dce513Schristos 		value &= (((bfd_vma)1 << 16) << 16) - 1;
135116dce513Schristos
135216dce513Schristos	      value >>= 16;
135316dce513Schristos	    }
135416dce513Schristos	  *valuep = value;
135516dce513Schristos	  return errmsg;
135616dce513Schristos	}
135716dce513Schristos      else if (strncasecmp (*strp + 1, "gprelhi(", 8) == 0)
135816dce513Schristos	{
135916dce513Schristos	  *strp += 9;
136016dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
136116dce513Schristos					   BFD_RELOC_FRV_GPRELHI,
136216dce513Schristos					   & result_type, & value);
136316dce513Schristos	  if (**strp != ')')
136416dce513Schristos	    return "missing ')'";
136516dce513Schristos	  ++*strp;
136616dce513Schristos	  *valuep = value;
136716dce513Schristos	  return errmsg;
136816dce513Schristos	}
136916dce513Schristos      else if (strncasecmp (*strp + 1, "gothi(", 6) == 0)
137016dce513Schristos	{
137116dce513Schristos	  *strp += 7;
137216dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
137316dce513Schristos					   BFD_RELOC_FRV_GOTHI,
137416dce513Schristos					   & result_type, & value);
137516dce513Schristos	  if (**strp != ')')
137616dce513Schristos	    return "missing ')'";
137716dce513Schristos	  ++*strp;
137816dce513Schristos	  *valuep = value;
137916dce513Schristos	  return errmsg;
138016dce513Schristos	}
138116dce513Schristos      else if (strncasecmp (*strp + 1, "gotfuncdeschi(", 14) == 0)
138216dce513Schristos	{
138316dce513Schristos	  *strp += 15;
138416dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
138516dce513Schristos					   BFD_RELOC_FRV_FUNCDESC_GOTHI,
138616dce513Schristos					   & result_type, & value);
138716dce513Schristos	  if (**strp != ')')
138816dce513Schristos	    return "missing ')'";
138916dce513Schristos	  ++*strp;
139016dce513Schristos	  *valuep = value;
139116dce513Schristos	  return errmsg;
139216dce513Schristos	}
139316dce513Schristos      else if (strncasecmp (*strp + 1, "gotoffhi(", 9) == 0)
139416dce513Schristos	{
139516dce513Schristos	  *strp += 10;
139616dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
139716dce513Schristos					   BFD_RELOC_FRV_GOTOFFHI,
139816dce513Schristos					   & result_type, & value);
139916dce513Schristos	  if (**strp != ')')
140016dce513Schristos	    return "missing ')'";
140116dce513Schristos	  ++*strp;
140216dce513Schristos	  *valuep = value;
140316dce513Schristos	  return errmsg;
140416dce513Schristos	}
140516dce513Schristos      else if (strncasecmp (*strp + 1, "gotofffuncdeschi(", 17) == 0)
140616dce513Schristos	{
140716dce513Schristos	  *strp += 18;
140816dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
140916dce513Schristos					   BFD_RELOC_FRV_FUNCDESC_GOTOFFHI,
141016dce513Schristos					   & result_type, & value);
141116dce513Schristos	  if (**strp != ')')
141216dce513Schristos	    return "missing ')'";
141316dce513Schristos	  ++*strp;
141416dce513Schristos	  *valuep = value;
141516dce513Schristos	  return errmsg;
141616dce513Schristos	}
141716dce513Schristos      else if (strncasecmp (*strp + 1, "gottlsdeschi(", 13) == 0)
141816dce513Schristos	{
141916dce513Schristos	  *strp += 14;
142016dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
142116dce513Schristos					   BFD_RELOC_FRV_GOTTLSDESCHI,
142216dce513Schristos					   &result_type, &value);
142316dce513Schristos	  if (**strp != ')')
142416dce513Schristos	    return "missing ')'";
142516dce513Schristos	  ++*strp;
142616dce513Schristos	  *valuep = value;
142716dce513Schristos	  return errmsg;
142816dce513Schristos	}
142916dce513Schristos      else if (strncasecmp (*strp + 1, "tlsmoffhi(", 10) == 0)
143016dce513Schristos	{
143116dce513Schristos	  *strp += 11;
143216dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
143316dce513Schristos					   BFD_RELOC_FRV_TLSMOFFHI,
143416dce513Schristos					   & result_type, & value);
143516dce513Schristos	  if (**strp != ')')
143616dce513Schristos	    return "missing ')'";
143716dce513Schristos	  ++*strp;
143816dce513Schristos	  *valuep = value;
143916dce513Schristos	  return errmsg;
144016dce513Schristos	}
144116dce513Schristos      else if (strncasecmp (*strp + 1, "gottlsoffhi(", 12) == 0)
144216dce513Schristos	{
144316dce513Schristos	  *strp += 13;
144416dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
144516dce513Schristos					   BFD_RELOC_FRV_GOTTLSOFFHI,
144616dce513Schristos					   & result_type, & value);
144716dce513Schristos	  if (**strp != ')')
144816dce513Schristos	    return "missing ')'";
144916dce513Schristos	  ++*strp;
145016dce513Schristos	  *valuep = value;
145116dce513Schristos	  return errmsg;
145216dce513Schristos	}
145316dce513Schristos    }
145416dce513Schristos  return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
145516dce513Schristos}
145616dce513Schristos
145716dce513Schristosstatic long
145816dce513Schristosparse_register_number (const char **strp)
145916dce513Schristos{
146016dce513Schristos  int regno;
146116dce513Schristos
146216dce513Schristos  if (**strp < '0' || **strp > '9')
146316dce513Schristos    return -1; /* error */
146416dce513Schristos
146516dce513Schristos  regno = **strp - '0';
146616dce513Schristos  for (++*strp; **strp >= '0' && **strp <= '9'; ++*strp)
146716dce513Schristos    regno = regno * 10 + (**strp - '0');
146816dce513Schristos
146916dce513Schristos  return regno;
147016dce513Schristos}
147116dce513Schristos
147216dce513Schristosstatic const char *
147316dce513Schristosparse_spr (CGEN_CPU_DESC cd,
147416dce513Schristos	   const char **strp,
147516dce513Schristos	   CGEN_KEYWORD * table,
147616dce513Schristos	   long *valuep)
147716dce513Schristos{
147816dce513Schristos  const char *save_strp;
147916dce513Schristos  long regno;
148016dce513Schristos
148116dce513Schristos  /* Check for spr index notation.  */
148216dce513Schristos  if (strncasecmp (*strp, "spr[", 4) == 0)
148316dce513Schristos    {
148416dce513Schristos      *strp += 4;
148516dce513Schristos      regno = parse_register_number (strp);
148616dce513Schristos      if (**strp != ']')
148716dce513Schristos        return _("missing `]'");
148816dce513Schristos      ++*strp;
148916dce513Schristos      if (! spr_valid (regno))
149016dce513Schristos	return _("Special purpose register number is out of range");
149116dce513Schristos      *valuep = regno;
149216dce513Schristos      return NULL;
149316dce513Schristos    }
149416dce513Schristos
149516dce513Schristos  save_strp = *strp;
149616dce513Schristos  regno = parse_register_number (strp);
149716dce513Schristos  if (regno != -1)
149816dce513Schristos    {
149916dce513Schristos      if (! spr_valid (regno))
150016dce513Schristos	return _("Special purpose register number is out of range");
150116dce513Schristos      *valuep = regno;
150216dce513Schristos      return NULL;
150316dce513Schristos    }
150416dce513Schristos
150516dce513Schristos  *strp = save_strp;
150616dce513Schristos  return cgen_parse_keyword (cd, strp, table, valuep);
150716dce513Schristos}
150816dce513Schristos
150916dce513Schristosstatic const char *
151016dce513Schristosparse_d12 (CGEN_CPU_DESC cd,
151116dce513Schristos	   const char **strp,
151216dce513Schristos	   int opindex,
151316dce513Schristos	   long *valuep)
151416dce513Schristos{
151516dce513Schristos  const char *errmsg;
151616dce513Schristos  enum cgen_parse_operand_result result_type;
151716dce513Schristos  bfd_vma value;
151816dce513Schristos
151916dce513Schristos  /* Check for small data reference.  */
152016dce513Schristos  if (**strp == '#' || **strp == '%')
152116dce513Schristos    {
152216dce513Schristos      if (strncasecmp (*strp + 1, "gprel12(", 8) == 0)
152316dce513Schristos        {
152416dce513Schristos          *strp += 9;
152516dce513Schristos          errmsg = parse_symbolic_address (cd, strp, opindex,
152616dce513Schristos					   BFD_RELOC_FRV_GPREL12,
152716dce513Schristos					   & result_type, & value);
152816dce513Schristos          if (**strp != ')')
152916dce513Schristos            return "missing `)'";
153016dce513Schristos          ++*strp;
153116dce513Schristos          *valuep = value;
153216dce513Schristos          return errmsg;
153316dce513Schristos        }
153416dce513Schristos      else if (strncasecmp (*strp + 1, "got12(", 6) == 0)
153516dce513Schristos	{
153616dce513Schristos	  *strp += 7;
153716dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
153816dce513Schristos					   BFD_RELOC_FRV_GOT12,
153916dce513Schristos					   & result_type, & value);
154016dce513Schristos	  if (**strp != ')')
154116dce513Schristos	    return "missing ')'";
154216dce513Schristos	  ++*strp;
154316dce513Schristos	  *valuep = value;
154416dce513Schristos	  return errmsg;
154516dce513Schristos	}
154616dce513Schristos      else if (strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
154716dce513Schristos	{
154816dce513Schristos	  *strp += 15;
154916dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
155016dce513Schristos					   BFD_RELOC_FRV_FUNCDESC_GOT12,
155116dce513Schristos					   & result_type, & value);
155216dce513Schristos	  if (**strp != ')')
155316dce513Schristos	    return "missing ')'";
155416dce513Schristos	  ++*strp;
155516dce513Schristos	  *valuep = value;
155616dce513Schristos	  return errmsg;
155716dce513Schristos	}
155816dce513Schristos      else if (strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
155916dce513Schristos	{
156016dce513Schristos	  *strp += 10;
156116dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
156216dce513Schristos					   BFD_RELOC_FRV_GOTOFF12,
156316dce513Schristos					   & result_type, & value);
156416dce513Schristos	  if (**strp != ')')
156516dce513Schristos	    return "missing ')'";
156616dce513Schristos	  ++*strp;
156716dce513Schristos	  *valuep = value;
156816dce513Schristos	  return errmsg;
156916dce513Schristos	}
157016dce513Schristos      else if (strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
157116dce513Schristos	{
157216dce513Schristos	  *strp += 18;
157316dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
157416dce513Schristos					   BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
157516dce513Schristos					   & result_type, & value);
157616dce513Schristos	  if (**strp != ')')
157716dce513Schristos	    return "missing ')'";
157816dce513Schristos	  ++*strp;
157916dce513Schristos	  *valuep = value;
158016dce513Schristos	  return errmsg;
158116dce513Schristos	}
158216dce513Schristos      else if (strncasecmp (*strp + 1, "gottlsdesc12(", 13) == 0)
158316dce513Schristos	{
158416dce513Schristos	  *strp += 14;
158516dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
158616dce513Schristos					   BFD_RELOC_FRV_GOTTLSDESC12,
158716dce513Schristos					   & result_type, & value);
158816dce513Schristos	  if (**strp != ')')
158916dce513Schristos	    return "missing ')'";
159016dce513Schristos	  ++*strp;
159116dce513Schristos	  *valuep = value;
159216dce513Schristos	  return errmsg;
159316dce513Schristos	}
159416dce513Schristos      else if (strncasecmp (*strp + 1, "tlsmoff12(", 10) == 0)
159516dce513Schristos	{
159616dce513Schristos	  *strp += 11;
159716dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
159816dce513Schristos					   BFD_RELOC_FRV_TLSMOFF12,
159916dce513Schristos					   & result_type, & value);
160016dce513Schristos	  if (**strp != ')')
160116dce513Schristos	    return "missing ')'";
160216dce513Schristos	  ++*strp;
160316dce513Schristos	  *valuep = value;
160416dce513Schristos	  return errmsg;
160516dce513Schristos	}
160616dce513Schristos      else if (strncasecmp (*strp + 1, "gottlsoff12(", 12) == 0)
160716dce513Schristos	{
160816dce513Schristos	  *strp += 13;
160916dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
161016dce513Schristos					   BFD_RELOC_FRV_GOTTLSOFF12,
161116dce513Schristos					   & result_type, & value);
161216dce513Schristos	  if (**strp != ')')
161316dce513Schristos	    return "missing ')'";
161416dce513Schristos	  ++*strp;
161516dce513Schristos	  *valuep = value;
161616dce513Schristos	  return errmsg;
161716dce513Schristos	}
161816dce513Schristos    }
161916dce513Schristos  return cgen_parse_signed_integer (cd, strp, opindex, valuep);
162016dce513Schristos}
162116dce513Schristos
162216dce513Schristosstatic const char *
162316dce513Schristosparse_s12 (CGEN_CPU_DESC cd,
162416dce513Schristos	   const char **strp,
162516dce513Schristos	   int opindex,
162616dce513Schristos	   long *valuep)
162716dce513Schristos{
162816dce513Schristos  const char *errmsg;
162916dce513Schristos  enum cgen_parse_operand_result result_type;
163016dce513Schristos  bfd_vma value;
163116dce513Schristos
163216dce513Schristos  /* Check for small data reference.  */
163316dce513Schristos  if (**strp == '#' || **strp == '%')
163416dce513Schristos    {
163516dce513Schristos      if (strncasecmp (*strp + 1, "gprel12(", 8) == 0)
163616dce513Schristos	{
163716dce513Schristos	  *strp += 9;
163816dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
163916dce513Schristos					   BFD_RELOC_FRV_GPREL12,
164016dce513Schristos					   & result_type, & value);
164116dce513Schristos	  if (**strp != ')')
164216dce513Schristos	    return "missing `)'";
164316dce513Schristos	  ++*strp;
164416dce513Schristos	  *valuep = value;
164516dce513Schristos	  return errmsg;
164616dce513Schristos	}
164716dce513Schristos      else if (strncasecmp (*strp + 1, "got12(", 6) == 0)
164816dce513Schristos	{
164916dce513Schristos	  *strp += 7;
165016dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
165116dce513Schristos					   BFD_RELOC_FRV_GOT12,
165216dce513Schristos					   & result_type, & value);
165316dce513Schristos	  if (**strp != ')')
165416dce513Schristos	    return "missing ')'";
165516dce513Schristos	  ++*strp;
165616dce513Schristos	  *valuep = value;
165716dce513Schristos	  return errmsg;
165816dce513Schristos	}
165916dce513Schristos      else if (strncasecmp (*strp + 1, "gotfuncdesc12(", 14) == 0)
166016dce513Schristos	{
166116dce513Schristos	  *strp += 15;
166216dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
166316dce513Schristos					   BFD_RELOC_FRV_FUNCDESC_GOT12,
166416dce513Schristos					   & result_type, & value);
166516dce513Schristos	  if (**strp != ')')
166616dce513Schristos	    return "missing ')'";
166716dce513Schristos	  ++*strp;
166816dce513Schristos	  *valuep = value;
166916dce513Schristos	  return errmsg;
167016dce513Schristos	}
167116dce513Schristos      else if (strncasecmp (*strp + 1, "gotoff12(", 9) == 0)
167216dce513Schristos	{
167316dce513Schristos	  *strp += 10;
167416dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
167516dce513Schristos					   BFD_RELOC_FRV_GOTOFF12,
167616dce513Schristos					   & result_type, & value);
167716dce513Schristos	  if (**strp != ')')
167816dce513Schristos	    return "missing ')'";
167916dce513Schristos	  ++*strp;
168016dce513Schristos	  *valuep = value;
168116dce513Schristos	  return errmsg;
168216dce513Schristos	}
168316dce513Schristos      else if (strncasecmp (*strp + 1, "gotofffuncdesc12(", 17) == 0)
168416dce513Schristos	{
168516dce513Schristos	  *strp += 18;
168616dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
168716dce513Schristos					   BFD_RELOC_FRV_FUNCDESC_GOTOFF12,
168816dce513Schristos					   & result_type, & value);
168916dce513Schristos	  if (**strp != ')')
169016dce513Schristos	    return "missing ')'";
169116dce513Schristos	  ++*strp;
169216dce513Schristos	  *valuep = value;
169316dce513Schristos	  return errmsg;
169416dce513Schristos	}
169516dce513Schristos      else if (strncasecmp (*strp + 1, "gottlsdesc12(", 13) == 0)
169616dce513Schristos	{
169716dce513Schristos	  *strp += 14;
169816dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
169916dce513Schristos					   BFD_RELOC_FRV_GOTTLSDESC12,
170016dce513Schristos					   & result_type, & value);
170116dce513Schristos	  if (**strp != ')')
170216dce513Schristos	    return "missing ')'";
170316dce513Schristos	  ++*strp;
170416dce513Schristos	  *valuep = value;
170516dce513Schristos	  return errmsg;
170616dce513Schristos	}
170716dce513Schristos      else if (strncasecmp (*strp + 1, "tlsmoff12(", 10) == 0)
170816dce513Schristos	{
170916dce513Schristos	  *strp += 11;
171016dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
171116dce513Schristos					   BFD_RELOC_FRV_TLSMOFF12,
171216dce513Schristos					   & result_type, & value);
171316dce513Schristos	  if (**strp != ')')
171416dce513Schristos	    return "missing ')'";
171516dce513Schristos	  ++*strp;
171616dce513Schristos	  *valuep = value;
171716dce513Schristos	  return errmsg;
171816dce513Schristos	}
171916dce513Schristos      else if (strncasecmp (*strp + 1, "gottlsoff12(", 12) == 0)
172016dce513Schristos	{
172116dce513Schristos	  *strp += 13;
172216dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
172316dce513Schristos					   BFD_RELOC_FRV_GOTTLSOFF12,
172416dce513Schristos					   & result_type, & value);
172516dce513Schristos	  if (**strp != ')')
172616dce513Schristos	    return "missing ')'";
172716dce513Schristos	  ++*strp;
172816dce513Schristos	  *valuep = value;
172916dce513Schristos	  return errmsg;
173016dce513Schristos	}
173116dce513Schristos    }
173216dce513Schristos
173316dce513Schristos  if (**strp == '#')
173416dce513Schristos    ++*strp;
173516dce513Schristos  return cgen_parse_signed_integer (cd, strp, opindex, valuep);
173616dce513Schristos}
173716dce513Schristos
173816dce513Schristosstatic const char *
173916dce513Schristosparse_u12 (CGEN_CPU_DESC cd,
174016dce513Schristos	   const char **strp,
174116dce513Schristos	   int opindex,
174216dce513Schristos	   long *valuep)
174316dce513Schristos{
174416dce513Schristos  const char *errmsg;
174516dce513Schristos  enum cgen_parse_operand_result result_type;
174616dce513Schristos  bfd_vma value;
174716dce513Schristos
174816dce513Schristos  /* Check for small data reference.  */
174916dce513Schristos  if ((**strp == '#' || **strp == '%')
175016dce513Schristos      && strncasecmp (*strp + 1, "gprel12(", 8) == 0)
175116dce513Schristos    {
175216dce513Schristos      *strp += 9;
175316dce513Schristos      errmsg = parse_symbolic_address (cd, strp, opindex,
175416dce513Schristos				       BFD_RELOC_FRV_GPRELU12,
175516dce513Schristos				       & result_type, & value);
175616dce513Schristos      if (**strp != ')')
175716dce513Schristos        return "missing `)'";
175816dce513Schristos      ++*strp;
175916dce513Schristos      *valuep = value;
176016dce513Schristos      return errmsg;
176116dce513Schristos    }
176216dce513Schristos  else
176316dce513Schristos    {
176416dce513Schristos      if (**strp == '#')
176516dce513Schristos        ++*strp;
176616dce513Schristos      return cgen_parse_signed_integer (cd, strp, opindex, valuep);
176716dce513Schristos    }
176816dce513Schristos}
176916dce513Schristos
177016dce513Schristosstatic const char *
177116dce513Schristosparse_A (CGEN_CPU_DESC cd,
177216dce513Schristos	 const char **strp,
177316dce513Schristos	 int opindex,
177416dce513Schristos	 unsigned long *valuep,
177516dce513Schristos	 unsigned long A)
177616dce513Schristos{
177716dce513Schristos  const char *errmsg;
177816dce513Schristos
177916dce513Schristos  if (**strp == '#')
178016dce513Schristos    ++*strp;
178116dce513Schristos
178216dce513Schristos  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
178316dce513Schristos  if (errmsg)
178416dce513Schristos    return errmsg;
178516dce513Schristos
178616dce513Schristos  if (*valuep != A)
178716dce513Schristos    return _("Value of A operand must be 0 or 1");
178816dce513Schristos
178916dce513Schristos  return NULL;
179016dce513Schristos}
179116dce513Schristos
179216dce513Schristosstatic const char *
179316dce513Schristosparse_A0 (CGEN_CPU_DESC cd,
179416dce513Schristos	  const char **strp,
179516dce513Schristos	  int opindex,
179616dce513Schristos	  unsigned long *valuep)
179716dce513Schristos{
179816dce513Schristos  return parse_A (cd, strp, opindex, valuep, 0);
179916dce513Schristos}
180016dce513Schristos
180116dce513Schristosstatic const char *
180216dce513Schristosparse_A1 (CGEN_CPU_DESC cd,
180316dce513Schristos	  const char **strp,
180416dce513Schristos	  int opindex,
180516dce513Schristos	  unsigned long *valuep)
180616dce513Schristos{
180716dce513Schristos  return parse_A (cd, strp, opindex, valuep, 1);
180816dce513Schristos}
180916dce513Schristos
181016dce513Schristosstatic const char *
181116dce513Schristosparse_even_register (CGEN_CPU_DESC  cd,
181216dce513Schristos		     const char **  strP,
181316dce513Schristos		     CGEN_KEYWORD * tableP,
181416dce513Schristos		     long *         valueP)
181516dce513Schristos{
181616dce513Schristos  const char * errmsg;
181716dce513Schristos  const char * saved_star_strP = * strP;
181816dce513Schristos
181916dce513Schristos  errmsg = cgen_parse_keyword (cd, strP, tableP, valueP);
182016dce513Schristos
182116dce513Schristos  if (errmsg == NULL && ((* valueP) & 1))
182216dce513Schristos    {
182316dce513Schristos      errmsg = _("register number must be even");
182416dce513Schristos      * strP = saved_star_strP;
182516dce513Schristos    }
182616dce513Schristos
182716dce513Schristos  return errmsg;
182816dce513Schristos}
182916dce513Schristos
183016dce513Schristosstatic const char *
183116dce513Schristosparse_call_label (CGEN_CPU_DESC cd,
183216dce513Schristos		  const char **strp,
183316dce513Schristos		  int opindex,
183416dce513Schristos		  int opinfo,
183516dce513Schristos		  enum cgen_parse_operand_result *resultp,
183616dce513Schristos		  bfd_vma *valuep)
183716dce513Schristos{
183816dce513Schristos  const char *errmsg;
183916dce513Schristos  bfd_vma value;
184016dce513Schristos
184116dce513Schristos  /* Check for small data reference.  */
184216dce513Schristos  if (opinfo == 0 && (**strp == '#' || **strp == '%'))
184316dce513Schristos    {
184416dce513Schristos      if (strncasecmp (*strp + 1, "gettlsoff(", 10) == 0)
184516dce513Schristos	{
184616dce513Schristos	  *strp += 11;
184716dce513Schristos	  errmsg = parse_symbolic_address (cd, strp, opindex,
184816dce513Schristos					   BFD_RELOC_FRV_GETTLSOFF,
184916dce513Schristos					   resultp, &value);
185016dce513Schristos	  if (**strp != ')')
185116dce513Schristos	    return _("missing `)'");
185216dce513Schristos	  ++*strp;
185316dce513Schristos	  *valuep = value;
185416dce513Schristos	  return errmsg;
185516dce513Schristos	}
185616dce513Schristos    }
185716dce513Schristos
185816dce513Schristos  return cgen_parse_address (cd, strp, opindex, opinfo, resultp, valuep);
185916dce513Schristos}
186016dce513Schristos
186116dce513Schristos/* -- */
186216dce513Schristos
186316dce513Schristos/* -- dis.c */
186416dce513Schristosstatic void
186516dce513Schristosprint_at (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
186616dce513Schristos	  void * dis_info,
186716dce513Schristos	  long reloc_ann ATTRIBUTE_UNUSED,
186816dce513Schristos	  long value ATTRIBUTE_UNUSED,
186916dce513Schristos	  bfd_vma pc ATTRIBUTE_UNUSED,
187016dce513Schristos	  int length ATTRIBUTE_UNUSED)
187116dce513Schristos{
187216dce513Schristos  disassemble_info *info = (disassemble_info *) dis_info;
187316dce513Schristos
187416dce513Schristos  (*info->fprintf_func) (info->stream, "@");
187516dce513Schristos}
187616dce513Schristos
187716dce513Schristosstatic void
187816dce513Schristosprint_spr (CGEN_CPU_DESC cd,
187916dce513Schristos	   void * dis_info,
188016dce513Schristos	   CGEN_KEYWORD *names,
188116dce513Schristos	   long regno,
188216dce513Schristos	   unsigned int attrs)
188316dce513Schristos{
188416dce513Schristos  /* Use the register index format for any unnamed registers.  */
188516dce513Schristos  if (cgen_keyword_lookup_value (names, regno) == NULL)
188616dce513Schristos    {
188716dce513Schristos      disassemble_info *info = (disassemble_info *) dis_info;
188816dce513Schristos      (*info->fprintf_func) (info->stream, "spr[%ld]", regno);
188916dce513Schristos    }
189016dce513Schristos  else
189116dce513Schristos    print_keyword (cd, dis_info, names, regno, attrs);
189216dce513Schristos}
189316dce513Schristos
189416dce513Schristosstatic void
189516dce513Schristosprint_hi (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
189616dce513Schristos	  void * dis_info,
189716dce513Schristos	  long value,
189816dce513Schristos	  unsigned int attrs ATTRIBUTE_UNUSED,
189916dce513Schristos	  bfd_vma pc ATTRIBUTE_UNUSED,
190016dce513Schristos	  int length ATTRIBUTE_UNUSED)
190116dce513Schristos{
190216dce513Schristos  disassemble_info *info = (disassemble_info *) dis_info;
190316dce513Schristos
190416dce513Schristos  (*info->fprintf_func) (info->stream, value ? "0x%lx" : "hi(0x%lx)", value);
190516dce513Schristos}
190616dce513Schristos
190716dce513Schristosstatic void
190816dce513Schristosprint_lo (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
190916dce513Schristos	  void * dis_info,
191016dce513Schristos	  long value,
191116dce513Schristos	  unsigned int attrs ATTRIBUTE_UNUSED,
191216dce513Schristos	  bfd_vma pc ATTRIBUTE_UNUSED,
191316dce513Schristos	  int length ATTRIBUTE_UNUSED)
191416dce513Schristos{
191516dce513Schristos  disassemble_info *info = (disassemble_info *) dis_info;
191616dce513Schristos  if (value)
191716dce513Schristos    (*info->fprintf_func) (info->stream, "0x%lx", value);
191816dce513Schristos  else
191916dce513Schristos    (*info->fprintf_func) (info->stream, "lo(0x%lx)", value);
192016dce513Schristos}
192116dce513Schristos
192216dce513Schristos/* -- */
1923