From a4c97499d90ab83a01d80d4c3df2455a73486e3c Mon Sep 17 00:00:00 2001 From: Andrew Cagney Date: Fri, 21 Feb 1997 02:49:21 +0000 Subject: [PATCH] Instruction decode generator taken from the PowerPC simulator and being made more generic. --- sim/igen/Makefile.in | 175 +++++++++++++++++ sim/igen/config.in | 31 +++ sim/igen/configure.in | 34 ++++ sim/igen/filter.c | 150 +++++++++++++++ sim/igen/filter.h | 43 +++++ sim/igen/filter_host.c | 37 ++++ sim/igen/filter_host.h | 27 +++ sim/igen/gen-engine.h | 29 +++ sim/igen/gen-icache.h | 68 +++++++ sim/igen/gen-idecode.h | 40 ++++ sim/igen/gen-itable.h | 28 +++ sim/igen/gen-model.c | 393 +++++++++++++++++++++++++++++++++++++++ sim/igen/gen-model.h | 30 +++ sim/igen/gen-semantics.h | 81 ++++++++ sim/igen/gen-support.h | 29 +++ sim/igen/ld-cache.c | 115 ++++++++++++ sim/igen/ld-cache.h | 81 ++++++++ sim/igen/ld-decode.c | 155 +++++++++++++++ sim/igen/ld-decode.h | 143 ++++++++++++++ sim/igen/misc.c | 226 ++++++++++++++++++++++ sim/igen/misc.h | 94 ++++++++++ 21 files changed, 2009 insertions(+) create mode 100644 sim/igen/Makefile.in create mode 100644 sim/igen/config.in create mode 100644 sim/igen/configure.in create mode 100644 sim/igen/filter.c create mode 100644 sim/igen/filter.h create mode 100644 sim/igen/filter_host.c create mode 100644 sim/igen/filter_host.h create mode 100644 sim/igen/gen-engine.h create mode 100644 sim/igen/gen-icache.h create mode 100644 sim/igen/gen-idecode.h create mode 100644 sim/igen/gen-itable.h create mode 100644 sim/igen/gen-model.c create mode 100644 sim/igen/gen-model.h create mode 100644 sim/igen/gen-semantics.h create mode 100644 sim/igen/gen-support.h create mode 100644 sim/igen/ld-cache.c create mode 100644 sim/igen/ld-cache.h create mode 100644 sim/igen/ld-decode.c create mode 100644 sim/igen/ld-decode.h create mode 100644 sim/igen/misc.c create mode 100644 sim/igen/misc.h diff --git a/sim/igen/Makefile.in b/sim/igen/Makefile.in new file mode 100644 index 0000000000..5c64c3bbc5 --- /dev/null +++ b/sim/igen/Makefile.in @@ -0,0 +1,175 @@ +# +# This file is part of the program psim. +# +# Copyright (C) 1994-1997, Andrew Cagney +# Copyright (C) 1997, 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 of the License, 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. +# + +default: all + +VPATH = @srcdir@ +srcdir = @srcdir@ +srcroot = $(srcdir)/../.. + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +host_alias = @host_alias@ +target_alias = @target_alias@ +program_transform_name = @program_transform_name@ +bindir = @bindir@ +libdir = @libdir@ +tooldir = $(libdir)/$(target_alias) + +datadir = @datadir@ +mandir = @mandir@ +man1dir = $(mandir)/man1 +man2dir = $(mandir)/man2 +man3dir = $(mandir)/man3 +man4dir = $(mandir)/man4 +man5dir = $(mandir)/man5 +man6dir = $(mandir)/man6 +man7dir = $(mandir)/man7 +man8dir = $(mandir)/man8 +man9dir = $(mandir)/man9 +infodir = @infodir@ +includedir = @includedir@ + +SHELL = /bin/sh + +INSTALL = $(srcroot)/install.sh -c +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_XFORM = $(INSTALL) -t='$(program_transform_name)' +INSTALL_XFORM1= $(INSTALL_XFORM) -b=.1 + +AR = @AR@ +AR_FLAGS = rc +CC = @CC@ +CFLAGS = @CFLAGS@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +BISON = bison +MAKEINFO = makeinfo +RANLIB = @RANLIB@ + +STD_CFLAGS = $(CFLAGS) $(INLINE_CFLAGS) $(CONFIG_CFLAGS) $(WARNING_CFLAGS) $(SIM_CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES) +NOWARN_CFLAGS = $(CFLAGS) $(INLINE_CFLAGS) $(CONFIG_CFLAGS) $(SIM_CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES) +BUILD_CFLAGS = -g -O $(INCLUDES) $(WARNING_CFLAGS) + +BUILD_LDFLAGS = + +.NOEXPORT: +MAKEOVERRIDES= + +LIB_INCLUDES = -I$(srcdir)/../../include +INCLUDES = -I. -I$(srcdir) $(LIB_INCLUDES) + +LIBIBERTY_LIB = ../../libiberty/libiberty.a + + +IGENLIB= libigen.a + +all: igen $(IGENLIB) + +.c.o: + $(CC_FOR_BUILD) -c $(STD_CFLAGS) $< + +filter_filename.o: filter_filename.c filter_filename.h config.h ppc-config.h + +igen: igen.o $(IGENLIB) + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o igen igen.o $(IGENLIB) $(LIBIBERTY_LIB) + +IGEN_OBJS=\ + table.o \ + lf.o misc.o \ + filter_host.o \ + ld-decode.o \ + ld-cache.o \ + filter.o \ + ld-insn.o \ + gen-model.o \ + gen-itable.o \ + gen-icache.o \ + gen-semantics.o \ + gen-idecode.o \ + gen-support.o \ + gen-engine.o + +igen.o: igen.c misc.h filter_host.h lf.h table.h ld-decode.h ld-cache.h ld-insn.h filter.h gen-model.h gen-itable.h gen-icache.h gen-idecode.h gen-engine.h gen-semantics.h gen-support.h igen.h + $(CC_FOR_BUILD) $(BUILD_CFLAGS) -c $(srcdir)/igen.c + +$(IGENLIB): $(IGEN_OBJS) + rm -f $(IGENLIB) + $(AR) $(AR_FLAGS) $(IGENLIB) $(IGEN_OBJS) + $(RANLIB) $(IGENLIB) + + +tmp-filter: filter.c misc.h misc.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-filter -DMAIN $(srcdir)/filter.c misc.o $(BUILD_LIBS) + +tmp-ld-decode: ld-decode.o misc.o lf.o table.o filter_host.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-decode -DMAIN $(srcdir)/ld-decode.c misc.o lf.o table.o filter_host.o $(BUILD_LIBS) + +tmp-ld-cache: ld-cache.o misc.o lf.o table.o filter_host.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-cache -DMAIN $(srcdir)/ld-cache.c misc.o lf.o table.o filter_host.o $(BUILD_LIBS) + +tmp-ld-insn: ld-insn.o misc.o lf.o table.o ld-decode.o filter_host.o filter.o + $(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o tmp-ld-insn -DMAIN $(srcdir)/ld-insn.c misc.o lf.o table.o ld-decode.o filter_host.o filter.o $(BUILD_LIBS) + +filter_host.o: filter_host.c filter_host.h +table.o: table.c misc.h filter_host.h lf.h table.h +lf.o: lf.c misc.h filter_host.h lf.h +filter.o: filter.c misc.h lf.h table.h filter.h +ld-decode.o: ld-decode.c misc.h lf.h table.h ld-decode.h +ld-cache.o: ld-cache.c misc.h lf.h table.h ld-cache.h +ld-insn.o: ld-insn.c misc.h lf.h table.h ld-insn.h ld-decode.h igen.h +gen-model.o: gen-model.c misc.h lf.h table.h gen-model.h ld-decode.h igen.h ld-insn.h +gen-itable.o: gen-itable.c misc.h lf.h table.h gen-itable.h ld-decode.h igen.h ld-insn.h igen.h +gen-icache.o: gen-icache.c misc.h lf.h table.h gen-icache.h ld-decode.h igen.h ld-insn.h gen-semantics.h gen-idecode.h +gen-semantics.o: gen-semantics.c misc.h lf.h table.h gen-semantics.h ld-decode.h igen.h ld-insn.h +gen-idecode.o: gen-idecode.c misc.h lf.h table.h gen-idecode.h gen-icache.h gen-semantics.h ld-decode.h igen.h ld-insn.h +gen-engine.o: gen-engine.c misc.h lf.h table.h gen-idecode.h gen-engine.h gen-icache.h gen-semantics.h ld-decode.h igen.h ld-insn.h +gen-support.o: gen-support.c misc.h lf.h table.h gen-support.h ld-decode.h igen.h ld-insn.h +misc.o: misc.c misc.h filter_host.h + + +tags etags: TAGS + +TAGS: + etags $(srcdir)/*.h $(srcdir)/*.c + +clean mostlyclean: + rm -f tmp-* *.[oasi] core igen + +distclean realclean: clean + rm -f TAGS Makefile config.cache config.status config.h defines.h stamp-h config.log + +maintainer-clean: distclean + rm -f *~ *.log ppc-config.h core *.core + +Makefile: Makefile.in config.status + CONFIG_FILES=Makefile CONFIG_HEADERS= $(SHELL) ./config.status + +config.h: stamp-h ; @true +stamp-h: config.in config.status + CONFIG_FILES= CONFIG_HEADERS=config.h:config.in $(SHELL) ./config.status + +config.status: configure + $(SHELL) ./config.status --recheck + +install: +# diff --git a/sim/igen/config.in b/sim/igen/config.in new file mode 100644 index 0000000000..4fcf519489 --- /dev/null +++ b/sim/igen/config.in @@ -0,0 +1,31 @@ +/* config.in. Generated automatically from configure.in by autoheader. */ + +/* Define if you have the header file. */ +#undef HAVE_DIRENT_H + +/* Define if you have the header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H diff --git a/sim/igen/configure.in b/sim/igen/configure.in new file mode 100644 index 0000000000..0e203d3c8a --- /dev/null +++ b/sim/igen/configure.in @@ -0,0 +1,34 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.5)dnl +AC_INIT(Makefile.in) + +AC_PROG_INSTALL +AC_PROG_CC + +# Put a plausible default for CC_FOR_BUILD in Makefile. +if test "x$cross_compiling" = "xno"; then + CC_FOR_BUILD='$(CC)' +else + CC_FOR_BUILD=gcc +fi + + +AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/../..) +AC_CANONICAL_SYSTEM +AC_ARG_PROGRAM + +. ${srcdir}/../../bfd/configure.host + +AC_CONFIG_HEADER(config.h:config.in) + +AC_CHECK_HEADERS(stdlib.h string.h strings.h sys/stat.h sys/types.h unistd.h) +AC_HEADER_DIRENT + +AC_SUBST(CC_FOR_BUILD) +AC_SUBST(CFLAGS) +AR=${AR-ar} +AC_SUBST(AR) +AC_PROG_RANLIB + +AC_OUTPUT(Makefile, +[case x$CONFIG_HEADERS in xconfig.h:config.in) echo > stamp-h ;; esac]) diff --git a/sim/igen/filter.c b/sim/igen/filter.c new file mode 100644 index 0000000000..c901a1777f --- /dev/null +++ b/sim/igen/filter.c @@ -0,0 +1,150 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + + +#include + +#include "config.h" + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif + +#include "misc.h" +#include "filter.h" + +struct _filter { + char *flag; + filter *next; +}; + + +filter * +new_filter(const char *filt, + filter *filters) +{ + while (strlen(filt) > 0) { + filter *new_filter; + /* break up the filt list */ + char *end = strchr(filt, ','); + char *next; + int len; + if (end == NULL) { + end = strchr(filt, '\0'); + next = end; + } + else { + next = end + 1; + } + len = end - filt; + /* add to filter list */ + new_filter = ZALLOC(filter); + new_filter->flag = (char*)zalloc(len + 1); + strncpy(new_filter->flag, filt, len); + new_filter->next = filters; + filters = new_filter; + filt = next; + } + return filters; +} + + +int +is_filtered_out(const char *flags, + filter *filters) +{ + while (strlen(flags) > 0) { + int present; + filter *filt = filters; + /* break the string up */ + char *end = strchr(flags, ','); + char *next; + int len; + if (end == NULL) { + end = strchr(flags, '\0'); + next = end; + } + else { + next = end + 1; + } + len = end - flags; + /* check that it is present */ + present = 0; + filt = filters; + while (filt != NULL) { + if (strncmp(flags, filt->flag, len) == 0 + && strlen(filt->flag) == len) { + present = 1; + break; + } + filt = filt->next; + } + if (!present) + return 1; + flags = next; + } + return 0; +} + + +int +it_is(const char *flag, + const char *flags) +{ + int flag_len = strlen(flag); + while (*flags != '\0') { + if (!strncmp(flags, flag, flag_len) + && (flags[flag_len] == ',' || flags[flag_len] == '\0')) + return 1; + while (*flags != ',') { + if (*flags == '\0') + return 0; + flags++; + } + flags++; + } + return 0; +} + + +#ifdef MAIN +int +main(int argc, char **argv) +{ + filter *filters = NULL; + int i; + if (argc < 2) { + printf("Usage: filter ...\n"); + exit (1); + } + /* load the filter up */ + for (i = 2; i < argc; i++) + filters = new_filter(argv[i], filters); + if (is_filtered_out(argv[1], filters)) + printf("fail\n"); + else + printf("pass\n"); + return 0; +} +#endif diff --git a/sim/igen/filter.h b/sim/igen/filter.h new file mode 100644 index 0000000000..814f704f8d --- /dev/null +++ b/sim/igen/filter.h @@ -0,0 +1,43 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + + +typedef struct _filter filter; + + +/* append the filter onto the end of the list */ + +extern filter *new_filter +(const char *filt, + filter *filters); + + +/* returns true if the flags are non empty and some are missing from the filter list */ + +extern int is_filtered_out +(const char *flags, + filter *filters); + +/* true if the flag is in the list */ + +extern int it_is +(const char *flag, + const char *flags); + diff --git a/sim/igen/filter_host.c b/sim/igen/filter_host.c new file mode 100644 index 0000000000..c15fef15aa --- /dev/null +++ b/sim/igen/filter_host.c @@ -0,0 +1,37 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + +#include "config.h" +#include "filter_host.h" + +/* Shorten traces by eliminating the directory component to filenames. */ +const char * +filter_filename (const char *filename) +{ + const char *p = filename; + const char *last = filename; + int ch; + + while ((ch = *p++) != '\0' && ch != ':') + if (ch == '/') + last = p; + + return last; +} diff --git a/sim/igen/filter_host.h b/sim/igen/filter_host.h new file mode 100644 index 0000000000..a60b4f2d7d --- /dev/null +++ b/sim/igen/filter_host.h @@ -0,0 +1,27 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + +#ifndef _FILTER_FILENAME_H +#define _FILTER_FILENAME_H + +/* Remove directory part from filename */ +extern const char * +filter_filename(const char *filename); +#endif diff --git a/sim/igen/gen-engine.h b/sim/igen/gen-engine.h new file mode 100644 index 0000000000..5b97de2cd1 --- /dev/null +++ b/sim/igen/gen-engine.h @@ -0,0 +1,29 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + +extern void gen_engine_h +(lf *file, + insn_table *table, + cache_table *cache_rules); + +extern void gen_engine_c +(lf *file, + insn_table *table, + cache_table *cache_rules); diff --git a/sim/igen/gen-icache.h b/sim/igen/gen-icache.h new file mode 100644 index 0000000000..c5ba71f7ff --- /dev/null +++ b/sim/igen/gen-icache.h @@ -0,0 +1,68 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + + + +/* Output code to manipulate the instruction cache: either create it + or reference it */ + +typedef enum { + declare_variables, + define_variables, + undef_variables, +} icache_decl_type; + +typedef enum { + do_not_use_icache = 0, + get_values_from_icache = 0x1, + put_values_in_icache = 0x2, + both_values_and_icache = 0x3, +} icache_body_type; + +extern void print_icache_body +(lf *file, + insn *instruction, + insn_bits *expanded_bits, + cache_table *cache_rules, + icache_decl_type what_to_declare, + icache_body_type what_to_do); + + +/* Output an instruction cache decode function */ + +extern insn_handler print_icache_declaration; +extern insn_handler print_icache_definition; + + +/* Output an instruction cache support function */ + +extern function_handler print_icache_internal_function_declaration; +extern function_handler print_icache_internal_function_definition; + + +/* Output the instruction cache table data structure */ + +extern void print_icache_struct +(insn_table *instructions, + cache_table *cache_rules, + lf *file); + + +/* Output a single instructions decoder */ diff --git a/sim/igen/gen-idecode.h b/sim/igen/gen-idecode.h new file mode 100644 index 0000000000..f46376bf9e --- /dev/null +++ b/sim/igen/gen-idecode.h @@ -0,0 +1,40 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + +extern void gen_idecode_h +(lf *file, + insn_table *table, + cache_table *cache_rules); + +extern void gen_idecode_c +(lf *file, + insn_table *table, + cache_table *cache_rules); + + +/* Output code to do any final checks on the decoded instruction. + This includes things like verifying any on decoded fields have the + correct value and checking that (for floating point) floating point + hardware isn't disabled */ + +extern void print_idecode_validate +(lf *file, + insn *instruction, + opcode_field *opcodes); diff --git a/sim/igen/gen-itable.h b/sim/igen/gen-itable.h new file mode 100644 index 0000000000..341dc67854 --- /dev/null +++ b/sim/igen/gen-itable.h @@ -0,0 +1,28 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + + +extern void gen_itable_h +(insn_table *table, + lf *file); + +extern void gen_itable_c +(insn_table *table, + lf *file); diff --git a/sim/igen/gen-model.c b/sim/igen/gen-model.c new file mode 100644 index 0000000000..4ec167717c --- /dev/null +++ b/sim/igen/gen-model.c @@ -0,0 +1,393 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + + +#include "misc.h" +#include "lf.h" +#include "table.h" + +#include "filter.h" + +#include "ld-decode.h" +#include "ld-insn.h" + +#include "gen-model.h" + +#ifndef NULL +#define NULL 0 +#endif + + +static void +model_c_or_h_data(insn_table *table, + lf *file, + table_entry *data) +{ + if (data->annex) { + table_entry_print_cpp_line_nr(file, data); + lf_print__c_code(file, data->annex); + lf_print__internal_reference(file); + lf_printf(file, "\n"); + } +} + +static void +model_c_or_h_function(insn_table *entry, + lf *file, + table_entry *function, + char *prefix) +{ + if (function->fields[function_type] == NULL + || function->fields[function_type][0] == '\0') { + error("Model function type not specified for %s", function->fields[function_name]); + } + lf_printf(file, "\n"); + lf_print_function_type(file, function->fields[function_type], prefix, " "); + lf_printf(file, "%s\n(%s);\n", + function->fields[function_name], + function->fields[function_param]); + lf_printf(file, "\n"); +} + +void +gen_model_h(insn_table *table, lf *file) +{ + insn *insn_ptr; + model *model_ptr; + insn *macro; + char *name; + int model_create_p = 0; + int model_init_p = 0; + int model_halt_p = 0; + int model_mon_info_p = 0; + int model_mon_info_free_p = 0; + + for(macro = model_macros; macro; macro = macro->next) { + model_c_or_h_data(table, file, macro->file_entry); + } + + lf_printf(file, "typedef enum _model_enum {\n"); + lf_printf(file, " MODEL_NONE,\n"); + for (model_ptr = models; model_ptr; model_ptr = model_ptr->next) { + lf_printf(file, " MODEL_%s,\n", model_ptr->name); + } + lf_printf(file, " nr_models\n"); + lf_printf(file, "} model_enum;\n"); + lf_printf(file, "\n"); + + lf_printf(file, "#define DEFAULT_MODEL MODEL_%s\n", (models) ? models->name : "NONE"); + lf_printf(file, "\n"); + + lf_printf(file, "typedef struct _model_data model_data;\n"); + lf_printf(file, "typedef struct _model_time model_time;\n"); + lf_printf(file, "\n"); + + lf_printf(file, "extern model_enum current_model;\n"); + lf_printf(file, "extern const char *model_name[ (int)nr_models ];\n"); + lf_printf(file, "extern const char *const *const model_func_unit_name[ (int)nr_models ];\n"); + lf_printf(file, "extern const model_time *const model_time_mapping[ (int)nr_models ];\n"); + lf_printf(file, "\n"); + + for(insn_ptr = model_functions; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_or_h_function(table, file, insn_ptr->file_entry, "INLINE_MODEL"); + name = insn_ptr->file_entry->fields[function_name]; + if (strcmp (name, "model_create") == 0) + model_create_p = 1; + else if (strcmp (name, "model_init") == 0) + model_init_p = 1; + else if (strcmp (name, "model_halt") == 0) + model_halt_p = 1; + else if (strcmp (name, "model_mon_info") == 0) + model_mon_info_p = 1; + else if (strcmp (name, "model_mon_info_free") == 0) + model_mon_info_free_p = 1; + } + + if (!model_create_p) { + lf_print_function_type(file, "model_data *", "INLINE_MODEL", " "); + lf_printf(file, "model_create\n"); + lf_printf(file, "(cpu *processor);\n"); + lf_printf(file, "\n"); + } + + if (!model_init_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", " "); + lf_printf(file, "model_init\n"); + lf_printf(file, "(model_data *model_ptr);\n"); + lf_printf(file, "\n"); + } + + if (!model_halt_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", " "); + lf_printf(file, "model_halt\n"); + lf_printf(file, "(model_data *model_ptr);\n"); + lf_printf(file, "\n"); + } + + if (!model_mon_info_p) { + lf_print_function_type(file, "model_print *", "INLINE_MODEL", " "); + lf_printf(file, "model_mon_info\n"); + lf_printf(file, "(model_data *model_ptr);\n"); + lf_printf(file, "\n"); + } + + if (!model_mon_info_free_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", " "); + lf_printf(file, "model_mon_info_free\n"); + lf_printf(file, "(model_data *model_ptr,\n"); + lf_printf(file, " model_print *info_ptr);\n"); + lf_printf(file, "\n"); + } + + lf_print_function_type(file, "void", "INLINE_MODEL", " "); + lf_printf(file, "model_set\n"); + lf_printf(file, "(const char *name);\n"); +} + +/****************************************************************/ + +typedef struct _model_c_passed_data model_c_passed_data; +struct _model_c_passed_data { + lf *file; + model *model_ptr; +}; + +static void +model_c_insn(insn_table *entry, + lf *phony_file, + void *data, + insn *instruction, + int depth) +{ + model_c_passed_data *data_ptr = (model_c_passed_data *)data; + lf *file = data_ptr->file; + char *current_name = data_ptr->model_ptr->printable_name; + table_model_entry *model_ptr = instruction->file_entry->model_first; + + while (model_ptr) { + if (model_ptr->fields[insn_model_name] == current_name) { + lf_printf(file, " { %-*s }, /* %s */\n", + max_model_fields_len, + model_ptr->fields[insn_model_fields], + instruction->file_entry->fields[insn_name]); + return; + } + + model_ptr = model_ptr->next; + } + + lf_printf(file, " { %-*s }, /* %s */\n", + max_model_fields_len, + data_ptr->model_ptr->insn_default, + instruction->file_entry->fields[insn_name]); +} + +static void +model_c_function(insn_table *table, + lf *file, + table_entry *function, + const char *prefix) +{ + if (function->fields[function_type] == NULL + || function->fields[function_type][0] == '\0') { + error("Model function return type not specified for %s", function->fields[function_name]); + } + else { + lf_printf(file, "\n"); + lf_print_function_type(file, function->fields[function_type], prefix, "\n"); + lf_printf(file, "%s(%s)\n", + function->fields[function_name], + function->fields[function_param]); + } + table_entry_print_cpp_line_nr(file, function); + lf_printf(file, "{\n"); + if (function->annex) { + lf_indent(file, +2); + lf_print__c_code(file, function->annex); + lf_indent(file, -2); + } + lf_printf(file, "}\n"); + lf_print__internal_reference(file); + lf_printf(file, "\n"); +} + +void +gen_model_c(insn_table *table, lf *file) +{ + insn *insn_ptr; + model *model_ptr; + char *name; + int model_create_p = 0; + int model_init_p = 0; + int model_halt_p = 0; + int model_mon_info_p = 0; + int model_mon_info_free_p = 0; + + lf_printf(file, "\n"); + lf_printf(file, "#include \"cpu.h\"\n"); + lf_printf(file, "#include \"mon.h\"\n"); + lf_printf(file, "\n"); + lf_printf(file, "#ifdef HAVE_STDLIB_H\n"); + lf_printf(file, "#include \n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + + for(insn_ptr = model_data; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_or_h_data(table, file, insn_ptr->file_entry); + } + + for(insn_ptr = model_static; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_or_h_function(table, file, insn_ptr->file_entry, "/*h*/STATIC"); + } + + for(insn_ptr = model_internal; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_or_h_function(table, file, insn_ptr->file_entry, "STATIC_INLINE_MODEL"); + } + + for(insn_ptr = model_static; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_function(table, file, insn_ptr->file_entry, "/*c*/STATIC"); + } + + for(insn_ptr = model_internal; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_function(table, file, insn_ptr->file_entry, "STATIC_INLINE_MODEL"); + } + + for(insn_ptr = model_functions; insn_ptr; insn_ptr = insn_ptr->next) { + model_c_function(table, file, insn_ptr->file_entry, "INLINE_MODEL"); + name = insn_ptr->file_entry->fields[function_name]; + if (strcmp (name, "model_create") == 0) + model_create_p = 1; + else if (strcmp (name, "model_init") == 0) + model_init_p = 1; + else if (strcmp (name, "model_halt") == 0) + model_halt_p = 1; + else if (strcmp (name, "model_mon_info") == 0) + model_mon_info_p = 1; + else if (strcmp (name, "model_mon_info_free") == 0) + model_mon_info_free_p = 1; + } + + if (!model_create_p) { + lf_print_function_type(file, "model_data *", "INLINE_MODEL", "\n"); + lf_printf(file, "model_create(cpu *processor)\n"); + lf_printf(file, "{\n"); + lf_printf(file, " return (model_data *)0;\n"); + lf_printf(file, "}\n"); + lf_printf(file, "\n"); + } + + if (!model_init_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); + lf_printf(file, "model_init(model_data *model_ptr)\n"); + lf_printf(file, "{\n"); + lf_printf(file, "}\n"); + lf_printf(file, "\n"); + } + + if (!model_halt_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); + lf_printf(file, "model_halt(model_data *model_ptr)\n"); + lf_printf(file, "{\n"); + lf_printf(file, "}\n"); + lf_printf(file, "\n"); + } + + if (!model_mon_info_p) { + lf_print_function_type(file, "model_print *", "INLINE_MODEL", "\n"); + lf_printf(file, "model_mon_info(model_data *model_ptr)\n"); + lf_printf(file, "{\n"); + lf_printf(file, " return (model_print *)0;\n"); + lf_printf(file, "}\n"); + lf_printf(file, "\n"); + } + + if (!model_mon_info_free_p) { + lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); + lf_printf(file, "model_mon_info_free(model_data *model_ptr,\n"); + lf_printf(file, " model_print *info_ptr)\n"); + lf_printf(file, "{\n"); + lf_printf(file, "}\n"); + lf_printf(file, "\n"); + } + + lf_printf(file, "/* Insn functional unit info */\n"); + for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { + model_c_passed_data data; + + lf_printf(file, "static const model_time model_time_%s[] = {\n", model_ptr->name); + data.file = file; + data.model_ptr = model_ptr; + insn_table_traverse_insn(table, + NULL, (void *)&data, + model_c_insn); + + lf_printf(file, "};\n"); + lf_printf(file, "\n"); + lf_printf(file, "\f\n"); + } + + lf_printf(file, "#ifndef _INLINE_C_\n"); + lf_printf(file, "const model_time *const model_time_mapping[ (int)nr_models ] = {\n"); + lf_printf(file, " (const model_time *const)0,\n"); + for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { + lf_printf(file, " model_time_%s,\n", model_ptr->name); + } + lf_printf(file, "};\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + + lf_printf(file, "\f\n"); + lf_printf(file, "/* map model enumeration into printable string */\n"); + lf_printf(file, "#ifndef _INLINE_C_\n"); + lf_printf(file, "const char *model_name[ (int)nr_models ] = {\n"); + lf_printf(file, " \"NONE\",\n"); + for (model_ptr = models; model_ptr; model_ptr = model_ptr->next) { + lf_printf(file, " \"%s\",\n", model_ptr->printable_name); + } + lf_printf(file, "};\n"); + lf_printf(file, "#endif\n"); + lf_printf(file, "\n"); + + lf_print_function_type(file, "void", "INLINE_MODEL", "\n"); + lf_printf(file, "model_set(const char *name)\n"); + lf_printf(file, "{\n"); + if (models) { + lf_printf(file, " model_enum model;\n"); + lf_printf(file, " for(model = MODEL_%s; model < nr_models; model++) {\n", models->name); + lf_printf(file, " if(strcmp(name, model_name[model]) == 0) {\n"); + lf_printf(file, " current_model = model;\n"); + lf_printf(file, " return;\n"); + lf_printf(file, " }\n"); + lf_printf(file, " }\n"); + lf_printf(file, "\n"); + lf_printf(file, " error(\"Unknown model '%%s', Models which are known are:%%s\n\",\n"); + lf_printf(file, " name,\n"); + lf_printf(file, " \""); + for(model_ptr = models; model_ptr; model_ptr = model_ptr->next) { + lf_printf(file, "\\n\\t%s", model_ptr->printable_name); + } + lf_printf(file, "\");\n"); + } else { + lf_printf(file, " error(\"No models are currently known about\");\n"); + } + + lf_printf(file, "}\n"); +} + diff --git a/sim/igen/gen-model.h b/sim/igen/gen-model.h new file mode 100644 index 0000000000..b465a75abf --- /dev/null +++ b/sim/igen/gen-model.h @@ -0,0 +1,30 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + + + +extern void gen_model_h +(insn_table *table, + lf *file); + + +extern void gen_model_c +(insn_table *table, + lf *file); diff --git a/sim/igen/gen-semantics.h b/sim/igen/gen-semantics.h new file mode 100644 index 0000000000..2c25715f7c --- /dev/null +++ b/sim/igen/gen-semantics.h @@ -0,0 +1,81 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + + +/* Creates the files semantics.[hc]. + + The generated file semantics contains functions that implement the + operations required to model a single target processor instruction. + + Several different variations on the semantics file can be created: + + o uncached + + No instruction cache exists. The semantic function + needs to generate any required values locally. + + o cached - separate cracker and semantic + + Two independant functions are created. Firstly the + function that cracks an instruction entering it into a + cache and secondly the semantic function propper that + uses the cache. + + o cached - semantic + cracking semantic + + The function that cracks the instruction and enters + all values into the cache also contains a copy of the + semantic code (avoiding the need to call both the + cracker and the semantic function when there is a + cache miss). + + For each of these general forms, several refinements can occure: + + o do/don't duplicate/expand semantic functions + + As a consequence of decoding an instruction, the + decoder, as part of its table may have effectivly made + certain of the variable fields in an instruction + constant. Separate functions for each of the + alternative values for what would have been treated as + a variable part can be created. + + o use cache struct directly. + + When a cracking cache is present, the semantic + functions can be generated to either hold intermediate + cache values in local variables or always refer to the + contents of the cache directly. */ + + + +extern insn_handler print_semantic_declaration; +extern insn_handler print_semantic_definition; + +extern void print_idecode_illegal +(lf *file, + const char *result); + +extern void print_semantic_body +(lf *file, + insn *instruction, + insn_bits *expanded_bits, + opcode_field *opcodes); + diff --git a/sim/igen/gen-support.h b/sim/igen/gen-support.h new file mode 100644 index 0000000000..70862d7688 --- /dev/null +++ b/sim/igen/gen-support.h @@ -0,0 +1,29 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + + +extern void gen_support_h +(insn_table *table, + lf *file); + +extern void gen_support_c +(insn_table *table, + lf *file); + diff --git a/sim/igen/ld-cache.c b/sim/igen/ld-cache.c new file mode 100644 index 0000000000..e7f119e057 --- /dev/null +++ b/sim/igen/ld-cache.c @@ -0,0 +1,115 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, Andrew Cagney + + 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 of the License, 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. + + */ + + +#include "misc.h" +#include "lf.h" +#include "table.h" +#include "ld-cache.h" + +#ifndef NULL +#define NULL 0 +#endif + + +enum { + ca_type, + ca_field_name, + ca_derived_name, + ca_type_def, + ca_expression, + nr_cache_rule_fields, +}; + +static const name_map cache_type_map[] = { + { "cache", cache_value }, + { "compute", compute_value }, + { "scratch", scratch_value }, + { NULL, 0 }, +}; + + +cache_table * +load_cache_table(char *file_name, + int hi_bit_nr) +{ + table *file = table_open(file_name, nr_cache_rule_fields, 0); + table_entry *entry; + cache_table *table = NULL; + cache_table **curr_rule = &table; + while ((entry = table_entry_read(file)) != NULL) { + cache_table *new_rule = ZALLOC(cache_table); + new_rule->type = name2i(entry->fields[ca_type], cache_type_map); + new_rule->field_name = entry->fields[ca_field_name]; + new_rule->derived_name = entry->fields[ca_derived_name]; + new_rule->type_def = (strlen(entry->fields[ca_type_def]) + ? entry->fields[ca_type_def] + : NULL); + new_rule->expression = (strlen(entry->fields[ca_expression]) > 0 + ? entry->fields[ca_expression] + : NULL); + new_rule->file_entry = entry; + *curr_rule = new_rule; + curr_rule = &new_rule->next; + } + return table; +} + + + +#ifdef MAIN + +static void +dump_cache_rule(cache_table* rule, + int indent) +{ + dumpf(indent, "((cache_table*)0x%x\n", rule); + dumpf(indent, " (type %s)\n", i2name(rule->type, cache_type_map)); + dumpf(indent, " (field_name \"%s\")\n", rule->field_name); + dumpf(indent, " (derived_name \"%s\")\n", rule->derived_name); + dumpf(indent, " (type-def \"%s\")\n", rule->type_def); + dumpf(indent, " (expression \"%s\")\n", rule->expression); + dumpf(indent, " (next 0x%x)\n", rule->next); + dumpf(indent, " )\n"); +} + + +static void +dump_cache_rules(cache_table* rule, + int indent) +{ + while (rule) { + dump_cache_rule(rule, indent); + rule = rule->next; + } +} + + +int +main(int argc, char **argv) +{ + cache_table *rules; + if (argc != 3) + error("Usage: cache \n"); + rules = load_cache_table(argv[1], a2i(argv[2])); + dump_cache_rules(rules, 0); + return 0; +} +#endif diff --git a/sim/igen/ld-cache.h b/sim/igen/ld-cache.h new file mode 100644 index 0000000000..fe9387b0ab --- /dev/null +++ b/sim/igen/ld-cache.h @@ -0,0 +1,81 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, Andrew Cagney + + 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 of the License, 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. + + */ + +/* Instruction unpacking: + + Once the instruction has been decoded, the register (and other) + fields within the instruction need to be extracted. + + The table that follows determines how each field should be treated. + Importantly it considers the case where the extracted field is to + be used immediatly or stored in an instruction cache. + + + + Indicates what to do with the cache entry. If a cache is to be + used. SCRATCH and CACHE values are defined when a cache entry is + being filled while CACHE and COMPUTE values are defined in the + semantic code. + + Zero marks the end of the table. More importantly 1. indicates + that the entry is valid and can be cached. 2. indicates that that + the entry is valid but can not be cached. + + + + The field name as given in the instruction spec. + + + + A new name for once it has been extracted from the + instruction (and possibly stored in the instruction cache). + + + + String specifying the storage type for (the extracted + field>. + + + + Specifies how to get from . If null, old and + new name had better be the same. */ + + +typedef enum { + scratch_value, + cache_value, + compute_value, +} cache_rule_type; + +typedef struct _cache_table cache_table; +struct _cache_table { + cache_rule_type type; + char *field_name; + char *derived_name; + char *type_def; + char *expression; + table_entry *file_entry; + cache_table *next; +}; + + +extern cache_table *load_cache_table +(char *file_name, + int hi_bit_nr); diff --git a/sim/igen/ld-decode.c b/sim/igen/ld-decode.c new file mode 100644 index 0000000000..e0be0c3de1 --- /dev/null +++ b/sim/igen/ld-decode.c @@ -0,0 +1,155 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, Andrew Cagney + + 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 of the License, 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. + + */ + +/* load the opcode stat structure */ + +#include "misc.h" +#include "lf.h" +#include "table.h" +#include "ld-decode.h" + +#ifndef NULL +#define NULL 0 +#endif + +enum { + op_options, + op_first, + op_last, + op_force_first, + op_force_last, + op_force_expansion, + op_special_mask, + op_special_value, + op_special_constant, + nr_decode_fields, +}; + +static const name_map decode_type_map[] = { + { "normal", normal_decode_rule }, + { "expand-forced", expand_forced_rule }, + { "boolean", boolean_rule }, + { NULL, normal_decode_rule }, +}; + +static const name_map decode_gen_map[] = { + { "array", array_gen }, + { "switch", switch_gen }, + { "padded-switch", padded_switch_gen }, + { "goto-switch", goto_switch_gen }, + { NULL, -1 }, +}; + +static const name_map decode_slash_map[] = { + { "variable-slash", 0 }, + { "constant-slash", 1 }, + { NULL }, +}; + + +static decode_gen_type overriding_gen_type = invalid_gen; + +void +force_decode_gen_type(const char *type) +{ + overriding_gen_type = name2i(type, decode_gen_map); +} + + +decode_table * +load_decode_table(char *file_name, + int hi_bit_nr) +{ + table *file = table_open(file_name, nr_decode_fields, 0); + table_entry *entry; + decode_table *table = NULL; + decode_table **curr_rule = &table; + while ((entry = table_entry_read(file)) != NULL) { + decode_table *new_rule = ZALLOC(decode_table); + new_rule->type = name2i(entry->fields[op_options], decode_type_map); + new_rule->gen = (overriding_gen_type != invalid_gen + ? overriding_gen_type + : name2i(entry->fields[op_options], decode_gen_map)); + new_rule->force_slash = name2i(entry->fields[op_options], decode_slash_map); + new_rule->first = target_a2i(hi_bit_nr, entry->fields[op_first]); + new_rule->last = target_a2i(hi_bit_nr, entry->fields[op_last]); + new_rule->force_first = (strlen(entry->fields[op_force_first]) + ? target_a2i(hi_bit_nr, entry->fields[op_force_first]) + : new_rule->last + 1); + new_rule->force_last = (strlen(entry->fields[op_force_last]) + ? target_a2i(hi_bit_nr, entry->fields[op_force_last]) + : new_rule->first - 1); + new_rule->force_expansion = entry->fields[op_force_expansion]; + new_rule->special_mask = a2i(entry->fields[op_special_mask]); + new_rule->special_value = a2i(entry->fields[op_special_value]); + new_rule->special_constant = a2i(entry->fields[op_special_constant]); + *curr_rule = new_rule; + curr_rule = &new_rule->next; + } + return table; +} + + +void +dump_decode_rule(decode_table *rule, + int indent) +{ + dumpf(indent, "((decode_table*)%p\n", rule); + if (rule) { + dumpf(indent, " (type %s)\n", i2name(rule->type, decode_type_map)); + dumpf(indent, " (gen %s)\n", i2name(rule->gen, decode_gen_map)); + dumpf(indent, " (force_slash %d)\n", rule->force_slash); + dumpf(indent, " (first %d)\n", rule->first); + dumpf(indent, " (last %d)\n", rule->last); + dumpf(indent, " (force_first %d)\n", rule->force_first); + dumpf(indent, " (force_last %d)\n", rule->force_last); + dumpf(indent, " (force_expansion \"%s\")\n", rule->force_expansion); + dumpf(indent, " (special_mask 0x%x)\n", rule->special_mask); + dumpf(indent, " (special_value 0x%x)\n", rule->special_value); + dumpf(indent, " (special_constant 0x%x)\n", rule->special_constant); + dumpf(indent, " (next 0x%x)\n", rule->next); + } + dumpf(indent, " )\n"); +} + + +#ifdef MAIN + +static void +dump_decode_rules(decode_table *rule, + int indent) +{ + while (rule) { + dump_decode_rule(rule, indent); + rule = rule->next; + } +} + +int +main(int argc, char **argv) +{ + decode_table *rules; + if (argc != 3) + error("Usage: decode \n"); + rules = load_decode_table(argv[1], a2i(argv[2])); + dump_decode_rules(rules, 0); + return 0; +} +#endif diff --git a/sim/igen/ld-decode.h b/sim/igen/ld-decode.h new file mode 100644 index 0000000000..de23181ba3 --- /dev/null +++ b/sim/igen/ld-decode.h @@ -0,0 +1,143 @@ +/* This file is part of the program psim. + + Copyright (C) 1994,1995,1996, Andrew Cagney + + 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 of the License, 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. + + */ + +/* Instruction decode table: + + ::::::... + + + + Ignore the below: + + + The instruction decode table contains rules that dictate how igen + is going to firstly break down the opcode table and secondly + + The table that follows is used by gen to construct a decision tree + that can identify each possible instruction. Gen then outputs this + decision tree as (according to config) a table or switch statement + as the function idecode. + + In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS + determines of the semantic functions themselves should be expanded + in a similar way. + + + + + Range of bits (within the instruction) that should be searched for + an instruction field. Within such ranges, gen looks for opcodes + (constants), registers (strings) and reserved bits (slash) and + according to the rules that follows includes or excludes them from + a possible instruction field. + + + + + If an instruction field was found, enlarge the field size so that + it is forced to at least include bits starting from + (). To stop this occuring, use = + + 1 and = - 1. + + + + Treat `/' fields as a constant instead of variable when looking for + an instruction field. + + + + Treat any contained register (string) fields as constant when + determining the instruction field. For the instruction decode (and + controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of + what would otherwize be non constant bits of an instruction. + + + + Should this table be expanded using a switch statement (val 1) and + if so, should it be padded with entries so as to force the compiler + to generate a jump table (val 2). Or a branch table (val 3). + + + + + + + Special rule to fine tune how specific (or groups) of instructions + are expanded. The applicability of the rule is determined by + + != 0 && (instruction> & ) == + + Where is obtained by looking only at constant fields + with in an instructions spec. When determining an expansion, the + rule is only considered when a node contains a single instruction. + can be any of: + + 0: for this instruction, expand by earlier rules + 1: expand bits .. only + 2: boolean expansion of only zero/non-zero cases + 3: boolean expansion of equality of special constant + + */ + + +typedef enum { + normal_decode_rule, + expand_forced_rule, + boolean_rule, + nr_decode_rules +} decode_special_type; + +typedef enum { + invalid_gen, + array_gen, + switch_gen, + padded_switch_gen, + goto_switch_gen, + nr_decode_gen_types, +} decode_gen_type; + + +typedef struct _decode_table decode_table; +struct _decode_table { + decode_special_type type; + decode_gen_type gen; + int first; + int last; + int force_first; + int force_last; + int force_slash; + char *force_expansion; + unsigned special_mask; + unsigned special_value; + unsigned special_constant; + decode_table *next; +}; + + +extern void force_decode_gen_type +(const char *type); + +extern decode_table *load_decode_table +(char *file_name, + int hi_bit_nr); + +extern void dump_decode_rule +(decode_table *rule, + int indent); diff --git a/sim/igen/misc.c b/sim/igen/misc.c new file mode 100644 index 0000000000..660570ca6a --- /dev/null +++ b/sim/igen/misc.c @@ -0,0 +1,226 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + + +#include +#include +#include + +#include "config.h" +#include "misc.h" + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif + +void +error (char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + vprintf(msg, ap); + va_end(ap); + exit (1); +} + +void * +zalloc(long size) +{ + void *memory = malloc(size); + if (memory == NULL) + error("zalloc failed\n"); + memset(memory, 0, size); + return memory; +} + +void +dumpf (int indent, char *msg, ...) +{ + va_list ap; + for (; indent > 0; indent--) + printf(" "); + va_start(ap, msg); + vprintf(msg, ap); + va_end(ap); +} + + +unsigned long long +a2i(const char *a) +{ + int neg = 0; + int base = 10; + unsigned long long num = 0; + int looping; + + while (isspace (*a)) + a++; + + if (*a == '-') { + neg = 1; + a++; + } + + if (*a == '0') { + if (a[1] == 'x' || a[1] == 'X') { + a += 2; + base = 16; + } else if (a[1] == 'b' || a[1] == 'b') { + a += 2; + base = 2; + } + else + base = 8; + } + + looping = 1; + while (looping) { + int ch = *a++; + + switch (base) { + default: + looping = 0; + break; + + case 2: + if (ch >= '0' && ch <= '1') { + num = (num * 2) + (ch - '0'); + } else { + looping = 0; + } + break; + + case 10: + if (ch >= '0' && ch <= '9') { + num = (num * 10) + (ch - '0'); + } else { + looping = 0; + } + break; + + case 8: + if (ch >= '0' && ch <= '7') { + num = (num * 8) + (ch - '0'); + } else { + looping = 0; + } + break; + + case 16: + if (ch >= '0' && ch <= '9') { + num = (num * 16) + (ch - '0'); + } else if (ch >= 'a' && ch <= 'f') { + num = (num * 16) + (ch - 'a' + 10); + } else if (ch >= 'A' && ch <= 'F') { + num = (num * 16) + (ch - 'A' + 10); + } else { + looping = 0; + } + break; + } + } + + if (neg) + num = - num; + + return num; +} + +unsigned +target_a2i(int ms_bit_nr, + const char *a) +{ + if (ms_bit_nr) + return (ms_bit_nr - a2i(a)); + else + return a2i(a); +} + +unsigned +i2target(int ms_bit_nr, + unsigned bit) +{ + if (ms_bit_nr) + return ms_bit_nr - bit; + else + return bit; +} + + +int +name2i(const char *names, + const name_map *map) +{ + const name_map *curr; + const char *name = names; + while (*name != '\0') { + /* find our name */ + char *end = strchr(name, ','); + char *next; + int len; + if (end == NULL) { + end = strchr(name, '\0'); + next = end; + } + else { + next = end + 1; + } + len = end - name; + /* look it up */ + curr = map; + while (curr->name != NULL) { + if (strncmp(curr->name, name, len) == 0 + && strlen(curr->name) == len) + return curr->i; + curr++; + } + name = next; + } + /* nothing found, possibly return a default */ + curr = map; + while (curr->name != NULL) + curr++; + if (curr->i >= 0) + return curr->i; + else + error("%s contains no valid names\n", names); + return 0; +} + +const char * +i2name(const int i, + const name_map *map) +{ + while (map->name != NULL) { + if (map->i == i) + return map->name; + map++; + } + error("map lookup failed for %d\n", i); + return NULL; +} diff --git a/sim/igen/misc.h b/sim/igen/misc.h new file mode 100644 index 0000000000..60351b4419 --- /dev/null +++ b/sim/igen/misc.h @@ -0,0 +1,94 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 of the License, 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. + + */ + + +/* Frustrating header junk */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#if !defined (__attribute__) && (!defined(__GNUC__) || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)) +#define __attribute__(arg) +#endif + + + +#include "filter_host.h" + +extern void error +(char *msg, ...); + +#define ASSERT(EXPRESSION) \ +do { \ + if (!(EXPRESSION)) { \ + error("%s:%d: assertion failed - %s\n", \ + filter_filename (__FILE__), __LINE__, #EXPRESSION); \ + } \ +} while (0) + +#define ZALLOC(TYPE) (TYPE*)zalloc(sizeof(TYPE)) + +extern void *zalloc +(long size); + +extern void dumpf +(int indent, char *msg, ...); + +extern unsigned target_a2i +(int ms_bit_nr, + const char *a); + +extern unsigned i2target +(int ms_bit_nr, + unsigned bit); + +extern unsigned long long a2i +(const char *a); + +/* Try looking for name in the map table (returning the corresponding + integer value). If that fails, try converting the name into an + integer */ + +typedef struct _name_map { + const char *name; + int i; +} name_map; + +extern int name2i +(const char *name, + const name_map *map); + +extern const char *i2name +(const int i, + const name_map *map); -- 2.34.1