-# generated automatically by aclocal 1.9.5 -*- Autoconf -*-
+# generated automatically by aclocal 1.9.2 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005 Free Software Foundation, Inc.
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
-# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+# -*- Autoconf -*-
+# Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+# Generated from amversion.in; do not edit by hand.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# AM_AUTOMAKE_VERSION(VERSION)
# ----------------------------
# Call AM_AUTOMAKE_VERSION so it can be traced.
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
- [AM_AUTOMAKE_VERSION([1.9.5])])
+ [AM_AUTOMAKE_VERSION([1.9.2])])
-# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+# AM_AUX_DIR_EXPAND
-# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
am_aux_dir=`cd $ac_aux_dir && pwd`
])
-# AM_CONDITIONAL -*- Autoconf -*-
+# AM_CONDITIONAL -*- Autoconf -*-
-# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
-# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+# Copyright (C) 1997, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
-# serial 7
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 6
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
# -------------------------------------
Usually this means the macro was only invoked conditionally.]])
fi])])
+# serial 7 -*- Autoconf -*-
-# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-# serial 8
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
# written in clear, in which case automake, when reading aclocal.m4,
# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
# _AM_DEPENDENCIES(NAME)
# ----------------------
# See how the compiler implements dependency checking.
AC_SUBST([AMDEPBACKSLASH])
])
-# Generate code to set up dependency tracking. -*- Autoconf -*-
+# Generate code to set up dependency tracking. -*- Autoconf -*-
-# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
-# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+# Free Software Foundation, Inc.
-#serial 3
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+#serial 2
# _AM_OUTPUT_DEPENDENCY_COMMANDS
# ------------------------------
[AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
])
-# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
-# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
-# serial 8
+# serial 7
# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS.
AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
-# Do all the work for Automake. -*- Autoconf -*-
+# Do all the work for Automake. -*- Autoconf -*-
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# This macro actually does too much some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-# serial 12
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
-# This macro actually does too much. Some checks are only needed if
-# your package does certain things. But this isn't really a big deal.
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 11
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
# AM_INIT_AUTOMAKE([OPTIONS])
done
echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
-# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
# AM_PROG_INSTALL_SH
# ------------------
# Define $install_sh.
+
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
AC_DEFUN([AM_PROG_INSTALL_SH],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
install_sh=${install_sh-"$am_aux_dir/install-sh"}
AC_SUBST(install_sh)])
-# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+# -*- Autoconf -*-
+# Copyright (C) 2003 Free Software Foundation, Inc.
-# serial 2
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 1
# Check whether the underlying file-system supports filenames
# with a leading dot. For instance MS-DOS doesn't.
rmdir .tst 2>/dev/null
AC_SUBST([am__leading_dot])])
-# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005
+
+# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-# serial 5
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 4
# AM_PROG_LEX
# -----------
LEX=${am_missing_run}flex
fi])
-# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# Add --enable-maintainer-mode option to configure.
# From Jim Meyering
-# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004
# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-# serial 4
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 3
AC_DEFUN([AM_MAINTAINER_MODE],
[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
-# Check to see how 'make' treats includes. -*- Autoconf -*-
+# Check to see how 'make' treats includes. -*- Autoconf -*-
-# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
-# serial 3
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 2
# AM_MAKE_INCLUDE()
# -----------------
rm -f confinc confmf
])
-# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+# -*- Autoconf -*-
-# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
-# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-# serial 4
+# Copyright (C) 1997, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 3
# AM_MISSING_PROG(NAME, PROGRAM)
# ------------------------------
fi
])
-# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
# AM_PROG_MKDIR_P
# ---------------
# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
-#
+
+# Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
# created by `make install' are always world readable, even if the
# installer happens to have an overly restrictive umask (e.g. 077).
fi
AC_SUBST([mkdir_p])])
-# Helper functions for option handling. -*- Autoconf -*-
+# Helper functions for option handling. -*- Autoconf -*-
-# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
-# serial 3
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 2
# _AM_MANGLE_OPTION(NAME)
# -----------------------
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
-# Check to make sure that the build environment is sane. -*- Autoconf -*-
-
-# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
-# Free Software Foundation, Inc.
#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+# Check to make sure that the build environment is sane.
+#
-# serial 4
+# Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 3
# AM_SANITY_CHECK
# ---------------
fi
AC_MSG_RESULT(yes)])
-# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
# AM_PROG_INSTALL_STRIP
-# ---------------------
+
+# Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
# One issue with vendor `install' (even GNU) is that you can't
# specify the program used to strip binaries. This is especially
# annoying in cross-compiling environments, where the build's strip
# Check how to create a tarball. -*- Autoconf -*-
-# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
+# Copyright (C) 2004 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# serial 1
-# serial 2
# _AM_PROG_TAR(FORMAT)
# --------------------
--- /dev/null
+/* bfin-parse.y ADI Blackfin parser
+ Copyright 2005
+ Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+%{
+
+#include <stdio.h>
+#include "bfin-aux.h"
+#include <stdarg.h>
+#include <obstack.h>
+
+#define DSP32ALU(aopcde, HL, dst1, dst0, src0, src1, s, x, aop) \
+ bfin_gen_dsp32alu (HL, aopcde, aop, s, x, dst0, dst1, src0, src1)
+
+#define DSP32MAC(op1, MM, mmod, w1, P, h01, h11, h00, h10, dst, op0, src0, src1, w0) \
+ bfin_gen_dsp32mac (op1, MM, mmod, w1, P, h01, h11, h00, h10, op0, \
+ dst, src0, src1, w0)
+
+#define DSP32MULT(op1, MM, mmod, w1, P, h01, h11, h00, h10, dst, op0, src0, src1, w0) \
+ bfin_gen_dsp32mult (op1, MM, mmod, w1, P, h01, h11, h00, h10, op0, \
+ dst, src0, src1, w0)
+
+#define DSP32SHIFT(sopcde, dst0, src0, src1, sop, hls) \
+ bfin_gen_dsp32shift (sopcde, dst0, src0, src1, sop, hls)
+
+#define DSP32SHIFTIMM(sopcde, dst0, immag, src1, sop, hls) \
+ bfin_gen_dsp32shiftimm (sopcde, dst0, immag, src1, sop, hls)
+
+#define LDIMMHALF_R(reg, h, s, z, hword) \
+ bfin_gen_ldimmhalf (reg, h, s, z, hword, 1)
+
+#define LDIMMHALF_R5(reg, h, s, z, hword) \
+ bfin_gen_ldimmhalf (reg, h, s, z, hword, 2)
+
+#define LDSTIDXI(ptr, reg, w, sz, z, offset) \
+ bfin_gen_ldstidxi (ptr, reg, w, sz, z, offset)
+
+#define LDST(ptr, reg, aop, sz, z, w) \
+ bfin_gen_ldst (ptr, reg, aop, sz, z, w)
+
+#define LDSTII(ptr, reg, offset, w, op) \
+ bfin_gen_ldstii (ptr, reg, offset, w, op)
+
+#define DSPLDST(i, m, reg, aop, w) \
+ bfin_gen_dspldst (i, reg, aop, w, m)
+
+#define LDSTPMOD(ptr, reg, idx, aop, w) \
+ bfin_gen_ldstpmod (ptr, reg, aop, w, idx)
+
+#define LDSTIIFP(offset, reg, w) \
+ bfin_gen_ldstiifp (reg, offset, w)
+
+#define LOGI2OP(dst, src, opc) \
+ bfin_gen_logi2op (opc, src, dst.regno & CODE_MASK)
+
+#define ALU2OP(dst, src, opc) \
+ bfin_gen_alu2op (dst, src, opc)
+
+#define BRCC(t, b, offset) \
+ bfin_gen_brcc (t, b, offset)
+
+#define UJUMP(offset) \
+ bfin_gen_ujump (offset)
+
+#define PROGCTRL(prgfunc, poprnd) \
+ bfin_gen_progctrl (prgfunc, poprnd)
+
+#define PUSHPOPMULTIPLE(dr, pr, d, p, w) \
+ bfin_gen_pushpopmultiple (dr, pr, d, p, w)
+
+#define PUSHPOPREG(reg, w) \
+ bfin_gen_pushpopreg (reg, w)
+
+#define CALLA(addr, s) \
+ bfin_gen_calla (addr, s)
+
+#define LINKAGE(r, framesize) \
+ bfin_gen_linkage (r, framesize)
+
+#define COMPI2OPD(dst, src, op) \
+ bfin_gen_compi2opd (dst, src, op)
+
+#define COMPI2OPP(dst, src, op) \
+ bfin_gen_compi2opp (dst, src, op)
+
+#define DAGMODIK(i, op) \
+ bfin_gen_dagmodik (i, op)
+
+#define DAGMODIM(i, m, op, br) \
+ bfin_gen_dagmodim (i, m, op, br)
+
+#define COMP3OP(dst, src0, src1, opc) \
+ bfin_gen_comp3op (src0, src1, dst, opc)
+
+#define PTR2OP(dst, src, opc) \
+ bfin_gen_ptr2op (dst, src, opc)
+
+#define CCFLAG(x, y, opc, i, g) \
+ bfin_gen_ccflag (x, y, opc, i, g)
+
+#define CCMV(src, dst, t) \
+ bfin_gen_ccmv (src, dst, t)
+
+#define CACTRL(reg, a, op) \
+ bfin_gen_cactrl (reg, a, op)
+
+#define LOOPSETUP(soffset, c, rop, eoffset, reg) \
+ bfin_gen_loopsetup (soffset, c, rop, eoffset, reg)
+
+#define HL2(r1, r0) (IS_H (r1) << 1 | IS_H (r0))
+#define IS_RANGE(bits, expr, sign, mul) \
+ value_match(expr, bits, sign, mul, 1)
+#define IS_URANGE(bits, expr, sign, mul) \
+ value_match(expr, bits, sign, mul, 0)
+#define IS_CONST(expr) (expr->type == Expr_Node_Constant)
+#define IS_RELOC(expr) (expr->type != Expr_Node_Constant)
+#define IS_IMM(expr, bits) value_match (expr, bits, 0, 1, 1)
+#define IS_UIMM(expr, bits) value_match (expr, bits, 0, 1, 0)
+
+#define IS_PCREL4(expr) \
+ (value_match (expr, 4, 0, 2, 0))
+
+#define IS_LPPCREL10(expr) \
+ (value_match (expr, 10, 0, 2, 0))
+
+#define IS_PCREL10(expr) \
+ (value_match (expr, 10, 0, 2, 1))
+
+#define IS_PCREL12(expr) \
+ (value_match (expr, 12, 0, 2, 1))
+
+#define IS_PCREL24(expr) \
+ (value_match (expr, 24, 0, 2, 1))
+
+
+static int value_match (Expr_Node *expr, int sz, int sign, int mul, int issigned);
+
+extern FILE *errorf;
+extern INSTR_T insn;
+
+static Expr_Node *binary (Expr_Op_Type, Expr_Node *, Expr_Node *);
+static Expr_Node *unary (Expr_Op_Type, Expr_Node *);
+
+static void notethat (char *format, ...);
+
+char *current_inputline;
+extern char *yytext;
+int yyerror (char *msg);
+
+void error (char *format, ...)
+{
+ va_list ap;
+ char buffer[2000];
+
+ va_start (ap, format);
+ vsprintf (buffer, format, ap);
+ va_end (ap);
+
+ as_bad (buffer);
+}
+
+int
+yyerror (char *msg)
+{
+ if (msg[0] == '\0')
+ error ("%s", msg);
+
+ else if (yytext[0] != ';')
+ error ("%s. Input text was %s.", msg, yytext);
+ else
+ error ("%s.", msg);
+
+ return -1;
+}
+
+static int
+in_range_p (Expr_Node *expr, int from, int to, unsigned int mask)
+{
+ int val = EXPR_VALUE (expr);
+ if (expr->type != Expr_Node_Constant)
+ return 0;
+ if (val < from || val > to)
+ return 0;
+ return (val & mask) == 0;
+}
+
+extern int yylex (void);
+
+#define imm3(x) EXPR_VALUE (x)
+#define imm4(x) EXPR_VALUE (x)
+#define uimm4(x) EXPR_VALUE (x)
+#define imm5(x) EXPR_VALUE (x)
+#define uimm5(x) EXPR_VALUE (x)
+#define imm6(x) EXPR_VALUE (x)
+#define imm7(x) EXPR_VALUE (x)
+#define imm16(x) EXPR_VALUE (x)
+#define uimm16s4(x) ((EXPR_VALUE (x)) >> 2)
+#define uimm16(x) EXPR_VALUE (x)
+
+/* Return true if a value is inside a range. */
+#define IN_RANGE(x, low, high) \
+ (((EXPR_VALUE(x)) >= (low)) && (EXPR_VALUE(x)) <= ((high)))
+
+/* Auxiliary functions. */
+
+static void
+neg_value (Expr_Node *expr)
+{
+ expr->value.i_value = -expr->value.i_value;
+}
+
+static int
+valid_dreg_pair (Register *reg1, Expr_Node *reg2)
+{
+ if (!IS_DREG (*reg1))
+ {
+ yyerror ("Dregs expected");
+ return 0;
+ }
+
+ if (reg1->regno != 1 && reg1->regno != 3)
+ {
+ yyerror ("Bad register pair");
+ return 0;
+ }
+
+ if (imm7 (reg2) != reg1->regno - 1)
+ {
+ yyerror ("Bad register pair");
+ return 0;
+ }
+
+ reg1->regno--;
+ return 1;
+}
+
+static int
+check_multiply_halfregs (Macfunc *aa, Macfunc *ab)
+{
+ if ((!REG_EQUAL (aa->s0, ab->s0) && !REG_EQUAL (aa->s0, ab->s1))
+ || (!REG_EQUAL (aa->s1, ab->s1) && !REG_EQUAL (aa->s1, ab->s0)))
+ return yyerror ("Source multiplication register mismatch");
+
+ return 0;
+}
+
+
+/* Check (vector) mac funcs and ops. */
+
+static int
+check_macfuncs (Macfunc *aa, Opt_mode *opa,
+ Macfunc *ab, Opt_mode *opb)
+{
+ /* Variables for swapping. */
+ Macfunc mtmp;
+ Opt_mode otmp;
+
+ /* If a0macfunc comes before a1macfunc, swap them. */
+
+ if (aa->n == 0)
+ {
+ /* (M) is not allowed here. */
+ if (opa->MM != 0)
+ return yyerror ("(M) not allowed with A0MAC");
+ if (ab->n != 1)
+ return yyerror ("Vector AxMACs can't be same");
+
+ mtmp = *aa; *aa = *ab; *ab = mtmp;
+ otmp = *opa; *opa = *opb; *opb = otmp;
+ }
+ else
+ {
+ if (opb->MM != 0)
+ return yyerror ("(M) not allowed with A0MAC");
+ if (opa->mod != 0)
+ return yyerror ("Bad opt mode");
+ if (ab->n != 0)
+ return yyerror ("Vector AxMACs can't be same");
+ }
+
+ /* If both ops are != 3, we have multiply_halfregs in both
+ assignment_or_macfuncs. */
+ if (aa->op == ab->op && aa->op != 3)
+ {
+ if (check_multiply_halfregs (aa, ab) < 0)
+ return -1;
+ }
+ else
+ {
+ /* Only one of the assign_macfuncs has a half reg multiply
+ Evil trick: Just 'OR' their source register codes:
+ We can do that, because we know they were initialized to 0
+ in the rules that don't use multiply_halfregs. */
+ aa->s0.regno |= (ab->s0.regno & CODE_MASK);
+ aa->s1.regno |= (ab->s1.regno & CODE_MASK);
+ }
+
+ if (aa->w == ab->w && aa->P != ab->P)
+ {
+ return yyerror ("macfuncs must differ");
+ if (aa->w && (aa->dst.regno - ab->dst.regno != 1))
+ return yyerror ("Destination Dregs must differ by one");
+ }
+ /* We assign to full regs, thus obey even/odd rules. */
+ else if ((aa->w && aa->P && IS_EVEN (aa->dst))
+ || (ab->w && ab->P && !IS_EVEN (ab->dst)))
+ return yyerror ("Even/Odd register assignment mismatch");
+ /* We assign to half regs, thus obey hi/low rules. */
+ else if ( (aa->w && !aa->P && !IS_H (aa->dst))
+ || (ab->w && !aa->P && IS_H (ab->dst)))
+ return yyerror ("High/Low register assignment mismatch");
+
+ /* Make sure first macfunc has got both P flags ORed. */
+ aa->P |= ab->P;
+
+ /* Make sure mod flags get ORed, too. */
+ opb->mod |= opa->mod;
+ return 0;
+}
+
+
+static int
+is_group1 (INSTR_T x)
+{
+ /* Group1 is dpsLDST, LDSTpmod, LDST, LDSTiiFP, LDSTii. */
+ if ((x->value & 0xc000) == 0x8000 || (x->value == 0x0000))
+ return 1;
+
+ return 0;
+}
+
+static int
+is_group2 (INSTR_T x)
+{
+ if ((((x->value & 0xfc00) == 0x9c00) /* dspLDST. */
+ && !((x->value & 0xfde0) == 0x9c60) /* dagMODim. */
+ && !((x->value & 0xfde0) == 0x9ce0) /* dagMODim with bit rev. */
+ && !((x->value & 0xfde0) == 0x9d60)) /* pick dagMODik. */
+ || (x->value == 0x0000))
+ return 1;
+ return 0;
+}
+
+%}
+
+%union {
+ INSTR_T instr;
+ Expr_Node *expr;
+ SYMBOL_T symbol;
+ long value;
+ Register reg;
+ Macfunc macfunc;
+ struct { int r0; int s0; int x0; int aop; } modcodes;
+ struct { int r0; } r0;
+ Opt_mode mod;
+}
+
+
+/* Tokens. */
+
+/* Vector Specific. */
+%token BYTEOP16P BYTEOP16M
+%token BYTEOP1P BYTEOP2P BYTEOP2M BYTEOP3P
+%token BYTEUNPACK BYTEPACK
+%token PACK
+%token SAA
+%token ALIGN8 ALIGN16 ALIGN24
+%token VIT_MAX
+%token EXTRACT DEPOSIT EXPADJ SEARCH
+%token ONES SIGN SIGNBITS
+
+/* Stack. */
+%token LINK UNLINK
+
+/* Registers. */
+%token REG
+%token PC
+%token CCREG BYTE_DREG
+%token REG_A_DOUBLE_ZERO REG_A_DOUBLE_ONE
+%token A_ZERO_DOT_L A_ZERO_DOT_H A_ONE_DOT_L A_ONE_DOT_H
+%token HALF_REG
+
+/* Progctrl. */
+%token NOP
+%token RTI RTS RTX RTN RTE
+%token HLT IDLE
+%token STI CLI
+%token CSYNC SSYNC
+%token EMUEXCPT
+%token RAISE EXCPT
+%token LSETUP
+%token LOOP
+%token LOOP_BEGIN
+%token LOOP_END
+%token DISALGNEXCPT
+%token JUMP JUMP_DOT_S JUMP_DOT_L
+%token CALL
+
+/* Emulator only. */
+%token ABORT
+
+/* Operators. */
+%token NOT TILDA BANG
+%token AMPERSAND BAR
+%token PERCENT
+%token CARET
+%token BXOR
+
+%token MINUS PLUS STAR SLASH
+%token NEG
+%token MIN MAX ABS
+%token DOUBLE_BAR
+%token _PLUS_BAR_PLUS _PLUS_BAR_MINUS _MINUS_BAR_PLUS _MINUS_BAR_MINUS
+%token _MINUS_MINUS _PLUS_PLUS
+
+/* Shift/rotate ops. */
+%token SHIFT LSHIFT ASHIFT BXORSHIFT
+%token _GREATER_GREATER_GREATER_THAN_ASSIGN
+%token ROT
+%token LESS_LESS GREATER_GREATER
+%token _GREATER_GREATER_GREATER
+%token _LESS_LESS_ASSIGN _GREATER_GREATER_ASSIGN
+%token DIVS DIVQ
+
+/* In place operators. */
+%token ASSIGN _STAR_ASSIGN
+%token _BAR_ASSIGN _CARET_ASSIGN _AMPERSAND_ASSIGN
+%token _MINUS_ASSIGN _PLUS_ASSIGN
+
+/* Assignments, comparisons. */
+%token _ASSIGN_BANG _LESS_THAN_ASSIGN _ASSIGN_ASSIGN
+%token GE LT LE GT
+%token LESS_THAN
+
+/* Cache. */
+%token FLUSHINV FLUSH
+%token IFLUSH PREFETCH
+
+/* Misc. */
+%token PRNT
+%token OUTC
+%token WHATREG
+%token TESTSET
+
+/* Modifiers. */
+%token ASL ASR
+%token B W
+%token NS S CO SCO
+%token TH TL
+%token BP
+%token BREV
+%token X Z
+%token M MMOD
+%token R RND RNDL RNDH RND12 RND20
+%token V
+%token LO HI
+
+/* Bit ops. */
+%token BITTGL BITCLR BITSET BITTST BITMUX
+
+/* Debug. */
+%token DBGAL DBGAH DBGHALT DBG DBGA DBGCMPLX
+
+/* Semantic auxiliaries. */
+
+%token IF COMMA BY
+%token COLON SEMICOLON
+%token RPAREN LPAREN LBRACK RBRACK
+%token STATUS_REG
+%token MNOP
+%token SYMBOL NUMBER
+%token GOT AT PLTPC
+
+/* Types. */
+%type <instr> asm
+%type <value> MMOD
+%type <mod> opt_mode
+
+%type <value> NUMBER
+%type <r0> aligndir
+%type <modcodes> byteop_mod
+%type <reg> a_assign
+%type <reg> a_plusassign
+%type <reg> a_minusassign
+%type <macfunc> multiply_halfregs
+%type <macfunc> assign_macfunc
+%type <macfunc> a_macfunc
+%type <expr> expr_1
+%type <instr> asm_1
+%type <r0> vmod
+%type <modcodes> vsmod
+%type <modcodes> ccstat
+%type <r0> cc_op
+%type <reg> CCREG
+%type <reg> reg_with_postinc
+%type <reg> reg_with_predec
+
+%type <r0> searchmod
+%type <expr> symbol
+%type <symbol> SYMBOL
+%type <expr> eterm
+%type <reg> REG
+%type <reg> BYTE_DREG
+%type <reg> REG_A_DOUBLE_ZERO
+%type <reg> REG_A_DOUBLE_ONE
+%type <reg> REG_A
+%type <reg> STATUS_REG
+%type <expr> expr
+%type <r0> xpmod
+%type <r0> xpmod1
+%type <modcodes> smod
+%type <modcodes> b3_op
+%type <modcodes> rnd_op
+%type <modcodes> post_op
+%type <reg> HALF_REG
+%type <r0> iu_or_nothing
+%type <r0> plus_minus
+%type <r0> asr_asl
+%type <r0> asr_asl_0
+%type <modcodes> sco
+%type <modcodes> amod0
+%type <modcodes> amod1
+%type <modcodes> amod2
+%type <r0> op_bar_op
+%type <r0> w32_or_nothing
+%type <r0> c_align
+%type <r0> min_max
+%type <expr> got
+%type <expr> got_or_expr
+%type <expr> pltpc
+
+
+/* Precedence rules. */
+%left BAR
+%left CARET
+%left AMPERSAND
+%left LESS_LESS GREATER_GREATER
+%left PLUS MINUS
+%left STAR SLASH PERCENT
+
+%right ASSIGN
+
+%right TILDA BANG
+%start statement
+%%
+statement:
+ | asm
+ {
+ insn = $1;
+ if (insn == (INSTR_T) 0)
+ return NO_INSN_GENERATED;
+ else if (insn == (INSTR_T) - 1)
+ return SEMANTIC_ERROR;
+ else
+ return INSN_GENERATED;
+ }
+ ;
+
+asm: asm_1 SEMICOLON
+ /* Parallel instructions. */
+ | asm_1 DOUBLE_BAR asm_1 DOUBLE_BAR asm_1 SEMICOLON
+ {
+ if (($1->value & 0xf800) == 0xc000)
+ {
+ if (is_group1 ($3) && is_group2 ($5))
+ $$ = bfin_gen_multi_instr ($1, $3, $5);
+ else if (is_group2 ($3) && is_group1 ($5))
+ $$ = bfin_gen_multi_instr ($1, $5, $3);
+ else
+ return yyerror ("Wrong 16 bit instructions groups, slot 2 and slot 3 must be 16-bit instrution group");
+ }
+ else if (($3->value & 0xf800) == 0xc000)
+ {
+ if (is_group1 ($1) && is_group2 ($5))
+ $$ = bfin_gen_multi_instr ($3, $1, $5);
+ else if (is_group2 ($1) && is_group1 ($5))
+ $$ = bfin_gen_multi_instr ($3, $5, $1);
+ else
+ return yyerror ("Wrong 16 bit instructions groups, slot 1 and slot 3 must be 16-bit instrution group");
+ }
+ else if (($5->value & 0xf800) == 0xc000)
+ {
+ if (is_group1 ($1) && is_group2 ($3))
+ $$ = bfin_gen_multi_instr ($5, $1, $3);
+ else if (is_group2 ($1) && is_group1 ($3))
+ $$ = bfin_gen_multi_instr ($5, $3, $1);
+ else
+ return yyerror ("Wrong 16 bit instructions groups, slot 1 and slot 2 must be 16-bit instrution group");
+ }
+ else
+ error ("\nIllegal Multi Issue Construct, at least any one of the slot must be DSP32 instruction group\n");
+ }
+
+ | asm_1 DOUBLE_BAR asm_1 SEMICOLON
+ {
+ if (($1->value & 0xf800) == 0xc000)
+ {
+ if (is_group1 ($3))
+ $$ = bfin_gen_multi_instr ($1, $3, 0);
+ else if (is_group2 ($3))
+ $$ = bfin_gen_multi_instr ($1, 0, $3);
+ else
+ return yyerror ("Wrong 16 bit instructions groups, slot 2 must be the 16-bit instruction group");
+ }
+ else if (($3->value & 0xf800) == 0xc000)
+ {
+ if (is_group1 ($1))
+ $$ = bfin_gen_multi_instr ($3, $1, 0);
+ else if (is_group2 ($1))
+ $$ = bfin_gen_multi_instr ($3, 0, $1);
+ else
+ return yyerror ("Wrong 16 bit instructions groups, slot 1 must be the 16-bit instruction group");
+ }
+ else if (is_group1 ($1) && is_group2 ($3))
+ $$ = bfin_gen_multi_instr (0, $1, $3);
+ else if (is_group2 ($1) && is_group1 ($3))
+ $$ = bfin_gen_multi_instr (0, $3, $1);
+ else
+ return yyerror ("Wrong 16 bit instructions groups, slot 1 and slot 2 must be the 16-bit instruction group");
+ }
+ | error
+ {
+ $$ = 0;
+ yyerror ("");
+ yyerrok;
+ }
+ ;
+
+/* DSPMAC. */
+
+asm_1:
+ MNOP
+ {
+ $$ = DSP32MAC (3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
+ }
+ | assign_macfunc opt_mode
+ {
+ int op0, op1;
+ int w0 = 0, w1 = 0;
+ int h00, h10, h01, h11;
+
+ if ($1.n == 0)
+ {
+ if ($2.MM)
+ return yyerror ("(m) not allowed with a0 unit");
+ op1 = 3;
+ op0 = $1.op;
+ w1 = 0;
+ w0 = $1.w;
+ h00 = IS_H ($1.s0);
+ h10 = IS_H ($1.s1);
+ h01 = h11 = 0;
+ }
+ else
+ {
+ op1 = $1.op;
+ op0 = 3;
+ w1 = $1.w;
+ w0 = 0;
+ h00 = h10 = 0;
+ h01 = IS_H ($1.s0);
+ h11 = IS_H ($1.s1);
+ }
+ $$ = DSP32MAC (op1, $2.MM, $2.mod, w1, $1.P, h01, h11, h00, h10,
+ &$1.dst, op0, &$1.s0, &$1.s1, w0);
+ }
+
+
+/* VECTOR MACs. */
+
+ | assign_macfunc opt_mode COMMA assign_macfunc opt_mode
+ {
+ Register *dst;
+
+ if (check_macfuncs (&$1, &$2, &$4, &$5) < 0)
+ return -1;
+ notethat ("assign_macfunc (.), assign_macfunc (.)\n");
+
+ if ($1.w)
+ dst = &$1.dst;
+ else
+ dst = &$4.dst;
+
+ $$ = DSP32MAC ($1.op, $2.MM, $5.mod, $1.w, $1.P,
+ IS_H ($1.s0), IS_H ($1.s1), IS_H ($4.s0), IS_H ($4.s1),
+ dst, $4.op, &$1.s0, &$1.s1, $4.w);
+ }
+
+/* DSPALU. */
+
+ | DISALGNEXCPT
+ {
+ notethat ("dsp32alu: DISALGNEXCPT\n");
+ $$ = DSP32ALU (18, 0, 0, 0, 0, 0, 0, 0, 3);
+ }
+ | REG ASSIGN LPAREN a_plusassign REG_A RPAREN
+ {
+ if (IS_DREG ($1) && !IS_A1 ($4) && IS_A1 ($5))
+ {
+ notethat ("dsp32alu: dregs = ( A0 += A1 )\n");
+ $$ = DSP32ALU (11, 0, 0, &$1, 0, 0, 0, 0, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+ | HALF_REG ASSIGN LPAREN a_plusassign REG_A RPAREN
+ {
+ if (!IS_A1 ($4) && IS_A1 ($5))
+ {
+ notethat ("dsp32alu: dregs_half = ( A0 += A1 )\n");
+ $$ = DSP32ALU (11, IS_H ($1), 0, &$1, 0, 0, 0, 0, 1);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+ | A_ZERO_DOT_H ASSIGN HALF_REG
+ {
+ notethat ("dsp32alu: A_ZERO_DOT_H = dregs_hi\n");
+ $$ = DSP32ALU (9, IS_H ($3), 0, 0, &$3, 0, 0, 0, 0);
+ }
+ | A_ONE_DOT_H ASSIGN HALF_REG
+ {
+ notethat ("dsp32alu: A_ZERO_DOT_H = dregs_hi\n");
+ $$ = DSP32ALU (9, IS_H ($3), 0, 0, &$3, 0, 0, 0, 2);
+ }
+ | LPAREN REG COMMA REG RPAREN ASSIGN BYTEOP16P LPAREN REG
+ COLON expr COMMA REG COLON expr RPAREN aligndir
+ {
+ if (!IS_DREG ($2) || !IS_DREG ($4))
+ return yyerror ("Dregs expected");
+ else if (!valid_dreg_pair (&$9, $11))
+ return yyerror ("Bad dreg pair");
+ else if (!valid_dreg_pair (&$13, $15))
+ return yyerror ("Bad dreg pair");
+ else
+ {
+ notethat ("dsp32alu: (dregs , dregs ) = BYTEOP16P (dregs_pair , dregs_pair ) (half)\n");
+ $$ = DSP32ALU (21, 0, &$2, &$4, &$9, &$13, $17.r0, 0, 0);
+ }
+ }
+
+ | LPAREN REG COMMA REG RPAREN ASSIGN BYTEOP16M LPAREN REG COLON expr COMMA
+ REG COLON expr RPAREN aligndir
+ {
+ if (!IS_DREG ($2) || !IS_DREG($4))
+ return yyerror ("Dregs expected");
+ else if (!valid_dreg_pair (&$9, $11))
+ return yyerror ("Bad dreg pair");
+ else if (!valid_dreg_pair (&$13, $15))
+ return yyerror ("Bad dreg pair");
+ else
+ {
+ notethat ("dsp32alu: (dregs , dregs ) = BYTEOP16M (dregs_pair , dregs_pair ) (aligndir)\n");
+ $$ = DSP32ALU (21, 0, &$2, &$4, &$9, &$13, $17.r0, 0, 1);
+ }
+ }
+
+ | LPAREN REG COMMA REG RPAREN ASSIGN BYTEUNPACK REG COLON expr aligndir
+ {
+ if (!IS_DREG ($2) || !IS_DREG ($4))
+ return yyerror ("Dregs expected");
+ else if (!valid_dreg_pair (&$8, $10))
+ return yyerror ("Bad dreg pair");
+ else
+ {
+ notethat ("dsp32alu: (dregs , dregs ) = BYTEUNPACK dregs_pair (aligndir)\n");
+ $$ = DSP32ALU (24, 0, &$2, &$4, &$8, 0, $11.r0, 0, 1);
+ }
+ }
+ | LPAREN REG COMMA REG RPAREN ASSIGN SEARCH REG LPAREN searchmod RPAREN
+ {
+ if (IS_DREG ($2) && IS_DREG ($4) && IS_DREG ($8))
+ {
+ notethat ("dsp32alu: (dregs , dregs ) = SEARCH dregs (searchmod)\n");
+ $$ = DSP32ALU (13, 0, &$2, &$4, &$8, 0, 0, 0, $10.r0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+ | REG ASSIGN A_ONE_DOT_L PLUS A_ONE_DOT_H COMMA
+ REG ASSIGN A_ZERO_DOT_L PLUS A_ZERO_DOT_H
+ {
+ if (IS_DREG ($1) && IS_DREG ($7))
+ {
+ notethat ("dsp32alu: dregs = A1.l + A1.h, dregs = A0.l + A0.h \n");
+ $$ = DSP32ALU (12, 0, &$1, &$7, 0, 0, 0, 0, 1);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+
+ | REG ASSIGN REG_A PLUS REG_A COMMA REG ASSIGN REG_A MINUS REG_A amod1
+ {
+ if (IS_DREG ($1) && IS_DREG ($7) && !REG_SAME ($3, $5)
+ && IS_A1 ($9) && !IS_A1 ($11))
+ {
+ notethat ("dsp32alu: dregs = A1 + A0 , dregs = A1 - A0 (amod1)\n");
+ $$ = DSP32ALU (17, 0, &$1, &$7, 0, 0, $12.s0, $12.x0, 0);
+
+ }
+ else if (IS_DREG ($1) && IS_DREG ($7) && !REG_SAME ($3, $5)
+ && !IS_A1 ($9) && IS_A1 ($11))
+ {
+ notethat ("dsp32alu: dregs = A0 + A1 , dregs = A0 - A1 (amod1)\n");
+ $$ = DSP32ALU (17, 0, &$1, &$7, 0, 0, $12.s0, $12.x0, 1);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN REG plus_minus REG COMMA REG ASSIGN REG plus_minus REG amod1
+ {
+ if ($4.r0 == $10.r0)
+ return yyerror ("Operators must differ");
+
+ if (IS_DREG ($1) && IS_DREG ($3) && IS_DREG ($5)
+ && REG_SAME ($3, $9) && REG_SAME ($5, $11))
+ {
+ notethat ("dsp32alu: dregs = dregs + dregs,"
+ "dregs = dregs - dregs (amod1)\n");
+ $$ = DSP32ALU (4, 0, &$1, &$7, &$3, &$5, $12.s0, $12.x0, 2);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+/* Bar Operations. */
+
+ | REG ASSIGN REG op_bar_op REG COMMA REG ASSIGN REG op_bar_op REG amod2
+ {
+ if (!REG_SAME ($3, $9) || !REG_SAME ($5, $11))
+ return yyerror ("Differing source registers");
+
+ if (!IS_DREG ($1) || !IS_DREG ($3) || !IS_DREG ($5) || !IS_DREG ($7))
+ return yyerror ("Dregs expected");
+
+
+ if ($4.r0 == 1 && $10.r0 == 2)
+ {
+ notethat ("dsp32alu: dregs = dregs .|. dregs , dregs = dregs .|. dregs (amod2)\n");
+ $$ = DSP32ALU (1, 1, &$1, &$7, &$3, &$5, $12.s0, $12.x0, $12.r0);
+ }
+ else if ($4.r0 == 0 && $10.r0 == 3)
+ {
+ notethat ("dsp32alu: dregs = dregs .|. dregs , dregs = dregs .|. dregs (amod2)\n");
+ $$ = DSP32ALU (1, 0, &$1, &$7, &$3, &$5, $12.s0, $12.x0, $12.r0);
+ }
+ else
+ return yyerror ("Bar operand mismatch");
+ }
+
+ | REG ASSIGN ABS REG vmod
+ {
+ int op;
+
+ if (IS_DREG ($1) && IS_DREG ($4))
+ {
+ if ($5.r0)
+ {
+ notethat ("dsp32alu: dregs = ABS dregs (v)\n");
+ op = 6;
+ }
+ else
+ {
+ /* Vector version of ABS. */
+ notethat ("dsp32alu: dregs = ABS dregs\n");
+ op = 7;
+ }
+ $$ = DSP32ALU (op, 0, 0, &$1, &$4, 0, 0, 0, 2);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+ | a_assign ABS REG_A
+ {
+ notethat ("dsp32alu: Ax = ABS Ax\n");
+ $$ = DSP32ALU (16, IS_A1 ($1), 0, 0, 0, 0, 0, 0, IS_A1 ($3));
+ }
+ | A_ZERO_DOT_L ASSIGN HALF_REG
+ {
+ if (IS_DREG_L ($3))
+ {
+ notethat ("dsp32alu: A0.l = reg_half\n");
+ $$ = DSP32ALU (9, IS_H ($3), 0, 0, &$3, 0, 0, 0, 0);
+ }
+ else
+ return yyerror ("A0.l = Rx.l expected");
+ }
+ | A_ONE_DOT_L ASSIGN HALF_REG
+ {
+ if (IS_DREG_L ($3))
+ {
+ notethat ("dsp32alu: A1.l = reg_half\n");
+ $$ = DSP32ALU (9, IS_H ($3), 0, 0, &$3, 0, 0, 0, 2);
+ }
+ else
+ return yyerror ("A1.l = Rx.l expected");
+ }
+
+ | REG ASSIGN c_align LPAREN REG COMMA REG RPAREN
+ {
+ if (IS_DREG ($1) && IS_DREG ($5) && IS_DREG ($7))
+ {
+ notethat ("dsp32shift: dregs = ALIGN8 (dregs , dregs )\n");
+ $$ = DSP32SHIFT (13, &$1, &$7, &$5, $3.r0, 0);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | REG ASSIGN BYTEOP1P LPAREN REG COLON expr COMMA REG COLON expr RPAREN byteop_mod
+ {
+ if (!IS_DREG ($1))
+ return yyerror ("Dregs expected");
+ else if (!valid_dreg_pair (&$5, $7))
+ return yyerror ("Bad dreg pair");
+ else if (!valid_dreg_pair (&$9, $11))
+ return yyerror ("Bad dreg pair");
+ else
+ {
+ notethat ("dsp32alu: dregs = BYTEOP1P (dregs_pair , dregs_pair ) (T)\n");
+ $$ = DSP32ALU (20, 0, 0, &$1, &$5, &$9, $13.s0, 0, $13.r0);
+ }
+ }
+ | REG ASSIGN BYTEOP1P LPAREN REG COLON expr COMMA REG COLON expr RPAREN
+ {
+ if (!IS_DREG ($1))
+ return yyerror ("Dregs expected");
+ else if (!valid_dreg_pair (&$5, $7))
+ return yyerror ("Bad dreg pair");
+ else if (!valid_dreg_pair (&$9, $11))
+ return yyerror ("Bad dreg pair");
+ else
+ {
+ notethat ("dsp32alu: dregs = BYTEOP1P (dregs_pair , dregs_pair ) (T)\n");
+ $$ = DSP32ALU (20, 0, 0, &$1, &$5, &$9, 0, 0, 0);
+ }
+ }
+
+ | REG ASSIGN BYTEOP2P LPAREN REG COLON expr COMMA REG COLON expr RPAREN
+ rnd_op
+ {
+ if (!IS_DREG ($1))
+ return yyerror ("Dregs expected");
+ else if (!valid_dreg_pair (&$5, $7))
+ return yyerror ("Bad dreg pair");
+ else if (!valid_dreg_pair (&$9, $11))
+ return yyerror ("Bad dreg pair");
+ else
+ {
+ notethat ("dsp32alu: dregs = BYTEOP2P (dregs_pair , dregs_pair ) (rnd_op)\n");
+ $$ = DSP32ALU (22, $13.r0, 0, &$1, &$5, &$9, $13.s0, $13.x0, $13.aop);
+ }
+ }
+
+ | REG ASSIGN BYTEOP2M LPAREN REG COLON expr COMMA REG COLON expr RPAREN
+ rnd_op
+ {
+ if (!IS_DREG ($1))
+ return yyerror ("Dregs expected");
+ else if (!valid_dreg_pair (&$5, $7))
+ return yyerror ("Bad dreg pair");
+ else if (!valid_dreg_pair (&$9, $11))
+ return yyerror ("Bad dreg pair");
+ else
+ {
+ notethat ("dsp32alu: dregs = BYTEOP2P (dregs_pair , dregs_pair ) (rnd_op)\n");
+ $$ = DSP32ALU (22, $13.r0, 0, &$1, &$5, &$9, $13.s0, 0, $13.x0);
+ }
+ }
+
+ | REG ASSIGN BYTEOP3P LPAREN REG COLON expr COMMA REG COLON expr RPAREN
+ b3_op
+ {
+ if (!IS_DREG ($1))
+ return yyerror ("Dregs expected");
+ else if (!valid_dreg_pair (&$5, $7))
+ return yyerror ("Bad dreg pair");
+ else if (!valid_dreg_pair (&$9, $11))
+ return yyerror ("Bad dreg pair");
+ else
+ {
+ notethat ("dsp32alu: dregs = BYTEOP3P (dregs_pair , dregs_pair ) (b3_op)\n");
+ $$ = DSP32ALU (23, $13.x0, 0, &$1, &$5, &$9, $13.s0, 0, 0);
+ }
+ }
+
+ | REG ASSIGN BYTEPACK LPAREN REG COMMA REG RPAREN
+ {
+ if (IS_DREG ($1) && IS_DREG ($5) && IS_DREG ($7))
+ {
+ notethat ("dsp32alu: dregs = BYTEPACK (dregs , dregs )\n");
+ $$ = DSP32ALU (24, 0, 0, &$1, &$5, &$7, 0, 0, 0);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | HALF_REG ASSIGN HALF_REG ASSIGN SIGN LPAREN HALF_REG RPAREN STAR
+ HALF_REG PLUS SIGN LPAREN HALF_REG RPAREN STAR HALF_REG
+ {
+ if (IS_HCOMPL ($1, $3) && IS_HCOMPL ($7, $14) && IS_HCOMPL ($10, $17))
+ {
+ notethat ("dsp32alu: dregs_hi = dregs_lo ="
+ "SIGN (dregs_hi) * dregs_hi + "
+ "SIGN (dregs_lo) * dregs_lo \n");
+
+ $$ = DSP32ALU (12, 0, 0, &$1, &$7, &$10, 0, 0, 0);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+ | REG ASSIGN REG plus_minus REG amod1
+ {
+ if (IS_DREG ($1) && IS_DREG ($3) && IS_DREG ($5))
+ {
+ if ($6.aop == 0)
+ {
+ /* No saturation flag specified, generate the 16 bit variant. */
+ notethat ("COMP3op: dregs = dregs +- dregs\n");
+ $$ = COMP3OP (&$1, &$3, &$5, $4.r0);
+ }
+ else
+ {
+ /* Saturation flag specified, generate the 32 bit variant. */
+ notethat ("dsp32alu: dregs = dregs +- dregs (amod1)\n");
+ $$ = DSP32ALU (4, 0, 0, &$1, &$3, &$5, $6.s0, $6.x0, $4.r0);
+ }
+ }
+ else
+ if (IS_PREG ($1) && IS_PREG ($3) && IS_PREG ($5) && $4.r0 == 0)
+ {
+ notethat ("COMP3op: pregs = pregs + pregs\n");
+ $$ = COMP3OP (&$1, &$3, &$5, 5);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+ | REG ASSIGN min_max LPAREN REG COMMA REG RPAREN vmod
+ {
+ int op;
+
+ if (IS_DREG ($1) && IS_DREG ($5) && IS_DREG ($7))
+ {
+ if ($9.r0)
+ op = 6;
+ else
+ op = 7;
+
+ notethat ("dsp32alu: dregs = {MIN|MAX} (dregs, dregs)\n");
+ $$ = DSP32ALU (op, 0, 0, &$1, &$5, &$7, 0, 0, $3.r0);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | a_assign MINUS REG_A
+ {
+ notethat ("dsp32alu: Ax = - Ax\n");
+ $$ = DSP32ALU (14, IS_A1 ($1), 0, 0, 0, 0, 0, 0, IS_A1 ($3));
+ }
+ | HALF_REG ASSIGN HALF_REG plus_minus HALF_REG amod1
+ {
+ notethat ("dsp32alu: dregs_lo = dregs_lo +- dregs_lo (amod1)\n");
+ $$ = DSP32ALU (2 | $4.r0, IS_H ($1), 0, &$1, &$3, &$5,
+ $6.s0, $6.x0, HL2 ($3, $5));
+ }
+ | a_assign a_assign expr
+ {
+ if (EXPR_VALUE ($3) == 0 && !REG_SAME ($1, $2))
+ {
+ notethat ("dsp32alu: A1 = A0 = 0\n");
+ $$ = DSP32ALU (8, 0, 0, 0, 0, 0, 0, 0, 2);
+ }
+ else
+ return yyerror ("Bad value, 0 expected");
+ }
+
+ /* Saturating. */
+ | a_assign REG_A LPAREN S RPAREN
+ {
+ if (REG_SAME ($1, $2))
+ {
+ notethat ("dsp32alu: Ax = Ax (S)\n");
+ $$ = DSP32ALU (8, 0, 0, 0, 0, 0, 1, 0, IS_A1 ($1));
+ }
+ else
+ return yyerror ("Registers must be equal");
+ }
+
+ | HALF_REG ASSIGN REG LPAREN RND RPAREN
+ {
+ if (IS_DREG ($3))
+ {
+ notethat ("dsp32alu: dregs_half = dregs (RND)\n");
+ $$ = DSP32ALU (12, IS_H ($1), 0, &$1, &$3, 0, 0, 0, 3);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | HALF_REG ASSIGN REG plus_minus REG LPAREN RND12 RPAREN
+ {
+ if (IS_DREG ($3) && IS_DREG ($5))
+ {
+ notethat ("dsp32alu: dregs_half = dregs (+-) dregs (RND12)\n");
+ $$ = DSP32ALU (5, IS_H ($1), 0, &$1, &$3, &$5, 0, 0, $4.r0);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | HALF_REG ASSIGN REG plus_minus REG LPAREN RND20 RPAREN
+ {
+ if (IS_DREG ($3) && IS_DREG ($5))
+ {
+ notethat ("dsp32alu: dregs_half = dregs -+ dregs (RND20)\n");
+ $$ = DSP32ALU (5, IS_H ($1), 0, &$1, &$3, &$5, 0, 1, $4.r0 | 2);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | a_assign REG_A
+ {
+ if (!REG_SAME ($1, $2))
+ {
+ notethat ("dsp32alu: An = Am\n");
+ $$ = DSP32ALU (8, 0, 0, 0, 0, 0, IS_A1 ($1), 0, 3);
+ }
+ else
+ return yyerror ("Accu reg arguments must differ");
+ }
+
+ | a_assign REG
+ {
+ if (IS_DREG ($2))
+ {
+ notethat ("dsp32alu: An = dregs\n");
+ $$ = DSP32ALU (9, 0, 0, 0, &$2, 0, 1, 0, IS_A1 ($1) << 1);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | REG ASSIGN HALF_REG xpmod
+ {
+ if (!IS_H ($3))
+ {
+ if ($1.regno == REG_A0x && IS_DREG ($3))
+ {
+ notethat ("dsp32alu: A0.x = dregs_lo\n");
+ $$ = DSP32ALU (9, 0, 0, 0, &$3, 0, 0, 0, 1);
+ }
+ else if ($1.regno == REG_A1x && IS_DREG ($3))
+ {
+ notethat ("dsp32alu: A1.x = dregs_lo\n");
+ $$ = DSP32ALU (9, 0, 0, 0, &$3, 0, 0, 0, 3);
+ }
+ else if (IS_DREG ($1) && IS_DREG ($3))
+ {
+ notethat ("ALU2op: dregs = dregs_lo\n");
+ $$ = ALU2OP (&$1, &$3, 10 | ($4.r0 ? 0: 1));
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+ else
+ return yyerror ("Low reg expected");
+ }
+
+ | HALF_REG ASSIGN expr
+ {
+ notethat ("LDIMMhalf: pregs_half = imm16\n");
+ if (!IS_IMM ($3, 16) && !IS_UIMM ($3, 16))
+ return yyerror ("Constant out of range");
+ $$ = LDIMMHALF_R (&$1, IS_H ($1), 0, 0, $3);
+ }
+
+ | a_assign expr
+ {
+ notethat ("dsp32alu: An = 0\n");
+
+ if (imm7 ($2) != 0)
+ return yyerror ("0 expected");
+
+ $$ = DSP32ALU (8, 0, 0, 0, 0, 0, 0, 0, IS_A1 ($1));
+ }
+
+ | REG ASSIGN expr xpmod1
+ {
+ if ($4.r0 == 0)
+ {
+ /* 7 bit immediate value if possible.
+ We will check for that constant value for efficiency
+ If it goes to reloc, it will be 16 bit. */
+ if (IS_CONST ($3) && IS_IMM ($3, 7) && (IS_DREG ($1) || IS_PREG ($1)))
+ {
+ /* if the expr is a relocation, generate it. */
+ if (IS_DREG ($1) && IS_IMM ($3, 7))
+ {
+ notethat ("COMPI2opD: dregs = imm7 (x) \n");
+ $$ = COMPI2OPD (&$1, imm7 ($3), 0);
+ }
+ else if (IS_PREG ($1) && IS_IMM ($3, 7))
+ {
+ notethat ("COMPI2opP: pregs = imm7 (x)\n");
+ $$ = COMPI2OPP (&$1, imm7 ($3), 0);
+ }
+ else
+ return yyerror ("Bad register or value for assigment");
+ }
+ else
+ {
+ notethat ("LDIMMhalf: regs = luimm16 (x)\n");
+ /* reg, H, S, Z. */
+ $$ = LDIMMHALF_R5 (&$1, 0, 1, 0, $3);
+ }
+ }
+ else
+ {
+ /* (z) There is no 7 bit zero extended instruction.
+ If the expr is a relocation, generate it. */
+ notethat ("LDIMMhalf: regs = luimm16 (x)\n");
+ /* reg, H, S, Z. */
+ $$ = LDIMMHALF_R5 (&$1, 0, 0, 1, $3);
+ }
+ }
+
+ | HALF_REG ASSIGN REG
+ {
+ if (IS_H ($1))
+ return yyerror ("Low reg expected");
+
+ if (IS_DREG ($1) && $3.regno == REG_A0x)
+ {
+ notethat ("dsp32alu: dregs_lo = A0.x\n");
+ $$ = DSP32ALU (10, 0, 0, &$1, 0, 0, 0, 0, 0);
+ }
+ else if (IS_DREG ($1) && $3.regno == REG_A1x)
+ {
+ notethat ("dsp32alu: dregs_lo = A1.x\n");
+ $$ = DSP32ALU (10, 0, 0, &$1, 0, 0, 0, 0, 1);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN REG op_bar_op REG amod0
+ {
+ if (IS_DREG ($1) && IS_DREG ($3) && IS_DREG ($5))
+ {
+ notethat ("dsp32alu: dregs = dregs .|. dregs (amod0)\n");
+ $$ = DSP32ALU (0, 0, 0, &$1, &$3, &$5, $6.s0, $6.x0, $4.r0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN BYTE_DREG xpmod
+ {
+ if (IS_DREG ($1) && IS_DREG ($3))
+ {
+ notethat ("ALU2op: dregs = dregs_byte\n");
+ $$ = ALU2OP (&$1, &$3, 12 | ($4.r0 ? 0: 1));
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | a_assign ABS REG_A COMMA a_assign ABS REG_A
+ {
+ if (REG_SAME ($1, $3) && REG_SAME ($5, $7) && !REG_SAME ($1, $5))
+ {
+ notethat ("dsp32alu: A1 = ABS A1 , A0 = ABS A0\n");
+ $$ = DSP32ALU (16, 0, 0, 0, 0, 0, 0, 0, 3);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | a_assign MINUS REG_A COMMA a_assign MINUS REG_A
+ {
+ if (REG_SAME ($1, $3) && REG_SAME ($5, $7) && !REG_SAME ($1, $5))
+ {
+ notethat ("dsp32alu: A1 = - A1 , A0 = - A0\n");
+ $$ = DSP32ALU (14, 0, 0, 0, 0, 0, 0, 0, 3);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | a_minusassign REG_A w32_or_nothing
+ {
+ if (!IS_A1 ($1) && IS_A1 ($2))
+ {
+ notethat ("dsp32alu: A0 -= A1\n");
+ $$ = DSP32ALU (11, 0, 0, 0, 0, 0, $3.r0, 0, 3);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG _MINUS_ASSIGN expr
+ {
+ if (IS_IREG ($1) && EXPR_VALUE ($3) == 4)
+ {
+ notethat ("dagMODik: iregs -= 4\n");
+ $$ = DAGMODIK (&$1, 3);
+ }
+ else if (IS_IREG ($1) && EXPR_VALUE ($3) == 2)
+ {
+ notethat ("dagMODik: iregs -= 2\n");
+ $$ = DAGMODIK (&$1, 1);
+ }
+ else
+ return yyerror ("Register or value mismatch");
+ }
+
+ | REG _PLUS_ASSIGN REG LPAREN BREV RPAREN
+ {
+ if (IS_IREG ($1) && IS_MREG ($3))
+ {
+ notethat ("dagMODim: iregs += mregs (opt_brev)\n");
+ /* i, m, op, br. */
+ $$ = DAGMODIM (&$1, &$3, 0, 1);
+ }
+ else if (IS_PREG ($1) && IS_PREG ($3))
+ {
+ notethat ("PTR2op: pregs += pregs (BREV )\n");
+ $$ = PTR2OP (&$1, &$3, 5);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG _MINUS_ASSIGN REG
+ {
+ if (IS_IREG ($1) && IS_MREG ($3))
+ {
+ notethat ("dagMODim: iregs -= mregs\n");
+ $$ = DAGMODIM (&$1, &$3, 1, 0);
+ }
+ else if (IS_PREG ($1) && IS_PREG ($3))
+ {
+ notethat ("PTR2op: pregs -= pregs\n");
+ $$ = PTR2OP (&$1, &$3, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG_A _PLUS_ASSIGN REG_A w32_or_nothing
+ {
+ if (!IS_A1 ($1) && IS_A1 ($3))
+ {
+ notethat ("dsp32alu: A0 += A1 (W32)\n");
+ $$ = DSP32ALU (11, 0, 0, 0, 0, 0, $4.r0, 0, 2);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG _PLUS_ASSIGN REG
+ {
+ if (IS_IREG ($1) && IS_MREG ($3))
+ {
+ notethat ("dagMODim: iregs += mregs\n");
+ $$ = DAGMODIM (&$1, &$3, 0, 0);
+ }
+ else
+ return yyerror ("iregs += mregs expected");
+ }
+
+ | REG _PLUS_ASSIGN expr
+ {
+ if (IS_IREG ($1))
+ {
+ if (EXPR_VALUE ($3) == 4)
+ {
+ notethat ("dagMODik: iregs += 4\n");
+ $$ = DAGMODIK (&$1, 2);
+ }
+ else if (EXPR_VALUE ($3) == 2)
+ {
+ notethat ("dagMODik: iregs += 2\n");
+ $$ = DAGMODIK (&$1, 0);
+ }
+ else
+ return yyerror ("iregs += [ 2 | 4 ");
+ }
+ else if (IS_PREG ($1) && IS_IMM ($3, 7))
+ {
+ notethat ("COMPI2opP: pregs += imm7\n");
+ $$ = COMPI2OPP (&$1, imm7 ($3), 1);
+ }
+ else if (IS_DREG ($1) && IS_IMM ($3, 7))
+ {
+ notethat ("COMPI2opD: dregs += imm7\n");
+ $$ = COMPI2OPD (&$1, imm7 ($3), 1);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG _STAR_ASSIGN REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($3))
+ {
+ notethat ("ALU2op: dregs *= dregs\n");
+ $$ = ALU2OP (&$1, &$3, 3);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | SAA LPAREN REG COLON expr COMMA REG COLON expr RPAREN aligndir
+ {
+ if (!valid_dreg_pair (&$3, $5))
+ return yyerror ("Bad dreg pair");
+ else if (!valid_dreg_pair (&$7, $9))
+ return yyerror ("Bad dreg pair");
+ else
+ {
+ notethat ("dsp32alu: SAA (dregs_pair , dregs_pair ) (aligndir)\n");
+ $$ = DSP32ALU (18, 0, 0, 0, &$3, &$7, $11.r0, 0, 0);
+ }
+ }
+
+ | a_assign REG_A LPAREN S RPAREN COMMA a_assign REG_A LPAREN S RPAREN
+ {
+ if (REG_SAME ($1, $2) && REG_SAME ($7, $8) && !REG_SAME ($1, $7))
+ {
+ notethat ("dsp32alu: A1 = A1 (S) , A0 = A0 (S)\n");
+ $$ = DSP32ALU (8, 0, 0, 0, 0, 0, 1, 0, 2);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN LPAREN REG PLUS REG RPAREN LESS_LESS expr
+ {
+ if (IS_DREG ($1) && IS_DREG ($4) && IS_DREG ($6)
+ && REG_SAME ($1, $4))
+ {
+ if (EXPR_VALUE ($9) == 1)
+ {
+ notethat ("ALU2op: dregs = (dregs + dregs) << 1\n");
+ $$ = ALU2OP (&$1, &$6, 4);
+ }
+ else if (EXPR_VALUE ($9) == 2)
+ {
+ notethat ("ALU2op: dregs = (dregs + dregs) << 2\n");
+ $$ = ALU2OP (&$1, &$6, 5);
+ }
+ else
+ return yyerror ("Bad shift value");
+ }
+ else if (IS_PREG ($1) && IS_PREG ($4) && IS_PREG ($6)
+ && REG_SAME ($1, $4))
+ {
+ if (EXPR_VALUE ($9) == 1)
+ {
+ notethat ("PTR2op: pregs = (pregs + pregs) << 1\n");
+ $$ = PTR2OP (&$1, &$6, 6);
+ }
+ else if (EXPR_VALUE ($9) == 2)
+ {
+ notethat ("PTR2op: pregs = (pregs + pregs) << 2\n");
+ $$ = PTR2OP (&$1, &$6, 7);
+ }
+ else
+ return yyerror ("Bad shift value");
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+/* COMP3 CCFLAG. */
+ | REG ASSIGN REG BAR REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($3) && IS_DREG ($5))
+ {
+ notethat ("COMP3op: dregs = dregs | dregs\n");
+ $$ = COMP3OP (&$1, &$3, &$5, 3);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+ | REG ASSIGN REG CARET REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($3) && IS_DREG ($5))
+ {
+ notethat ("COMP3op: dregs = dregs ^ dregs\n");
+ $$ = COMP3OP (&$1, &$3, &$5, 4);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+ | REG ASSIGN REG PLUS LPAREN REG LESS_LESS expr RPAREN
+ {
+ if (IS_PREG ($1) && IS_PREG ($3) && IS_PREG ($6))
+ {
+ if (EXPR_VALUE ($8) == 1)
+ {
+ notethat ("COMP3op: pregs = pregs + (pregs << 1)\n");
+ $$ = COMP3OP (&$1, &$3, &$6, 6);
+ }
+ else if (EXPR_VALUE ($8) == 2)
+ {
+ notethat ("COMP3op: pregs = pregs + (pregs << 2)\n");
+ $$ = COMP3OP (&$1, &$3, &$6, 7);
+ }
+ else
+ return yyerror ("Bad shift value");
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+ | CCREG ASSIGN REG_A _ASSIGN_ASSIGN REG_A
+ {
+ if (!REG_SAME ($3, $5))
+ {
+ notethat ("CCflag: CC = A0 == A1\n");
+ $$ = CCFLAG (0, 0, 5, 0, 0);
+ }
+ else
+ return yyerror ("CC register expected");
+ }
+ | CCREG ASSIGN REG_A LESS_THAN REG_A
+ {
+ if (!REG_SAME ($3, $5))
+ {
+ notethat ("CCflag: CC = A0 < A1\n");
+ $$ = CCFLAG (0, 0, 6, 0, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+ | CCREG ASSIGN REG LESS_THAN REG iu_or_nothing
+ {
+ if (REG_CLASS($3) == REG_CLASS($5))
+ {
+ notethat ("CCflag: CC = dpregs < dpregs\n");
+ $$ = CCFLAG (&$3, $5.regno & CODE_MASK, $6.r0, 0, IS_PREG ($3) ? 1 : 0);
+ }
+ else
+ return yyerror ("Compare only of same register class");
+ }
+ | CCREG ASSIGN REG LESS_THAN expr iu_or_nothing
+ {
+ if (($6.r0 == 1 && IS_IMM ($5, 3))
+ || ($6.r0 == 3 && IS_UIMM ($5, 3)))
+ {
+ notethat ("CCflag: CC = dpregs < (u)imm3\n");
+ $$ = CCFLAG (&$3, imm3 ($5), $6.r0, 1, IS_PREG ($3) ? 1 : 0);
+ }
+ else
+ return yyerror ("Bad constant value");
+ }
+ | CCREG ASSIGN REG _ASSIGN_ASSIGN REG
+ {
+ if (REG_CLASS($3) == REG_CLASS($5))
+ {
+ notethat ("CCflag: CC = dpregs == dpregs\n");
+ $$ = CCFLAG (&$3, $5.regno & CODE_MASK, 0, 0, IS_PREG ($3) ? 1 : 0);
+ }
+ }
+ | CCREG ASSIGN REG _ASSIGN_ASSIGN expr
+ {
+ if (IS_IMM ($5, 3))
+ {
+ notethat ("CCflag: CC = dpregs == imm3\n");
+ $$ = CCFLAG (&$3, imm3 ($5), 0, 1, IS_PREG ($3) ? 1 : 0);
+ }
+ else
+ return yyerror ("Bad constant range");
+ }
+ | CCREG ASSIGN REG_A _LESS_THAN_ASSIGN REG_A
+ {
+ if (!REG_SAME ($3, $5))
+ {
+ notethat ("CCflag: CC = A0 <= A1\n");
+ $$ = CCFLAG (0, 0, 7, 0, 0);
+ }
+ else
+ return yyerror ("CC register expected");
+ }
+ | CCREG ASSIGN REG _LESS_THAN_ASSIGN REG iu_or_nothing
+ {
+ if (REG_CLASS($3) == REG_CLASS($5))
+ {
+ notethat ("CCflag: CC = pregs <= pregs (..)\n");
+ $$ = CCFLAG (&$3, $5.regno & CODE_MASK,
+ 1 + $6.r0, 0, IS_PREG ($3) ? 1 : 0);
+ }
+ else
+ return yyerror ("Compare only of same register class");
+ }
+ | CCREG ASSIGN REG _LESS_THAN_ASSIGN expr iu_or_nothing
+ {
+ if (($6.r0 == 1 && IS_IMM ($5, 3))
+ || ($6.r0 == 3 && IS_UIMM ($5, 3)))
+ {
+ if (IS_DREG ($3))
+ {
+ notethat ("CCflag: CC = dregs <= (u)imm3\n");
+ /* x y opc I G */
+ $$ = CCFLAG (&$3, imm3 ($5), 1 + $6.r0, 1, 0);
+ }
+ else if (IS_PREG ($3))
+ {
+ notethat ("CCflag: CC = pregs <= (u)imm3\n");
+ /* x y opc I G */
+ $$ = CCFLAG (&$3, imm3 ($5), 1 + $6.r0, 1, 1);
+ }
+ else
+ return yyerror ("Dreg or Preg expected");
+ }
+ else
+ return yyerror ("Bad constant value");
+ }
+
+ | REG ASSIGN REG AMPERSAND REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($3) && IS_DREG ($5))
+ {
+ notethat ("COMP3op: dregs = dregs & dregs\n");
+ $$ = COMP3OP (&$1, &$3, &$5, 2);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | ccstat
+ {
+ notethat ("CC2stat operation\n");
+ $$ = bfin_gen_cc2stat ($1.r0, $1.x0, $1.s0);
+ }
+
+ | REG ASSIGN REG
+ {
+ if (IS_ALLREG ($1) && IS_ALLREG ($3))
+ {
+ notethat ("REGMV: allregs = allregs\n");
+ $$ = bfin_gen_regmv (&$3, &$1);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | CCREG ASSIGN REG
+ {
+ if (IS_DREG ($3))
+ {
+ notethat ("CC2dreg: CC = dregs\n");
+ $$ = bfin_gen_cc2dreg (1, &$3);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN CCREG
+ {
+ if (IS_DREG ($1))
+ {
+ notethat ("CC2dreg: dregs = CC\n");
+ $$ = bfin_gen_cc2dreg (0, &$1);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | CCREG _ASSIGN_BANG CCREG
+ {
+ notethat ("CC2dreg: CC =! CC\n");
+ $$ = bfin_gen_cc2dreg (3, 0);
+ }
+
+/* DSPMULT. */
+
+ | HALF_REG ASSIGN multiply_halfregs opt_mode
+ {
+ notethat ("dsp32mult: dregs_half = multiply_halfregs (opt_mode)\n");
+
+ if (!IS_H ($1) && $4.MM)
+ return yyerror ("(M) not allowed with MAC0");
+
+ if (IS_H ($1))
+ {
+ $$ = DSP32MULT (0, $4.MM, $4.mod, 1, 0,
+ IS_H ($3.s0), IS_H ($3.s1), 0, 0,
+ &$1, 0, &$3.s0, &$3.s1, 0);
+ }
+ else
+ {
+ $$ = DSP32MULT (0, 0, $4.mod, 0, 0,
+ 0, 0, IS_H ($3.s0), IS_H ($3.s1),
+ &$1, 0, &$3.s0, &$3.s1, 1);
+ }
+ }
+
+ | REG ASSIGN multiply_halfregs opt_mode
+ {
+ /* Odd registers can use (M). */
+ if (!IS_DREG ($1))
+ return yyerror ("Dreg expected");
+
+ if (!IS_EVEN ($1))
+ {
+ notethat ("dsp32mult: dregs = multiply_halfregs (opt_mode)\n");
+
+ $$ = DSP32MULT (0, $4.MM, $4.mod, 1, 1,
+ IS_H ($3.s0), IS_H ($3.s1), 0, 0,
+ &$1, 0, &$3.s0, &$3.s1, 0);
+ }
+ else if ($4.MM == 0)
+ {
+ notethat ("dsp32mult: dregs = multiply_halfregs opt_mode\n");
+ $$ = DSP32MULT (0, 0, $4.mod, 0, 1,
+ 0, 0, IS_H ($3.s0), IS_H ($3.s1),
+ &$1, 0, &$3.s0, &$3.s1, 1);
+ }
+ else
+ return yyerror ("Register or mode mismatch");
+ }
+
+ | HALF_REG ASSIGN multiply_halfregs opt_mode COMMA
+ HALF_REG ASSIGN multiply_halfregs opt_mode
+ {
+ if (!IS_DREG ($1) || !IS_DREG ($6))
+ return yyerror ("Dregs expected");
+
+ if (check_multiply_halfregs (&$3, &$8) < 0)
+ return -1;
+
+ if (IS_H ($1) && !IS_H ($6))
+ {
+ notethat ("dsp32mult: dregs_hi = multiply_halfregs mxd_mod, "
+ "dregs_lo = multiply_halfregs opt_mode\n");
+ $$ = DSP32MULT (0, $4.MM, $9.mod, 1, 0,
+ IS_H ($3.s0), IS_H ($3.s1), IS_H ($8.s0), IS_H ($8.s1),
+ &$1, 0, &$3.s0, &$3.s1, 1);
+ }
+ else if (!IS_H ($1) && IS_H ($6) && $4.MM == 0)
+ {
+ $$ = DSP32MULT (0, $9.MM, $9.mod, 1, 0,
+ IS_H ($8.s0), IS_H ($8.s1), IS_H ($3.s0), IS_H ($3.s1),
+ &$1, 0, &$3.s0, &$3.s1, 1);
+ }
+ else
+ return yyerror ("Multfunc Register or mode mismatch");
+ }
+
+ | REG ASSIGN multiply_halfregs opt_mode COMMA REG ASSIGN multiply_halfregs opt_mode
+ {
+ if (!IS_DREG ($1) || !IS_DREG ($6))
+ return yyerror ("Dregs expected");
+
+ if (check_multiply_halfregs (&$3, &$8) < 0)
+ return -1;
+
+ notethat ("dsp32mult: dregs = multiply_halfregs mxd_mod, "
+ "dregs = multiply_halfregs opt_mode\n");
+ if (IS_EVEN ($1))
+ {
+ if ($6.regno - $1.regno != 1 || $4.MM != 0)
+ return yyerror ("Dest registers or mode mismatch");
+
+ /* op1 MM mmod */
+ $$ = DSP32MULT (0, 0, $9.mod, 1, 1,
+ IS_H ($8.s0), IS_H ($8.s1), IS_H ($3.s0), IS_H ($3.s1),
+ &$1, 0, &$3.s0, &$3.s1, 1);
+
+ }
+ else
+ {
+ if ($1.regno - $6.regno != 1)
+ return yyerror ("Dest registers mismatch");
+
+ $$ = DSP32MULT (0, $9.MM, $9.mod, 1, 1,
+ IS_H ($3.s0), IS_H ($3.s1), IS_H ($8.s0), IS_H ($8.s1),
+ &$1, 0, &$3.s0, &$3.s1, 1);
+ }
+ }
+
+\f
+/* SHIFTs. */
+ | a_assign ASHIFT REG_A BY HALF_REG
+ {
+ if (!REG_SAME ($1, $3))
+ return yyerror ("Aregs must be same");
+
+ if (IS_DREG ($5) && !IS_H ($5))
+ {
+ notethat ("dsp32shift: A0 = ASHIFT A0 BY dregs_lo\n");
+ $$ = DSP32SHIFT (3, 0, &$5, 0, 0, IS_A1 ($1));
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | HALF_REG ASSIGN ASHIFT HALF_REG BY HALF_REG smod
+ {
+ if (IS_DREG ($6) && !IS_H ($6))
+ {
+ notethat ("dsp32shift: dregs_half = ASHIFT dregs_half BY dregs_lo\n");
+ $$ = DSP32SHIFT (0, &$1, &$6, &$4, $7.s0, HL2 ($1, $4));
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | a_assign REG_A LESS_LESS expr
+ {
+ if (!REG_SAME ($1, $2))
+ return yyerror ("Aregs must be same");
+
+ if (IS_UIMM ($4, 5))
+ {
+ notethat ("dsp32shiftimm: A0 = A0 << uimm5\n");
+ $$ = DSP32SHIFTIMM (3, 0, imm5 ($4), 0, 0, IS_A1 ($1));
+ }
+ else
+ return yyerror ("Bad shift value");
+ }
+
+ | REG ASSIGN REG LESS_LESS expr vsmod
+ {
+ if (IS_DREG ($1) && IS_DREG ($3) && IS_UIMM ($5, 5))
+ {
+ if ($6.r0)
+ {
+ /* Vector? */
+ notethat ("dsp32shiftimm: dregs = dregs << expr (V, .)\n");
+ $$ = DSP32SHIFTIMM (1, &$1, imm4 ($5), &$3, $6.s0 ? 1 : 2, 0);
+ }
+ else
+ {
+ notethat ("dsp32shiftimm: dregs = dregs << uimm5 (.)\n");
+ $$ = DSP32SHIFTIMM (2, &$1, imm6 ($5), &$3, $6.s0 ? 1 : 2, 0);
+ }
+ }
+ else if ($6.s0 == 0 && IS_PREG ($1) && IS_PREG ($3))
+ {
+ if (EXPR_VALUE ($5) == 2)
+ {
+ notethat ("PTR2op: pregs = pregs << 2\n");
+ $$ = PTR2OP (&$1, &$3, 1);
+ }
+ else if (EXPR_VALUE ($5) == 1)
+ {
+ notethat ("COMP3op: pregs = pregs << 1\n");
+ $$ = COMP3OP (&$1, &$3, &$3, 5);
+ }
+ else
+ return yyerror ("Bad shift value");
+ }
+ else
+ return yyerror ("Bad shift value or register");
+ }
+ | HALF_REG ASSIGN HALF_REG LESS_LESS expr
+ {
+ if (IS_UIMM ($5, 4))
+ {
+ notethat ("dsp32shiftimm: dregs_half = dregs_half << uimm4\n");
+ $$ = DSP32SHIFTIMM (0x0, &$1, imm5 ($5), &$3, 2, HL2 ($1, $3));
+ }
+ else
+ return yyerror ("Bad shift value");
+ }
+ | HALF_REG ASSIGN HALF_REG LESS_LESS expr smod
+ {
+ if (IS_UIMM ($5, 4))
+ {
+ notethat ("dsp32shiftimm: dregs_half = dregs_half << uimm4\n");
+ $$ = DSP32SHIFTIMM (0x0, &$1, imm5 ($5), &$3, $6.s0, HL2 ($1, $3));
+ }
+ else
+ return yyerror ("Bad shift value");
+ }
+ | REG ASSIGN ASHIFT REG BY HALF_REG vsmod
+ {
+ int op;
+
+ if (IS_DREG ($1) && IS_DREG ($4) && IS_DREG ($6) && !IS_H ($6))
+ {
+ if ($7.r0)
+ {
+ op = 1;
+ notethat ("dsp32shift: dregs = ASHIFT dregs BY "
+ "dregs_lo (V, .)\n");
+ }
+ else
+ {
+
+ op = 2;
+ notethat ("dsp32shift: dregs = ASHIFT dregs BY dregs_lo (.)\n");
+ }
+ $$ = DSP32SHIFT (op, &$1, &$6, &$4, $7.s0, 0);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+/* EXPADJ. */
+ | HALF_REG ASSIGN EXPADJ LPAREN REG COMMA HALF_REG RPAREN vmod
+ {
+ if (IS_DREG_L ($1) && IS_DREG_L ($5) && IS_DREG_L ($7))
+ {
+ notethat ("dsp32shift: dregs_lo = EXPADJ (dregs , dregs_lo )\n");
+ $$ = DSP32SHIFT (7, &$1, &$7, &$5, $9.r0, 0);
+ }
+ else
+ return yyerror ("Bad shift value or register");
+ }
+
+
+ | HALF_REG ASSIGN EXPADJ LPAREN HALF_REG COMMA HALF_REG RPAREN
+ {
+ if (IS_DREG_L ($1) && IS_DREG_L ($5) && IS_DREG_L ($7))
+ {
+ notethat ("dsp32shift: dregs_lo = EXPADJ (dregs_lo, dregs_lo)\n");
+ $$ = DSP32SHIFT (7, &$1, &$7, &$5, 2, 0);
+ }
+ else if (IS_DREG_L ($1) && IS_DREG_H ($5) && IS_DREG_L ($7))
+ {
+ notethat ("dsp32shift: dregs_lo = EXPADJ (dregs_hi, dregs_lo)\n");
+ $$ = DSP32SHIFT (7, &$1, &$7, &$5, 3, 0);
+ }
+ else
+ return yyerror ("Bad shift value or register");
+ }
+
+/* DEPOSIT. */
+
+ | REG ASSIGN DEPOSIT LPAREN REG COMMA REG RPAREN
+ {
+ if (IS_DREG ($1) && IS_DREG ($5) && IS_DREG ($7))
+ {
+ notethat ("dsp32shift: dregs = DEPOSIT (dregs , dregs )\n");
+ $$ = DSP32SHIFT (10, &$1, &$7, &$5, 2, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN DEPOSIT LPAREN REG COMMA REG RPAREN LPAREN X RPAREN
+ {
+ if (IS_DREG ($1) && IS_DREG ($5) && IS_DREG ($7))
+ {
+ notethat ("dsp32shift: dregs = DEPOSIT (dregs , dregs ) (X)\n");
+ $$ = DSP32SHIFT (10, &$1, &$7, &$5, 3, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN EXTRACT LPAREN REG COMMA HALF_REG RPAREN xpmod
+ {
+ if (IS_DREG ($1) && IS_DREG ($5) && IS_DREG_L ($7))
+ {
+ notethat ("dsp32shift: dregs = EXTRACT (dregs, dregs_lo ) (.)\n");
+ $$ = DSP32SHIFT (10, &$1, &$7, &$5, $9.r0, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | a_assign REG_A _GREATER_GREATER_GREATER expr
+ {
+ if (!REG_SAME ($1, $2))
+ return yyerror ("Aregs must be same");
+
+ if (IS_UIMM ($4, 5))
+ {
+ notethat ("dsp32shiftimm: Ax = Ax >>> uimm5\n");
+ $$ = DSP32SHIFTIMM (3, 0, -imm6 ($4), 0, 0, IS_A1 ($1));
+ }
+ else
+ return yyerror ("Shift value range error");
+ }
+ | a_assign LSHIFT REG_A BY HALF_REG
+ {
+ if (REG_SAME ($1, $3) && IS_DREG_L ($5))
+ {
+ notethat ("dsp32shift: Ax = LSHIFT Ax BY dregs_lo\n");
+ $$ = DSP32SHIFT (3, 0, &$5, 0, 1, IS_A1 ($1));
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | HALF_REG ASSIGN LSHIFT HALF_REG BY HALF_REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($4) && IS_DREG_L ($6))
+ {
+ notethat ("dsp32shift: dregs_lo = LSHIFT dregs_hi BY dregs_lo\n");
+ $$ = DSP32SHIFT (0, &$1, &$6, &$4, 2, HL2 ($1, $4));
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN LSHIFT REG BY HALF_REG vmod
+ {
+ if (IS_DREG ($1) && IS_DREG ($4) && IS_DREG_L ($6))
+ {
+ notethat ("dsp32shift: dregs = LSHIFT dregs BY dregs_lo (V )\n");
+ $$ = DSP32SHIFT ($7.r0 ? 1: 2, &$1, &$6, &$4, 2, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN SHIFT REG BY HALF_REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($4) && IS_DREG_L ($6))
+ {
+ notethat ("dsp32shift: dregs = SHIFT dregs BY dregs_lo\n");
+ $$ = DSP32SHIFT (2, &$1, &$6, &$4, 2, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | a_assign REG_A GREATER_GREATER expr
+ {
+ if (REG_SAME ($1, $2) && IS_IMM ($4, 6) >= 0)
+ {
+ notethat ("dsp32shiftimm: Ax = Ax >> imm6\n");
+ $$ = DSP32SHIFTIMM (3, 0, -imm6 ($4), 0, 1, IS_A1 ($1));
+ }
+ else
+ return yyerror ("Accu register expected");
+ }
+
+ | REG ASSIGN REG GREATER_GREATER expr vmod
+ {
+ if ($6.r0 == 1)
+ {
+ if (IS_DREG ($1) && IS_DREG ($3) && IS_UIMM ($5, 5))
+ {
+ notethat ("dsp32shiftimm: dregs = dregs >> uimm5 (V)\n");
+ $$ = DSP32SHIFTIMM (1, &$1, -uimm5 ($5), &$3, 2, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+ else
+ {
+ if (IS_DREG ($1) && IS_DREG ($3) && IS_UIMM ($5, 5))
+ {
+ notethat ("dsp32shiftimm: dregs = dregs >> uimm5\n");
+ $$ = DSP32SHIFTIMM (2, &$1, -imm6 ($5), &$3, 2, 0);
+ }
+ else if (IS_PREG ($1) && IS_PREG ($3) && EXPR_VALUE ($5) == 2)
+ {
+ notethat ("PTR2op: pregs = pregs >> 2\n");
+ $$ = PTR2OP (&$1, &$3, 3);
+ }
+ else if (IS_PREG ($1) && IS_PREG ($3) && EXPR_VALUE ($5) == 1)
+ {
+ notethat ("PTR2op: pregs = pregs >> 1\n");
+ $$ = PTR2OP (&$1, &$3, 4);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+ }
+ | HALF_REG ASSIGN HALF_REG GREATER_GREATER expr
+ {
+ if (IS_UIMM ($5, 5))
+ {
+ notethat ("dsp32shiftimm: dregs_half = dregs_half >> uimm5\n");
+ $$ = DSP32SHIFTIMM (0, &$1, -uimm5 ($5), &$3, 2, HL2 ($1, $3));
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+ | HALF_REG ASSIGN HALF_REG _GREATER_GREATER_GREATER expr smod
+ {
+ if (IS_UIMM ($5, 5))
+ {
+ notethat ("dsp32shiftimm: dregs_half = dregs_half >>> uimm5\n");
+ $$ = DSP32SHIFTIMM (0, &$1, -uimm5 ($5), &$3,
+ $6.s0, HL2 ($1, $3));
+ }
+ else
+ return yyerror ("Register or modifier mismatch");
+ }
+
+
+ | REG ASSIGN REG _GREATER_GREATER_GREATER expr vsmod
+ {
+ if (IS_DREG ($1) && IS_DREG ($3) && IS_UIMM ($5, 5))
+ {
+ if ($6.r0)
+ {
+ /* Vector? */
+ notethat ("dsp32shiftimm: dregs = dregs >>> uimm5 (V, .)\n");
+ $$ = DSP32SHIFTIMM (1, &$1, -uimm5 ($5), &$3, $6.s0, 0);
+ }
+ else
+ {
+ notethat ("dsp32shiftimm: dregs = dregs >>> uimm5 (.)\n");
+ $$ = DSP32SHIFTIMM (2, &$1, -uimm5 ($5), &$3, $6.s0, 0);
+ }
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | HALF_REG ASSIGN ONES REG
+ {
+ if (IS_DREG_L ($1) && IS_DREG ($4))
+ {
+ notethat ("dsp32shift: dregs_lo = ONES dregs\n");
+ $$ = DSP32SHIFT (6, &$1, 0, &$4, 3, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN PACK LPAREN HALF_REG COMMA HALF_REG RPAREN
+ {
+ if (IS_DREG ($1) && IS_DREG ($5) && IS_DREG ($7))
+ {
+ notethat ("dsp32shift: dregs = PACK (dregs_hi , dregs_hi )\n");
+ $$ = DSP32SHIFT (4, &$1, &$7, &$5, HL2 ($5, $7), 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | HALF_REG ASSIGN CCREG ASSIGN BXORSHIFT LPAREN REG_A COMMA REG RPAREN
+ {
+ if (IS_DREG ($1)
+ && $7.regno == REG_A0
+ && IS_DREG ($9) && !IS_H ($1) && !IS_A1 ($7))
+ {
+ notethat ("dsp32shift: dregs_lo = CC = BXORSHIFT (A0 , dregs )\n");
+ $$ = DSP32SHIFT (11, &$1, &$9, 0, 0, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | HALF_REG ASSIGN CCREG ASSIGN BXOR LPAREN REG_A COMMA REG RPAREN
+ {
+ if (IS_DREG ($1)
+ && $7.regno == REG_A0
+ && IS_DREG ($9) && !IS_H ($1) && !IS_A1 ($7))
+ {
+ notethat ("dsp32shift: dregs_lo = CC = BXOR (A0 , dregs)\n");
+ $$ = DSP32SHIFT (11, &$1, &$9, 0, 1, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | HALF_REG ASSIGN CCREG ASSIGN BXOR LPAREN REG_A COMMA REG_A COMMA CCREG RPAREN
+ {
+ if (IS_DREG ($1) && !IS_H ($1) && !REG_SAME ($7, $9))
+ {
+ notethat ("dsp32shift: dregs_lo = CC = BXOR (A0 , A1 , CC)\n");
+ $$ = DSP32SHIFT (12, &$1, 0, 0, 1, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | a_assign ROT REG_A BY HALF_REG
+ {
+ if (REG_SAME ($1, $3) && IS_DREG_L ($5))
+ {
+ notethat ("dsp32shift: Ax = ROT Ax BY dregs_lo\n");
+ $$ = DSP32SHIFT (3, 0, &$5, 0, 2, IS_A1 ($1));
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN ROT REG BY HALF_REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($4) && IS_DREG_L ($6))
+ {
+ notethat ("dsp32shift: dregs = ROT dregs BY dregs_lo\n");
+ $$ = DSP32SHIFT (2, &$1, &$6, &$4, 3, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | a_assign ROT REG_A BY expr
+ {
+ if (IS_IMM ($5, 6))
+ {
+ notethat ("dsp32shiftimm: An = ROT An BY imm6\n");
+ $$ = DSP32SHIFTIMM (3, 0, imm6 ($5), 0, 2, IS_A1 ($1));
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN ROT REG BY expr
+ {
+ if (IS_DREG ($1) && IS_DREG ($4) && IS_IMM ($6, 6))
+ {
+ $$ = DSP32SHIFTIMM (2, &$1, imm6 ($6), &$4, 3, IS_A1 ($1));
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | HALF_REG ASSIGN SIGNBITS REG_A
+ {
+ if (IS_DREG_L ($1))
+ {
+ notethat ("dsp32shift: dregs_lo = SIGNBITS An\n");
+ $$ = DSP32SHIFT (6, &$1, 0, 0, IS_A1 ($4), 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | HALF_REG ASSIGN SIGNBITS REG
+ {
+ if (IS_DREG_L ($1) && IS_DREG ($4))
+ {
+ notethat ("dsp32shift: dregs_lo = SIGNBITS dregs\n");
+ $$ = DSP32SHIFT (5, &$1, 0, &$4, 0, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | HALF_REG ASSIGN SIGNBITS HALF_REG
+ {
+ if (IS_DREG_L ($1))
+ {
+ notethat ("dsp32shift: dregs_lo = SIGNBITS dregs_lo\n");
+ $$ = DSP32SHIFT (5, &$1, 0, &$4, 1 + IS_H ($4), 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ /* The ASR bit is just inverted here. */
+ | HALF_REG ASSIGN VIT_MAX LPAREN REG RPAREN asr_asl
+ {
+ if (IS_DREG_L ($1) && IS_DREG ($5))
+ {
+ notethat ("dsp32shift: dregs_lo = VIT_MAX (dregs) (..)\n");
+ $$ = DSP32SHIFT (9, &$1, 0, &$5, ($7.r0 ? 0 : 1), 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | REG ASSIGN VIT_MAX LPAREN REG COMMA REG RPAREN asr_asl
+ {
+ if (IS_DREG ($1) && IS_DREG ($5) && IS_DREG ($7))
+ {
+ notethat ("dsp32shift: dregs = VIT_MAX (dregs, dregs) (ASR)\n");
+ $$ = DSP32SHIFT (9, &$1, &$7, &$5, 2 | ($9.r0 ? 0 : 1), 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | BITMUX LPAREN REG COMMA REG COMMA REG_A RPAREN asr_asl
+ {
+ if (IS_DREG ($3) && IS_DREG ($5) && !IS_A1 ($7))
+ {
+ notethat ("dsp32shift: BITMUX (dregs , dregs , A0) (ASR)\n");
+ $$ = DSP32SHIFT (8, 0, &$3, &$5, $9.r0, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | a_assign BXORSHIFT LPAREN REG_A COMMA REG_A COMMA CCREG RPAREN
+ {
+ if (!IS_A1 ($1) && !IS_A1 ($4) && IS_A1 ($6))
+ {
+ notethat ("dsp32shift: A0 = BXORSHIFT (A0 , A1 , CC )\n");
+ $$ = DSP32SHIFT (12, 0, 0, 0, 0, 0);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+
+/* LOGI2op: BITCLR (dregs, uimm5). */
+ | BITCLR LPAREN REG COMMA expr RPAREN
+ {
+ if (IS_DREG ($3) && IS_UIMM ($5, 5))
+ {
+ notethat ("LOGI2op: BITCLR (dregs , uimm5 )\n");
+ $$ = LOGI2OP ($3, uimm5 ($5), 4);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+/* LOGI2op: BITSET (dregs, uimm5). */
+ | BITSET LPAREN REG COMMA expr RPAREN
+ {
+ if (IS_DREG ($3) && IS_UIMM ($5, 5))
+ {
+ notethat ("LOGI2op: BITCLR (dregs , uimm5 )\n");
+ $$ = LOGI2OP ($3, uimm5 ($5), 2);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+/* LOGI2op: BITTGL (dregs, uimm5). */
+ | BITTGL LPAREN REG COMMA expr RPAREN
+ {
+ if (IS_DREG ($3) && IS_UIMM ($5, 5))
+ {
+ notethat ("LOGI2op: BITCLR (dregs , uimm5 )\n");
+ $$ = LOGI2OP ($3, uimm5 ($5), 3);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | CCREG _ASSIGN_BANG BITTST LPAREN REG COMMA expr RPAREN
+ {
+ if (IS_DREG ($5) && IS_UIMM ($7, 5))
+ {
+ notethat ("LOGI2op: CC =! BITTST (dregs , uimm5 )\n");
+ $$ = LOGI2OP ($5, uimm5 ($7), 0);
+ }
+ else
+ return yyerror ("Register mismatch or value error");
+ }
+
+ | CCREG ASSIGN BITTST LPAREN REG COMMA expr RPAREN
+ {
+ if (IS_DREG ($5) && IS_UIMM ($7, 5))
+ {
+ notethat ("LOGI2op: CC = BITTST (dregs , uimm5 )\n");
+ $$ = LOGI2OP ($5, uimm5 ($7), 1);
+ }
+ else
+ return yyerror ("Register mismatch or value error");
+ }
+
+ | IF BANG CCREG REG ASSIGN REG
+ {
+ if ((IS_DREG ($4) || IS_PREG ($4))
+ && (IS_DREG ($6) || IS_PREG ($6)))
+ {
+ notethat ("ccMV: IF ! CC gregs = gregs\n");
+ $$ = CCMV (&$6, &$4, 0);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | IF CCREG REG ASSIGN REG
+ {
+ if ((IS_DREG ($5) || IS_PREG ($5))
+ && (IS_DREG ($3) || IS_PREG ($3)))
+ {
+ notethat ("ccMV: IF CC gregs = gregs\n");
+ $$ = CCMV (&$5, &$3, 1);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+ | IF BANG CCREG JUMP expr
+ {
+ if (IS_PCREL10 ($5))
+ {
+ notethat ("BRCC: IF !CC JUMP pcrel11m2\n");
+ $$ = BRCC (0, 0, $5);
+ }
+ else
+ return yyerror ("Bad jump offset");
+ }
+
+ | IF BANG CCREG JUMP expr LPAREN BP RPAREN
+ {
+ if (IS_PCREL10 ($5))
+ {
+ notethat ("BRCC: IF !CC JUMP pcrel11m2\n");
+ $$ = BRCC (0, 1, $5);
+ }
+ else
+ return yyerror ("Bad jump offset");
+ }
+
+ | IF CCREG JUMP expr
+ {
+ if (IS_PCREL10 ($4))
+ {
+ notethat ("BRCC: IF CC JUMP pcrel11m2\n");
+ $$ = BRCC (1, 0, $4);
+ }
+ else
+ return yyerror ("Bad jump offset");
+ }
+
+ | IF CCREG JUMP expr LPAREN BP RPAREN
+ {
+ if (IS_PCREL10 ($4))
+ {
+ notethat ("BRCC: IF !CC JUMP pcrel11m2\n");
+ $$ = BRCC (1, 1, $4);
+ }
+ else
+ return yyerror ("Bad jump offset");
+ }
+ | NOP
+ {
+ notethat ("ProgCtrl: NOP\n");
+ $$ = PROGCTRL (0, 0);
+ }
+
+ | RTS
+ {
+ notethat ("ProgCtrl: RTS\n");
+ $$ = PROGCTRL (1, 0);
+ }
+
+ | RTI
+ {
+ notethat ("ProgCtrl: RTI\n");
+ $$ = PROGCTRL (1, 1);
+ }
+
+ | RTX
+ {
+ notethat ("ProgCtrl: RTX\n");
+ $$ = PROGCTRL (1, 2);
+ }
+
+ | RTN
+ {
+ notethat ("ProgCtrl: RTN\n");
+ $$ = PROGCTRL (1, 3);
+ }
+
+ | RTE
+ {
+ notethat ("ProgCtrl: RTE\n");
+ $$ = PROGCTRL (1, 4);
+ }
+
+ | IDLE
+ {
+ notethat ("ProgCtrl: IDLE\n");
+ $$ = PROGCTRL (2, 0);
+ }
+
+ | CSYNC
+ {
+ notethat ("ProgCtrl: CSYNC\n");
+ $$ = PROGCTRL (2, 3);
+ }
+
+ | SSYNC
+ {
+ notethat ("ProgCtrl: SSYNC\n");
+ $$ = PROGCTRL (2, 4);
+ }
+
+ | EMUEXCPT
+ {
+ notethat ("ProgCtrl: EMUEXCPT\n");
+ $$ = PROGCTRL (2, 5);
+ }
+
+ | CLI REG
+ {
+ if (IS_DREG ($2))
+ {
+ notethat ("ProgCtrl: CLI dregs\n");
+ $$ = PROGCTRL (3, $2.regno & CODE_MASK);
+ }
+ else
+ return yyerror ("Dreg expected for CLI");
+ }
+
+ | STI REG
+ {
+ if (IS_DREG ($2))
+ {
+ notethat ("ProgCtrl: STI dregs\n");
+ $$ = PROGCTRL (4, $2.regno & CODE_MASK);
+ }
+ else
+ return yyerror ("Dreg expected for STI");
+ }
+
+ | JUMP LPAREN REG RPAREN
+ {
+ if (IS_PREG ($3))
+ {
+ notethat ("ProgCtrl: JUMP (pregs )\n");
+ $$ = PROGCTRL (5, $3.regno & CODE_MASK);
+ }
+ else
+ return yyerror ("Bad register for indirect jump");
+ }
+
+ | CALL LPAREN REG RPAREN
+ {
+ if (IS_PREG ($3))
+ {
+ notethat ("ProgCtrl: CALL (pregs )\n");
+ $$ = PROGCTRL (6, $3.regno & CODE_MASK);
+ }
+ else
+ return yyerror ("Bad register for indirect call");
+ }
+
+ | CALL LPAREN PC PLUS REG RPAREN
+ {
+ if (IS_PREG ($5))
+ {
+ notethat ("ProgCtrl: CALL (PC + pregs )\n");
+ $$ = PROGCTRL (7, $5.regno & CODE_MASK);
+ }
+ else
+ return yyerror ("Bad register for indirect call");
+ }
+
+ | JUMP LPAREN PC PLUS REG RPAREN
+ {
+ if (IS_PREG ($5))
+ {
+ notethat ("ProgCtrl: JUMP (PC + pregs )\n");
+ $$ = PROGCTRL (8, $5.regno & CODE_MASK);
+ }
+ else
+ return yyerror ("Bad register for indirect jump");
+ }
+
+ | RAISE expr
+ {
+ if (IS_UIMM ($2, 4))
+ {
+ notethat ("ProgCtrl: RAISE uimm4\n");
+ $$ = PROGCTRL (9, uimm4 ($2));
+ }
+ else
+ return yyerror ("Bad value for RAISE");
+ }
+
+ | EXCPT expr
+ {
+ notethat ("ProgCtrl: EMUEXCPT\n");
+ $$ = PROGCTRL (10, uimm4 ($2));
+ }
+
+ | TESTSET LPAREN REG RPAREN
+ {
+ if (IS_PREG ($3))
+ {
+ notethat ("ProgCtrl: TESTSET (pregs )\n");
+ $$ = PROGCTRL (11, $3.regno & CODE_MASK);
+ }
+ else
+ return yyerror ("Preg expected");
+ }
+
+ | JUMP expr
+ {
+ if (IS_PCREL12 ($2))
+ {
+ notethat ("UJUMP: JUMP pcrel12\n");
+ $$ = UJUMP ($2);
+ }
+ else
+ return yyerror ("Bad value for relative jump");
+ }
+
+ | JUMP_DOT_S expr
+ {
+ if (IS_PCREL12 ($2))
+ {
+ notethat ("UJUMP: JUMP_DOT_S pcrel12\n");
+ $$ = UJUMP($2);
+ }
+ else
+ return yyerror ("Bad value for relative jump");
+ }
+
+ | JUMP_DOT_L expr
+ {
+ if (IS_PCREL24 ($2))
+ {
+ notethat ("CALLa: jump.l pcrel24\n");
+ $$ = CALLA ($2, 0);
+ }
+ else
+ return yyerror ("Bad value for long jump");
+ }
+
+ | JUMP_DOT_L pltpc
+ {
+ if (IS_PCREL24 ($2))
+ {
+ notethat ("CALLa: jump.l pcrel24\n");
+ $$ = CALLA ($2, 2);
+ }
+ else
+ return yyerror ("Bad value for long jump");
+ }
+
+ | CALL expr
+ {
+ if (IS_PCREL24 ($2))
+ {
+ notethat ("CALLa: CALL pcrel25m2\n");
+ $$ = CALLA ($2, 1);
+ }
+ else
+ return yyerror ("Bad call address");
+ }
+ | CALL pltpc
+ {
+ if (IS_PCREL24 ($2))
+ {
+ notethat ("CALLa: CALL pcrel25m2\n");
+ $$ = CALLA ($2, 2);
+ }
+ else
+ return yyerror ("Bad call address");
+ }
+
+/* ALU2ops. */
+/* ALU2op: DIVQ (dregs, dregs). */
+ | DIVQ LPAREN REG COMMA REG RPAREN
+ {
+ if (IS_DREG ($3) && IS_DREG ($5))
+ $$ = ALU2OP (&$3, &$5, 8);
+ else
+ return yyerror ("Bad registers for DIVQ");
+ }
+
+ | DIVS LPAREN REG COMMA REG RPAREN
+ {
+ if (IS_DREG ($3) && IS_DREG ($5))
+ $$ = ALU2OP (&$3, &$5, 9);
+ else
+ return yyerror ("Bad registers for DIVS");
+ }
+
+ | REG ASSIGN MINUS REG vsmod
+ {
+ if (IS_DREG ($1) && IS_DREG ($4))
+ {
+ if ($5.r0 == 0 && $5.s0 == 0 && $5.aop == 0)
+ {
+ notethat ("ALU2op: dregs = - dregs\n");
+ $$ = ALU2OP (&$1, &$4, 14);
+ }
+ else if ($5.r0 == 1 && $5.s0 == 0 && $5.aop == 3)
+ {
+ notethat ("dsp32alu: dregs = - dregs (.)\n");
+ $$ = DSP32ALU (15, 0, 0, &$1, &$4, 0, $5.s0, 0, 3);
+ }
+ else
+ {
+ notethat ("dsp32alu: dregs = - dregs (.)\n");
+ $$ = DSP32ALU (7, 0, 0, &$1, &$4, 0, $5.s0, 0, 3);
+ }
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | REG ASSIGN TILDA REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($4))
+ {
+ notethat ("ALU2op: dregs = ~dregs\n");
+ $$ = ALU2OP (&$1, &$4, 15);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | REG _GREATER_GREATER_ASSIGN REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($3))
+ {
+ notethat ("ALU2op: dregs >>= dregs\n");
+ $$ = ALU2OP (&$1, &$3, 1);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | REG _GREATER_GREATER_ASSIGN expr
+ {
+ if (IS_DREG ($1) && IS_UIMM ($3, 5))
+ {
+ notethat ("LOGI2op: dregs >>= uimm5\n");
+ $$ = LOGI2OP ($1, uimm5 ($3), 6);
+ }
+ else
+ return yyerror ("Dregs expected or value error");
+ }
+
+ | REG _GREATER_GREATER_GREATER_THAN_ASSIGN REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($3))
+ {
+ notethat ("ALU2op: dregs >>>= dregs\n");
+ $$ = ALU2OP (&$1, &$3, 0);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | REG _LESS_LESS_ASSIGN REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($3))
+ {
+ notethat ("ALU2op: dregs <<= dregs\n");
+ $$ = ALU2OP (&$1, &$3, 2);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+ | REG _LESS_LESS_ASSIGN expr
+ {
+ if (IS_DREG ($1) && IS_UIMM ($3, 5))
+ {
+ notethat ("LOGI2op: dregs <<= uimm5\n");
+ $$ = LOGI2OP ($1, uimm5 ($3), 7);
+ }
+ else
+ return yyerror ("Dregs expected or const value error");
+ }
+
+
+ | REG _GREATER_GREATER_GREATER_THAN_ASSIGN expr
+ {
+ if (IS_DREG ($1) && IS_UIMM ($3, 5))
+ {
+ notethat ("LOGI2op: dregs >>>= uimm5\n");
+ $$ = LOGI2OP ($1, uimm5 ($3), 5);
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+
+/* Cache Control. */
+
+ | FLUSH LBRACK REG RBRACK
+ {
+ notethat ("CaCTRL: FLUSH [ pregs ]\n");
+ if (IS_PREG ($3))
+ $$ = CACTRL (&$3, 0, 2);
+ else
+ return yyerror ("Bad register(s) for FLUSH");
+ }
+
+ | FLUSH reg_with_postinc
+ {
+ if (IS_PREG ($2))
+ {
+ notethat ("CaCTRL: FLUSH [ pregs ++ ]\n");
+ $$ = CACTRL (&$2, 1, 2);
+ }
+ else
+ return yyerror ("Bad register(s) for FLUSH");
+ }
+
+ | FLUSHINV LBRACK REG RBRACK
+ {
+ if (IS_PREG ($3))
+ {
+ notethat ("CaCTRL: FLUSHINV [ pregs ]\n");
+ $$ = CACTRL (&$3, 0, 1);
+ }
+ else
+ return yyerror ("Bad register(s) for FLUSH");
+ }
+
+ | FLUSHINV reg_with_postinc
+ {
+ if (IS_PREG ($2))
+ {
+ notethat ("CaCTRL: FLUSHINV [ pregs ++ ]\n");
+ $$ = CACTRL (&$2, 1, 1);
+ }
+ else
+ return yyerror ("Bad register(s) for FLUSH");
+ }
+
+/* CaCTRL: IFLUSH [pregs]. */
+ | IFLUSH LBRACK REG RBRACK
+ {
+ if (IS_PREG ($3))
+ {
+ notethat ("CaCTRL: IFLUSH [ pregs ]\n");
+ $$ = CACTRL (&$3, 0, 3);
+ }
+ else
+ return yyerror ("Bad register(s) for FLUSH");
+ }
+
+ | IFLUSH reg_with_postinc
+ {
+ if (IS_PREG ($2))
+ {
+ notethat ("CaCTRL: IFLUSH [ pregs ++ ]\n");
+ $$ = CACTRL (&$2, 1, 3);
+ }
+ else
+ return yyerror ("Bad register(s) for FLUSH");
+ }
+
+ | PREFETCH LBRACK REG RBRACK
+ {
+ if (IS_PREG ($3))
+ {
+ notethat ("CaCTRL: PREFETCH [ pregs ]\n");
+ $$ = CACTRL (&$3, 0, 0);
+ }
+ else
+ return yyerror ("Bad register(s) for PREFETCH");
+ }
+
+ | PREFETCH reg_with_postinc
+ {
+ if (IS_PREG ($2))
+ {
+ notethat ("CaCTRL: PREFETCH [ pregs ++ ]\n");
+ $$ = CACTRL (&$2, 1, 0);
+ }
+ else
+ return yyerror ("Bad register(s) for PREFETCH");
+ }
+
+/* LOAD/STORE. */
+/* LDST: B [ pregs <post_op> ] = dregs. */
+
+ | B LBRACK REG post_op RBRACK ASSIGN REG
+ {
+ if (IS_PREG ($3) && IS_DREG ($7))
+ {
+ notethat ("LDST: B [ pregs <post_op> ] = dregs\n");
+ $$ = LDST (&$3, &$7, $4.x0, 2, 0, 1);
+ }
+ else
+ return yyerror ("Register mismatch");
+ }
+
+/* LDSTidxI: B [ pregs + imm16 ] = dregs. */
+ | B LBRACK REG plus_minus expr RBRACK ASSIGN REG
+ {
+ if (IS_PREG ($3) && IS_RANGE(16, $5, $4.r0, 1) && IS_DREG ($8))
+ {
+ notethat ("LDST: B [ pregs + imm16 ] = dregs\n");
+ if ($4.r0)
+ neg_value ($5);
+ $$ = LDSTIDXI (&$3, &$8, 1, 2, 0, $5);
+ }
+ else
+ return yyerror ("Register mismatch or const size wrong");
+ }
+
+
+/* LDSTii: W [ pregs + uimm4s2 ] = dregs. */
+ | W LBRACK REG plus_minus expr RBRACK ASSIGN REG
+ {
+ if (IS_PREG ($3) && IS_URANGE (4, $5, $4.r0, 2) && IS_DREG ($8))
+ {
+ notethat ("LDSTii: W [ pregs +- uimm5m2 ] = dregs\n");
+ $$ = LDSTII (&$3, &$8, $5, 1, 1);
+ }
+ else if (IS_PREG ($3) && IS_RANGE(16, $5, $4.r0, 2) && IS_DREG ($8))
+ {
+ notethat ("LDSTidxI: W [ pregs + imm17m2 ] = dregs\n");
+ if ($4.r0)
+ neg_value ($5);
+ $$ = LDSTIDXI (&$3, &$8, 1, 1, 0, $5);
+ }
+ else
+ return yyerror ("Bad register(s) or wrong constant size");
+ }
+
+/* LDST: W [ pregs <post_op> ] = dregs. */
+ | W LBRACK REG post_op RBRACK ASSIGN REG
+ {
+ if (IS_PREG ($3) && IS_DREG ($7))
+ {
+ notethat ("LDST: W [ pregs <post_op> ] = dregs\n");
+ $$ = LDST (&$3, &$7, $4.x0, 1, 0, 1);
+ }
+ else
+ return yyerror ("Bad register(s) for STORE");
+ }
+
+ | W LBRACK REG post_op RBRACK ASSIGN HALF_REG
+ {
+ if (IS_IREG ($3))
+ {
+ notethat ("dspLDST: W [ iregs <post_op> ] = dregs_half\n");
+ $$ = DSPLDST (&$3, 1 + IS_H ($7), &$7, $4.x0, 1);
+ }
+ else if ($4.x0 == 2 && IS_PREG ($3) && IS_DREG ($7))
+ {
+ notethat ("LDSTpmod: W [ pregs <post_op>] = dregs_half\n");
+ $$ = LDSTPMOD (&$3, &$7, &$3, 1 + IS_H ($7), 1);
+
+ }
+ else
+ return yyerror ("Bad register(s) for STORE");
+ }
+
+/* LDSTiiFP: [ FP - const ] = dpregs. */
+ | LBRACK REG plus_minus expr RBRACK ASSIGN REG
+ {
+ Expr_Node *tmp = $4;
+ int ispreg = IS_PREG ($7);
+
+ if (!IS_PREG ($2))
+ return yyerror ("Preg expected for indirect");
+
+ if (!IS_DREG ($7) && !ispreg)
+ return yyerror ("Bad source register for STORE");
+
+ if ($3.r0)
+ tmp = unary (Expr_Op_Type_NEG, tmp);
+
+ if (in_range_p (tmp, 0, 63, 3))
+ {
+ notethat ("LDSTii: dpregs = [ pregs + uimm6m4 ]\n");
+ $$ = LDSTII (&$2, &$7, tmp, 1, ispreg ? 3 : 0);
+ }
+ else if ($2.regno == REG_FP && in_range_p (tmp, -128, 0, 3))
+ {
+ notethat ("LDSTiiFP: dpregs = [ FP - uimm7m4 ]\n");
+ tmp = unary (Expr_Op_Type_NEG, tmp);
+ $$ = LDSTIIFP (tmp, &$7, 1);
+ }
+ else if (in_range_p (tmp, -131072, 131071, 3))
+ {
+ notethat ("LDSTidxI: [ pregs + imm18m4 ] = dpregs\n");
+ $$ = LDSTIDXI (&$2, &$7, 1, 0, ispreg ? 1: 0, tmp);
+ }
+ else
+ return yyerror ("Displacement out of range for store");
+ }
+
+ | REG ASSIGN W LBRACK REG plus_minus expr RBRACK xpmod
+ {
+ if (IS_DREG ($1) && IS_PREG ($5) && IS_URANGE (4, $7, $6.r0, 2))
+ {
+ notethat ("LDSTii: dregs = W [ pregs + uimm4s2 ] (.)\n");
+ $$ = LDSTII (&$5, &$1, $7, 0, 1 << $9.r0);
+ }
+ else if (IS_DREG ($1) && IS_PREG ($5) && IS_RANGE(16, $7, $6.r0, 2))
+ {
+ notethat ("LDSTidxI: dregs = W [ pregs + imm17m2 ] (.)\n");
+ if ($6.r0)
+ neg_value ($7);
+ $$ = LDSTIDXI (&$5, &$1, 0, 1, $9.r0, $7);
+ }
+ else
+ return yyerror ("Bad register or constant for LOAD");
+ }
+
+ | HALF_REG ASSIGN W LBRACK REG post_op RBRACK
+ {
+ if (IS_IREG ($5))
+ {
+ notethat ("dspLDST: dregs_half = W [ iregs ]\n");
+ $$ = DSPLDST(&$5, 1 + IS_H ($1), &$1, $6.x0, 0);
+ }
+ else if ($6.x0 == 2 && IS_DREG ($1) && IS_PREG ($5))
+ {
+ notethat ("LDSTpmod: dregs_half = W [ pregs ]\n");
+ $$ = LDSTPMOD (&$5, &$1, &$5, 1 + IS_H ($1), 0);
+ }
+ else
+ return yyerror ("Bad register or post_op for LOAD");
+ }
+
+
+ | REG ASSIGN W LBRACK REG post_op RBRACK xpmod
+ {
+ if (IS_DREG ($1) && IS_PREG ($5))
+ {
+ notethat ("LDST: dregs = W [ pregs <post_op> ] (.)\n");
+ $$ = LDST (&$5, &$1, $6.x0, 1, $8.r0, 0);
+ }
+ else
+ return yyerror ("Bad register for LOAD");
+ }
+
+ | REG ASSIGN W LBRACK REG _PLUS_PLUS REG RBRACK xpmod
+ {
+ if (IS_DREG ($1) && IS_PREG ($5) && IS_PREG ($7))
+ {
+ notethat ("LDSTpmod: dregs = W [ pregs ++ pregs ] (.)\n");
+ $$ = LDSTPMOD (&$5, &$1, &$7, 3, $9.r0);
+ }
+ else
+ return yyerror ("Bad register for LOAD");
+ }
+
+ | HALF_REG ASSIGN W LBRACK REG _PLUS_PLUS REG RBRACK
+ {
+ if (IS_DREG ($1) && IS_PREG ($5) && IS_PREG ($7))
+ {
+ notethat ("LDSTpmod: dregs_half = W [ pregs ++ pregs ]\n");
+ $$ = LDSTPMOD (&$5, &$1, &$7, 1 + IS_H ($1), 0);
+ }
+ else
+ return yyerror ("Bad register for LOAD");
+ }
+
+ | LBRACK REG post_op RBRACK ASSIGN REG
+ {
+ if (IS_IREG ($2) && IS_DREG ($6))
+ {
+ notethat ("dspLDST: [ iregs <post_op> ] = dregs\n");
+ $$ = DSPLDST(&$2, 0, &$6, $3.x0, 1);
+ }
+ else if (IS_PREG ($2) && IS_DREG ($6))
+ {
+ notethat ("LDST: [ pregs <post_op> ] = dregs\n");
+ $$ = LDST (&$2, &$6, $3.x0, 0, 0, 1);
+ }
+ else if (IS_PREG ($2) && IS_PREG ($6))
+ {
+ notethat ("LDST: [ pregs <post_op> ] = pregs\n");
+ $$ = LDST (&$2, &$6, $3.x0, 0, 1, 1);
+ }
+ else
+ return yyerror ("Bad register for STORE");
+ }
+
+ | LBRACK REG _PLUS_PLUS REG RBRACK ASSIGN REG
+ {
+ if (! IS_DREG ($7))
+ return yyerror ("Expected Dreg for last argument");
+
+ if (IS_IREG ($2) && IS_MREG ($4))
+ {
+ notethat ("dspLDST: [ iregs ++ mregs ] = dregs\n");
+ $$ = DSPLDST(&$2, $4.regno & CODE_MASK, &$7, 3, 1);
+ }
+ else if (IS_PREG ($2) && IS_PREG ($4))
+ {
+ notethat ("LDSTpmod: [ pregs ++ pregs ] = dregs\n");
+ $$ = LDSTPMOD (&$2, &$7, &$4, 0, 1);
+ }
+ else
+ return yyerror ("Bad register for STORE");
+ }
+
+ | W LBRACK REG _PLUS_PLUS REG RBRACK ASSIGN HALF_REG
+ {
+ if (!IS_DREG ($8))
+ return yyerror ("Expect Dreg as last argument");
+ if (IS_PREG ($3) && IS_PREG ($5))
+ {
+ notethat ("LDSTpmod: W [ pregs ++ pregs ] = dregs_half\n");
+ $$ = LDSTPMOD (&$3, &$8, &$5, 1 + IS_H ($8), 1);
+ }
+ else
+ return yyerror ("Bad register for STORE");
+ }
+
+ | REG ASSIGN B LBRACK REG plus_minus expr RBRACK xpmod
+ {
+ if (IS_DREG ($1) && IS_PREG ($5) && IS_RANGE(16, $7, $6.r0, 1))
+ {
+ notethat ("LDSTidxI: dregs = B [ pregs + imm16 ] (%c)\n",
+ $9.r0 ? 'X' : 'Z');
+ if ($6.r0)
+ neg_value ($7);
+ $$ = LDSTIDXI (&$5, &$1, 0, 2, $9.r0, $7);
+ }
+ else
+ return yyerror ("Bad register or value for LOAD");
+ }
+
+ | REG ASSIGN B LBRACK REG post_op RBRACK xpmod
+ {
+ if (IS_DREG ($1) && IS_PREG ($5))
+ {
+ notethat ("LDST: dregs = B [ pregs <post_op> ] (%c)\n",
+ $8.r0 ? 'X' : 'Z');
+ $$ = LDST (&$5, &$1, $6.x0, 2, $8.r0, 0);
+ }
+ else
+ return yyerror ("Bad register for LOAD");
+ }
+
+ | REG ASSIGN LBRACK REG _PLUS_PLUS REG RBRACK
+ {
+ if (IS_DREG ($1) && IS_IREG ($4) && IS_MREG ($6))
+ {
+ notethat ("dspLDST: dregs = [ iregs ++ mregs ]\n");
+ $$ = DSPLDST(&$4, $6.regno & CODE_MASK, &$1, 3, 0);
+ }
+ else if (IS_DREG ($1) && IS_PREG ($4) && IS_PREG ($6))
+ {
+ notethat ("LDSTpmod: dregs = [ pregs ++ pregs ]\n");
+ $$ = LDSTPMOD (&$4, &$1, &$6, 0, 0);
+ }
+ else
+ return yyerror ("Bad register for LOAD");
+ }
+
+ | REG ASSIGN LBRACK REG plus_minus got_or_expr RBRACK
+ {
+ Expr_Node *tmp = $6;
+ int ispreg = IS_PREG ($1);
+ int isgot = IS_RELOC($6);
+
+ if (!IS_PREG ($4))
+ return yyerror ("Preg expected for indirect");
+
+ if (!IS_DREG ($1) && !ispreg)
+ return yyerror ("Bad destination register for LOAD");
+
+ if ($5.r0)
+ tmp = unary (Expr_Op_Type_NEG, tmp);
+
+ if(isgot){
+ notethat ("LDSTidxI: dpregs = [ pregs + sym@got ]\n");
+ $$ = LDSTIDXI (&$4, &$1, 0, 0, ispreg ? 1: 0, tmp);
+ }
+ else if (in_range_p (tmp, 0, 63, 3))
+ {
+ notethat ("LDSTii: dpregs = [ pregs + uimm7m4 ]\n");
+ $$ = LDSTII (&$4, &$1, tmp, 0, ispreg ? 3 : 0);
+ }
+ else if ($4.regno == REG_FP && in_range_p (tmp, -128, 0, 3))
+ {
+ notethat ("LDSTiiFP: dpregs = [ FP - uimm7m4 ]\n");
+ tmp = unary (Expr_Op_Type_NEG, tmp);
+ $$ = LDSTIIFP (tmp, &$1, 0);
+ }
+ else if (in_range_p (tmp, -131072, 131071, 3))
+ {
+ notethat ("LDSTidxI: dpregs = [ pregs + imm18m4 ]\n");
+ $$ = LDSTIDXI (&$4, &$1, 0, 0, ispreg ? 1: 0, tmp);
+
+ }
+ else
+ return yyerror ("Displacement out of range for load");
+ }
+
+ | REG ASSIGN LBRACK REG post_op RBRACK
+ {
+ if (IS_DREG ($1) && IS_IREG ($4))
+ {
+ notethat ("dspLDST: dregs = [ iregs <post_op> ]\n");
+ $$ = DSPLDST (&$4, 0, &$1, $5.x0, 0);
+ }
+ else if (IS_DREG ($1) && IS_PREG ($4))
+ {
+ notethat ("LDST: dregs = [ pregs <post_op> ]\n");
+ $$ = LDST (&$4, &$1, $5.x0, 0, 0, 0);
+ }
+ else if (IS_PREG ($1) && IS_PREG ($4))
+ {
+ if (REG_SAME ($1, $4) && $5.x0 != 2)
+ return yyerror ("Pregs can't be same");
+
+ notethat ("LDST: pregs = [ pregs <post_op> ]\n");
+ $$ = LDST (&$4, &$1, $5.x0, 0, 1, 0);
+ }
+ else if ($4.regno == REG_SP && IS_ALLREG ($1) && $5.x0 == 0)
+ {
+ notethat ("PushPopReg: allregs = [ SP ++ ]\n");
+ $$ = PUSHPOPREG (&$1, 0);
+ }
+ else
+ return yyerror ("Bad register or value");
+ }
+
+
+
+/* Expression Assignment. */
+
+ | expr ASSIGN expr
+ {
+ bfin_equals ($1);
+ $$ = 0;
+ }
+
+
+/* PushPopMultiple. */
+ | reg_with_predec ASSIGN LPAREN REG COLON expr COMMA REG COLON expr RPAREN
+ {
+ if ($1.regno != REG_SP)
+ yyerror ("Stack Pointer expected");
+ if ($4.regno == REG_R7
+ && IN_RANGE ($6, 0, 7)
+ && $8.regno == REG_P5
+ && IN_RANGE ($10, 0, 5))
+ {
+ notethat ("PushPopMultiple: [ -- SP ] = (R7 : reglim , P5 : reglim )\n");
+ $$ = PUSHPOPMULTIPLE (imm5 ($6), imm5 ($10), 1, 1, 1);
+ }
+ else
+ return yyerror ("Bad register for PushPopMultiple");
+ }
+
+ | reg_with_predec ASSIGN LPAREN REG COLON expr RPAREN
+ {
+ if ($1.regno != REG_SP)
+ yyerror ("Stack Pointer expected");
+
+ if ($4.regno == REG_R7 && IN_RANGE ($6, 0, 7))
+ {
+ notethat ("PushPopMultiple: [ -- SP ] = (R7 : reglim )\n");
+ $$ = PUSHPOPMULTIPLE (imm5 ($6), 0, 1, 0, 1);
+ }
+ else if ($4.regno == REG_P5 && IN_RANGE ($6, 0, 6))
+ {
+ notethat ("PushPopMultiple: [ -- SP ] = (P5 : reglim )\n");
+ $$ = PUSHPOPMULTIPLE (0, imm5 ($6), 0, 1, 1);
+ }
+ else
+ return yyerror ("Bad register for PushPopMultiple");
+ }
+
+ | LPAREN REG COLON expr COMMA REG COLON expr RPAREN ASSIGN reg_with_postinc
+ {
+ if ($11.regno != REG_SP)
+ yyerror ("Stack Pointer expected");
+ if ($2.regno == REG_R7 && (IN_RANGE ($4, 0, 7))
+ && $6.regno == REG_P5 && (IN_RANGE ($8, 0, 6)))
+ {
+ notethat ("PushPopMultiple: (R7 : reglim , P5 : reglim ) = [ SP ++ ]\n");
+ $$ = PUSHPOPMULTIPLE (imm5 ($4), imm5 ($8), 1, 1, 0);
+ }
+ else
+ return yyerror ("Bad register range for PushPopMultiple");
+ }
+
+ | LPAREN REG COLON expr RPAREN ASSIGN reg_with_postinc
+ {
+ if ($7.regno != REG_SP)
+ yyerror ("Stack Pointer expected");
+
+ if ($2.regno == REG_R7 && IN_RANGE ($4, 0, 7))
+ {
+ notethat ("PushPopMultiple: (R7 : reglim ) = [ SP ++ ]\n");
+ $$ = PUSHPOPMULTIPLE (imm5 ($4), 0, 1, 0, 0);
+ }
+ else if ($2.regno == REG_P5 && IN_RANGE ($4, 0, 6))
+ {
+ notethat ("PushPopMultiple: (P5 : reglim ) = [ SP ++ ]\n");
+ $$ = PUSHPOPMULTIPLE (0, imm5 ($4), 0, 1, 0);
+ }
+ else
+ return yyerror ("Bad register range for PushPopMultiple");
+ }
+
+ | reg_with_predec ASSIGN REG
+ {
+ if ($1.regno != REG_SP)
+ yyerror ("Stack Pointer expected");
+
+ if (IS_ALLREG ($3))
+ {
+ notethat ("PushPopReg: [ -- SP ] = allregs\n");
+ $$ = PUSHPOPREG (&$3, 1);
+ }
+ else
+ return yyerror ("Bad register for PushPopReg");
+ }
+
+/* Linkage. */
+
+ | LINK expr
+ {
+ if (IS_URANGE (16, $2, 0, 4))
+ $$ = LINKAGE (0, uimm16s4 ($2));
+ else
+ return yyerror ("Bad constant for LINK");
+ }
+
+ | UNLINK
+ {
+ notethat ("linkage: UNLINK\n");
+ $$ = LINKAGE (1, 0);
+ }
+
+
+/* LSETUP. */
+
+ | LSETUP LPAREN expr COMMA expr RPAREN REG
+ {
+ if (IS_PCREL4 ($3) && IS_LPPCREL10 ($5) && IS_CREG ($7))
+ {
+ notethat ("LoopSetup: LSETUP (pcrel4 , lppcrel10 ) counters\n");
+ $$ = LOOPSETUP ($3, &$7, 0, $5, 0);
+ }
+ else
+ return yyerror ("Bad register or values for LSETUP");
+
+ }
+ | LSETUP LPAREN expr COMMA expr RPAREN REG ASSIGN REG
+ {
+ if (IS_PCREL4 ($3) && IS_LPPCREL10 ($5)
+ && IS_PREG ($9) && IS_CREG ($7))
+ {
+ notethat ("LoopSetup: LSETUP (pcrel4 , lppcrel10 ) counters = pregs\n");
+ $$ = LOOPSETUP ($3, &$7, 1, $5, &$9);
+ }
+ else
+ return yyerror ("Bad register or values for LSETUP");
+ }
+
+ | LSETUP LPAREN expr COMMA expr RPAREN REG ASSIGN REG GREATER_GREATER expr
+ {
+ if (IS_PCREL4 ($3) && IS_LPPCREL10 ($5)
+ && IS_PREG ($9) && IS_CREG ($7)
+ && EXPR_VALUE ($11) == 1)
+ {
+ notethat ("LoopSetup: LSETUP (pcrel4 , lppcrel10 ) counters = pregs >> 1\n");
+ $$ = LOOPSETUP ($3, &$7, 3, $5, &$9);
+ }
+ else
+ return yyerror ("Bad register or values for LSETUP");
+ }
+
+/* LOOP. */
+ | LOOP expr REG
+ {
+ if (!IS_RELOC ($2))
+ return yyerror ("Invalid expression in loop statement");
+ if (!IS_CREG ($3))
+ return yyerror ("Invalid loop counter register");
+ $$ = bfin_gen_loop ($2, &$3, 0, 0);
+ }
+ | LOOP expr REG ASSIGN REG
+ {
+ if (IS_RELOC ($2) && IS_PREG ($5) && IS_CREG ($3))
+ {
+ notethat ("Loop: LOOP expr counters = pregs\n");
+ $$ = bfin_gen_loop ($2, &$3, 1, &$5);
+ }
+ else
+ return yyerror ("Bad register or values for LOOP");
+ }
+ | LOOP expr REG ASSIGN REG GREATER_GREATER expr
+ {
+ if (IS_RELOC ($2) && IS_PREG ($5) && IS_CREG ($3) && EXPR_VALUE ($7) == 1)
+ {
+ notethat ("Loop: LOOP expr counters = pregs >> 1\n");
+ $$ = bfin_gen_loop ($2, &$3, 3, &$5);
+ }
+ else
+ return yyerror ("Bad register or values for LOOP");
+ }
+/* pseudoDEBUG. */
+
+ | DBG
+ {
+ notethat ("pseudoDEBUG: DBG\n");
+ $$ = bfin_gen_pseudodbg (3, 7, 0);
+ }
+ | DBG REG_A
+ {
+ notethat ("pseudoDEBUG: DBG REG_A\n");
+ $$ = bfin_gen_pseudodbg (3, IS_A1 ($2), 0);
+ }
+ | DBG REG
+ {
+ notethat ("pseudoDEBUG: DBG allregs\n");
+ $$ = bfin_gen_pseudodbg (0, $2.regno & CODE_MASK, $2.regno & CLASS_MASK);
+ }
+
+ | DBGCMPLX LPAREN REG RPAREN
+ {
+ if (!IS_DREG ($3))
+ return yyerror ("Dregs expected");
+ notethat ("pseudoDEBUG: DBGCMPLX (dregs )\n");
+ $$ = bfin_gen_pseudodbg (3, 6, $3.regno & CODE_MASK);
+ }
+
+ | DBGHALT
+ {
+ notethat ("psedoDEBUG: DBGHALT\n");
+ $$ = bfin_gen_pseudodbg (3, 5, 0);
+ }
+
+ | DBGA LPAREN HALF_REG COMMA expr RPAREN
+ {
+ notethat ("pseudodbg_assert: DBGA (dregs_lo , uimm16 )\n");
+ $$ = bfin_gen_pseudodbg_assert (IS_H ($3), &$3, uimm16 ($5));
+ }
+
+ | DBGAH LPAREN REG COMMA expr RPAREN
+ {
+ notethat ("pseudodbg_assert: DBGAH (dregs , uimm16 )\n");
+ $$ = bfin_gen_pseudodbg_assert (3, &$3, uimm16 ($5));
+ }
+
+ | DBGAL LPAREN REG COMMA expr RPAREN
+ {
+ notethat ("psedodbg_assert: DBGAL (dregs , uimm16 )\n");
+ $$ = bfin_gen_pseudodbg_assert (2, &$3, uimm16 ($5));
+ }
+
+
+;
+
+/* AUX RULES. */
+
+/* Register rules. */
+
+REG_A: REG_A_DOUBLE_ZERO
+ {
+ $$ = $1;
+ }
+ | REG_A_DOUBLE_ONE
+ {
+ $$ = $1;
+ }
+ ;
+
+
+/* Modifiers. */
+
+opt_mode:
+ {
+ $$.MM = 0;
+ $$.mod = 0;
+ }
+ | LPAREN M COMMA MMOD RPAREN
+ {
+ $$.MM = 1;
+ $$.mod = $4;
+ }
+ | LPAREN MMOD COMMA M RPAREN
+ {
+ $$.MM = 1;
+ $$.mod = $2;
+ }
+ | LPAREN MMOD RPAREN
+ {
+ $$.MM = 0;
+ $$.mod = $2;
+ }
+ | LPAREN M RPAREN
+ {
+ $$.MM = 1;
+ $$.mod = 0;
+ }
+ ;
+
+asr_asl: LPAREN ASL RPAREN
+ {
+ $$.r0 = 1;
+ }
+ | LPAREN ASR RPAREN
+ {
+ $$.r0 = 0;
+ }
+ ;
+
+sco:
+ {
+ $$.s0 = 0;
+ $$.x0 = 0;
+ }
+ | S
+ {
+ $$.s0 = 1;
+ $$.x0 = 0;
+ }
+ | CO
+ {
+ $$.s0 = 0;
+ $$.x0 = 1;
+ }
+ | SCO
+ {
+ $$.s0 = 1;
+ $$.x0 = 1;
+ }
+ ;
+
+asr_asl_0:
+ ASL
+ {
+ $$.r0 = 1;
+ }
+ | ASR
+ {
+ $$.r0 = 0;
+ }
+ ;
+
+amod0:
+ {
+ $$.s0 = 0;
+ $$.x0 = 0;
+ }
+ | LPAREN sco RPAREN
+ {
+ $$.s0 = $2.s0;
+ $$.x0 = $2.x0;
+ }
+ ;
+
+amod1:
+ {
+ $$.s0 = 0;
+ $$.x0 = 0;
+ $$.aop = 0;
+ }
+ | LPAREN NS RPAREN
+ {
+ $$.s0 = 0;
+ $$.x0 = 0;
+ $$.aop = 1;
+ }
+ | LPAREN S RPAREN
+ {
+ $$.s0 = 1;
+ $$.x0 = 0;
+ $$.aop = 1;
+ }
+ ;
+
+amod2:
+ {
+ $$.r0 = 0;
+ $$.s0 = 0;
+ $$.x0 = 0;
+ }
+ | LPAREN asr_asl_0 RPAREN
+ {
+ $$.r0 = 2 + $2.r0;
+ $$.s0 = 0;
+ $$.x0 = 0;
+ }
+ | LPAREN sco RPAREN
+ {
+ $$.r0 = 0;
+ $$.s0 = $2.s0;
+ $$.x0 = $2.x0;
+ }
+ | LPAREN asr_asl_0 COMMA sco RPAREN
+ {
+ $$.r0 = 2 + $2.r0;
+ $$.s0 = $4.s0;
+ $$.x0 = $4.x0;
+ }
+ | LPAREN sco COMMA asr_asl_0 RPAREN
+ {
+ $$.r0 = 2 + $4.r0;
+ $$.s0 = $2.s0;
+ $$.x0 = $2.x0;
+ }
+ ;
+
+xpmod:
+ {
+ $$.r0 = 0;
+ }
+ | LPAREN Z RPAREN
+ {
+ $$.r0 = 0;
+ }
+ | LPAREN X RPAREN
+ {
+ $$.r0 = 1;
+ }
+ ;
+
+xpmod1:
+ {
+ $$.r0 = 0;
+ }
+ | LPAREN X RPAREN
+ {
+ $$.r0 = 0;
+ }
+ | LPAREN Z RPAREN
+ {
+ $$.r0 = 1;
+ }
+ ;
+
+vsmod:
+ {
+ $$.r0 = 0;
+ $$.s0 = 0;
+ $$.aop = 0;
+ }
+ | LPAREN NS RPAREN
+ {
+ $$.r0 = 0;
+ $$.s0 = 0;
+ $$.aop = 3;
+ }
+ | LPAREN S RPAREN
+ {
+ $$.r0 = 0;
+ $$.s0 = 1;
+ $$.aop = 3;
+ }
+ | LPAREN V RPAREN
+ {
+ $$.r0 = 1;
+ $$.s0 = 0;
+ $$.aop = 3;
+ }
+ | LPAREN V COMMA S RPAREN
+ {
+ $$.r0 = 1;
+ $$.s0 = 1;
+ }
+ | LPAREN S COMMA V RPAREN
+ {
+ $$.r0 = 1;
+ $$.s0 = 1;
+ }
+ ;
+
+vmod:
+ {
+ $$.r0 = 0;
+ }
+ | LPAREN V RPAREN
+ {
+ $$.r0 = 1;
+ }
+ ;
+
+smod:
+ {
+ $$.s0 = 0;
+ }
+ | LPAREN S RPAREN
+ {
+ $$.s0 = 1;
+ }
+ ;
+
+searchmod:
+ GE
+ {
+ $$.r0 = 1;
+ }
+ | GT
+ {
+ $$.r0 = 0;
+ }
+ | LE
+ {
+ $$.r0 = 3;
+ }
+ | LT
+ {
+ $$.r0 = 2;
+ }
+ ;
+
+aligndir:
+ {
+ $$.r0 = 0;
+ }
+ | LPAREN R RPAREN
+ {
+ $$.r0 = 1;
+ }
+ ;
+
+byteop_mod:
+ LPAREN R RPAREN
+ {
+ $$.r0 = 0;
+ $$.s0 = 1;
+ }
+ | LPAREN MMOD RPAREN
+ {
+ if ($2 != M_T)
+ return yyerror ("Bad modifier");
+ $$.r0 = 1;
+ $$.s0 = 0;
+ }
+ | LPAREN MMOD COMMA R RPAREN
+ {
+ if ($2 != M_T)
+ return yyerror ("Bad modifier");
+ $$.r0 = 1;
+ $$.s0 = 1;
+ }
+ | LPAREN R COMMA MMOD RPAREN
+ {
+ if ($4 != M_T)
+ return yyerror ("Bad modifier");
+ $$.r0 = 1;
+ $$.s0 = 1;
+ }
+ ;
+
+
+
+c_align:
+ ALIGN8
+ {
+ $$.r0 = 0;
+ }
+ | ALIGN16
+ {
+ $$.r0 = 1;
+ }
+ | ALIGN24
+ {
+ $$.r0 = 2;
+ }
+ ;
+
+w32_or_nothing:
+ {
+ $$.r0 = 0;
+ }
+ | LPAREN MMOD RPAREN
+ {
+ if ($2 == M_W32)
+ $$.r0 = 1;
+ else
+ return yyerror ("Only (W32) allowed");
+ }
+ ;
+
+iu_or_nothing:
+ {
+ $$.r0 = 1;
+ }
+ | LPAREN MMOD RPAREN
+ {
+ if ($2 == M_IU)
+ $$.r0 = 3;
+ else
+ return yyerror ("(IU) expected");
+ }
+ ;
+
+reg_with_predec: LBRACK _MINUS_MINUS REG RBRACK
+ {
+ $$ = $3;
+ }
+ ;
+
+reg_with_postinc: LBRACK REG _PLUS_PLUS RBRACK
+ {
+ $$ = $2;
+ }
+ ;
+
+/* Operators. */
+
+min_max:
+ MIN
+ {
+ $$.r0 = 1;
+ }
+ | MAX
+ {
+ $$.r0 = 0;
+ }
+ ;
+
+op_bar_op:
+ _PLUS_BAR_PLUS
+ {
+ $$.r0 = 0;
+ }
+ | _PLUS_BAR_MINUS
+ {
+ $$.r0 = 1;
+ }
+ | _MINUS_BAR_PLUS
+ {
+ $$.r0 = 2;
+ }
+ | _MINUS_BAR_MINUS
+ {
+ $$.r0 = 3;
+ }
+ ;
+
+plus_minus:
+ PLUS
+ {
+ $$.r0 = 0;
+ }
+ | MINUS
+ {
+ $$.r0 = 1;
+ }
+ ;
+
+rnd_op:
+ LPAREN RNDH RPAREN
+ {
+ $$.r0 = 1; /* HL. */
+ $$.s0 = 0; /* s. */
+ $$.x0 = 0; /* x. */
+ $$.aop = 0; /* aop. */
+ }
+
+ | LPAREN TH RPAREN
+ {
+ $$.r0 = 1; /* HL. */
+ $$.s0 = 0; /* s. */
+ $$.x0 = 0; /* x. */
+ $$.aop = 1; /* aop. */
+ }
+
+ | LPAREN RNDL RPAREN
+ {
+ $$.r0 = 0; /* HL. */
+ $$.s0 = 0; /* s. */
+ $$.x0 = 0; /* x. */
+ $$.aop = 0; /* aop. */
+ }
+
+ | LPAREN TL RPAREN
+ {
+ $$.r0 = 0; /* HL. */
+ $$.s0 = 0; /* s. */
+ $$.x0 = 0; /* x. */
+ $$.aop = 1;
+ }
+
+ | LPAREN RNDH COMMA R RPAREN
+ {
+ $$.r0 = 1; /* HL. */
+ $$.s0 = 1; /* s. */
+ $$.x0 = 0; /* x. */
+ $$.aop = 0; /* aop. */
+ }
+ | LPAREN TH COMMA R RPAREN
+ {
+ $$.r0 = 1; /* HL. */
+ $$.s0 = 1; /* s. */
+ $$.x0 = 0; /* x. */
+ $$.aop = 1; /* aop. */
+ }
+ | LPAREN RNDL COMMA R RPAREN
+ {
+ $$.r0 = 0; /* HL. */
+ $$.s0 = 1; /* s. */
+ $$.x0 = 0; /* x. */
+ $$.aop = 0; /* aop. */
+ }
+
+ | LPAREN TL COMMA R RPAREN
+ {
+ $$.r0 = 0; /* HL. */
+ $$.s0 = 1; /* s. */
+ $$.x0 = 0; /* x. */
+ $$.aop = 1; /* aop. */
+ }
+ ;
+
+b3_op:
+ LPAREN LO RPAREN
+ {
+ $$.s0 = 0; /* s. */
+ $$.x0 = 0; /* HL. */
+ }
+ | LPAREN HI RPAREN
+ {
+ $$.s0 = 0; /* s. */
+ $$.x0 = 1; /* HL. */
+ }
+ | LPAREN LO COMMA R RPAREN
+ {
+ $$.s0 = 1; /* s. */
+ $$.x0 = 0; /* HL. */
+ }
+ | LPAREN HI COMMA R RPAREN
+ {
+ $$.s0 = 1; /* s. */
+ $$.x0 = 1; /* HL. */
+ }
+ ;
+
+post_op:
+ {
+ $$.x0 = 2;
+ }
+ | _PLUS_PLUS
+ {
+ $$.x0 = 0;
+ }
+ | _MINUS_MINUS
+ {
+ $$.x0 = 1;
+ }
+ ;
+
+/* Assignments, Macfuncs. */
+
+a_assign:
+ REG_A ASSIGN
+ {
+ $$ = $1;
+ }
+ ;
+
+a_minusassign:
+ REG_A _MINUS_ASSIGN
+ {
+ $$ = $1;
+ }
+ ;
+
+a_plusassign:
+ REG_A _PLUS_ASSIGN
+ {
+ $$ = $1;
+ }
+ ;
+
+assign_macfunc:
+ REG ASSIGN REG_A
+ {
+ $$.w = 1;
+ $$.P = 1;
+ $$.n = IS_A1 ($3);
+ $$.op = 3;
+ $$.dst = $1;
+ $$.s0.regno = 0;
+ $$.s1.regno = 0;
+
+ if (IS_A1 ($3) && IS_EVEN ($1))
+ return yyerror ("Cannot move A1 to even register");
+ else if (!IS_A1 ($3) && !IS_EVEN ($1))
+ return yyerror ("Cannot move A0 to odd register");
+ }
+ | a_macfunc
+ {
+ $$ = $1;
+ $$.w = 0; $$.P = 0;
+ $$.dst.regno = 0;
+ }
+ | REG ASSIGN LPAREN a_macfunc RPAREN
+ {
+ $$ = $4;
+ $$.w = 1;
+ $$.P = 1;
+ $$.dst = $1;
+ }
+
+ | HALF_REG ASSIGN LPAREN a_macfunc RPAREN
+ {
+ $$ = $4;
+ $$.w = 1;
+ $$.P = 0;
+ $$.dst = $1;
+ }
+
+ | HALF_REG ASSIGN REG_A
+ {
+ $$.w = 1;
+ $$.P = 0;
+ $$.n = IS_A1 ($3);
+ $$.op = 3;
+ $$.dst = $1;
+ $$.s0.regno = 0;
+ $$.s1.regno = 0;
+
+ if (IS_A1 ($3) && !IS_H ($1))
+ return yyerror ("Cannot move A1 to low half of register");
+ else if (!IS_A1 ($3) && IS_H ($1))
+ return yyerror ("Cannot move A0 to high half of register");
+ }
+ ;
+
+a_macfunc:
+ a_assign multiply_halfregs
+ {
+ $$.n = IS_A1 ($1);
+ $$.op = 0;
+ $$.s0 = $2.s0;
+ $$.s1 = $2.s1;
+ }
+ | a_plusassign multiply_halfregs
+ {
+ $$.n = IS_A1 ($1);
+ $$.op = 1;
+ $$.s0 = $2.s0;
+ $$.s1 = $2.s1;
+ }
+ | a_minusassign multiply_halfregs
+ {
+ $$.n = IS_A1 ($1);
+ $$.op = 2;
+ $$.s0 = $2.s0;
+ $$.s1 = $2.s1;
+ }
+ ;
+
+multiply_halfregs:
+ HALF_REG STAR HALF_REG
+ {
+ if (IS_DREG ($1) && IS_DREG ($3))
+ {
+ $$.s0 = $1;
+ $$.s1 = $3;
+ }
+ else
+ return yyerror ("Dregs expected");
+ }
+ ;
+
+cc_op:
+ ASSIGN
+ {
+ $$.r0 = 0;
+ }
+ | _BAR_ASSIGN
+ {
+ $$.r0 = 1;
+ }
+ | _AMPERSAND_ASSIGN
+ {
+ $$.r0 = 2;
+ }
+ | _CARET_ASSIGN
+ {
+ $$.r0 = 3;
+ }
+ ;
+
+ccstat:
+ CCREG cc_op STATUS_REG
+ {
+ $$.r0 = $3.regno;
+ $$.x0 = $2.r0;
+ $$.s0 = 0;
+ }
+ | CCREG cc_op V
+ {
+ $$.r0 = 0x18;
+ $$.x0 = $2.r0;
+ $$.s0 = 0;
+ }
+ | STATUS_REG cc_op CCREG
+ {
+ $$.r0 = $1.regno;
+ $$.x0 = $2.r0;
+ $$.s0 = 1;
+ }
+ | V cc_op CCREG
+ {
+ $$.r0 = 0x18;
+ $$.x0 = $2.r0;
+ $$.s0 = 1;
+ }
+ ;
+
+/* Expressions and Symbols. */
+
+symbol: SYMBOL
+ {
+ Expr_Node_Value val;
+ val.s_value = S_GET_NAME($1);
+ $$ = Expr_Node_Create (Expr_Node_Reloc, val, NULL, NULL);
+ }
+ ;
+
+got: symbol AT GOT
+ {
+ $$ = $1;
+ }
+ ;
+
+got_or_expr: got
+ {
+ $$ = $1;
+ }
+ | expr
+ {
+ $$ = $1;
+ }
+ ;
+
+pltpc :
+ symbol AT PLTPC
+ {
+ $$ = $1;
+ }
+ ;
+
+eterm: NUMBER
+ {
+ Expr_Node_Value val;
+ val.i_value = $1;
+ $$ = Expr_Node_Create (Expr_Node_Constant, val, NULL, NULL);
+ }
+ | symbol
+ {
+ $$ = $1;
+ }
+ | LPAREN expr_1 RPAREN
+ {
+ $$ = $2;
+ }
+ | TILDA expr_1
+ {
+ $$ = unary (Expr_Op_Type_COMP, $2);
+ }
+ | MINUS expr_1 %prec TILDA
+ {
+ $$ = unary (Expr_Op_Type_NEG, $2);
+ }
+ ;
+
+expr: expr_1
+ {
+ $$ = $1;
+ }
+ ;
+
+expr_1: expr_1 STAR expr_1
+ {
+ $$ = binary (Expr_Op_Type_Mult, $1, $3);
+ }
+ | expr_1 SLASH expr_1
+ {
+ $$ = binary (Expr_Op_Type_Div, $1, $3);
+ }
+ | expr_1 PERCENT expr_1
+ {
+ $$ = binary (Expr_Op_Type_Mod, $1, $3);
+ }
+ | expr_1 PLUS expr_1
+ {
+ $$ = binary (Expr_Op_Type_Add, $1, $3);
+ }
+ | expr_1 MINUS expr_1
+ {
+ $$ = binary (Expr_Op_Type_Sub, $1, $3);
+ }
+ | expr_1 LESS_LESS expr_1
+ {
+ $$ = binary (Expr_Op_Type_Lshift, $1, $3);
+ }
+ | expr_1 GREATER_GREATER expr_1
+ {
+ $$ = binary (Expr_Op_Type_Rshift, $1, $3);
+ }
+ | expr_1 AMPERSAND expr_1
+ {
+ $$ = binary (Expr_Op_Type_BAND, $1, $3);
+ }
+ | expr_1 CARET expr_1
+ {
+ $$ = binary (Expr_Op_Type_LOR, $1, $3);
+ }
+ | expr_1 BAR expr_1
+ {
+ $$ = binary (Expr_Op_Type_BOR, $1, $3);
+ }
+ | eterm
+ {
+ $$ = $1;
+ }
+ ;
+
+
+%%
+
+EXPR_T
+mkexpr (int x, SYMBOL_T s)
+{
+ EXPR_T e = (EXPR_T) ALLOCATE (sizeof (struct expression_cell));
+ e->value = x;
+ EXPR_SYMBOL(e) = s;
+ return e;
+}
+
+static int
+value_match (Expr_Node *expr, int sz, int sign, int mul, int issigned)
+{
+ long umax = (1L << sz) - 1;
+ long min = -1L << (sz - 1);
+ long max = (1L << (sz - 1)) - 1;
+
+ long v = EXPR_VALUE (expr);
+
+ if ((v % mul) != 0)
+ {
+ error ("%s:%d: Value Error -- Must align to %d\n", __LINE__, __FILE__, mul);
+ return 0;
+ }
+
+ v /= mul;
+
+ if (sign)
+ v = -v;
+
+ if (issigned)
+ {
+ if (v >= min && v <= max) return 1;
+
+#ifdef DEBUG
+ fprintf(stderr, "signed value %lx out of range\n", v * mul);
+#endif
+ return 0;
+ }
+ if (v <= umax && v >= 0)
+ return 1;
+#ifdef DEBUG
+ fprintf(stderr, "unsigned value %lx out of range\n", v * mul);
+#endif
+ return 0;
+}
+
+/* Return the expression structure that allows symbol operations.
+ If the left and right children are constants, do the operation. */
+static Expr_Node *
+binary (Expr_Op_Type op, Expr_Node *x, Expr_Node *y)
+{
+ if (x->type == Expr_Node_Constant && y->type == Expr_Node_Constant)
+ {
+ switch (op)
+ {
+ case Expr_Op_Type_Add:
+ x->value.i_value += y->value.i_value;
+ break;
+ case Expr_Op_Type_Sub:
+ x->value.i_value -= y->value.i_value;
+ break;
+ case Expr_Op_Type_Mult:
+ x->value.i_value *= y->value.i_value;
+ break;
+ case Expr_Op_Type_Div:
+ if (y->value.i_value == 0)
+ error ("Illegal Expression: Division by zero.");
+ else
+ x->value.i_value /= y->value.i_value;
+ break;
+ case Expr_Op_Type_Mod:
+ x->value.i_value %= y->value.i_value;
+ break;
+ case Expr_Op_Type_Lshift:
+ x->value.i_value <<= y->value.i_value;
+ break;
+ case Expr_Op_Type_Rshift:
+ x->value.i_value >>= y->value.i_value;
+ break;
+ case Expr_Op_Type_BAND:
+ x->value.i_value &= y->value.i_value;
+ break;
+ case Expr_Op_Type_BOR:
+ x->value.i_value |= y->value.i_value;
+ break;
+ case Expr_Op_Type_BXOR:
+ x->value.i_value ^= y->value.i_value;
+ break;
+ case Expr_Op_Type_LAND:
+ x->value.i_value = x->value.i_value && y->value.i_value;
+ break;
+ case Expr_Op_Type_LOR:
+ x->value.i_value = x->value.i_value || y->value.i_value;
+ break;
+
+ default:
+ error ("%s:%d: Internal compiler error\n", __LINE__, __FILE__);
+ }
+ return x;
+ }
+ else
+ {
+ /* Create a new expression structure. */
+ Expr_Node_Value val;
+ val.op_value = op;
+ return Expr_Node_Create (Expr_Node_Binop, val, x, y);
+ }
+}
+
+static Expr_Node *
+unary (Expr_Op_Type op, Expr_Node *x)
+{
+ if (x->type == Expr_Node_Constant)
+ {
+ switch (op)
+ {
+ case Expr_Op_Type_NEG:
+ x->value.i_value = -x->value.i_value;
+ break;
+ case Expr_Op_Type_COMP:
+ x->value.i_value = ~x->value.i_value;
+ break;
+ default:
+ error ("%s:%d: Internal compiler error\n", __LINE__, __FILE__);
+ }
+ return x;
+ }
+ else
+ {
+ /* Create a new expression structure. */
+ Expr_Node_Value val;
+ val.op_value = op;
+ return Expr_Node_Create (Expr_Node_Unop, val, x, NULL);
+ }
+}
+
+int debug_codeselection = 0;
+static void
+notethat (char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ if (debug_codeselection)
+ {
+ vfprintf (errorf, format, ap);
+ }
+ va_end (ap);
+}
+
+#ifdef TEST
+main (int argc, char **argv)
+{
+ yyparse();
+}
+#endif
+
--- /dev/null
+/* tc-bfin.c -- Assembler for the ADI Blackfin.
+ Copyright 2005
+ Free Software Foundation, Inc.
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include "as.h"
+#include "struc-symbol.h"
+#include "obj-elf.h"
+#include "bfin-defs.h"
+#include "obstack.h"
+#include "safe-ctype.h"
+#ifdef OBJ_ELF
+#include "dwarf2dbg.h"
+#endif
+
+extern int yyparse (void);
+struct yy_buffer_state;
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+extern YY_BUFFER_STATE yy_scan_string (const char *yy_str);
+extern void yy_delete_buffer (YY_BUFFER_STATE b);
+static parse_state parse (char *line);
+static void bfin_s_bss PARAMS ((int));
+static int md_chars_to_number PARAMS ((unsigned char *, int));
+
+/* Global variables. */
+struct bfin_insn *insn;
+int last_insn_size;
+
+extern struct obstack mempool;
+FILE *errorf;
+
+/* Registers list. */
+struct bfin_reg_entry
+{
+ const char *name;
+ int number;
+};
+
+static const struct bfin_reg_entry bfin_reg_info[] = {
+ {"R0.L", REG_RL0},
+ {"R1.L", REG_RL1},
+ {"R2.L", REG_RL2},
+ {"R3.L", REG_RL3},
+ {"R4.L", REG_RL4},
+ {"R5.L", REG_RL5},
+ {"R6.L", REG_RL6},
+ {"R7.L", REG_RL7},
+ {"R0.H", REG_RH0},
+ {"R1.H", REG_RH1},
+ {"R2.H", REG_RH2},
+ {"R3.H", REG_RH3},
+ {"R4.H", REG_RH4},
+ {"R5.H", REG_RH5},
+ {"R6.H", REG_RH6},
+ {"R7.H", REG_RH7},
+ {"R0", REG_R0},
+ {"R1", REG_R1},
+ {"R2", REG_R2},
+ {"R3", REG_R3},
+ {"R4", REG_R4},
+ {"R5", REG_R5},
+ {"R6", REG_R6},
+ {"R7", REG_R7},
+ {"P0", REG_P0},
+ {"P0.H", REG_P0},
+ {"P0.L", REG_P0},
+ {"P1", REG_P1},
+ {"P1.H", REG_P1},
+ {"P1.L", REG_P1},
+ {"P2", REG_P2},
+ {"P2.H", REG_P2},
+ {"P2.L", REG_P2},
+ {"P3", REG_P3},
+ {"P3.H", REG_P3},
+ {"P3.L", REG_P3},
+ {"P4", REG_P4},
+ {"P4.H", REG_P4},
+ {"P4.L", REG_P4},
+ {"P5", REG_P5},
+ {"P5.H", REG_P5},
+ {"P5.L", REG_P5},
+ {"SP", REG_SP},
+ {"SP.L", REG_SP},
+ {"SP.H", REG_SP},
+ {"FP", REG_FP},
+ {"FP.L", REG_FP},
+ {"FP.H", REG_FP},
+ {"A0x", REG_A0x},
+ {"A1x", REG_A1x},
+ {"A0w", REG_A0w},
+ {"A1w", REG_A1w},
+ {"A0.x", REG_A0x},
+ {"A1.x", REG_A1x},
+ {"A0.w", REG_A0w},
+ {"A1.w", REG_A1w},
+ {"A0", REG_A0},
+ {"A0.L", REG_A0},
+ {"A0.H", REG_A0},
+ {"A1", REG_A1},
+ {"A1.L", REG_A1},
+ {"A1.H", REG_A1},
+ {"I0", REG_I0},
+ {"I0.L", REG_I0},
+ {"I0.H", REG_I0},
+ {"I1", REG_I1},
+ {"I1.L", REG_I1},
+ {"I1.H", REG_I1},
+ {"I2", REG_I2},
+ {"I2.L", REG_I2},
+ {"I2.H", REG_I2},
+ {"I3", REG_I3},
+ {"I3.L", REG_I3},
+ {"I3.H", REG_I3},
+ {"M0", REG_M0},
+ {"M0.H", REG_M0},
+ {"M0.L", REG_M0},
+ {"M1", REG_M1},
+ {"M1.H", REG_M1},
+ {"M1.L", REG_M1},
+ {"M2", REG_M2},
+ {"M2.H", REG_M2},
+ {"M2.L", REG_M2},
+ {"M3", REG_M3},
+ {"M3.H", REG_M3},
+ {"M3.L", REG_M3},
+ {"B0", REG_B0},
+ {"B0.H", REG_B0},
+ {"B0.L", REG_B0},
+ {"B1", REG_B1},
+ {"B1.H", REG_B1},
+ {"B1.L", REG_B1},
+ {"B2", REG_B2},
+ {"B2.H", REG_B2},
+ {"B2.L", REG_B2},
+ {"B3", REG_B3},
+ {"B3.H", REG_B3},
+ {"B3.L", REG_B3},
+ {"L0", REG_L0},
+ {"L0.H", REG_L0},
+ {"L0.L", REG_L0},
+ {"L1", REG_L1},
+ {"L1.H", REG_L1},
+ {"L1.L", REG_L1},
+ {"L2", REG_L2},
+ {"L2.H", REG_L2},
+ {"L2.L", REG_L2},
+ {"L3", REG_L3},
+ {"L3.H", REG_L3},
+ {"L3.L", REG_L3},
+ {"AZ", S_AZ},
+ {"AN", S_AN},
+ {"AC0", S_AC0},
+ {"AC1", S_AC1},
+ {"AV0", S_AV0},
+ {"AV0S", S_AV0S},
+ {"AV1", S_AV1},
+ {"AV1S", S_AV1S},
+ {"AQ", S_AQ},
+ {"V", S_V},
+ {"VS", S_VS},
+ {"sftreset", REG_sftreset},
+ {"omode", REG_omode},
+ {"excause", REG_excause},
+ {"emucause", REG_emucause},
+ {"idle_req", REG_idle_req},
+ {"hwerrcause", REG_hwerrcause},
+ {"CC", REG_CC},
+ {"LC0", REG_LC0},
+ {"LC1", REG_LC1},
+ {"ASTAT", REG_ASTAT},
+ {"RETS", REG_RETS},
+ {"LT0", REG_LT0},
+ {"LB0", REG_LB0},
+ {"LT1", REG_LT1},
+ {"LB1", REG_LB1},
+ {"CYCLES", REG_CYCLES},
+ {"CYCLES2", REG_CYCLES2},
+ {"USP", REG_USP},
+ {"SEQSTAT", REG_SEQSTAT},
+ {"SYSCFG", REG_SYSCFG},
+ {"RETI", REG_RETI},
+ {"RETX", REG_RETX},
+ {"RETN", REG_RETN},
+ {"RETE", REG_RETE},
+ {"EMUDAT", REG_EMUDAT},
+ {0, 0}
+};
+
+
+const pseudo_typeS md_pseudo_table[] = {
+ {"align", s_align_bytes, 0},
+ {"byte2", cons, 2},
+ {"byte4", cons, 4},
+ {"code", obj_elf_section, 0},
+ {"db", cons, 1},
+ {"dd", cons, 4},
+ {"dw", cons, 2},
+ {"p", s_ignore, 0},
+ {"pdata", s_ignore, 0},
+ {"var", s_ignore, 0},
+ {"bss", bfin_s_bss, 0},
+ {0, 0, 0}
+};
+
+static void
+bfin_s_bss (int ignore ATTRIBUTE_UNUSED)
+{
+ register int temp;
+
+ temp = get_absolute_expression ();
+ subseg_set (bss_section, (subsegT) temp);
+ demand_empty_rest_of_line ();
+}
+
+
+/* Characters that are used to denote comments and line separators. */
+const char comment_chars[] = "";
+const char line_comment_chars[] = "#";
+const char line_separator_chars[] = ";";
+
+/* Characters that can be used to separate the mantissa from the
+ exponent in floating point numbers. */
+const char EXP_CHARS[] = "eE";
+
+/* Characters that mean this number is a floating point constant.
+ As in 0f12.456 or 0d1.2345e12. */
+const char FLT_CHARS[] = "fFdDxX";
+
+/* Define bfin-specific command-line options (there are none). */
+const char *md_shortopts = "";
+
+struct option md_longopts[] = {
+ {NULL, no_argument, NULL, 0}
+};
+size_t md_longopts_size = sizeof (md_longopts);
+
+
+int
+md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+void
+md_show_usage (FILE * stream ATTRIBUTE_UNUSED)
+{
+ fprintf (stream, _(" BFIN specific command line options:\n"));
+}
+
+/* Perform machine-specific initializations. */
+void
+md_begin ()
+{
+ /* Set the default machine type. */
+ if (!bfd_set_arch_mach (stdoutput, bfd_arch_bfin, 0))
+ as_warn ("Could not set architecture and machine.");
+
+ /* Ensure that lines can begin with '(', for multiple
+ register stack pops. */
+ lex_type ['('] = 3;
+
+#ifdef OBJ_ELF
+ record_alignment (text_section, 2);
+ record_alignment (data_section, 2);
+ record_alignment (bss_section, 2);
+#endif
+
+ errorf = stderr;
+ obstack_init (&mempool);
+
+#ifdef DEBUG
+ extern int debug_codeselection;
+ debug_codeselection = 1;
+#endif
+
+ last_insn_size = 0;
+}
+
+/* Perform the main parsing, and assembly of the input here. Also,
+ call the required routines for alignment and fixups here.
+ This is called for every line that contains real assembly code. */
+
+void
+md_assemble (char *line)
+{
+ char *toP = 0;
+ extern char *current_inputline;
+ int size, insn_size;
+ struct bfin_insn *tmp_insn;
+ size_t len;
+ static size_t buffer_len = 0;
+ parse_state state;
+
+ len = strlen (line);
+ if (len + 2 > buffer_len)
+ {
+ if (buffer_len > 0)
+ free (current_inputline);
+ buffer_len = len + 40;
+ current_inputline = xmalloc (buffer_len);
+ }
+ memcpy (current_inputline, line, len);
+ current_inputline[len] = ';';
+ current_inputline[len + 1] = '\0';
+
+ state = parse (current_inputline);
+ if (state == NO_INSN_GENERATED)
+ return;
+
+ for (insn_size = 0, tmp_insn = insn; tmp_insn; tmp_insn = tmp_insn->next)
+ if (!tmp_insn->reloc || !tmp_insn->exp->symbol)
+ insn_size += 2;
+
+ if (insn_size)
+ toP = frag_more (insn_size);
+
+ last_insn_size = insn_size;
+
+#ifdef DEBUG
+ printf ("INS:");
+#endif
+ while (insn)
+ {
+ if (insn->reloc && insn->exp->symbol)
+ {
+ char *prev_toP = toP - 2;
+ switch (insn->reloc)
+ {
+ case BFD_RELOC_BFIN_24_PCREL_JUMP_L:
+ case BFD_RELOC_24_PCREL:
+ case BFD_RELOC_BFIN_16_LOW:
+ case BFD_RELOC_BFIN_16_HIGH:
+ size = 4;
+ break;
+ default:
+ size = 2;
+ }
+
+ /* Following if condition checks for the arithmetic relocations.
+ If the case then it doesn't required to generate the code.
+ It has been assumed that, their ID will be contiguous. */
+ if ((BFD_ARELOC_BFIN_PUSH <= insn->reloc
+ && BFD_ARELOC_BFIN_COMP >= insn->reloc)
+ || insn->reloc == BFD_RELOC_BFIN_16_IMM)
+ {
+ size = 2;
+ }
+ if (insn->reloc == BFD_ARELOC_BFIN_CONST
+ || insn->reloc == BFD_ARELOC_BFIN_PUSH)
+ size = 4;
+
+ fix_new (frag_now,
+ (prev_toP - frag_now->fr_literal),
+ size, insn->exp->symbol, insn->exp->value,
+ insn->pcrel, insn->reloc);
+ }
+ else
+ {
+ md_number_to_chars (toP, insn->value, 2);
+ toP += 2;
+ }
+
+#ifdef DEBUG
+ printf (" reloc :");
+ printf (" %02x%02x", ((unsigned char *) &insn->value)[0],
+ ((unsigned char *) &insn->value)[1]);
+ printf ("\n");
+#endif
+ insn = insn->next;
+ }
+#ifdef OBJ_ELF
+ dwarf2_emit_insn (insn_size);
+#endif
+}
+
+/* Parse one line of instructions, and generate opcode for it.
+ To parse the line, YACC and LEX are used, because the instruction set
+ syntax doesn't confirm to the AT&T assembly syntax.
+ To call a YACC & LEX generated parser, we must provide the input via
+ a FILE stream, otherwise stdin is used by default. Below the input
+ to the function will be put into a temporary file, then the generated
+ parser uses the temporary file for parsing. */
+
+static parse_state
+parse (char *line)
+{
+ parse_state state;
+ YY_BUFFER_STATE buffstate;
+
+ buffstate = yy_scan_string (line);
+
+ /* our lex requires setting the start state to keyword
+ every line as the first word may be a keyword.
+ Fixes a bug where we could not have keywords as labels. */
+ set_start_state ();
+
+ /* Call yyparse here. */
+ state = yyparse ();
+ if (state == SEMANTIC_ERROR)
+ {
+ as_bad ("Parse failed.");
+ insn = 0;
+ }
+
+ yy_delete_buffer (buffstate);
+ return state;
+}
+
+/* We need to handle various expressions properly.
+ Such as, [SP--] = 34, concerned by md_assemble(). */
+
+void
+md_operand (expressionS * expressionP)
+{
+ if (*input_line_pointer == '[')
+ {
+ as_tsktsk ("We found a '['!");
+ input_line_pointer++;
+ expression (expressionP);
+ }
+}
+
+/* Handle undefined symbols. */
+symbolS *
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
+{
+ return (symbolS *) 0;
+}
+
+int
+md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
+ segT segment ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+/* Convert from target byte order to host byte order. */
+
+static int
+md_chars_to_number (val, n)
+ unsigned char *val; /* Value in target byte order. */
+ int n; /* Number of bytes in the input. */
+{
+ int retval;
+
+ for (retval = 0; n--;)
+ {
+ retval <<= 8;
+ retval |= val[n];
+ }
+ return retval;
+}
+
+void
+md_apply_fix (fixS *fixP, valueT *valueP, segT seg ATTRIBUTE_UNUSED)
+{
+ char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
+
+ long value = *valueP;
+ long newval;
+
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_BFIN_GOT:
+ fixP->fx_no_overflow = 1;
+ newval = md_chars_to_number (where, 2);
+ newval |= 0x0 & 0x7f;
+ md_number_to_chars (where, newval, 2);
+ break;
+
+ case BFD_RELOC_BFIN_10_PCREL:
+ if (!value)
+ break;
+ if (value < -1024 || value > 1022)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ "pcrel too far BFD_RELOC_BFIN_10");
+
+ /* 11 bit offset even numbered, so we remove right bit. */
+ value = value >> 1;
+ newval = md_chars_to_number (where, 2);
+ newval |= value & 0x03ff;
+ md_number_to_chars (where, newval, 2);
+ break;
+
+ case BFD_RELOC_BFIN_12_PCREL_JUMP:
+ case BFD_RELOC_BFIN_12_PCREL_JUMP_S:
+ case BFD_RELOC_12_PCREL:
+ if (!value)
+ break;
+
+ if (value < -4096 || value > 4094)
+ as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far BFD_RELOC_BFIN_12");
+ /* 13 bit offset even numbered, so we remove right bit. */
+ value = value >> 1;
+ newval = md_chars_to_number (where, 2);
+ newval |= value & 0xfff;
+ md_number_to_chars (where, newval, 2);
+ break;
+
+ case BFD_RELOC_BFIN_16_LOW:
+ case BFD_RELOC_BFIN_16_HIGH:
+ fixP->fx_done = FALSE;
+ break;
+
+ case BFD_RELOC_BFIN_24_PCREL_JUMP_L:
+ case BFD_RELOC_BFIN_24_PCREL_CALL_X:
+ case BFD_RELOC_24_PCREL:
+ if (!value)
+ break;
+
+ if (value < -16777216 || value > 16777214)
+ as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far BFD_RELOC_BFIN_24");
+
+ /* 25 bit offset even numbered, so we remove right bit. */
+ value = value >> 1;
+ value++;
+
+ md_number_to_chars (where - 2, value >> 16, 1);
+ md_number_to_chars (where, value, 1);
+ md_number_to_chars (where + 1, value >> 8, 1);
+ break;
+
+ case BFD_RELOC_BFIN_5_PCREL: /* LSETUP (a, b) : "a" */
+ if (!value)
+ break;
+ if (value < 4 || value > 30)
+ as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far BFD_RELOC_BFIN_5");
+ value = value >> 1;
+ newval = md_chars_to_number (where, 1);
+ newval = (newval & 0xf0) | (value & 0xf);
+ md_number_to_chars (where, newval, 1);
+ break;
+
+ case BFD_RELOC_BFIN_11_PCREL: /* LSETUP (a, b) : "b" */
+ if (!value)
+ break;
+ value += 2;
+ if (value < 4 || value > 2046)
+ as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far BFD_RELOC_BFIN_11_PCREL");
+ /* 11 bit unsigned even, so we remove right bit. */
+ value = value >> 1;
+ newval = md_chars_to_number (where, 2);
+ newval |= value & 0x03ff;
+ md_number_to_chars (where, newval, 2);
+ break;
+
+ case BFD_RELOC_8:
+ if (value < -0x80 || value >= 0x7f)
+ as_bad_where (fixP->fx_file, fixP->fx_line, "rel too far BFD_RELOC_8");
+ md_number_to_chars (where, value, 1);
+ break;
+
+ case BFD_RELOC_BFIN_16_IMM:
+ case BFD_RELOC_16:
+ if (value < -0x8000 || value >= 0x7fff)
+ as_bad_where (fixP->fx_file, fixP->fx_line, "rel too far BFD_RELOC_8");
+ md_number_to_chars (where, value, 2);
+ break;
+
+ case BFD_RELOC_32:
+ md_number_to_chars (where, value, 4);
+ break;
+
+ case BFD_RELOC_BFIN_PLTPC:
+ md_number_to_chars (where, value, 2);
+ break;
+
+ case BFD_RELOC_VTABLE_INHERIT:
+ case BFD_RELOC_VTABLE_ENTRY:
+ fixP->fx_done = FALSE;
+ break;
+
+ default:
+ if ((BFD_ARELOC_BFIN_PUSH > fixP->fx_r_type) || (BFD_ARELOC_BFIN_COMP < fixP->fx_r_type))
+ {
+ fprintf (stderr, "Relocation %d not handled in gas." " Contact support.\n", fixP->fx_r_type);
+ return;
+ }
+ }
+
+ if (!fixP->fx_addsy)
+ fixP->fx_done = TRUE;
+
+}
+
+/* Round up a section size to the appropriate boundary. */
+valueT
+md_section_align (segment, size)
+ segT segment;
+ valueT size;
+{
+ int boundary = bfd_get_section_alignment (stdoutput, segment);
+ return ((size + (1 << boundary) - 1) & (-1 << boundary));
+}
+
+
+/* Turn a string in input_line_pointer into a floating point
+ constant of type type, and store the appropriate bytes in
+ *litP. The number of LITTLENUMS emitted is stored in *sizeP.
+ An error message is returned, or NULL on OK. */
+
+/* Equal to MAX_PRECISION in atof-ieee.c. */
+#define MAX_LITTLENUMS 6
+
+char *
+md_atof (type, litP, sizeP)
+ char type;
+ char * litP;
+ int * sizeP;
+{
+ int prec;
+ LITTLENUM_TYPE words [MAX_LITTLENUMS];
+ LITTLENUM_TYPE *wordP;
+ char * t;
+
+ switch (type)
+ {
+ case 'f':
+ case 'F':
+ prec = 2;
+ break;
+
+ case 'd':
+ case 'D':
+ prec = 4;
+ break;
+
+ /* FIXME: Some targets allow other format chars for bigger sizes here. */
+
+ default:
+ *sizeP = 0;
+ return _("Bad call to md_atof()");
+ }
+
+ t = atof_ieee (input_line_pointer, type, words);
+ if (t)
+ input_line_pointer = t;
+ *sizeP = prec * sizeof (LITTLENUM_TYPE);
+
+ *sizeP = prec * sizeof (LITTLENUM_TYPE);
+ /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
+ the littleendianness of the processor. */
+ for (wordP = words + prec - 1; prec--;)
+ {
+ md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE));
+ litP += sizeof (LITTLENUM_TYPE);
+ }
+
+ return 0;
+}
+
+
+/* If while processing a fixup, a reloc really needs to be created
+ then it is done here. */
+
+arelent *
+tc_gen_reloc (seg, fixp)
+ asection *seg ATTRIBUTE_UNUSED;
+ fixS *fixp;
+{
+ arelent *reloc;
+
+ reloc = (arelent *) xmalloc (sizeof (arelent));
+ reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+ reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+ reloc->addend = fixp->fx_offset;
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
+
+ if (reloc->howto == (reloc_howto_type *) NULL)
+ {
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ /* xgettext:c-format. */
+ _("reloc %d not supported by object file format"),
+ (int) fixp->fx_r_type);
+
+ xfree (reloc);
+
+ return NULL;
+ }
+
+ return reloc;
+}
+
+/* The location from which a PC relative jump should be calculated,
+ given a PC relative reloc. */
+
+long
+md_pcrel_from_section (fixP, sec)
+ fixS *fixP;
+ segT sec;
+{
+ if (fixP->fx_addsy != (symbolS *) NULL
+ && (!S_IS_DEFINED (fixP->fx_addsy)
+ || S_GET_SEGMENT (fixP->fx_addsy) != sec))
+ {
+ /* The symbol is undefined (or is defined but not in this section).
+ Let the linker figure it out. */
+ return 0;
+ }
+ return fixP->fx_frag->fr_address + fixP->fx_where;
+}
+
+/* Return true if the fix can be handled by GAS, false if it must
+ be passed through to the linker. */
+
+bfd_boolean
+bfin_fix_adjustable (fixS *fixP)
+{
+ switch (fixP->fx_r_type)
+ {
+ /* Adjust_reloc_syms doesn't know about the GOT. */
+ case BFD_RELOC_BFIN_GOT :
+ case BFD_RELOC_BFIN_PLTPC :
+ /* We need the symbol name for the VTABLE entries. */
+ case BFD_RELOC_VTABLE_INHERIT:
+ case BFD_RELOC_VTABLE_ENTRY:
+ return 0;
+
+ default:
+ return 1;
+ }
+}
+
+
+/* Handle the LOOP_BEGIN and LOOP_END statements.
+ Parse the Loop_Begin/Loop_End and create a label. */
+void
+bfin_start_line_hook ()
+{
+ bfd_boolean maybe_begin = FALSE;
+ bfd_boolean maybe_end = FALSE;
+
+ char *c1, *label_name;
+ symbolS *line_label;
+ char *c = input_line_pointer;
+
+ while (ISSPACE (*c))
+ c++;
+
+ /* Look for LSETUP(. */
+ if (!strncasecmp (input_line_pointer, "lsetup(", 7))
+ {
+ /* Need to insert space between lsetup and paren. */
+ input_line_pointer --;
+ input_line_pointer[0] = 'l';
+ input_line_pointer[1] = 's';
+ input_line_pointer[2] = 'e';
+ input_line_pointer[3] = 't';
+ input_line_pointer[4] = 'u';
+ input_line_pointer[5] = 'p';
+ input_line_pointer[6] = ' ';
+ return;
+ }
+
+ /* Look for Loop_Begin or Loop_End statements. */
+
+ if (*c != 'L' && *c != 'l')
+ return;
+
+ c++;
+ if (*c != 'O' && *c != 'o')
+ return;
+
+ c++;
+ if (*c != 'O' && *c != 'o')
+ return;
+
+ c++;
+ if (*c != 'P' && *c != 'p')
+ return;
+
+ c++;
+ if (*c != '_')
+ return;
+
+ c++;
+ if (*c == 'E' || *c == 'e')
+ maybe_end = TRUE;
+ else if (*c == 'B' || *c == 'b')
+ maybe_begin = TRUE;
+ else
+ return;
+
+ if (maybe_end)
+ {
+ c++;
+ if (*c != 'N' && *c != 'n')
+ return;
+
+ c++;
+ if (*c != 'D' && *c != 'd')
+ return;
+ }
+
+ if (maybe_begin)
+ {
+ c++;
+ if (*c != 'E' && *c != 'e')
+ return;
+
+ c++;
+ if (*c != 'G' && *c != 'g')
+ return;
+
+ c++;
+ if (*c != 'I' && *c != 'i')
+ return;
+
+ c++;
+ if (*c != 'N' && *c != 'n')
+ return;
+ }
+
+ c++;
+ while (ISSPACE (*c)) c++;
+ c1 = c;
+ while (ISALPHA (*c) || ISDIGIT (*c) || *c == '_') c++;
+
+ input_line_pointer = c;
+ if (maybe_end)
+ {
+ label_name = (char *) xmalloc ((c - c1) + strlen ("__END") + 1);
+ label_name[0] = 0;
+ strncat (label_name, c1, c-c1);
+ strcat (label_name, "__END");
+ }
+ else /* maybe_begin. */
+ {
+ label_name = (char *) xmalloc ((c - c1) + strlen ("__BEGIN") + 1);
+ label_name[0] = 0;
+ strncat (label_name, c1, c-c1);
+ strcat (label_name, "__BEGIN");
+ }
+
+ line_label = colon (label_name);
+
+ /* Loop_End follows the last instruction in the loop.
+ Adjust label address. */
+ if (maybe_end)
+ line_label->sy_value.X_add_number -= last_insn_size;
+
+}
+
+/* Special extra functions that help bfin-parse.y perform its job. */
+
+#include <stdio.h>
+#include <assert.h>
+#include <obstack.h>
+#include <bfd.h>
+#include "bfin-defs.h"
+
+struct obstack mempool;
+
+INSTR_T
+conscode (INSTR_T head, INSTR_T tail)
+{
+ if (!head)
+ return tail;
+ head->next = tail;
+ return head;
+}
+
+INSTR_T
+conctcode (INSTR_T head, INSTR_T tail)
+{
+ INSTR_T temp = (head);
+ if (!head)
+ return tail;
+ while (temp->next)
+ temp = temp->next;
+ temp->next = tail;
+
+ return head;
+}
+
+INSTR_T
+note_reloc (INSTR_T code, Expr_Node * symbol, int reloc, int pcrel)
+{
+ /* Assert that the symbol is not an operator. */
+ assert (symbol->type == Expr_Node_Reloc);
+
+ return note_reloc1 (code, symbol->value.s_value, reloc, pcrel);
+
+}
+
+INSTR_T
+note_reloc1 (INSTR_T code, const char *symbol, int reloc, int pcrel)
+{
+ code->reloc = reloc;
+ code->exp = mkexpr (0, symbol_find_or_make (symbol));
+ code->pcrel = pcrel;
+ return code;
+}
+
+INSTR_T
+note_reloc2 (INSTR_T code, const char *symbol, int reloc, int value, int pcrel)
+{
+ code->reloc = reloc;
+ code->exp = mkexpr (value, symbol_find_or_make (symbol));
+ code->pcrel = pcrel;
+ return code;
+}
+
+INSTR_T
+gencode (unsigned long x)
+{
+ INSTR_T cell = (INSTR_T) obstack_alloc (&mempool, sizeof (struct bfin_insn));
+ memset (cell, 0, sizeof (struct bfin_insn));
+ cell->value = (x);
+ return cell;
+}
+
+int reloc;
+int ninsns;
+int count_insns;
+
+static void *
+allocate (int n)
+{
+ return (void *) obstack_alloc (&mempool, n);
+}
+
+Expr_Node *
+Expr_Node_Create (Expr_Node_Type type,
+ Expr_Node_Value value,
+ Expr_Node *Left_Child,
+ Expr_Node *Right_Child)
+{
+
+
+ Expr_Node *node = (Expr_Node *) allocate (sizeof (Expr_Node));
+ node->type = type;
+ node->value = value;
+ node->Left_Child = Left_Child;
+ node->Right_Child = Right_Child;
+ return node;
+}
+
+static const char *con = ".__constant";
+static const char *op = ".__operator";
+static INSTR_T Expr_Node_Gen_Reloc_R (Expr_Node * head);
+INSTR_T Expr_Node_Gen_Reloc (Expr_Node *head, int parent_reloc);
+
+INSTR_T
+Expr_Node_Gen_Reloc (Expr_Node * head, int parent_reloc)
+{
+ /* Top level reloction expression generator VDSP style.
+ If the relocation is just by itself, generate one item
+ else generate this convoluted expression. */
+
+ INSTR_T note = NULL_CODE;
+ INSTR_T note1 = NULL_CODE;
+ int pcrel = 1; /* Is the parent reloc pcrelative?
+ This calculation here and HOWTO should match. */
+
+ if (parent_reloc)
+ {
+ /* If it's 32 bit quantity then 16bit code needs to be added. */
+ int value = 0;
+
+ if (head->type == Expr_Node_Constant)
+ {
+ /* If note1 is not null code, we have to generate a right
+ aligned value for the constant. Otherwise the reloc is
+ a part of the basic command and the yacc file
+ generates this. */
+ value = head->value.i_value;
+ }
+ switch (parent_reloc)
+ {
+ /* Some reloctions will need to allocate extra words. */
+ case BFD_RELOC_BFIN_16_IMM:
+ case BFD_RELOC_BFIN_16_LOW:
+ case BFD_RELOC_BFIN_16_HIGH:
+ note1 = conscode (gencode (value), NULL_CODE);
+ pcrel = 0;
+ break;
+ case BFD_RELOC_BFIN_PLTPC:
+ note1 = conscode (gencode (value), NULL_CODE);
+ pcrel = 0;
+ break;
+ case BFD_RELOC_16:
+ case BFD_RELOC_BFIN_GOT:
+ note1 = conscode (gencode (value), NULL_CODE);
+ pcrel = 0;
+ break;
+ case BFD_RELOC_24_PCREL:
+ case BFD_RELOC_BFIN_24_PCREL_JUMP_L:
+ case BFD_RELOC_BFIN_24_PCREL_CALL_X:
+ /* These offsets are even numbered pcrel. */
+ note1 = conscode (gencode (value >> 1), NULL_CODE);
+ break;
+ default:
+ note1 = NULL_CODE;
+ }
+ }
+ if (head->type == Expr_Node_Constant)
+ note = note1;
+ else if (head->type == Expr_Node_Reloc)
+ {
+ note = note_reloc1 (gencode (0), head->value.s_value, parent_reloc, pcrel);
+ if (note1 != NULL_CODE)
+ note = conscode (note1, note);
+ }
+ else
+ {
+ /* Call the recursive function. */
+ note = note_reloc1 (gencode (0), op, parent_reloc, pcrel);
+ if (note1 != NULL_CODE)
+ note = conscode (note1, note);
+ note = conctcode (Expr_Node_Gen_Reloc_R (head), note);
+ }
+ return note;
+}
+
+static INSTR_T
+Expr_Node_Gen_Reloc_R (Expr_Node * head)
+{
+
+ INSTR_T note = 0;
+ INSTR_T note1 = 0;
+
+ switch (head->type)
+ {
+ case Expr_Node_Constant:
+ note = conscode (note_reloc2 (gencode (0), con, BFD_ARELOC_BFIN_CONST, head->value.i_value, 0), NULL_CODE);
+ break;
+ case Expr_Node_Reloc:
+ note = conscode (note_reloc (gencode (0), head, BFD_ARELOC_BFIN_PUSH, 0), NULL_CODE);
+ break;
+ case Expr_Node_Binop:
+ note1 = conctcode (Expr_Node_Gen_Reloc_R (head->Left_Child), Expr_Node_Gen_Reloc_R (head->Right_Child));
+ switch (head->value.op_value)
+ {
+ case Expr_Op_Type_Add:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_ADD, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_Sub:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_SUB, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_Mult:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_MULT, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_Div:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_DIV, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_Mod:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_MOD, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_Lshift:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_LSHIFT, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_Rshift:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_RSHIFT, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_BAND:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_AND, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_BOR:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_OR, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_BXOR:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_XOR, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_LAND:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_LAND, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_LOR:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_LOR, 0), NULL_CODE));
+ break;
+ default:
+ fprintf (stderr, "%s:%d:Unkonwn operator found for arithmetic" " relocation", __FILE__, __LINE__);
+
+
+ }
+ break;
+ case Expr_Node_Unop:
+ note1 = conscode (Expr_Node_Gen_Reloc_R (head->Left_Child), NULL_CODE);
+ switch (head->value.op_value)
+ {
+ case Expr_Op_Type_NEG:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_NEG, 0), NULL_CODE));
+ break;
+ case Expr_Op_Type_COMP:
+ note = conctcode (note1, conscode (note_reloc1 (gencode (0), op, BFD_ARELOC_BFIN_COMP, 0), NULL_CODE));
+ break;
+ default:
+ fprintf (stderr, "%s:%d:Unkonwn operator found for arithmetic" " relocation", __FILE__, __LINE__);
+ }
+ break;
+ default:
+ fprintf (stderr, "%s:%d:Unknown node expression found during " "arithmetic relocation generation", __FILE__, __LINE__);
+ }
+ return note;
+}
+
+
+/* Blackfin opcode generation. */
+
+/* These functions are called by the generated parser
+ (from bfin-parse.y), the register type classification
+ happens in bfin-lex.l. */
+
+#include "bfin-aux.h"
+#include "opcode/bfin.h"
+
+#define INIT(t) t c_code = init_##t
+#define ASSIGN(x) c_code.opcode |= ((x & c_code.mask_##x)<<c_code.bits_##x)
+#define ASSIGN_R(x) c_code.opcode |= (((x ? (x->regno & CODE_MASK) : 0) & c_code.mask_##x)<<c_code.bits_##x)
+
+#define HI(x) ((x >> 16) & 0xffff)
+#define LO(x) ((x ) & 0xffff)
+
+#define GROUP(x) ((x->regno & CLASS_MASK) >> 4)
+
+#define GEN_OPCODE32() \
+ conscode (gencode (HI (c_code.opcode)), \
+ conscode (gencode (LO (c_code.opcode)), NULL_CODE))
+
+#define GEN_OPCODE16() \
+ conscode (gencode (c_code.opcode), NULL_CODE)
+
+
+/* 32 BIT INSTRUCTIONS. */
+
+
+/* DSP32 instruction generation. */
+
+INSTR_T
+bfin_gen_dsp32mac (int op1, int MM, int mmod, int w1, int P,
+ int h01, int h11, int h00, int h10, int op0,
+ REG_T dst, REG_T src0, REG_T src1, int w0)
+{
+ INIT (DSP32Mac);
+
+ ASSIGN (op0);
+ ASSIGN (op1);
+ ASSIGN (MM);
+ ASSIGN (mmod);
+ ASSIGN (w0);
+ ASSIGN (w1);
+ ASSIGN (h01);
+ ASSIGN (h11);
+ ASSIGN (h00);
+ ASSIGN (h10);
+ ASSIGN (P);
+
+ /* If we have full reg assignments, mask out LSB to encode
+ single or simultaneous even/odd register moves. */
+ if (P)
+ {
+ dst->regno &= 0x06;
+ }
+
+ ASSIGN_R (dst);
+ ASSIGN_R (src0);
+ ASSIGN_R (src1);
+
+ return GEN_OPCODE32 ();
+}
+
+INSTR_T
+bfin_gen_dsp32mult (int op1, int MM, int mmod, int w1, int P,
+ int h01, int h11, int h00, int h10, int op0,
+ REG_T dst, REG_T src0, REG_T src1, int w0)
+{
+ INIT (DSP32Mult);
+
+ ASSIGN (op0);
+ ASSIGN (op1);
+ ASSIGN (MM);
+ ASSIGN (mmod);
+ ASSIGN (w0);
+ ASSIGN (w1);
+ ASSIGN (h01);
+ ASSIGN (h11);
+ ASSIGN (h00);
+ ASSIGN (h10);
+ ASSIGN (P);
+
+ if (P)
+ {
+ dst->regno &= 0x06;
+ }
+
+ ASSIGN_R (dst);
+ ASSIGN_R (src0);
+ ASSIGN_R (src1);
+
+ return GEN_OPCODE32 ();
+}
+
+INSTR_T
+bfin_gen_dsp32alu (int HL, int aopcde, int aop, int s, int x,
+ REG_T dst0, REG_T dst1, REG_T src0, REG_T src1)
+{
+ INIT (DSP32Alu);
+
+ ASSIGN (HL);
+ ASSIGN (aopcde);
+ ASSIGN (aop);
+ ASSIGN (s);
+ ASSIGN (x);
+ ASSIGN_R (dst0);
+ ASSIGN_R (dst1);
+ ASSIGN_R (src0);
+ ASSIGN_R (src1);
+
+ return GEN_OPCODE32 ();
+}
+
+INSTR_T
+bfin_gen_dsp32shift (int sopcde, REG_T dst0, REG_T src0,
+ REG_T src1, int sop, int HLs)
+{
+ INIT (DSP32Shift);
+
+ ASSIGN (sopcde);
+ ASSIGN (sop);
+ ASSIGN (HLs);
+
+ ASSIGN_R (dst0);
+ ASSIGN_R (src0);
+ ASSIGN_R (src1);
+
+ return GEN_OPCODE32 ();
+}
+
+INSTR_T
+bfin_gen_dsp32shiftimm (int sopcde, REG_T dst0, int immag,
+ REG_T src1, int sop, int HLs)
+{
+ INIT (DSP32ShiftImm);
+
+ ASSIGN (sopcde);
+ ASSIGN (sop);
+ ASSIGN (HLs);
+
+ ASSIGN_R (dst0);
+ ASSIGN (immag);
+ ASSIGN_R (src1);
+
+ return GEN_OPCODE32 ();
+}
+
+/* LOOP SETUP. */
+
+INSTR_T
+bfin_gen_loopsetup (Expr_Node * psoffset, REG_T c, int rop,
+ Expr_Node * peoffset, REG_T reg)
+{
+ int soffset, eoffset;
+ INIT (LoopSetup);
+
+ soffset = (EXPR_VALUE (psoffset) >> 1);
+ ASSIGN (soffset);
+ eoffset = (EXPR_VALUE (peoffset) >> 1);
+ ASSIGN (eoffset);
+ ASSIGN (rop);
+ ASSIGN_R (c);
+ ASSIGN_R (reg);
+
+ return
+ conscode (gencode (HI (c_code.opcode)),
+ conctcode (Expr_Node_Gen_Reloc (psoffset, BFD_RELOC_BFIN_5_PCREL),
+ conctcode (gencode (LO (c_code.opcode)), Expr_Node_Gen_Reloc (peoffset, BFD_RELOC_BFIN_11_PCREL))));
+
+}
+
+/* Call, Link. */
+
+INSTR_T
+bfin_gen_calla (Expr_Node * addr, int S)
+{
+ int val;
+ int high_val;
+ int reloc = 0;
+ INIT (CALLa);
+
+ switch(S){
+ case 0 : reloc = BFD_RELOC_BFIN_24_PCREL_JUMP_L; break;
+ case 1 : reloc = BFD_RELOC_24_PCREL; break;
+ case 2 : reloc = BFD_RELOC_BFIN_PLTPC; break;
+ default : break;
+ }
+
+ ASSIGN (S);
+
+ val = EXPR_VALUE (addr) >> 1;
+ high_val = val >> 16;
+
+ return conscode (gencode (HI (c_code.opcode) | (high_val & 0xff)),
+ Expr_Node_Gen_Reloc (addr, reloc));
+ }
+
+INSTR_T
+bfin_gen_linkage (int R, int framesize)
+{
+ INIT (Linkage);
+
+ ASSIGN (R);
+ ASSIGN (framesize);
+
+ return GEN_OPCODE32 ();
+}
+
+
+/* Load and Store. */
+
+INSTR_T
+bfin_gen_ldimmhalf (REG_T reg, int H, int S, int Z, Expr_Node * phword, int reloc)
+{
+ int grp, hword;
+ unsigned val = EXPR_VALUE (phword);
+ INIT (LDIMMhalf);
+
+ ASSIGN (H);
+ ASSIGN (S);
+ ASSIGN (Z);
+
+ ASSIGN_R (reg);
+ grp = (GROUP (reg));
+ ASSIGN (grp);
+ if (reloc == 2)
+ {
+ return conscode (gencode (HI (c_code.opcode)), Expr_Node_Gen_Reloc (phword, BFD_RELOC_BFIN_16_IMM));
+ }
+ else if (reloc == 1)
+ {
+ return conscode (gencode (HI (c_code.opcode)), Expr_Node_Gen_Reloc (phword, IS_H (*reg) ? BFD_RELOC_BFIN_16_HIGH : BFD_RELOC_BFIN_16_LOW));
+ }
+ else
+ {
+ hword = val;
+ ASSIGN (hword);
+ }
+ return GEN_OPCODE32 ();
+}
+
+INSTR_T
+bfin_gen_ldstidxi (REG_T ptr, REG_T reg, int W, int sz, int Z, Expr_Node * poffset)
+{
+ int offset;
+ int value = 0;
+ INIT (LDSTidxI);
+
+ if (!IS_PREG (*ptr) || (!IS_DREG (*reg) && !Z))
+ {
+ fprintf (stderr, "Warning: possible mixup of Preg/Dreg\n");
+ return 0;
+ }
+
+ ASSIGN_R (ptr);
+ ASSIGN_R (reg);
+ ASSIGN (W);
+ ASSIGN (sz);
+ switch (sz)
+ {
+ case 0:
+ value = EXPR_VALUE (poffset) >> 2;
+ break;
+ case 1:
+ value = EXPR_VALUE (poffset) >> 1;
+ break;
+ case 2:
+ value = EXPR_VALUE (poffset);
+ break;
+ }
+
+
+ ASSIGN (Z);
+
+ offset = (value & 0xffff);
+ ASSIGN (offset);
+ /* TODO : test if you need to check this here.
+ The reloc case should automatically generate instruction
+ if constant. */
+ if(poffset->type != Expr_Node_Constant){
+ /* A GOT relocation such as R0 = [P5 + symbol@GOT].
+ Distinguish between R0 = [P5 + symbol@GOT] and
+ P5 = [P5 + _current_shared_library_p5_offset_]. */
+ if(!strcmp(poffset->value.s_value, "_current_shared_library_p5_offset_")){
+ return conscode (gencode (HI (c_code.opcode)),
+ Expr_Node_Gen_Reloc(poffset, BFD_RELOC_16));
+ }
+ else
+ {
+ return conscode (gencode (HI (c_code.opcode)),
+ Expr_Node_Gen_Reloc(poffset, BFD_RELOC_BFIN_GOT));
+ }
+ }
+ else{
+ return GEN_OPCODE32 ();
+ }
+}
+
+
+INSTR_T
+bfin_gen_ldst (REG_T ptr, REG_T reg, int aop, int sz, int Z, int W)
+{
+ INIT (LDST);
+
+ if (!IS_PREG (*ptr) || (!IS_DREG (*reg) && !Z))
+ {
+ fprintf (stderr, "Warning: possible mixup of Preg/Dreg\n");
+ return 0;
+ }
+
+ ASSIGN_R (ptr);
+ ASSIGN_R (reg);
+ ASSIGN (aop);
+ ASSIGN (sz);
+ ASSIGN (Z);
+ ASSIGN (W);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_ldstii (REG_T ptr, REG_T reg, Expr_Node * poffset, int W, int op)
+{
+ int offset;
+ int value = 0;
+ INIT (LDSTii);
+
+
+ if (!IS_PREG (*ptr))
+ {
+ fprintf (stderr, "Warning: possible mixup of Preg/Dreg\n");
+ return 0;
+ }
+
+ switch (op)
+ {
+ case 1:
+ case 2:
+ value = EXPR_VALUE (poffset) >> 1;
+ break;
+ case 0:
+ case 3:
+ value = EXPR_VALUE (poffset) >> 2;
+ break;
+ }
+
+ ASSIGN_R (ptr);
+ ASSIGN_R (reg);
+
+ offset = value;
+ ASSIGN (offset);
+ ASSIGN (W);
+ ASSIGN (op);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_ldstiifp (REG_T sreg, Expr_Node * poffset, int W)
+{
+ /* Set bit 4 if it's a Preg. */
+ int reg = (sreg->regno & CODE_MASK) | (IS_PREG (*sreg) ? 0x8 : 0x0);
+ int offset = ((~(EXPR_VALUE (poffset) >> 2)) & 0x1f) + 1;
+ INIT (LDSTiiFP);
+ ASSIGN (reg);
+ ASSIGN (offset);
+ ASSIGN (W);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_ldstpmod (REG_T ptr, REG_T reg, int aop, int W, REG_T idx)
+{
+ INIT (LDSTpmod);
+
+ ASSIGN_R (ptr);
+ ASSIGN_R (reg);
+ ASSIGN (aop);
+ ASSIGN (W);
+ ASSIGN_R (idx);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_dspldst (REG_T i, REG_T reg, int aop, int W, int m)
+{
+ INIT (DspLDST);
+
+ ASSIGN_R (i);
+ ASSIGN_R (reg);
+ ASSIGN (aop);
+ ASSIGN (W);
+ ASSIGN (m);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_logi2op (int opc, int src, int dst)
+{
+ INIT (LOGI2op);
+
+ ASSIGN (opc);
+ ASSIGN (src);
+ ASSIGN (dst);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_brcc (int T, int B, Expr_Node * poffset)
+{
+ int offset;
+ INIT (BRCC);
+
+ ASSIGN (T);
+ ASSIGN (B);
+ offset = ((EXPR_VALUE (poffset) >> 1));
+ ASSIGN (offset);
+ return conscode (gencode (c_code.opcode), Expr_Node_Gen_Reloc (poffset, BFD_RELOC_BFIN_10_PCREL));
+}
+
+INSTR_T
+bfin_gen_ujump (Expr_Node * poffset)
+{
+ int offset;
+ INIT (UJump);
+
+ offset = ((EXPR_VALUE (poffset) >> 1));
+ ASSIGN (offset);
+
+ return conscode (gencode (c_code.opcode),
+ Expr_Node_Gen_Reloc (
+ poffset, BFD_RELOC_BFIN_12_PCREL_JUMP_S));
+}
+
+INSTR_T
+bfin_gen_alu2op (REG_T dst, REG_T src, int opc)
+{
+ INIT (ALU2op);
+
+ ASSIGN_R (dst);
+ ASSIGN_R (src);
+ ASSIGN (opc);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_compi2opd (REG_T dst, int src, int op)
+{
+ INIT (COMPI2opD);
+
+ ASSIGN_R (dst);
+ ASSIGN (src);
+ ASSIGN (op);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_compi2opp (REG_T dst, int src, int op)
+{
+ INIT (COMPI2opP);
+
+ ASSIGN_R (dst);
+ ASSIGN (src);
+ ASSIGN (op);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_dagmodik (REG_T i, int op)
+{
+ INIT (DagMODik);
+
+ ASSIGN_R (i);
+ ASSIGN (op);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_dagmodim (REG_T i, REG_T m, int op, int br)
+{
+ INIT (DagMODim);
+
+ ASSIGN_R (i);
+ ASSIGN_R (m);
+ ASSIGN (op);
+ ASSIGN (br);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_ptr2op (REG_T dst, REG_T src, int opc)
+{
+ INIT (PTR2op);
+
+ ASSIGN_R (dst);
+ ASSIGN_R (src);
+ ASSIGN (opc);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_comp3op (REG_T src0, REG_T src1, REG_T dst, int opc)
+{
+ INIT (COMP3op);
+
+ ASSIGN_R (src0);
+ ASSIGN_R (src1);
+ ASSIGN_R (dst);
+ ASSIGN (opc);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_ccflag (REG_T x, int y, int opc, int I, int G)
+{
+ INIT (CCflag);
+
+ ASSIGN_R (x);
+ ASSIGN (y);
+ ASSIGN (opc);
+ ASSIGN (I);
+ ASSIGN (G);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_ccmv (REG_T src, REG_T dst, int T)
+{
+ int s, d;
+ INIT (CCmv);
+
+ ASSIGN_R (src);
+ ASSIGN_R (dst);
+ s = (GROUP (src));
+ ASSIGN (s);
+ d = (GROUP (dst));
+ ASSIGN (d);
+ ASSIGN (T);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_cc2stat (int cbit, int op, int D)
+{
+ INIT (CC2stat);
+
+ ASSIGN (cbit);
+ ASSIGN (op);
+ ASSIGN (D);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_regmv (REG_T src, REG_T dst)
+{
+ int gs, gd;
+ INIT (RegMv);
+
+ ASSIGN_R (src);
+ ASSIGN_R (dst);
+
+ gs = (GROUP (src));
+ ASSIGN (gs);
+ gd = (GROUP (dst));
+ ASSIGN (gd);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_cc2dreg (int op, REG_T reg)
+{
+ INIT (CC2dreg);
+
+ ASSIGN (op);
+ ASSIGN_R (reg);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_progctrl (int prgfunc, int poprnd)
+{
+ INIT (ProgCtrl);
+
+ ASSIGN (prgfunc);
+ ASSIGN (poprnd);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_cactrl (REG_T reg, int a, int op)
+{
+ INIT (CaCTRL);
+
+ ASSIGN_R (reg);
+ ASSIGN (a);
+ ASSIGN (op);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_pushpopmultiple (int dr, int pr, int d, int p, int W)
+{
+ INIT (PushPopMultiple);
+
+ ASSIGN (dr);
+ ASSIGN (pr);
+ ASSIGN (d);
+ ASSIGN (p);
+ ASSIGN (W);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_pushpopreg (REG_T reg, int W)
+{
+ int grp;
+ INIT (PushPopReg);
+
+ ASSIGN_R (reg);
+ grp = (GROUP (reg));
+ ASSIGN (grp);
+ ASSIGN (W);
+
+ return GEN_OPCODE16 ();
+}
+
+/* Pseudo Debugging Support. */
+
+INSTR_T
+bfin_gen_pseudodbg (int fn, int reg, int grp)
+{
+ INIT (PseudoDbg);
+
+ ASSIGN (fn);
+ ASSIGN (reg);
+ ASSIGN (grp);
+
+ return GEN_OPCODE16 ();
+}
+
+INSTR_T
+bfin_gen_pseudodbg_assert (int dbgop, REG_T regtest, int expected)
+{
+ INIT (PseudoDbg_Assert);
+
+ ASSIGN (dbgop);
+ ASSIGN_R (regtest);
+ ASSIGN (expected);
+
+ return GEN_OPCODE32 ();
+}
+
+/* Multiple instruction generation. */
+
+INSTR_T
+bfin_gen_multi_instr (INSTR_T dsp32, INSTR_T dsp16_grp1, INSTR_T dsp16_grp2)
+{
+ INSTR_T walk;
+
+ /* If it's a 0, convert into MNOP. */
+ if (dsp32)
+ {
+ walk = dsp32->next;
+ SET_MULTI_INSTRUCTION_BIT (dsp32);
+ }
+ else
+ {
+ dsp32 = gencode (0xc803);
+ walk = gencode (0x1800);
+ dsp32->next = walk;
+ }
+
+ if (!dsp16_grp1)
+ {
+ dsp16_grp1 = gencode (0x0000);
+ }
+
+ if (!dsp16_grp2)
+ {
+ dsp16_grp2 = gencode (0x0000);
+ }
+
+ walk->next = dsp16_grp1;
+ dsp16_grp1->next = dsp16_grp2;
+ dsp16_grp2->next = NULL_CODE;
+
+ return dsp32;
+}
+
+INSTR_T
+bfin_gen_loop (Expr_Node *expr, REG_T reg, int rop, REG_T preg)
+{
+ const char *loopsym;
+ char *lbeginsym, *lendsym;
+ Expr_Node_Value lbeginval, lendval;
+ Expr_Node *lbegin, *lend;
+
+ loopsym = expr->value.s_value;
+ lbeginsym = (char *) xmalloc (strlen (loopsym) + strlen ("__BEGIN") + 1);
+ lendsym = (char *) xmalloc (strlen (loopsym) + strlen ("__END") + 1);
+
+ lbeginsym[0] = 0;
+ lendsym[0] = 0;
+
+ strcat (lbeginsym, loopsym);
+ strcat (lbeginsym, "__BEGIN");
+
+ strcat (lendsym, loopsym);
+ strcat (lendsym, "__END");
+
+ lbeginval.s_value = lbeginsym;
+ lendval.s_value = lendsym;
+
+ lbegin = Expr_Node_Create (Expr_Node_Reloc, lbeginval, NULL, NULL);
+ lend = Expr_Node_Create (Expr_Node_Reloc, lendval, NULL, NULL);
+ return bfin_gen_loopsetup(lbegin, reg, rop, lend, preg);
+}
+
+bfd_boolean
+bfin_eol_in_insn (char *line)
+{
+ /* Allow a new-line to appear in the middle of a multi-issue instruction. */
+
+ char *temp = line;
+
+ if (*line != '\n')
+ return FALSE;
+
+ /* A semi-colon followed by a newline is always the end of a line. */
+ if (line[-1] == ';')
+ return FALSE;
+
+ if (line[-1] == '|')
+ return TRUE;
+
+ /* If the || is on the next line, there might be leading whitespace. */
+ temp++;
+ while (*temp == ' ' || *temp == '\t') temp++;
+
+ if (*temp == '|')
+ return TRUE;
+
+ return FALSE;
+}
+
+bfd_boolean
+bfin_name_is_register (char *name)
+{
+ int i;
+
+ if (*name == '[' || *name == '(')
+ return TRUE;
+
+ if ((name[0] == 'W' || name[0] == 'w') && name[1] == '[')
+ return TRUE;
+
+ if ((name[0] == 'B' || name[0] == 'b') && name[1] == '[')
+ return TRUE;
+
+ if (!strncasecmp (name, "saa(", 4))
+ return TRUE;
+
+ if (!strncasecmp (name, "lsetup(", 7))
+ return TRUE;
+
+ for (i=0; bfin_reg_info[i].name != 0; i++)
+ {
+ if (!strcasecmp (bfin_reg_info[i].name, name))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+bfin_equals (Expr_Node *sym)
+{
+ char *c;
+
+ c = input_line_pointer;
+ while (*c != '=')
+ c--;
+
+ input_line_pointer = c;
+
+ equals ((char *) sym->value.s_value, 1);
+}
+
+bfd_boolean
+bfin_start_label (char *ptr)
+{
+ ptr--;
+ while (!ISSPACE (*ptr) && !is_end_of_line[(unsigned char) *ptr])
+ ptr--;
+
+ ptr++;
+ if (*ptr == '(' || *ptr == '[')
+ return FALSE;
+
+ if (!strncmp (ptr, "saa(", 4))
+ return FALSE;
+
+ if (!strncmp (ptr, "lsetup(", 7))
+ return FALSE;
+
+ return TRUE;
+}
+
+int
+bfin_force_relocation (struct fix *fixp)
+{
+ if (fixp->fx_r_type ==BFD_RELOC_BFIN_16_LOW
+ || fixp->fx_r_type == BFD_RELOC_BFIN_16_HIGH)
+ return TRUE;
+
+ return generic_force_reloc (fixp);
+}