diff options
author | Catherine Moore <clm@redhat.com> | 2005-09-30 15:05:07 +0000 |
---|---|---|
committer | Catherine Moore <clm@redhat.com> | 2005-09-30 15:05:07 +0000 |
commit | 07c1b327c74f8ed0552ac3871e1c47e33faecfd8 (patch) | |
tree | dc589f4974d25ae5e92ad097cddb9584869a1bd3 /gas | |
parent | bfe2612a1433668c85da535144ea3b045dd817f4 (diff) | |
download | binutils-gdb-07c1b327c74f8ed0552ac3871e1c47e33faecfd8.tar.gz |
* Makefile.am: Bfin support.
* Makefile.in: Regenerated.
* aclocal.m4: Regenerated.
* configure: Regenerated.
* configure.in: Bfin support.
* configure.tgt: Bfin support.
* config/bfin-aux.h: New file.
* config/bfin-defs.h: New file.
* config/bfin-lex.l: New file.
* config/bfin-parse.y: New file.
* config/tc-bfin.c: New file.
* config/tc-bfin.h: New file.
* doc/Makefile.am: Recognize c-bfin.texi.
* doc/Makefile.in: Regenerated.
* doc/all.texi: Bfin support.
* doc/as.texinfo: Likewise.
* doc/c-bfin.texi: Document bfin-specific syntax and
directives.
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 21 | ||||
-rw-r--r-- | gas/Makefile.am | 34 | ||||
-rw-r--r-- | gas/Makefile.in | 76 | ||||
-rw-r--r-- | gas/aclocal.m4 | 457 | ||||
-rwxr-xr-x | gas/config/bfin-aux.h | 151 | ||||
-rw-r--r-- | gas/config/bfin-defs.h | 383 | ||||
-rw-r--r-- | gas/config/bfin-lex.l | 554 | ||||
-rw-r--r-- | gas/config/bfin-parse.y | 4360 | ||||
-rw-r--r-- | gas/config/tc-bfin.c | 1951 | ||||
-rw-r--r-- | gas/config/tc-bfin.h | 75 | ||||
-rwxr-xr-x | gas/configure | 13 | ||||
-rw-r--r-- | gas/configure.in | 13 | ||||
-rw-r--r-- | gas/configure.tgt | 5 | ||||
-rw-r--r-- | gas/doc/Makefile.am | 1 | ||||
-rw-r--r-- | gas/doc/Makefile.in | 7 | ||||
-rw-r--r-- | gas/doc/all.texi | 1 | ||||
-rw-r--r-- | gas/doc/as.texinfo | 7 | ||||
-rw-r--r-- | gas/doc/c-bfin.texi | 187 |
18 files changed, 8140 insertions, 156 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 88b6511c096..c885fcfb0cc 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,24 @@ +2005-09-30 Catherine Moore <clm@cm00re.com> + + * Makefile.am: Bfin support. + * Makefile.in: Regenerated. + * aclocal.m4: Regenerated. + * configure: Regenerated. + * configure.in: Bfin support. + * configure.tgt: Bfin support. + * config/bfin-aux.h: New file. + * config/bfin-defs.h: New file. + * config/bfin-lex.l: New file. + * config/bfin-parse.y: New file. + * config/tc-bfin.c: New file. + * config/tc-bfin.h: New file. + * doc/Makefile.am: Recognize c-bfin.texi. + * doc/Makefile.in: Regenerated. + * doc/all.texi: Bfin support. + * doc/as.texinfo: Likewise. + * doc/c-bfin.texi: Document bfin-specific syntax and + directives. + 2005-09-30 Paul Brook <paul@codesourcery.com> * config/tc-arm.c (opcode_tag): Add OT_cinfix3_legacy. diff --git a/gas/Makefile.am b/gas/Makefile.am index eecedec1925..40fbc7d787a 100644 --- a/gas/Makefile.am +++ b/gas/Makefile.am @@ -45,6 +45,7 @@ CPU_TYPES = \ arc \ arm \ avr \ + bfin \ cris \ crx \ d10v \ @@ -227,6 +228,7 @@ TARGET_CPU_CFILES = \ config/tc-arc.c \ config/tc-arm.c \ config/tc-avr.c \ + config/tc-bfin.c \ config/tc-cris.c \ config/tc-crx.c \ config/tc-d10v.c \ @@ -275,6 +277,7 @@ TARGET_CPU_HFILES = \ config/tc-arc.h \ config/tc-arm.h \ config/tc-avr.h \ + config/tc-bfin.h \ config/tc-cris.h \ config/tc-crx.h \ config/tc-d10v.h \ @@ -437,7 +440,9 @@ noinst_PROGRAMS = as-new noinst_SCRIPTS = $(GDBINIT) EXTRA_SCRIPTS = .gdbinit -EXTRA_DIST = m68k-parse.c itbl-parse.c itbl-parse.h itbl-lex.c +EXTRA_DIST = m68k-parse.c itbl-parse.c itbl-parse.h itbl-lex.c \ + bfin-parse.c bfin-lex.l bfin-defs.h + diststuff: $(EXTRA_DIST) info all: info @@ -567,7 +572,7 @@ xtensa-relax.o: $(srcdir)/config/xtensa-relax.c # The m68k operand parser. -EXTRA_as_new_SOURCES = config/m68k-parse.y +EXTRA_as_new_SOURCES = config/m68k-parse.y config/bfin-parse.y # If m68k-parse.y is in a different directory, then ylwrap will use an # absolute path when it invokes yacc, which will cause yacc to put the @@ -600,6 +605,18 @@ m68k-parse.o: m68k-parse.c $(srcdir)/config/m68k-parse.h m68k-parse.h: ; @true $(srcdir)/config/m68k-parse.h: ; @true +bfin-parse.c bfin-parse.tab.h: $(srcdir)/config/bfin-parse.y + $(SHELL) $(YLWRAP) $(srcdir)/config/bfin-parse.y y.tab.c bfin-parse.c y.tab.h bfin-parse.tab.h -- $(YACCCOMPILE) -d ; +bfin-parse.o: bfin-parse.c bfin-parse.tab.h $(srcdir)/config/bfin-defs.h + +bfin-defs.h: ; @true +$(srcdir)/config/bfin-defs.h: ; @true + +bfin-lex.c: $(srcdir)/config/bfin-lex.l + $(SHELL) $(YLWRAP) "$(LEX)" <$(srcdir)/config/bfin-lex.l lex.yy.c bfin-lex.c +bfin-lex.o: bfin-lex.c bfin-parse.tab.h $(srcdir)/config/bfin-defs.h + $(COMPILE) -c $< $(NO_WERROR) + # The instruction table specification lexical analyzer and parser. itbl-lex.c: $(srcdir)/itbl-lex.l @@ -989,6 +1006,11 @@ DEPTC_avr_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-avr.h \ $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ $(INCDIR)/opcode/avr.h +DEPTC_bfin_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ + $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-bfin.h \ + $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ + $(INCDIR)/opcode/bfin.h $(srcdir)/config/bfin-defs.h DEPTC_cris_aout = $(INCDIR)/symcat.h $(srcdir)/config/obj-aout.h \ $(srcdir)/config/tc-cris.h $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h \ $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ @@ -1525,6 +1547,11 @@ DEPOBJ_avr_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-avr.h \ $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ struc-symbol.h dwarf2dbg.h $(INCDIR)/aout/aout64.h +DEPOBJ_bfin_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ + $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-bfin.h \ + $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ + struc-symbol.h dwarf2dbg.h $(INCDIR)/aout/aout64.h DEPOBJ_cris_aout = $(INCDIR)/symcat.h $(srcdir)/config/obj-aout.h \ $(srcdir)/config/tc-cris.h $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h \ $(INCDIR)/aout/aout64.h $(INCDIR)/obstack.h @@ -1968,6 +1995,9 @@ DEP_avr_coff = $(srcdir)/config/obj-coff.h $(srcdir)/config/tc-avr.h \ DEP_avr_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \ $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-avr.h +DEP_bfin_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \ + $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-bfin.h DEP_cris_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-cris.h \ $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h DEP_cris_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \ diff --git a/gas/Makefile.in b/gas/Makefile.in index e61635b180e..94b34e8ec77 100644 --- a/gas/Makefile.in +++ b/gas/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.9.5 from Makefile.am. +# Makefile.in generated by automake 1.9.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -42,14 +42,16 @@ host_triplet = @host@ target_triplet = @target@ noinst_PROGRAMS = as-new$(EXEEXT) EXTRA_PROGRAMS = itbl-test$(EXEEXT) -DIST_COMMON = $(srcdir)/../config.guess $(srcdir)/../config.sub NEWS \ - README ChangeLog $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ +DIST_COMMON = $(srcdir)/../config.guess $(srcdir)/../config.sub \ + INSTALL NEWS README AUTHORS ChangeLog THANKS \ + $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.in $(srcdir)/../mkinstalldirs \ $(srcdir)/gdbinit.in $(srcdir)/gdbinit.in \ - $(top_srcdir)/po/Make-in m68k-parse.c itbl-parse.c itbl-lex.c \ - $(srcdir)/../ylwrap $(srcdir)/../ltmain.sh \ - $(srcdir)/../config.guess $(srcdir)/../config.sub + $(top_srcdir)/po/Make-in m68k-parse.c bfin-parse.c \ + itbl-parse.c itbl-lex.c $(srcdir)/../ylwrap \ + $(srcdir)/../ltmain.sh $(srcdir)/../config.guess \ + $(srcdir)/../config.sub subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ @@ -274,6 +276,7 @@ CPU_TYPES = \ arc \ arm \ avr \ + bfin \ cris \ crx \ d10v \ @@ -454,6 +457,7 @@ TARGET_CPU_CFILES = \ config/tc-arc.c \ config/tc-arm.c \ config/tc-avr.c \ + config/tc-bfin.c \ config/tc-cris.c \ config/tc-crx.c \ config/tc-d10v.c \ @@ -502,6 +506,7 @@ TARGET_CPU_HFILES = \ config/tc-arc.h \ config/tc-arm.h \ config/tc-avr.h \ + config/tc-bfin.h \ config/tc-cris.h \ config/tc-crx.h \ config/tc-d10v.h \ @@ -656,7 +661,9 @@ POTFILES = $(MULTI_CFILES) $(TARGET_ENV_HFILES) $(OBJ_FORMAT_HFILES) \ noinst_SCRIPTS = $(GDBINIT) EXTRA_SCRIPTS = .gdbinit -EXTRA_DIST = m68k-parse.c itbl-parse.c itbl-parse.h itbl-lex.c +EXTRA_DIST = m68k-parse.c itbl-parse.c itbl-parse.h itbl-lex.c \ + bfin-parse.c bfin-lex.l bfin-defs.h + DISTCLEANFILES = targ-cpu.h obj-format.h targ-env.h itbl-cpu.h cgen-desc.h # Now figure out from those variables how to compile and link. @@ -698,7 +705,7 @@ RUNTEST = runtest RUNTESTFLAGS = # The m68k operand parser. -EXTRA_as_new_SOURCES = config/m68k-parse.y +EXTRA_as_new_SOURCES = config/m68k-parse.y config/bfin-parse.y itbl_test_SOURCES = itbl-parse.y itbl-lex.l itbl_test_LDADD = itbl-tops.o itbl-test.o $(GASLIBS) @LEXLIB@ @@ -786,6 +793,12 @@ DEPTC_avr_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ $(INCDIR)/opcode/avr.h +DEPTC_bfin_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ + $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-bfin.h \ + $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ + $(INCDIR)/opcode/bfin.h $(srcdir)/config/bfin-defs.h + DEPTC_cris_aout = $(INCDIR)/symcat.h $(srcdir)/config/obj-aout.h \ $(srcdir)/config/tc-cris.h $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h \ $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ @@ -1426,6 +1439,12 @@ DEPOBJ_avr_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ struc-symbol.h dwarf2dbg.h $(INCDIR)/aout/aout64.h +DEPOBJ_bfin_elf = $(INCDIR)/symcat.h $(srcdir)/config/obj-elf.h \ + $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-bfin.h \ + $(INCDIR)/safe-ctype.h subsegs.h $(INCDIR)/obstack.h \ + struc-symbol.h dwarf2dbg.h $(INCDIR)/aout/aout64.h + DEPOBJ_cris_aout = $(INCDIR)/symcat.h $(srcdir)/config/obj-aout.h \ $(srcdir)/config/tc-cris.h $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h \ $(INCDIR)/aout/aout64.h $(INCDIR)/obstack.h @@ -1972,6 +1991,10 @@ DEP_avr_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \ $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-avr.h +DEP_bfin_elf = $(srcdir)/config/obj-elf.h $(INCDIR)/symcat.h \ + $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(srcdir)/config/tc-bfin.h + DEP_cris_aout = $(srcdir)/config/obj-aout.h $(srcdir)/config/tc-cris.h \ $(BFDDIR)/libaout.h $(INCDIR)/bfdlink.h @@ -2438,6 +2461,9 @@ distclean-compile: .y.c: $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE) +bfin-parse.c: config/bfin-parse.y + $(SHELL) $(YLWRAP) `test -f 'config/bfin-parse.y' || echo '$(srcdir)/'`config/bfin-parse.y y.tab.c bfin-parse.c y.tab.h bfin-parse.h y.output bfin-parse.output -- $(YACC) $(YFLAGS) $(AM_YFLAGS) + mostlyclean-libtool: -rm -f *.lo @@ -2455,13 +2481,7 @@ uninstall-info-am: # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): - @failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ + @set fnord $$MAKEFLAGS; amf=$$2; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ @@ -2473,7 +2493,7 @@ $(RECURSIVE_TARGETS): local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ @@ -2481,13 +2501,7 @@ $(RECURSIVE_TARGETS): mostlyclean-recursive clean-recursive distclean-recursive \ maintainer-clean-recursive: - @failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ + @set fnord $$MAKEFLAGS; amf=$$2; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ @@ -2508,7 +2522,7 @@ maintainer-clean-recursive: local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ @@ -2637,6 +2651,7 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." + -rm -f bfin-parse.c -rm -f itbl-lex.c -rm -f itbl-parse.c -rm -f m68k-parse.c @@ -2713,6 +2728,7 @@ uninstall-info: uninstall-info-recursive po/POTFILES.in: @MAINT@ Makefile for f in $(POTFILES); do echo $$f; done | LC_COLLATE= sort > tmp \ && mv tmp $(srcdir)/po/POTFILES.in + diststuff: $(EXTRA_DIST) info all: info @@ -2827,6 +2843,18 @@ m68k-parse.o: m68k-parse.c $(srcdir)/config/m68k-parse.h m68k-parse.h: ; @true $(srcdir)/config/m68k-parse.h: ; @true +bfin-parse.c bfin-parse.tab.h: $(srcdir)/config/bfin-parse.y + $(SHELL) $(YLWRAP) $(srcdir)/config/bfin-parse.y y.tab.c bfin-parse.c y.tab.h bfin-parse.tab.h -- $(YACCCOMPILE) -d ; +bfin-parse.o: bfin-parse.c bfin-parse.tab.h $(srcdir)/config/bfin-defs.h + +bfin-defs.h: ; @true +$(srcdir)/config/bfin-defs.h: ; @true + +bfin-lex.c: $(srcdir)/config/bfin-lex.l + $(SHELL) $(YLWRAP) "$(LEX)" <$(srcdir)/config/bfin-lex.l lex.yy.c bfin-lex.c +bfin-lex.o: bfin-lex.c bfin-parse.tab.h $(srcdir)/config/bfin-defs.h + $(COMPILE) -c $< $(NO_WERROR) + # The instruction table specification lexical analyzer and parser. itbl-lex.c: $(srcdir)/itbl-lex.l diff --git a/gas/aclocal.m4 b/gas/aclocal.m4 index ca849970a1b..389bef76886 100644 --- a/gas/aclocal.m4 +++ b/gas/aclocal.m4 @@ -1,4 +1,4 @@ -# 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. @@ -11,11 +11,23 @@ # 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) # ---------------------------- @@ -28,15 +40,26 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) # 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 @@ -83,16 +106,26 @@ AC_PREREQ([2.50])dnl 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) # ------------------------------------- @@ -116,15 +149,26 @@ AC_CONFIG_COMMANDS_PRE( 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, @@ -133,6 +177,7 @@ fi])]) # CC etc. in the Makefile, will ask for an AC_PROG_CC use... + # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. @@ -272,16 +317,27 @@ AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) 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 # ------------------------------ @@ -340,31 +396,54 @@ AC_DEFUN([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]) @@ -466,27 +545,51 @@ for _am_header in $config_headers :; do 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. @@ -501,14 +604,26 @@ fi 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 # ----------- @@ -522,17 +637,28 @@ if test "$LEX" = :; then 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]) @@ -551,15 +677,26 @@ AC_DEFUN([AM_MAINTAINER_MODE], 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() # ----------------- @@ -603,16 +740,27 @@ AC_MSG_RESULT([$_am_result]) 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) # ------------------------------ @@ -638,16 +786,27 @@ else 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). @@ -701,15 +860,26 @@ else 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) # ----------------------- @@ -734,16 +904,28 @@ AC_DEFUN([_AM_SET_OPTIONS], 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 # --------------- @@ -786,14 +968,25 @@ Check your system clock]) 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 @@ -816,13 +1009,25 @@ AC_SUBST([INSTALL_STRIP_PROGRAM])]) # 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) # -------------------- diff --git a/gas/config/bfin-aux.h b/gas/config/bfin-aux.h new file mode 100755 index 00000000000..be6b63a65ec --- /dev/null +++ b/gas/config/bfin-aux.h @@ -0,0 +1,151 @@ +/* bfin-aux.h ADI Blackfin Header file for gas
+ 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 "bfin-defs.h"
+
+#define REG_T Register *
+
+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);
+
+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);
+
+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);
+
+INSTR_T
+bfin_gen_dsp32shift (int sopcde, REG_T dst0, REG_T src0, REG_T src1,
+ int sop, int hls);
+
+INSTR_T
+bfin_gen_dsp32shiftimm (int sopcde, REG_T dst0, int immag, REG_T src1,
+ int sop, int hls);
+
+INSTR_T
+bfin_gen_ldimmhalf (REG_T reg, int h, int s, int z, Expr_Node *hword,
+ int reloc);
+
+INSTR_T
+bfin_gen_ldstidxi (REG_T ptr, REG_T reg, int w, int sz, int z,
+ Expr_Node *offset);
+
+INSTR_T
+bfin_gen_ldst (REG_T ptr, REG_T reg, int aop, int sz, int z, int w);
+
+INSTR_T
+bfin_gen_ldstii (REG_T ptr, REG_T reg, Expr_Node *offset, int w, int op);
+
+INSTR_T
+bfin_gen_ldstiifp (REG_T reg, Expr_Node *offset, int w);
+
+INSTR_T
+bfin_gen_ldstpmod (REG_T ptr, REG_T reg, int aop, int w, REG_T idx);
+
+INSTR_T
+bfin_gen_dspldst (REG_T i, REG_T reg, int aop, int w, int m);
+
+INSTR_T
+bfin_gen_alu2op (REG_T dst, REG_T src, int opc);
+
+INSTR_T
+bfin_gen_compi2opd (REG_T dst, int src, int op);
+
+INSTR_T
+bfin_gen_compi2opp (REG_T dst, int src, int op);
+
+INSTR_T
+bfin_gen_dagmodik (REG_T i, int op);
+
+INSTR_T
+bfin_gen_dagmodim (REG_T i, REG_T m, int op, int br);
+
+INSTR_T
+bfin_gen_ptr2op (REG_T dst, REG_T src, int opc);
+
+INSTR_T
+bfin_gen_logi2op (int dst, int src, int opc);
+
+INSTR_T
+bfin_gen_comp3op (REG_T src0, REG_T src1, REG_T dst, int opc);
+
+INSTR_T
+bfin_gen_ccmv (REG_T src, REG_T dst, int t);
+
+INSTR_T
+bfin_gen_ccflag (REG_T x, int y, int opc, int i, int g);
+
+INSTR_T
+bfin_gen_cc2stat (int cbit, int op, int d);
+
+INSTR_T
+bfin_gen_regmv (REG_T src, REG_T dst);
+
+INSTR_T
+bfin_gen_cc2dreg (int op, REG_T reg);
+
+INSTR_T
+bfin_gen_brcc (int t, int b, Expr_Node *offset);
+
+INSTR_T
+bfin_gen_ujump (Expr_Node *offset);
+
+INSTR_T
+bfin_gen_cactrl (REG_T reg, int a, int op);
+
+INSTR_T
+bfin_gen_progctrl (int prgfunc, int poprnd);
+
+INSTR_T
+bfin_gen_loopsetup (Expr_Node *soffset, REG_T c, int rop,
+ Expr_Node *eoffset, REG_T reg);
+
+INSTR_T
+bfin_gen_loop (Expr_Node *expr, REG_T reg, int rop, REG_T preg);
+
+INSTR_T
+bfin_gen_pushpopmultiple (int dr, int pr, int d, int p, int w);
+
+INSTR_T
+bfin_gen_pushpopreg (REG_T reg, int w);
+
+INSTR_T
+bfin_gen_calla (Expr_Node *addr, int s);
+
+INSTR_T
+bfin_gen_linkage (int r, int framesize);
+
+INSTR_T
+bfin_gen_pseudodbg (int fn, int reg, int grp);
+
+INSTR_T
+bfin_gen_pseudodbg_assert (int dbgop, REG_T regtest, int expected);
+
+bfd_boolean
+bfin_resource_conflict (INSTR_T dsp32, INSTR_T dsp16_grp1, INSTR_T dsp16_grp2);
+
+INSTR_T
+bfin_gen_multi_instr (INSTR_T dsp32, INSTR_T dsp16_grp1, INSTR_T dsp16_grp2);
diff --git a/gas/config/bfin-defs.h b/gas/config/bfin-defs.h new file mode 100644 index 00000000000..221e8c40c8f --- /dev/null +++ b/gas/config/bfin-defs.h @@ -0,0 +1,383 @@ +/* bfin-defs.h ADI Blackfin gas header file + 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. */ + +#ifndef BFIN_PARSE_H +#define BFIN_PARSE_H + +#include <bfd.h> +#include "as.h" + +#define PCREL 1 +#define CODE_FRAG_SIZE 4096 /* 1 page. */ + + +/* Definition for all status bits. */ +typedef enum +{ + c_0, + c_1, + c_4, + c_2, + c_uimm2, + c_uimm3, + c_imm3, + c_pcrel4, + c_imm4, + c_uimm4s4, + c_uimm4, + c_uimm4s2, + c_negimm5s4, + c_imm5, + c_uimm5, + c_imm6, + c_imm7, + c_imm8, + c_uimm8, + c_pcrel8, + c_uimm8s4, + c_pcrel8s4, + c_lppcrel10, + c_pcrel10, + c_pcrel12, + c_imm16s4, + c_luimm16, + c_imm16, + c_huimm16, + c_rimm16, + c_imm16s2, + c_uimm16s4, + c_uimm16, + c_pcrel24 +} const_forms_t; + + +/* High-Nibble: group code, low nibble: register code. */ + + +#define T_REG_R 0x00 +#define T_REG_P 0x10 +#define T_REG_I 0x20 +#define T_REG_B 0x30 +#define T_REG_L 0x34 +#define T_REG_M 0x24 +#define T_REG_A 0x40 + +/* All registers above this value don't + belong to a usuable register group. */ +#define T_NOGROUP 0xa0 + +/* Flags. */ +#define F_REG_ALL 0x1000 +#define F_REG_HIGH 0x2000 /* Half register: high half. */ + +enum machine_registers +{ + REG_R0 = T_REG_R, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7, + REG_P0 = T_REG_P, REG_P1, REG_P2, REG_P3, REG_P4, REG_P5, REG_SP, REG_FP, + REG_I0 = T_REG_I, REG_I1, REG_I2, REG_I3, + REG_M0 = T_REG_M, REG_M1, REG_M2, REG_M3, + REG_B0 = T_REG_B, REG_B1, REG_B2, REG_B3, + REG_L0 = T_REG_L, REG_L1, REG_L2, REG_L3, + REG_A0x = T_REG_A, REG_A0w, REG_A1x, REG_A1w, + REG_ASTAT = 0x46, + REG_RETS = 0x47, + REG_LC0 = 0x60, REG_LT0, REG_LB0, REG_LC1, REG_LT1, REG_LB1, + REG_CYCLES, REG_CYCLES2, + REG_USP = 0x70, REG_SEQSTAT, REG_SYSCFG, + REG_RETI, REG_RETX, REG_RETN, REG_RETE, REG_EMUDAT, + +/* These don't have groups. */ + REG_sftreset = T_NOGROUP, REG_omode, REG_excause, REG_emucause, + REG_idle_req, REG_hwerrcause, + REG_A0 = 0xc0, REG_A1, REG_CC, +/* Pseudo registers, used only for distinction from symbols. */ + REG_RL0, REG_RL1, REG_RL2, REG_RL3, + REG_RL4, REG_RL5, REG_RL6, REG_RL7, + REG_RH0, REG_RH1, REG_RH2, REG_RH3, + REG_RH4, REG_RH5, REG_RH6, REG_RH7, + REG_LASTREG +}; + +/* Status register flags. */ + +enum statusflags +{ + S_AZ = 0, + S_AN, + S_AQ = 6, + S_AC0 = 12, + S_AC1, + S_AV0 = 16, + S_AV0S, + S_AV1, + S_AV1S, + S_V = 24, + S_VS = 25 +}; + + +enum reg_class +{ + rc_dregs_lo, + rc_dregs_hi, + rc_dregs, + rc_dregs_pair, + rc_pregs, + rc_spfp, + rc_dregs_hilo, + rc_accum_ext, + rc_accum_word, + rc_accum, + rc_iregs, + rc_mregs, + rc_bregs, + rc_lregs, + rc_dpregs, + rc_gregs, + rc_regs, + rc_statbits, + rc_ignore_bits, + rc_ccstat, + rc_counters, + rc_dregs2_sysregs1, + rc_open, + rc_sysregs2, + rc_sysregs3, + rc_allregs, + LIM_REG_CLASSES +}; + +/* mmod field. */ +#define M_S2RND 1 +#define M_T 2 +#define M_W32 3 +#define M_FU 4 +#define M_TFU 6 +#define M_IS 8 +#define M_ISS2 9 +#define M_IH 11 +#define M_IU 12 + +/* Register type checking macros. */ + +#define CODE_MASK 0x07 +#define CLASS_MASK 0xf0 + +#define REG_SAME(a, b) ((a).regno == (b).regno) +#define REG_EQUAL(a, b) (((a).regno & CODE_MASK) == ((b).regno & CODE_MASK)) +#define REG_CLASS(a) ((a.regno) & 0xf0) +#define IS_A1(a) ((a).regno == REG_A1) +#define IS_H(a) ((a).regno & F_REG_HIGH ? 1: 0) +#define IS_EVEN(r) (r.regno % 2 == 0) +#define IS_HCOMPL(a, b) (REG_EQUAL(a, b) && \ + ((a).regno & F_REG_HIGH) != ((b).regno & F_REG_HIGH)) + +/* register type checking. */ +#define _TYPECHECK(r, x) (((r).regno & CLASS_MASK) == T_REG_##x) + +#define IS_DREG(r) _TYPECHECK(r, R) +#define IS_DREG_H(r) (_TYPECHECK(r, R) && IS_H(r)) +#define IS_DREG_L(r) (_TYPECHECK(r, R) && !IS_H(r)) +#define IS_PREG(r) _TYPECHECK(r, P) +#define IS_IREG(r) (((r).regno & 0xf4) == T_REG_I) +#define IS_MREG(r) (((r).regno & 0xf4) == T_REG_M) +#define IS_CREG(r) ((r).regno == REG_LC0 || (r).regno == REG_LC1) +#define IS_ALLREG(r) ((r).regno < T_NOGROUP) + +/* Expression value macros. */ + +typedef enum +{ + ones_compl, + twos_compl, + mult, + divide, + mod, + add, + sub, + lsh, + rsh, + logand, + logior, + logxor +} expr_opcodes_t; + +struct expressionS; + +#define SYMBOL_T symbolS* + +struct expression_cell +{ + int value; + SYMBOL_T symbol; +}; + +/* User Type Definitions. */ +struct bfin_insn +{ + unsigned long value; + struct bfin_insn *next; + struct expression_cell *exp; + int pcrel; + int reloc; +}; + +#define INSTR_T struct bfin_insn* +#define EXPR_T struct expression_cell* + +typedef struct expr_node_struct Expr_Node; + +extern INSTR_T gencode (unsigned long x); +extern INSTR_T conscode (INSTR_T head, INSTR_T tail); +extern INSTR_T conctcode (INSTR_T head, INSTR_T tail); +extern INSTR_T note_reloc + (INSTR_T code, Expr_Node *, int reloc,int pcrel); +extern INSTR_T note_reloc1 + (INSTR_T code, const char * sym, int reloc, int pcrel); +extern INSTR_T note_reloc2 + (INSTR_T code, const char *symbol, int reloc, int value, int pcrel); + +/* Types of expressions. */ +typedef enum +{ + Expr_Node_Binop, /* Binary operator. */ + Expr_Node_Unop, /* Unary operator. */ + Expr_Node_Reloc, /* Symbol to be relocated. */ + Expr_Node_Constant /* Constant. */ +} Expr_Node_Type; + +/* Types of operators. */ +typedef enum +{ + Expr_Op_Type_Add, + Expr_Op_Type_Sub, + Expr_Op_Type_Mult, + Expr_Op_Type_Div, + Expr_Op_Type_Mod, + Expr_Op_Type_Lshift, + Expr_Op_Type_Rshift, + Expr_Op_Type_BAND, /* Bitwise AND. */ + Expr_Op_Type_BOR, /* Bitwise OR. */ + Expr_Op_Type_BXOR, /* Bitwise exclusive OR. */ + Expr_Op_Type_LAND, /* Logical AND. */ + Expr_Op_Type_LOR, /* Logical OR. */ + Expr_Op_Type_NEG, + Expr_Op_Type_COMP /* Complement. */ +} Expr_Op_Type; + +/* The value that can be stored ... depends on type. */ +typedef union +{ + const char *s_value; /* if relocation symbol, the text. */ + int i_value; /* if constant, the value. */ + Expr_Op_Type op_value; /* if operator, the value. */ +} Expr_Node_Value; + +/* The expression node. */ +struct expr_node_struct +{ + Expr_Node_Type type; + Expr_Node_Value value; + Expr_Node *Left_Child; + Expr_Node *Right_Child; +}; + + +/* Operations on the expression node. */ +Expr_Node *Expr_Node_Create (Expr_Node_Type type, + Expr_Node_Value value, + Expr_Node *Left_Child, + Expr_Node *Right_Child); + +/* Generate the reloc structure as a series of instructions. */ +INSTR_T Expr_Node_Gen_Reloc (Expr_Node *head, int parent_reloc); + +#define MKREF(x) mkexpr (0,x) +#define ALLOCATE(x) malloc (x) + +#define NULL_CODE ((INSTR_T) 0) + +#ifndef EXPR_VALUE +#define EXPR_VALUE(x) (((x)->type == Expr_Node_Constant) ? ((x)->value.i_value) : 0) +#endif +#ifndef EXPR_SYMBOL +#define EXPR_SYMBOL(x) ((x)->symbol) +#endif + + +typedef long reg_t; + + +typedef struct _register +{ + reg_t regno; /* Register ID as defined in machine_registers. */ + int flags; +} Register; + + +typedef struct _macfunc +{ + char n; + char op; + char w; + char P; + Register dst; + Register s0; + Register s1; +} Macfunc; + +typedef struct _opt_mode +{ + int MM; + int mod; +} Opt_mode; + +typedef enum +{ + SEMANTIC_ERROR, + NO_INSN_GENERATED, + INSN_GENERATED +} parse_state; + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int debug_codeselection; + +void error (char *format, ...); +void warn (char *format, ...); +int semantic_error (char *syntax); +void semantic_error_2 (char *syntax); + +EXPR_T mkexpr (int, SYMBOL_T); + +extern void bfin_equals (Expr_Node *sym); +/* Defined in bfin-lex.l. */ +void set_start_state (void); + +#ifdef __cplusplus +} +#endif + +#endif /* BFIN_PARSE_H */ + diff --git a/gas/config/bfin-lex.l b/gas/config/bfin-lex.l new file mode 100644 index 00000000000..df650350a2f --- /dev/null +++ b/gas/config/bfin-lex.l @@ -0,0 +1,554 @@ +/* bfin-lex.l ADI Blackfin lexer + 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 <stdlib.h> +#include <string.h> +#include "bfin-defs.h" +#include "bfin-parse.tab.h" +#include "as.h" + +static long parse_int (char **end); +static int parse_halfreg (Register *r, int cl, char *hr); +static int parse_reg (Register *r, int type, char *rt); +int yylex (void); + +#define _REG yylval.reg + + +%} + +/* Define Start States ... Actually we will use exclusion. + If no start state is specified it should match any state + and <INITIAL> would match some keyword rules only with + initial. */ +%s KEYWORD + +%% +[sS][fF][tT][rR][eE][sS][eE][tT] _REG.regno = REG_sftreset; return REG; +[oO][mM][oO][dD][eE] _REG.regno = REG_omode; return REG; +[iI][dD][lL][eE]_[rR][eE][qQ] _REG.regno = REG_idle_req; return REG; +[hH][wW][eE][rR][rR][cC][aA][uU][sS][eE] _REG.regno = REG_hwerrcause; return REG; +[eE][xX][cC][aA][uU][sS][eE] _REG.regno = REG_excause; return REG; +[eE][mM][uU][cC][aA][uU][sS][eE] _REG.regno = REG_emucause; return REG; +[zZ] return Z; +[xX] return X; +[wW]32 yylval.value = M_W32; return MMOD; +[wW] return W; +[vV][iI][tT]_[mM][aA][xX] return VIT_MAX; +[vV] return V; /* Special: V is a statflag and a modifier. */ +[uU][sS][pP] _REG.regno = REG_USP; return REG; +[tT][lL] return TL; +[tT][hH] return TH; +[tT][fF][uU] yylval.value = M_TFU; return MMOD; +[tT][eE][sS][tT][sS][eE][tT] return TESTSET; +[tT] yylval.value = M_T; return MMOD; +[sS] return S; +[sS][yY][sS][cC][fF][gG] _REG.regno = REG_SYSCFG; return REG; +[sS][tT][iI] return STI; +[sS][sS][yY][nN][cC] return SSYNC; +[sS][pP]"."[lL] _REG.regno = REG_SP; return HALF_REG; +[sS][pP]"."[hH] _REG.regno = REG_SP | F_REG_HIGH; return HALF_REG; +[sS][pP] _REG.regno = REG_SP; return REG; +[sS][iI][gG][nN][bB][iI][tT][sS] return SIGNBITS; +[sS][iI][gG][nN] return SIGN; +[sS][eE][qQ][sS][tT][aA][tT] _REG.regno = REG_SEQSTAT; return REG; +[sS][eE][aA][rR][cC][hH] return SEARCH; +[sS][hH][iI][fF][tT] return SHIFT; +[sS][cC][oO] return SCO; + +[sS][aA][aA] return SAA; +[sS]2[rR][nN][dD] yylval.value = M_S2RND; return MMOD; +[rR][tT][xX] return RTX; +[rR][tT][sS] return RTS; +[rR][tT][nN] return RTN; +[rR][tT][iI] return RTI; +[rR][tT][eE] return RTE; +[rR][oO][tT] return ROT; +[rR][nN][dD]20 return RND20; +[rR][nN][dD]12 return RND12; +[rR][nN][dD][lL] return RNDL; +[rR][nN][dD][hH] return RNDH; +[rR][nN][dD] return RND; + +[rR][0-7]"."[lLhHbB] return parse_halfreg(&yylval.reg, T_REG_R, yytext); + +[rR][eE][tT][sS] _REG.regno = REG_RETS; return REG; +[rR][eE][tT][iI] _REG.regno = REG_RETI; return REG; +[rR][eE][tT][xX] _REG.regno = REG_RETX; return REG; +[rR][eE][tT][nN] _REG.regno = REG_RETN; return REG; +[rR][eE][tT][eE] _REG.regno = REG_RETE; return REG; +[eE][mM][uU][dD][aA][tT] _REG.regno = REG_EMUDAT; return REG; +[rR][aA][iI][sS][eE] return RAISE; + +[rR][0-7] return parse_reg (&yylval.reg, T_REG_R, yytext); + +[rR] return R; +[pP][rR][nN][tT] return PRNT; +[pP][cC] return PC; +[pP][aA][cC][kK] return PACK; + +[pP][0-5]"."[lLhH] return parse_halfreg (&yylval.reg, T_REG_P, yytext); +[pP][0-5] return parse_reg (&yylval.reg, T_REG_P, yytext); + +[oO][uU][tT][cC] return OUTC; +[oO][nN][eE][sS] return ONES; + +[nN][oO][tT] return NOT; +[nN][oO][pP] return NOP; +[mM][nN][oO][pP] return MNOP; +[nN][sS] return NS; + + +[mM][iI][nN] return MIN; +[mM][aA][xX] return MAX; + +[mM][0-3]"."[lLhH] return parse_halfreg (&yylval.reg, T_REG_M, yytext); +[mM][0-3] return parse_reg (&yylval.reg, T_REG_M, yytext); + +[mM] return M; +[lL][tT] return LT; +[lL][sS][hH][iI][fF][tT] return LSHIFT; +[lL][sS][eE][tT][uU][pP] return LSETUP; +[lL][oO][oO][pP] return LOOP; +[lL][oO][oO][pP]_[bB][eE][gG][iI][nN] return LOOP_BEGIN; +[lL][oO][oO][pP]_[eE][nN][dD] return LOOP_END; + +[lL][eE] return LE; +[lL][cC]0 _REG.regno = REG_LC0; return REG; +[lL][tT]0 _REG.regno = REG_LT0; return REG; +[lL][bB]0 _REG.regno = REG_LB0; return REG; +[lL][cC]1 _REG.regno = REG_LC1; return REG; +[lL][tT]1 _REG.regno = REG_LT1; return REG; +[lL][bB]1 _REG.regno = REG_LB1; return REG; + +[lL][0-3]"."[lLhH] return parse_halfreg (&yylval.reg, T_REG_L, yytext); +[lL][0-3] return parse_reg (&yylval.reg, T_REG_L, yytext); +[lL][oO] return LO; +[jJ][uU][mM][pP]"."[sS] { BEGIN 0; return JUMP_DOT_S;} +[jJ][uU][mM][pP]"."[lL] { BEGIN 0; return JUMP_DOT_L;} +[jJ][uU][mM][pP] { BEGIN 0; return JUMP;} +[jJ][uU][mM][pP]"."[xX] { BEGIN 0; return JUMP_DOT_L; } +[iI][uU] yylval.value = M_IU; return MMOD; +[iI][sS][sS]2 yylval.value = M_ISS2; return MMOD; +[iI][sS] yylval.value = M_IS; return MMOD; +[iI][hH] yylval.value = M_IH; return MMOD; +[iI][fF] return IF; +[iI][0-3]"."[lLhH] return parse_halfreg (&yylval.reg, T_REG_I, yytext); +[iI][0-3] return parse_reg (&yylval.reg, T_REG_I, yytext); +[hH][lL][tT] return HLT; +[hH][iI] return HI; +[gG][tT] return GT; +[gG][eE] return GE; +[fF][uU] yylval.value = M_FU; return MMOD; +[fF][pP] _REG.regno = REG_FP; return REG; +[fF][pP]"."[lL] _REG.regno = REG_FP; return HALF_REG; +[fF][pP]"."[hH] _REG.regno = REG_FP | F_REG_HIGH; return HALF_REG; + +[eE][xX][tT][rR][aA][cC][tT] return EXTRACT; +[eE][xX][pP][aA][dD][jJ] return EXPADJ; +[eE][xX][cC][pP][tT] return EXCPT; +[eE][mM][uU][eE][xX][cC][pP][tT] return EMUEXCPT; +[dD][iI][vV][sS] return DIVS; +[dD][iI][vV][qQ] return DIVQ; +[dD][iI][sS][aA][lL][gG][nN][eE][xX][cC][pP][tT] return DISALGNEXCPT; +[dD][eE][pP][oO][sS][iI][tT] return DEPOSIT; +[dD][bB][gG][hH][aA][lL][tT] return DBGHALT; +[dD][bB][gG][cC][mM][pP][lL][xX] return DBGCMPLX; +[dD][bB][gG][aA][lL] return DBGAL; +[dD][bB][gG][aA][hH] return DBGAH; +[dD][bB][gG][aA] return DBGA; +[dD][bB][gG] return DBG; +[cC][yY][cC][lL][eE][sS]2 { _REG.regno = REG_CYCLES2; return REG; } +[cC][yY][cC][lL][eE][sS] { _REG.regno = REG_CYCLES; return REG; } +[cC][sS][yY][nN][cC] return CSYNC; +[cC][oO] return CO; +[cC][lL][iI] return CLI; + +[cC][cC] _REG.regno = REG_CC; return CCREG; +[cC][aA][lL][lL]"."[xX] { BEGIN 0; return CALL;} +[cC][aA][lL][lL] { BEGIN 0; return CALL;} +[bB][yY][tT][eE][uU][nN][pP][aA][cC][kK] return BYTEUNPACK; +[bB][yY][tT][eE][pP][aA][cC][kK] return BYTEPACK; +[bB][yY][tT][eE][oO][pP]16[mM] return BYTEOP16M; +[bB][yY][tT][eE][oO][pP]16[pP] return BYTEOP16P; +[bB][yY][tT][eE][oO][pP]3[pP] return BYTEOP3P; +[bB][yY][tT][eE][oO][pP]2[mM] return BYTEOP2M; +[bB][yY][tT][eE][oO][pP]2[pP] return BYTEOP2P; +[bB][yY][tT][eE][oO][pP]1[pP] return BYTEOP1P; +[bB][yY] return BY; +[bB][xX][oO][rR][sS][hH][iI][fF][tT] return BXORSHIFT; +[bB][xX][oO][rR] return BXOR; + +[bB][rR][eE][vV] return BREV; +[bB][pP] return BP; +[bB][iI][tT][tT][sS][tT] return BITTST; +[bB][iI][tT][tT][gG][lL] return BITTGL; +[bB][iI][tT][sS][eE][tT] return BITSET; +[bB][iI][tT][mM][uU][xX] return BITMUX; +[bB][iI][tT][cC][lL][rR] return BITCLR; +[bB][0-3]"."[lLhH] return parse_halfreg (&yylval.reg, T_REG_B, yytext); +[bB][0-3] return parse_reg (&yylval.reg, T_REG_B, yytext); +[bB] return B; +[aA][zZ] _REG.regno = S_AZ; return STATUS_REG; +[aA][nN] _REG.regno = S_AN; return STATUS_REG; +[aA][qQ] _REG.regno = S_AQ; return STATUS_REG; +[aA][cC]0 _REG.regno = S_AC0; return STATUS_REG; +[aA][cC]1 _REG.regno = S_AC1; return STATUS_REG; +[aA][vV]0 _REG.regno = S_AV0; return STATUS_REG; +[aA][vV]0[sS] _REG.regno = S_AV0S; return STATUS_REG; +[aA][vV]1 _REG.regno = S_AV1; return STATUS_REG; +[aA][vV]1[sS] _REG.regno = S_AV1S; return STATUS_REG; +[vV] _REG.regno = S_V; return STATUS_REG; +[vV][sS] _REG.regno = S_VS; return STATUS_REG; + + +[aA][sS][tT][aA][tT] _REG.regno = REG_ASTAT; return REG; +[aA][sS][hH][iI][fF][tT] return ASHIFT; +[aA][sS][lL] return ASL; +[aA][sS][rR] return ASR; +[aA][lL][iI][gG][nN]8 return ALIGN8; +[aA][lL][iI][gG][nN]16 return ALIGN16; +[aA][lL][iI][gG][nN]24 return ALIGN24; +[aA]1"."[lL] return A_ONE_DOT_L; +[aA]0"."[lL] return A_ZERO_DOT_L; +[aA]1"."[hH] return A_ONE_DOT_H; +[aA]0"."[hH] return A_ZERO_DOT_H; +[aA][bB][sS] return ABS; +abort return ABORT; +[aA]1"."[xX] _REG.regno = REG_A1x; return REG; +[aA]1"."[wW] _REG.regno = REG_A1w; return REG; +[aA]1 _REG.regno = REG_A1; return REG_A_DOUBLE_ONE; +[aA]0"."[xX] _REG.regno = REG_A0x; return REG; +[aA]0"."[wW] _REG.regno = REG_A0w; return REG; +[aA]0 _REG.regno = REG_A0; return REG_A_DOUBLE_ZERO; +[Gg][Oo][Tt] return GOT; +[Pp][Ll][Tt][Pp][Cc] return PLTPC; + + +"~" return TILDA; +"|=" return _BAR_ASSIGN; +"|" return BAR; +"^=" return _CARET_ASSIGN; +"^" return CARET; +"]" return RBRACK; +"[" return LBRACK; +">>>=" return _GREATER_GREATER_GREATER_THAN_ASSIGN; +">>=" return _GREATER_GREATER_ASSIGN; +">>>" return _GREATER_GREATER_GREATER; +">>" return GREATER_GREATER; +"==" return _ASSIGN_ASSIGN; +"=" return ASSIGN; +"<=" return _LESS_THAN_ASSIGN; +"<<=" return _LESS_LESS_ASSIGN; +"<<" return LESS_LESS; +"<" return LESS_THAN; +"(" return LPAREN; +")" return RPAREN; +":" return COLON; +"/" return SLASH; +"-=" return _MINUS_ASSIGN; +"+|+" return _PLUS_BAR_PLUS; +"-|+" return _MINUS_BAR_PLUS; +"+|-" return _PLUS_BAR_MINUS; +"-|-" return _MINUS_BAR_MINUS; +"--" return _MINUS_MINUS; +"-" return MINUS; +"," return COMMA; +"+=" return _PLUS_ASSIGN; +"++" return _PLUS_PLUS; +"+" return PLUS; +"*=" return _STAR_ASSIGN; +"*" return STAR; +"&=" return _AMPERSAND_ASSIGN; +"&" return AMPERSAND; +"%" return PERCENT; +"!" return BANG; +";" return SEMICOLON; +"=!" return _ASSIGN_BANG; +"||" return DOUBLE_BAR; +"@" return AT; +<KEYWORD>[pP][rR][eE][fF][eE][tT][cC][hH] return PREFETCH; +<KEYWORD>[uU][nN][lL][iI][nN][kK] return UNLINK; +<KEYWORD>[lL][iI][nN][kK] return LINK; +<KEYWORD>[iI][dD][lL][eE] return IDLE; +<KEYWORD>[iI][fF][lL][uU][sS][hH] return IFLUSH; +<KEYWORD>[fF][lL][uU][sS][hH][iI][nN][vV] return FLUSHINV; +<KEYWORD>[fF][lL][uU][sS][hH] return FLUSH; +([0-9]+)|(0[xX][0-9a-fA-F]+)|([bhfodBHOFD]#[0-9a-fA-F]+)|(0.[0-9]+) { + yylval.value = parse_int (&yytext); + return NUMBER; + } +[A-Za-z_$.][A-Za-z0-9_$.]* { + yylval.symbol = symbol_find_or_make (yytext); + symbol_mark_used (yylval.symbol); + return SYMBOL; + } +[0-9][bfBF] { + char *name; + char *ref = strdup (yytext); + if (ref[1] == 'b' || ref[1] == 'B') + { + name = fb_label_name ((int) (ref[0] - '0'), 0); + yylval.symbol = symbol_find (name); + + if ((yylval.symbol != NULL) + && (S_IS_DEFINED (yylval.symbol))) + return SYMBOL; + as_bad ("backward reference to unknown label %d:", + (int) (ref[0] - '0')); + } + else if (ref[1] == 'f' || ref[1] == 'F') + { + /* Forward reference. Expect symbol to be undefined or + unknown. undefined: seen it before. unknown: never seen + it before. + + Construct a local label name, then an undefined symbol. + Just return it as never seen before. */ + + name = fb_label_name ((int) (ref[0] - '0'), 1); + yylval.symbol = symbol_find_or_make (name); + /* We have no need to check symbol properties. */ + return SYMBOL; + } + } +[ \t\n] ; +"/*".*"*/" ; +. return yytext[0]; +%% +static long parse_int (char **end) +{ + char fmt = '\0'; + int not_done = 1; + int shiftvalue = 0; + char * char_bag; + long value = 0; + char c; + char *arg = *end; + + while (*arg && *arg == ' ') + arg++; + + switch (*arg) + { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + fmt = 'd'; + break; + + case '0': /* Accept different formated integers hex octal and binary. */ + { + c = *++arg; + arg++; + if (c == 'x' || c == 'X') /* Hex input. */ + fmt = 'h'; + else if (c == 'b' || c == 'B') + fmt = 'b'; + else if (c == '.') + fmt = 'f'; + else + { /* Octal. */ + arg--; + fmt = 'o'; + } + break; + } + + case 'd': + case 'D': + case 'h': + case 'H': + case 'o': + case 'O': + case 'b': + case 'B': + case 'f': + case 'F': + { + fmt = *arg++; + if (*arg == '#') + arg++; + } + } + + switch (fmt) + { + case 'h': + case 'H': + shiftvalue = 4; + char_bag = "0123456789ABCDEFabcdef"; + break; + + case 'o': + case 'O': + shiftvalue = 3; + char_bag = "01234567"; + break; + + case 'b': + case 'B': + shiftvalue = 1; + char_bag = "01"; + break; + +/* The assembler allows for fractional constants to be created + by either the 0.xxxx or the f#xxxx format + + i.e. 0.5 would result in 0x4000 + + note .5 would result in the identifier .5. + + The assembler converts to fractional format 1.15 by the simple rule: + + value = (short) (finput * (1 << 15)). */ + + case 'f': + case 'F': + { + float fval = 0.0; + float pos = 10.0; + while (1) + { + int c; + c = *arg++; + + if (c >= '0' && c <= '9') + { + float digit = (c - '0') / pos; + fval = fval + digit; + pos = pos * 10.0; + } + else + { + *--arg = c; + value = (short) (fval * (1 << 15)); + break; + } + } + *end = arg+1; + return value; + } + + case 'd': + case 'D': + default: + { + while (1) + { + int c; + c = *arg++; + if (c >= '0' && c <= '9') + value = (value * 10) + (c - '0'); + else + { + /* Constants that are suffixed with k|K are multiplied by 1024 + This suffix is only allowed on decimal constants. */ + if (c == 'k' || c == 'K') + value *= 1024; + else + *--arg = c; + break; + } + } + *end = arg+1; + return value; + } + } + + while (not_done) + { + char c; + c = *arg++; + if (c == 0 || !index (char_bag, c)) + { + not_done = 0; + *--arg = c; + } + else + { + if (c >= 'a' && c <= 'z') + c = c - ('a' - '9') + 1; + else if (c >= 'A' && c <= 'Z') + c = c - ('A' - '9') + 1; + + c -= '0'; + value = (value << shiftvalue) + c; + } + } + *end = arg+1; + return value; +} + + +static int parse_reg (Register *r, int cl, char *rt) +{ + r->regno = cl | (rt[1] - '0'); + return REG; +} + +static int parse_halfreg (Register *r, int cl, char *rt) +{ + r->regno = cl | (rt[1] - '0'); + + switch (rt[3]) + { + case 'b': + case 'B': + return BYTE_DREG; + + case 'l': + case 'L': + break; + + case 'h': + case 'H': + r->regno |= F_REG_HIGH; + break; + } + + return HALF_REG; +} + +/* Our start state is KEYWORD as we have + command keywords such as PREFETCH. */ + +void +set_start_state (void) +{ + BEGIN KEYWORD; +} + + +#ifndef yywrap +int +yywrap () +{ + return 1; +} +#endif diff --git a/gas/config/bfin-parse.y b/gas/config/bfin-parse.y new file mode 100644 index 00000000000..7751b688d00 --- /dev/null +++ b/gas/config/bfin-parse.y @@ -0,0 +1,4360 @@ +/* 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); + } + } + + +/* 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 + diff --git a/gas/config/tc-bfin.c b/gas/config/tc-bfin.c new file mode 100644 index 00000000000..90763dadb3a --- /dev/null +++ b/gas/config/tc-bfin.c @@ -0,0 +1,1951 @@ +/* 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); +} diff --git a/gas/config/tc-bfin.h b/gas/config/tc-bfin.h new file mode 100644 index 00000000000..9252e25d9a7 --- /dev/null +++ b/gas/config/tc-bfin.h @@ -0,0 +1,75 @@ +/* tc-bfin.h - header file for tc-bfin.c + 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. */ + +#define TC_BFIN 1 +#define TC_ADI_BFIN 1 + +#define TARGET_BYTES_BIG_ENDIAN 0 + +#define TARGET_ARCH bfd_arch_bfin + +/* + * Define the target format macro here. The value for this should be + * "elf32-bfin", not "elf32-little-bfin". Since the BFD source file + * elf32-bfin.c defines TARGET_LITTLE_NAME to be "elf32-little-bfin", + * we must use this value, until this is corrected and BFD is rebuilt. */ +#ifdef OBJ_ELF +#define TARGET_FORMAT "elf32-bfin" +#endif + +#define LISTING_HEADER "BFIN GAS " + +#define WORKING_DOT_WORD + +extern void bfin_start_line_hook PARAMS ((void)); +extern bfd_boolean bfin_start_label PARAMS ((char *)); + +#define md_start_line_hook() bfin_start_line_hook() +#define md_number_to_chars number_to_chars_littleendian +#define md_convert_frag(b,s,f) as_fatal ("bfin convert_frag\n"); + +/* Allow for [, ], etc. */ +#define LEX_BR 6 + +#define TC_EOL_IN_INSN(PTR) (bfin_eol_in_insn(PTR) ? 1 : 0) +extern bfd_boolean bfin_eol_in_insn PARAMS ((char *)); + +/* The instruction is permitted to contain an = character. */ +#define TC_EQUAL_IN_INSN(C, NAME) (bfin_name_is_register (NAME) ? 1 : 0) +extern bfd_boolean bfin_name_is_register PARAMS ((char *)); +#define NOP_OPCODE 0x0000 + +#define LOCAL_LABELS_FB 1 + +#define DOUBLESLASH_LINE_COMMENTS + +#define TC_START_LABEL(ch ,ptr) (ch == ':' && bfin_start_label (ptr)) +#define tc_fix_adjustable(FIX) bfin_fix_adjustable (FIX) +extern bfd_boolean bfin_fix_adjustable PARAMS ((struct fix *)); + +#define TC_FORCE_RELOCATION(FIX) bfin_force_relocation (FIX) +extern int bfin_force_relocation PARAMS ((struct fix *)); + +/* Call md_pcrel_from_section(), not md_pcrel_from(). */ +#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section (FIX, SEC) +extern long md_pcrel_from_section PARAMS ((struct fix *, segT)); + +/* end of tc-bfin.h */ diff --git a/gas/configure b/gas/configure index fcf6b6223f9..8b026ad7458 100755 --- a/gas/configure +++ b/gas/configure @@ -4641,6 +4641,19 @@ _ACEOF # Any other special object files needed ? case ${cpu_type} in + + bfin) + echo ${extra_objects} | grep -s "bfin-parse.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects bfin-parse.o" + fi + + echo ${extra_objects} | grep -s "bfin-lex.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects bfin-lex.o" + fi + ;; + fr30 | ip2k | iq2000 | m32r | openrisc) using_cgen=yes ;; diff --git a/gas/configure.in b/gas/configure.in index 87c339e7860..3449a7dac76 100644 --- a/gas/configure.in +++ b/gas/configure.in @@ -274,6 +274,19 @@ changequote([,])dnl # Any other special object files needed ? case ${cpu_type} in + + bfin) + echo ${extra_objects} | grep -s "bfin-parse.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects bfin-parse.o" + fi + + echo ${extra_objects} | grep -s "bfin-lex.o" + if test $? -ne 0 ; then + extra_objects="$extra_objects bfin-lex.o" + fi + ;; + fr30 | ip2k | iq2000 | m32r | openrisc) using_cgen=yes ;; diff --git a/gas/configure.tgt b/gas/configure.tgt index dd30a017bb7..b2ce87956fc 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -33,6 +33,7 @@ case ${cpu} in am33_2.0) cpu_type=mn10300 endian=little ;; arm*be|arm*b) cpu_type=arm endian=big ;; arm*) cpu_type=arm endian=little ;; + bfin*) cpu_type=bfin endian=little ;; c4x*) cpu_type=tic4x ;; crisv32) cpu_type=cris arch=crisv32 ;; crx*) cpu_type=crx endian=little ;; @@ -117,7 +118,9 @@ case ${generic_target} in arm-*-pe | thumb-*-pe) fmt=coff em=pe ;; arm-*-riscix*) fmt=aout em=riscix ;; - avr-*-*) fmt=elf ;; + avr-*-*) fmt=elf bfd_gas=yes ;; + bfin-*-*) fmt=elf bfd_gas=yes ;; + bfin-*elf) fmt=elf ;; cris-*-linux-* | crisv32-*-linux-*) fmt=multi em=linux ;; diff --git a/gas/doc/Makefile.am b/gas/doc/Makefile.am index 0fdbe830e16..b3b25808e1a 100644 --- a/gas/doc/Makefile.am +++ b/gas/doc/Makefile.am @@ -27,6 +27,7 @@ CPU_DOCS = \ c-alpha.texi \ c-arc.texi \ c-arm.texi \ + c-bfin.texi \ c-d10v.texi \ c-cris.texi \ c-h8300.texi \ diff --git a/gas/doc/Makefile.in b/gas/doc/Makefile.in index 04de8175dd8..4456fa64a94 100644 --- a/gas/doc/Makefile.in +++ b/gas/doc/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.9.5 from Makefile.am. +# Makefile.in generated by automake 1.9.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -218,6 +218,7 @@ CPU_DOCS = \ c-alpha.texi \ c-arc.texi \ c-arm.texi \ + c-bfin.texi \ c-d10v.texi \ c-cris.texi \ c-h8300.texi \ @@ -346,7 +347,7 @@ as.html: as.texinfo $(DVIPS) -o $@ $< uninstall-info-am: - @$(PRE_UNINSTALL) + $(PRE_UNINSTALL) @if (install-info --version && \ install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \ list='$(INFO_DEPS)'; \ @@ -362,7 +363,7 @@ uninstall-info-am: relfile=`echo "$$file" | sed 's|^.*/||'`; \ relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \ (if cd "$(DESTDIR)$(infodir)"; then \ - echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \ + echo " rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9])"; \ rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \ else :; fi); \ done diff --git a/gas/doc/all.texi b/gas/doc/all.texi index 6eb0e2a4589..77ff5e97e85 100644 --- a/gas/doc/all.texi +++ b/gas/doc/all.texi @@ -29,6 +29,7 @@ @set ALPHA @set ARC @set ARM +@set BFIN @set CRIS @set D10V @set D30V diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index 63cc5d135fa..6e8ff3d54fe 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -6083,6 +6083,9 @@ subject, see the hardware manufacturer's manual. @ifset ARM * ARM-Dependent:: ARM Dependent Features @end ifset +@ifset BFIN +* BFIN-Dependent:: BFIN Dependent Features +@end ifset @ifset CRIS * CRIS-Dependent:: CRIS Dependent Features @end ifset @@ -6193,6 +6196,10 @@ subject, see the hardware manufacturer's manual. @include c-arm.texi @end ifset +@ifset BFIN +@include c-bfin.texi +@end ifset + @ifset CRIS @include c-cris.texi @end ifset diff --git a/gas/doc/c-bfin.texi b/gas/doc/c-bfin.texi new file mode 100644 index 00000000000..dcf649a2b89 --- /dev/null +++ b/gas/doc/c-bfin.texi @@ -0,0 +1,187 @@ +@c Copyright 2005 +@c Free Software Foundation, Inc. +@c This is part of the GAS manual. +@c For copying conditions, see the file as.texinfo. +@ifset GENERIC +@page +@node BFIN-Dependent +@chapter Blackfin Dependent Features +@end ifset +@ifclear GENERIC +@node Machine Dependencies +@chapter Blackfin Dependent Features +@end ifclear + +@cindex Blackfin support +@menu +* BFIN Syntax:: BFIN Syntax +* BFIN Directives:: BFIN Directives +@end menu + +@node BFIN Syntax +@section Syntax +@cindex BFIN syntax +@cindex syntax, BFIN + +@table @code +@item Special Characters +Assembler input is free format and may appear anywhere on the line. +One instruction may extend across multiple lines or more than one +instruction may appear on the same line. White space (space, tab, +comments or newline) may appear anywhere between tokens. A token must +not have embedded spaces. Tokens include numbers, register names, +keywords, user identifiers, and also some multicharacter special +symbols like "+=", "/*" or "||". + +@item Instruction Delimiting +A semicolon must terminate every instruction. Sometimes a complete +instruction will consist of more than one operation. There are two +cases where this occurs. The first is when two general operations +are combined. Normally a comma separates the different parts, as in + +@smallexample +a0= r3.h * r2.l, a1 = r3.l * r2.h ; +@end smallexample + +The second case occurs when a general instruction is combined with one +or two memory references for joint issue. The latter portions are +set off by a "||" token. + +@smallexample +a0 = r3.h * r2.l || r1 = [p3++] || r4 = [i2++]; +@end smallexample + +@item Register Names + +The assembler treats register names and instruction keywords in a case +insensitive manner. User identifiers are case sensitive. Thus, R3.l, +R3.L, r3.l and r3.L are all equivalent input to the assembler. + +Register names are reserved and may not be used as program identifiers. + +Some operations (such as "Move Register") require a register pair. +Register pairs are always data registers and are denoted using a colon, +eg., R3:2. The larger number must be written firsts. Note that the +hardware only supports odd-even pairs, eg., R7:6, R5:4, R3:2, and R1:0. + +Some instructions (such as --SP (Push Multiple)) require a group of +adjacent registers. Adjacent registers are denoted in the syntax by +the range enclosed in parentheses and separated by a colon, eg., (R7:3). +Again, the larger number appears first. + +Portions of a particular register may be individually specified. This +is written with a dot (".") following the register name and then a +letter denoting the desired portion. For 32-bit registers, ".H" +denotes the most significant ("High") portion. ".L" denotes the +least-significant portion. The subdivisions of the 40-bit registers +are described later. + +@item Accumulators +The set of 40-bit registers A1 and A0 that normally contain data that +is being manipulated. Each accumulator can be accessed in four ways. + +@table @code +@item one 40-bit register +The register will be referred to as A1 or A0. +@item one 32-bit register +The registers are designated as A1.W or A0.W. +@item two 16-bit registers +The registers are designated as A1.H, A1.L, A0.H or A0.L. +@item one 8-bit register +The registers are designated as A1.X or A0.X for the bits that +extend beyond bit 31. +@end table + +@item Data Registers +The set of 32-bit registers (R0, R1, R2, R3, R4, R5, R6 and R7) that +normally contain data for manipulation. These are abbreviated as +D-register or Dreg. Data registers can be accessed as 32-bit registers +or as two independent 16-bit registers. The least significant 16 bits +of each register is called the "low" half and is desginated with ".L" +following the register name. The most significant 16 bits are called +the "high" half and is designated with ".H". following the name. + +@smallexample + R7.L, r2.h, r4.L, R0.H +@end smallexample + +@item Pointer Registers +The set of 32-bit registers (P0, P1, P2, P3, P4, P5, SP and FP) that +normally contain byte addresses of data structures. These are +abbreviated as P-register or Preg. + +@smallexample +p2, p5, fp, sp +@end smallexample + +@item Stack Pointer SP +The stack pointer contains the 32-bit address of the last occupied +byte location in the stack. The stack grows by decrementing the +stack pointer. + +@item Frame Pointer FP +The frame pointer contains the 32-bit address of the previous frame +pointer in the stack. It is located at the top of a frame. + +@item Loop Top +LT0 and LT1. These registers contain the 32-bit address of the top of +a zero overhead loop. + +@item Loop Count +LC0 and LC1. These registers contain the 32-bit counter of the zero +overhead loop executions. + +@item Loop Bottom +LB0 and LB1. These registers contain the 32-bit address of the bottom +of a zero overhead loop. + +@item Index Registers +The set of 32-bit registers (I0, I1, I2, I3) that normally contain byte +addresses of data structures. Abbreviated I-register or Ireg. + +@item Modify Registers +The set of 32-bit registers (M0, M1, M2, M3) that normally contain +offset values that are added and subracted to one of the index +registers. Abbreviated as Mreg. + +@item Length Registers +The set of 32-bit registers (L0, L1, L2, L3) that normally contain the +length in bytes of the circular buffer. Abbreviated as Lreg. Clear +the Lreg to disable circular addressing for the corresponding Ireg. + +@item Base Registers +The set of 32-bit registers (B0, B1, B2, B3) that normally contain the +base address in bytes of the circular buffer. Abbreviated as Breg. + +@item Floating Point +The Blackfin family has no hardware floating point but the .float +directive generates ieee floating point numbers for use with software +floating point libraries. + +@item Blackfin Opcodes +For detailed information on the Blackfin machine instruction set, see +the Blackfin(r) Processor Instruction Set Reference. + +@end table + +@node BFIN Directives +@section Directives +@cindex BFIN directives +@cindex directives, BFIN + +The following directives are provided for compatibility with the VDSP assembler. + +@table @code +@item .byte2 +Initializes a four byte data object. +@item .byte4 +Initializes a two byte data object. +@item .db +TBD +@item .dd +TBD +@item .dw +TBD +@item .var +Define and initialize a 32 bit data object. +@end table |