Instruction decode generator taken from the PowerPC simulator

and being made more generic.
This commit is contained in:
Andrew Cagney 1997-02-21 02:49:21 +00:00
parent 317df3b530
commit a4c97499d9
21 changed files with 2009 additions and 0 deletions

175
sim/igen/Makefile.in Normal file
View File

@ -0,0 +1,175 @@
#
# This file is part of the program psim.
#
# Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
# 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:
#

31
sim/igen/config.in Normal file
View File

@ -0,0 +1,31 @@
/* config.in. Generated automatically from configure.in by autoheader. */
/* Define if you have the <dirent.h> header file. */
#undef HAVE_DIRENT_H
/* Define if you have the <ndir.h> header file. */
#undef HAVE_NDIR_H
/* Define if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define if you have the <sys/dir.h> header file. */
#undef HAVE_SYS_DIR_H
/* Define if you have the <sys/ndir.h> header file. */
#undef HAVE_SYS_NDIR_H
/* Define if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H

34
sim/igen/configure.in Normal file
View File

@ -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])

150
sim/igen/filter.c Normal file
View File

@ -0,0 +1,150 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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 <stdio.h>
#include "config.h"
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#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 <flags> <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

43
sim/igen/filter.h Normal file
View File

@ -0,0 +1,43 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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);

37
sim/igen/filter_host.c Normal file
View File

@ -0,0 +1,37 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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;
}

27
sim/igen/filter_host.h Normal file
View File

@ -0,0 +1,27 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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

29
sim/igen/gen-engine.h Normal file
View File

@ -0,0 +1,29 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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);

68
sim/igen/gen-icache.h Normal file
View File

@ -0,0 +1,68 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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 */

40
sim/igen/gen-idecode.h Normal file
View File

@ -0,0 +1,40 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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);

28
sim/igen/gen-itable.h Normal file
View File

@ -0,0 +1,28 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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);

393
sim/igen/gen-model.c Normal file
View File

@ -0,0 +1,393 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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 <stdlib.h>\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");
}

30
sim/igen/gen-model.h Normal file
View File

@ -0,0 +1,30 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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);

81
sim/igen/gen-semantics.h Normal file
View File

@ -0,0 +1,81 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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);

29
sim/igen/gen-support.h Normal file
View File

@ -0,0 +1,29 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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);

115
sim/igen/ld-cache.c Normal file
View File

@ -0,0 +1,115 @@
/* This file is part of the program psim.
Copyright (C) 1994,1995,1996, Andrew Cagney <cagney@highland.com.au>
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 <cache-file> <hi-bit-nr>\n");
rules = load_cache_table(argv[1], a2i(argv[2]));
dump_cache_rules(rules, 0);
return 0;
}
#endif

81
sim/igen/ld-cache.h Normal file
View File

@ -0,0 +1,81 @@
/* This file is part of the program psim.
Copyright (C) 1994,1995,1996, Andrew Cagney <cagney@highland.com.au>
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.
<type>
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.
<field_name>
The field name as given in the instruction spec.
<derived_name>
A new name for <field_name> once it has been extracted from the
instruction (and possibly stored in the instruction cache).
<type>
String specifying the storage type for <new_name> (the extracted
field>.
<expression>
Specifies how to get <new_name> from <old_name>. 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);

155
sim/igen/ld-decode.c Normal file
View File

@ -0,0 +1,155 @@
/* This file is part of the program psim.
Copyright (C) 1994,1995,1996, Andrew Cagney <cagney@highland.com.au>
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 <decode-file> <hi-bit-nr>\n");
rules = load_decode_table(argv[1], a2i(argv[2]));
dump_decode_rules(rules, 0);
return 0;
}
#endif

143
sim/igen/ld-decode.h Normal file
View File

@ -0,0 +1,143 @@
/* This file is part of the program psim.
Copyright (C) 1994,1995,1996, Andrew Cagney <cagney@highland.com.au>
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:
<options>:<first>:<last>:<force-first>:<force-last>:<force-expand>:<special>...
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.
<first>
<last>
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.
<force_first>
<force_last>
If an instruction field was found, enlarge the field size so that
it is forced to at least include bits starting from <force_first>
(<force_last>). To stop this occuring, use <force_first> = <last>
+ 1 and <force_last> = <first> - 1.
<force_slash>
Treat `/' fields as a constant instead of variable when looking for
an instruction field.
<force_expansion>
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.
<use_switch>
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_mask>
<special_value>
<special_rule>
<special_constant>
Special rule to fine tune how specific (or groups) of instructions
are expanded. The applicability of the rule is determined by
<special_mask> != 0 && (instruction> & <special_mask>) == <special_value>
Where <instruction> 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.
<special_rule> can be any of:
0: for this instruction, expand by earlier rules
1: expand bits <force_low> .. <force_hi> 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);

226
sim/igen/misc.c Normal file
View File

@ -0,0 +1,226 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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 <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include "config.h"
#include "misc.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#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;
}

94
sim/igen/misc.h Normal file
View File

@ -0,0 +1,94 @@
/* This file is part of the program psim.
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
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 <stdio.h>
#include <ctype.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#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);